From efc84fbb9756d28ce9be03359104a4e7f0ef70a3 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 23 Apr 2026 21:37:43 +0800 Subject: [PATCH] feat(doc): add yao doc CLI commands and YAML documentation for all packages Implement yao doc process list/inspect/validate and yao doc runtime list/inspect/validate commands. Validate uses engine addressing logic (process.Of) and checks dynamic-ID group registries (model, store, fs, task, schedule) to verify resources actually exist. - cmd/doc/: CLI command tree with process and runtime subcommands - cmd/root.go: wire docCmd into rootCmd - 27 process doc.yml + doc.go pairs across yao packages - cmd/doc/doc_test.go: integration tests Made-with: Cursor --- agent/caller/doc.go | 11 + agent/caller/doc.yml | 13 + agent/llm/doc.go | 11 + agent/llm/doc.yml | 25 ++ agent/robot/doc.go | 11 + agent/robot/doc.yml | 80 ++++ attachment/doc.go | 11 + attachment/doc.yml | 177 +++++++++ cmd/doc/doc.go | 74 ++++ cmd/doc/doc_test.go | 345 +++++++++++++++++ cmd/doc/process.go | 298 ++++++++++++++ cmd/doc/runtime.go | 182 +++++++++ cmd/root.go | 18 + crypto/doc.go | 11 + crypto/doc.yml | 171 ++++++++ engine/doc.go | 11 + engine/doc.yml | 92 +++++ excel/doc.go | 12 + excel/doc.yml | 678 ++++++++++++++++++++++++++++++++ helper/doc.go | 12 + helper/doc.yml | 473 +++++++++++++++++++++++ openai/doc.go | 12 + openai/doc.yml | 97 +++++ openapi/job/doc.go | 12 + openapi/job/doc.yml | 166 ++++++++ openapi/kb/doc.go | 12 + openapi/kb/doc.yml | 118 ++++++ openapi/oauth/doc.go | 12 + openapi/oauth/doc.yml | 48 +++ openapi/otp/doc.go | 12 + openapi/otp/doc.yml | 50 +++ openapi/user/doc.go | 12 + openapi/user/doc.yml | 264 +++++++++++++ pipe/doc.go | 17 + pipe/doc.yml | 96 +++++ pipe/doc_pipes.yml | 13 + rss/doc.go | 11 + rss/doc.yml | 66 ++++ seed/doc.go | 12 + seed/doc.yml | 21 + sitemap/doc.go | 11 + sitemap/doc.yml | 103 +++++ sui/api/doc.go | 11 + sui/api/doc.yml | 772 +++++++++++++++++++++++++++++++++++++ utils/doc.go | 11 + utils/doc.yml | 377 ++++++++++++++++++ widgets/app/doc.go | 11 + widgets/app/doc.yml | 84 ++++ widgets/chart/doc.go | 11 + widgets/chart/doc.yml | 62 +++ widgets/component/doc.go | 11 + widgets/component/doc.yml | 24 ++ widgets/dashboard/doc.go | 11 + widgets/dashboard/doc.yml | 62 +++ widgets/doc.go | 11 + widgets/doc.yml | 37 ++ widgets/expression/doc.go | 11 + widgets/expression/doc.yml | 32 ++ widgets/login/doc.go | 11 + widgets/login/doc.yml | 14 + 60 files changed, 5444 insertions(+) create mode 100644 agent/caller/doc.go create mode 100644 agent/caller/doc.yml create mode 100644 agent/llm/doc.go create mode 100644 agent/llm/doc.yml create mode 100644 agent/robot/doc.go create mode 100644 agent/robot/doc.yml create mode 100644 attachment/doc.go create mode 100644 attachment/doc.yml create mode 100644 cmd/doc/doc.go create mode 100644 cmd/doc/doc_test.go create mode 100644 cmd/doc/process.go create mode 100644 cmd/doc/runtime.go create mode 100644 crypto/doc.go create mode 100644 crypto/doc.yml create mode 100644 engine/doc.go create mode 100644 engine/doc.yml create mode 100644 excel/doc.go create mode 100644 excel/doc.yml create mode 100644 helper/doc.go create mode 100644 helper/doc.yml create mode 100644 openai/doc.go create mode 100644 openai/doc.yml create mode 100644 openapi/job/doc.go create mode 100644 openapi/job/doc.yml create mode 100644 openapi/kb/doc.go create mode 100644 openapi/kb/doc.yml create mode 100644 openapi/oauth/doc.go create mode 100644 openapi/oauth/doc.yml create mode 100644 openapi/otp/doc.go create mode 100644 openapi/otp/doc.yml create mode 100644 openapi/user/doc.go create mode 100644 openapi/user/doc.yml create mode 100644 pipe/doc.go create mode 100644 pipe/doc.yml create mode 100644 pipe/doc_pipes.yml create mode 100644 rss/doc.go create mode 100644 rss/doc.yml create mode 100644 seed/doc.go create mode 100644 seed/doc.yml create mode 100644 sitemap/doc.go create mode 100644 sitemap/doc.yml create mode 100644 sui/api/doc.go create mode 100644 sui/api/doc.yml create mode 100644 utils/doc.go create mode 100644 utils/doc.yml create mode 100644 widgets/app/doc.go create mode 100644 widgets/app/doc.yml create mode 100644 widgets/chart/doc.go create mode 100644 widgets/chart/doc.yml create mode 100644 widgets/component/doc.go create mode 100644 widgets/component/doc.yml create mode 100644 widgets/dashboard/doc.go create mode 100644 widgets/dashboard/doc.yml create mode 100644 widgets/doc.go create mode 100644 widgets/doc.yml create mode 100644 widgets/expression/doc.go create mode 100644 widgets/expression/doc.yml create mode 100644 widgets/login/doc.go create mode 100644 widgets/login/doc.yml diff --git a/agent/caller/doc.go b/agent/caller/doc.go new file mode 100644 index 00000000..d1468ecf --- /dev/null +++ b/agent/caller/doc.go @@ -0,0 +1,11 @@ +package caller + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/agent/caller/doc.yml b/agent/caller/doc.yml new file mode 100644 index 00000000..bcdca4d4 --- /dev/null +++ b/agent/caller/doc.yml @@ -0,0 +1,13 @@ +group: agent +type: process +entries: + - name: Call + desc: Call an agent from contexts without agent.Context, enabling agent-to-agent communication + args: + - name: request + type: object + required: true + desc: "Request object with fields: assistant_id (string, required), messages (array of message objects, required), model (string, connector override), skip (object, skip config), metadata (object, passed to hooks), locale (string), route (string), chat_id (string, auto-generated if empty), timeout (number, seconds, default 600)" + return: + type: object + desc: "Result object: { agent_id (string), response (object, full agent response), content (string, extracted text), error (string, error message if failed) }" diff --git a/agent/llm/doc.go b/agent/llm/doc.go new file mode 100644 index 00000000..ace76e42 --- /dev/null +++ b/agent/llm/doc.go @@ -0,0 +1,11 @@ +package llm + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/agent/llm/doc.yml b/agent/llm/doc.yml new file mode 100644 index 00000000..a938bbba --- /dev/null +++ b/agent/llm/doc.yml @@ -0,0 +1,25 @@ +group: llm +type: process +entries: + - name: ChatCompletions + desc: Universal LLM chat completions that auto-detects connector type and routes accordingly + args: + - name: connector + type: string + required: true + desc: Connector ID (supports any type, e.g. openai, anthropic) + - name: messages + type: array + required: true + desc: "Message array in OpenAI format: each element is an object with role, content (string or multimodal array), and optional name, tool_call_id, tool_calls" + - name: opts + type: object + required: false + desc: "Completion options: temperature, max_tokens, and other model parameters" + - name: callback + type: function + required: false + desc: "Streaming callback function that receives data chunks; signature: func(data []byte) int" + return: + type: object + desc: "OpenAI-compatible response: { id, object, created, model, choices: [{ index, message: { role, content, tool_calls? }, finish_reason }], usage? }" diff --git a/agent/robot/doc.go b/agent/robot/doc.go new file mode 100644 index 00000000..ce9692b4 --- /dev/null +++ b/agent/robot/doc.go @@ -0,0 +1,11 @@ +package robot + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/agent/robot/doc.yml b/agent/robot/doc.yml new file mode 100644 index 00000000..01774805 --- /dev/null +++ b/agent/robot/doc.yml @@ -0,0 +1,80 @@ +group: robot +type: process +entries: + - name: get + desc: Get a robot's details by member ID + args: + - name: memberID + type: string + required: true + desc: The member ID of the robot to retrieve + return: + type: object + desc: Robot detail object + + - name: list + desc: List all robots with optional filtering and pagination + args: + - name: filter + type: object + required: false + desc: "Filter options: page (number), pagesize (number), status (string), search (string, keywords), team_id (string)" + return: + type: object + desc: Paginated list of robots + + - name: status + desc: Get the current status of a robot by member ID + args: + - name: memberID + type: string + required: true + desc: The member ID of the robot + return: + type: object + desc: Robot status object + + - name: executions + desc: List executions for a robot with optional filtering and pagination + args: + - name: memberID + type: string + required: true + desc: The member ID of the robot + - name: filter + type: object + required: false + desc: "Filter options: page (number), pagesize (number), status (string, execution status), trigger (string, trigger type)" + return: + type: object + desc: Paginated list of execution records + + - name: execution + desc: Get a specific execution record by member ID and execution ID + args: + - name: memberID + type: string + required: true + desc: The member ID of the robot (reserved for permission scoping) + - name: executionID + type: string + required: true + desc: The execution ID to retrieve + return: + type: object + desc: Execution status and details + + - name: updateChatTitle + desc: Update the title of a chat session + args: + - name: chatID + type: string + required: true + desc: The chat session ID to update + - name: title + type: string + required: true + desc: The new title for the chat session + return: + type: "null" + desc: Returns null on success diff --git a/attachment/doc.go b/attachment/doc.go new file mode 100644 index 00000000..dc7fbcee --- /dev/null +++ b/attachment/doc.go @@ -0,0 +1,11 @@ +package attachment + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/attachment/doc.yml b/attachment/doc.yml new file mode 100644 index 00000000..d9a56e0e --- /dev/null +++ b/attachment/doc.yml @@ -0,0 +1,177 @@ +group: attachment +type: process +desc: "File attachment management processes for uploading, reading, listing, and managing files" +entries: + - name: Save + desc: Save a file from base64 data URI or plain base64 string + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID (e.g. \"default\", \"__yao.attachment\")" + - name: content + type: string + required: true + desc: "Base64 data URI (e.g. \"data:image/png;base64,xxxx\") or plain base64 string" + - name: filename + type: string + required: false + desc: "Original filename; auto-generated from content type if omitted" + - name: option + type: object + required: false + desc: "Upload options: groups (array), gzip (bool), compress_image (bool), compress_size (number), public (bool), share (string: \"private\" or \"team\")" + return: + type: object + desc: "File object with file_id, path, bytes, created_at, filename, content_type, and status fields" + + - name: Read + desc: Read file content as a base64 data URI + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: fileID + type: string + required: true + desc: "File ID to read" + return: + type: string + desc: "Base64 data URI string (e.g. \"data:image/png;base64,xxxx\")" + + - name: Info + desc: Get file metadata information + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: fileID + type: string + required: true + desc: "File ID to query" + return: + type: object + desc: "File object with file_id, path, bytes, created_at, filename, content_type, and status fields" + + - name: List + desc: List files with pagination and filtering + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: option + type: object + required: false + desc: "List options: page (number), page_size (number, max 100), filters (object), order_by (string), select (array of field names)" + return: + type: object + desc: "Paginated result with files (array), total (number), page (number), page_size (number), and total_pages (number)" + + - name: Delete + desc: Delete a file by ID + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: fileID + type: string + required: true + desc: "File ID to delete" + return: + type: bool + desc: "True on success" + + - name: Exists + desc: Check if a file exists + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: fileID + type: string + required: true + desc: "File ID to check" + return: + type: bool + desc: "True if the file exists" + + - name: URL + desc: Get the URL for a file + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: fileID + type: string + required: true + desc: "File ID" + return: + type: string + desc: "File URL string" + + - name: SaveText + desc: Save parsed text content for a file + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: fileID + type: string + required: true + desc: "File ID to save text for" + - name: text + type: string + required: true + desc: "Text content to save" + return: + type: bool + desc: "True on success" + + - name: GetText + desc: Get parsed text content for a file + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID" + - name: fileID + type: string + required: true + desc: "File ID to get text for" + - name: fullContent + type: bool + required: false + desc: "If true, return full content; if false (default), return preview (first 2000 chars)" + return: + type: string + desc: "Text content string" + + - name: Zip + desc: Package multiple attachment files into a zip archive and upload it + args: + - name: uploaderID + type: string + required: true + desc: "Uploader/manager ID (e.g. \"__yao.attachment\")" + - name: fileIDs + type: array + required: true + desc: "Array of file ID strings to include in the zip" + - name: zipFilename + type: string + required: true + desc: "Output zip filename (e.g. \"archive.zip\"); .zip extension added automatically if missing" + - name: option + type: object + required: false + desc: "Upload options for the zip file: groups (array), gzip (bool), public (bool), share (string)" + return: + type: object + desc: "Uploaded zip file object with file_id, filename, bytes, and other file metadata" diff --git a/cmd/doc/doc.go b/cmd/doc/doc.go new file mode 100644 index 00000000..c0d3e50e --- /dev/null +++ b/cmd/doc/doc.go @@ -0,0 +1,74 @@ +package doc + +import ( + "encoding/json" + "fmt" + "os" + "strings" + + "github.com/yaoapp/gou/doc" +) + +var jsonOutput bool + +func printJSON(v any) { + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + enc.Encode(v) +} + +func formatArgs(args []doc.TypeValue) string { + if len(args) == 0 { + return "()" + } + parts := make([]string, 0, len(args)) + for _, a := range args { + s := a.Name + " " + a.Type + if !a.Required { + s += "?" + } + parts = append(parts, s) + } + return "(" + strings.Join(parts, ", ") + ")" +} + +func formatReturn(ret *doc.TypeValue) string { + if ret == nil { + return "void" + } + return ret.Type +} + +func init() { + ProcessCmd.AddCommand(processListCmd) + ProcessCmd.AddCommand(processValidateCmd) + ProcessCmd.AddCommand(processInspectCmd) + RuntimeCmd.AddCommand(runtimeListCmd) + RuntimeCmd.AddCommand(runtimeValidateCmd) + RuntimeCmd.AddCommand(runtimeInspectCmd) + + processListCmd.Flags().StringVarP(&groupFlag, "group", "g", "", "Filter by group") + processListCmd.Flags().StringVarP(&searchFlag, "search", "s", "", "Search keyword") + processListCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output as JSON") + processListCmd.Flags().BoolVar(&showAll, "all", false, "Include undocumented processes") + + processValidateCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output as JSON") + processInspectCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output as JSON") + + runtimeListCmd.Flags().StringVarP(&typeFlag, "type", "t", "", "Filter by type: object, function, class") + runtimeListCmd.Flags().StringVarP(&searchFlag, "search", "s", "", "Search keyword") + runtimeListCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output as JSON") + + runtimeValidateCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output as JSON") + runtimeInspectCmd.Flags().BoolVar(&jsonOutput, "json", false, "Output as JSON") +} + +var groupFlag string +var searchFlag string +var typeFlag string +var showAll bool + +func errExit(format string, a ...any) { + fmt.Fprintf(os.Stderr, format+"\n", a...) + os.Exit(1) +} diff --git a/cmd/doc/doc_test.go b/cmd/doc/doc_test.go new file mode 100644 index 00000000..55a6fd33 --- /dev/null +++ b/cmd/doc/doc_test.go @@ -0,0 +1,345 @@ +package doc + +import ( + "testing" + + "github.com/yaoapp/gou/doc" +) + +const sampleProcessYAML = ` +group: test +type: process +entries: + - name: test.hello + desc: Greet someone + args: + - name: name + type: string + required: true + return: + type: string + - name: test.add + desc: Add two numbers + args: + - name: a + type: number + required: true + - name: b + type: number + required: true + return: + type: number +` + +const sampleShortNameYAML = ` +group: http +type: process +entries: + - name: get + desc: Send HTTP GET + args: + - name: url + type: string + required: true + return: + type: object + - name: post + desc: Send HTTP POST + args: + - name: url + type: string + required: true + return: + type: object +` + +const sampleSubGroupYAML = ` +group: utils +type: process +entries: + - name: throw.Forbidden + desc: Throw 403 + return: + type: void +` + +const sampleRuntimeYAML = ` +group: objects +type: js_object +entries: + - name: log + desc: Logging utility + methods: + - name: Info + desc: Log info + args: + - name: msg + type: string + required: true + return: + type: void +` + +const sampleClassYAML = ` +group: objects +type: js_class +entries: + - name: FS + desc: File system operations + args: + - name: name + type: string + methods: + - name: ReadFile + desc: Read file + args: + - name: path + type: string + required: true + return: + type: string +` + +const sampleFunctionYAML = ` +group: functions +type: js_function +entries: + - name: Process + desc: Execute a Yao process + args: + - name: name + type: string + required: true + return: + type: any +` + +func setupTestData(t *testing.T) { + t.Helper() + doc.Reset() + for _, yaml := range []string{ + sampleProcessYAML, sampleShortNameYAML, sampleSubGroupYAML, + sampleRuntimeYAML, sampleClassYAML, sampleFunctionYAML, + } { + if err := doc.LoadYAML([]byte(yaml)); err != nil { + t.Fatalf("LoadYAML failed: %v", err) + } + } +} + +func TestNormalisedNames(t *testing.T) { + setupTestData(t) + + // "test.hello" already has prefix → stays "test.hello" + e, ok := doc.Get(doc.TypeProcess, "test.hello") + if !ok { + t.Fatal("test.hello not found") + } + if e.Name != "test.hello" { + t.Errorf("name = %q, want test.hello", e.Name) + } + + // short name "get" with group "http" → normalised to "http.get" + e, ok = doc.Get(doc.TypeProcess, "http.get") + if !ok { + t.Fatal("http.get not found — short name was not normalised") + } + if e.Name != "http.get" { + t.Errorf("name = %q, want http.get", e.Name) + } + + // sub-group name "throw.Forbidden" with group "utils" → "utils.throw.Forbidden" + e, ok = doc.Get(doc.TypeProcess, "utils.throw.Forbidden") + if !ok { + t.Fatal("utils.throw.Forbidden not found") + } + if e.Name != "utils.throw.Forbidden" { + t.Errorf("name = %q, want utils.throw.Forbidden", e.Name) + } +} + +func TestProcessListCommand(t *testing.T) { + setupTestData(t) + + entries := doc.List(doc.TypeProcess) + if len(entries) != 5 { + t.Errorf("expected 5 process entries, got %d", len(entries)) + } +} + +func TestProcessListWithGroupFilter(t *testing.T) { + setupTestData(t) + + entries := doc.List(doc.TypeProcess, doc.ListOption{Group: "http"}) + if len(entries) != 2 { + t.Errorf("expected 2 http entries, got %d", len(entries)) + } + + entries = doc.List(doc.TypeProcess, doc.ListOption{Group: "nonexistent"}) + if len(entries) != 0 { + t.Errorf("expected 0, got %d", len(entries)) + } +} + +func TestProcessListWithSearch(t *testing.T) { + setupTestData(t) + + entries := doc.List(doc.TypeProcess, doc.ListOption{Search: "hello"}) + if len(entries) != 1 { + t.Fatalf("expected 1, got %d", len(entries)) + } + if entries[0].Name != "test.hello" { + t.Errorf("expected test.hello, got %s", entries[0].Name) + } +} + +func TestProcessGet_FullName(t *testing.T) { + setupTestData(t) + + e, ok := doc.Get(doc.TypeProcess, "http.post") + if !ok { + t.Fatal("http.post not found") + } + if e.Desc != "Send HTTP POST" { + t.Errorf("desc = %q", e.Desc) + } +} + +func TestProcessValidate_OK(t *testing.T) { + setupTestData(t) + + r := doc.Validate(doc.TypeProcess, "test.hello") + if !r.Valid { + t.Fatal("expected valid") + } + if r.Status != "ok" { + t.Errorf("status = %q", r.Status) + } +} + +func TestProcessValidate_FullName(t *testing.T) { + setupTestData(t) + + r := doc.Validate(doc.TypeProcess, "http.get") + if !r.Valid { + t.Fatal("expected valid for http.get") + } +} + +func TestProcessValidate_NotFound(t *testing.T) { + setupTestData(t) + + r := doc.Validate(doc.TypeProcess, "does.not.exist") + if r.Valid { + t.Fatal("expected not valid") + } +} + +func TestProcessValidate_Suggestions(t *testing.T) { + setupTestData(t) + + r := doc.Validate(doc.TypeProcess, "test.hell") + if r.Valid { + t.Fatal("expected not valid") + } + found := false + for _, s := range r.Suggestion { + if s == "test.hello" { + found = true + } + } + if !found { + t.Errorf("expected test.hello in suggestions: %v", r.Suggestion) + } +} + +func TestRuntimeList(t *testing.T) { + setupTestData(t) + + objects := doc.List(doc.TypeJSObject) + if len(objects) != 1 { + t.Errorf("expected 1 object, got %d", len(objects)) + } + + classes := doc.List(doc.TypeJSClass) + if len(classes) != 1 { + t.Errorf("expected 1 class, got %d", len(classes)) + } + + functions := doc.List(doc.TypeJSFunction) + if len(functions) != 1 { + t.Errorf("expected 1 function, got %d", len(functions)) + } +} + +func TestRuntimeValidate_Object(t *testing.T) { + setupTestData(t) + + r := doc.Validate(doc.TypeJSObject, "log") + if !r.Valid { + t.Fatal("expected valid") + } +} + +func TestRuntimeValidate_Class(t *testing.T) { + setupTestData(t) + + r := doc.Validate(doc.TypeJSClass, "FS") + if !r.Valid { + t.Fatal("expected valid") + } +} + +func TestRuntimeValidate_Function(t *testing.T) { + setupTestData(t) + + r := doc.Validate(doc.TypeJSFunction, "Process") + if !r.Valid { + t.Fatal("expected valid") + } +} + +func TestFindRuntime(t *testing.T) { + setupTestData(t) + + e := findRuntime("log") + if e == nil { + t.Fatal("expected to find log") + } + + e = findRuntime("FS") + if e == nil { + t.Fatal("expected to find FS") + } + + e = findRuntime("nonexistent") + if e != nil { + t.Fatal("expected nil") + } +} + +func TestFormatArgs(t *testing.T) { + args := []doc.TypeValue{ + {Name: "name", Type: "string", Required: true}, + {Name: "options", Type: "object"}, + } + s := formatArgs(args) + if s != "(name string, options object?)" { + t.Errorf("formatArgs = %q", s) + } + + s = formatArgs(nil) + if s != "()" { + t.Errorf("formatArgs nil = %q", s) + } +} + +func TestFormatReturn(t *testing.T) { + if formatReturn(nil) != "void" { + t.Error("nil should return void") + } + tv := &doc.TypeValue{Type: "string"} + if formatReturn(tv) != "string" { + t.Error("string type mismatch") + } +} diff --git a/cmd/doc/process.go b/cmd/doc/process.go new file mode 100644 index 00000000..a69119ac --- /dev/null +++ b/cmd/doc/process.go @@ -0,0 +1,298 @@ +package doc + +import ( + "fmt" + "strings" + + "github.com/spf13/cobra" + "github.com/yaoapp/gou/doc" + "github.com/yaoapp/gou/fs" + "github.com/yaoapp/gou/model" + "github.com/yaoapp/gou/process" + "github.com/yaoapp/gou/schedule" + "github.com/yaoapp/gou/store" + "github.com/yaoapp/gou/task" +) + +// ProcessCmd is the parent command for process documentation. +var ProcessCmd = &cobra.Command{ + Use: "process", + Short: "Process documentation", + Long: "List, inspect and validate Yao process documentation", + Run: func(cmd *cobra.Command, args []string) { cmd.Help() }, +} + +var processListCmd = &cobra.Command{ + Use: "list", + Short: "List documented processes", + Long: `List all documented processes in flat format (one per line). +Designed for grep/pipe usage: + yao doc process list | grep model + yao doc process list --group http`, + Run: func(cmd *cobra.Command, args []string) { + opts := doc.ListOption{Group: groupFlag, Search: searchFlag} + entries := doc.List(doc.TypeProcess, opts) + + if jsonOutput { + printJSON(entries) + return + } + + for _, e := range entries { + fmt.Printf("%-45s %s\n", doc.CallableName(e), e.Desc) + } + + if showAll { + undoc := doc.AutoDiscover() + if len(undoc) > 0 { + fmt.Printf("\nUNDOCUMENTED: %d processes\n", len(undoc)) + for _, name := range undoc { + fmt.Printf("%-45s (no documentation)\n", name) + } + } + } + }, +} + +var processInspectCmd = &cobra.Command{ + Use: "inspect [process-name]", + Short: "Show detailed info for a process", + Long: `Show full documentation for a single process, including arguments, +return type, field descriptions, and examples. + yao doc process inspect http.get + yao doc process inspect models.user.Find`, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + e, ok := doc.Get(doc.TypeProcess, name) + if !ok { + fmt.Fprintf(cmd.ErrOrStderr(), "Process %q not found.\n", name) + result := doc.Validate(doc.TypeProcess, name) + if len(result.Suggestion) > 0 { + fmt.Fprintln(cmd.ErrOrStderr(), "Did you mean:") + for _, s := range result.Suggestion { + fmt.Fprintf(cmd.ErrOrStderr(), " - %s\n", s) + } + } + return + } + + if jsonOutput { + printJSON(e) + return + } + + printProcessDetail(e) + }, +} + +var processValidateCmd = &cobra.Command{ + Use: "validate [process-name]", + Short: "Validate a process name", + Long: `Validate a process call using the engine's addressing logic, +check that the referenced resource exists, and show documentation. + +Examples: + yao doc process validate models.user.Find + yao doc process validate http.get + yao doc process validate stores.cache.set`, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + + p, err := process.Of(name) + if err != nil { + printError(cmd, name, err.Error()) + return + } + + if process.Handlers[p.Handler] == nil { + printError(cmd, name, fmt.Sprintf("handler %q not registered", p.Handler)) + return + } + + if reason := checkID(p); reason != "" { + printError(cmd, name, reason) + return + } + + docResult := doc.Validate(doc.TypeProcess, name) + + if jsonOutput { + out := map[string]interface{}{ + "name": name, + "valid": true, + "handler": p.Handler, + "group": p.Group, + "id": p.ID, + "method": p.Method, + "documented": docResult.Valid, + } + if docResult.Entry != nil { + out["entry"] = docResult.Entry + } + printJSON(out) + return + } + + fmt.Printf("✓ %s — valid\n", name) + fmt.Printf(" Handler: %s\n", p.Handler) + fmt.Printf(" Group: %s\n", p.Group) + if p.ID != "" { + fmt.Printf(" ID: %s\n", p.ID) + } + fmt.Printf(" Method: %s\n", p.Method) + fmt.Println() + + if docResult.Valid && docResult.Entry != nil { + printProcessDetail(docResult.Entry) + } else { + fmt.Printf("⚠ no documentation found for %s\n", name) + } + }, +} + +// checkID validates the segment for dynamic-ID groups by looking up the +// actual runtime registry. Returns an error message or "" if OK. +func checkID(p *process.Process) string { + switch p.Group { + case "models": + if p.ID == "" { + return fmt.Sprintf("missing , correct format: models..%s", p.Method) + } + if !model.Exists(p.ID) { + return fmt.Sprintf("model %q not loaded", p.ID) + } + + case "schemas": + if p.ID == "" { + return fmt.Sprintf("missing , correct format: schemas..%s", p.Method) + } + + case "stores": + if p.ID == "" { + return fmt.Sprintf("missing , correct format: stores..%s", p.Method) + } + if _, has := store.Pools[p.ID]; !has { + return fmt.Sprintf("store %q not loaded", p.ID) + } + + case "fs": + if p.ID == "" { + return fmt.Sprintf("missing , correct format: fs..%s", p.Method) + } + if _, has := fs.FileSystems[p.ID]; !has { + return fmt.Sprintf("filesystem %q not registered", p.ID) + } + + case "tasks": + if p.ID == "" { + return fmt.Sprintf("missing , correct format: tasks..%s", p.Method) + } + if _, has := task.Tasks[p.ID]; !has { + return fmt.Sprintf("task %q not loaded", p.ID) + } + + case "schedules": + if p.ID == "" { + return fmt.Sprintf("missing , correct format: schedules..%s", p.Method) + } + if _, has := schedule.Schedules[p.ID]; !has { + return fmt.Sprintf("schedule %q not loaded", p.ID) + } + } + return "" +} + +func printError(cmd *cobra.Command, name, msg string) { + if jsonOutput { + printJSON(map[string]interface{}{ + "name": name, + "valid": false, + "error": msg, + }) + return + } + fmt.Fprintf(cmd.ErrOrStderr(), "✗ %s — %s\n", name, msg) +} + +func printProcessDetail(e *doc.Entry) { + fmt.Printf("Process: %s\n", doc.CallableName(e)) + fmt.Printf("Group: %s\n", e.Group) + fmt.Printf("Desc: %s\n", e.Desc) + fmt.Println() + + if len(e.Args) > 0 { + fmt.Println("Arguments:") + for i, a := range e.Args { + req := "required" + if !a.Required { + req = "optional" + } + fmt.Printf(" [%d] %s (%s, %s)\n", i, a.Name, a.Type, req) + if a.Desc != "" { + fmt.Printf(" %s\n", a.Desc) + } + if a.Example != nil { + fmt.Printf(" Example: %v\n", a.Example) + } + printTypeFields(a.Fields, 6) + } + fmt.Println() + } + + fmt.Println("Returns:") + if e.Return == nil { + fmt.Println(" void") + } else { + printTypeValue(e.Return, 2) + } +} + +func printTypeValue(tv *doc.TypeValue, indent int) { + pad := strings.Repeat(" ", indent) + fmt.Printf("%s%s", pad, tv.Type) + if tv.Desc != "" { + fmt.Printf(" — %s", tv.Desc) + } + fmt.Println() + if tv.Example != nil { + fmt.Printf("%sExample: %v\n", pad, tv.Example) + } + + if len(tv.Fields) > 0 { + printTypeFields(tv.Fields, indent) + } + if tv.Items != nil { + fmt.Printf("%sItems:\n", pad) + printTypeValue(tv.Items, indent+2) + } + if len(tv.Variants) > 0 { + for i, v := range tv.Variants { + fmt.Printf("%sVariant %d: ", pad, i+1) + desc := v.Type + if v.Desc != "" { + desc += " — " + v.Desc + } + fmt.Println(desc) + } + } +} + +func printTypeFields(fields []doc.TypeValue, indent int) { + if len(fields) == 0 { + return + } + pad := strings.Repeat(" ", indent) + fmt.Printf("%sFields:\n", pad) + for _, f := range fields { + req := "" + if f.Required { + req = ", required" + } + fmt.Printf("%s .%-20s %s%s\n", pad, f.Name, f.Type, req) + if f.Desc != "" { + fmt.Printf("%s %s\n", pad, f.Desc) + } + } +} diff --git a/cmd/doc/runtime.go b/cmd/doc/runtime.go new file mode 100644 index 00000000..c9ccbfec --- /dev/null +++ b/cmd/doc/runtime.go @@ -0,0 +1,182 @@ +package doc + +import ( + "fmt" + + "github.com/spf13/cobra" + "github.com/yaoapp/gou/doc" +) + +// RuntimeCmd is the parent command for runtime API documentation. +var RuntimeCmd = &cobra.Command{ + Use: "runtime", + Short: "JS runtime API documentation", + Long: "List, inspect and validate JS runtime global objects, functions, and classes", + Run: func(cmd *cobra.Command, args []string) { cmd.Help() }, +} + +var runtimeListCmd = &cobra.Command{ + Use: "list", + Short: "List JS runtime APIs", + Long: `List all documented JS global objects, functions, and classes. +Designed for grep/pipe usage: + yao doc runtime list | grep FS + yao doc runtime list --type class`, + Run: func(cmd *cobra.Command, args []string) { + types := runtimeTypes() + var allEntries []*doc.Entry + for _, t := range types { + opts := doc.ListOption{Search: searchFlag} + allEntries = append(allEntries, doc.List(t, opts)...) + } + + if jsonOutput { + printJSON(allEntries) + return + } + + for _, e := range allEntries { + tag := string(e.Type) + extra := "" + if len(e.Methods) > 0 { + extra = fmt.Sprintf(" (%d methods)", len(e.Methods)) + } + fmt.Printf("%-20s [%-11s] %s%s\n", e.Name, tag, e.Desc, extra) + } + }, +} + +var runtimeInspectCmd = &cobra.Command{ + Use: "inspect [name]", + Short: "Show detailed info for a JS runtime API", + Long: `Show full documentation for a JS global object, function, or class. + yao doc runtime inspect FS + yao doc runtime inspect log + yao doc runtime inspect Process`, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + entry := findRuntime(name) + if entry == nil { + fmt.Fprintf(cmd.ErrOrStderr(), "Runtime API %q not found.\n", name) + for _, t := range []doc.EntryType{doc.TypeJSObject, doc.TypeJSClass, doc.TypeJSFunction} { + r := doc.Validate(t, name) + if len(r.Suggestion) > 0 { + fmt.Fprintln(cmd.ErrOrStderr(), "Did you mean:") + for _, s := range r.Suggestion { + fmt.Fprintf(cmd.ErrOrStderr(), " - %s\n", s) + } + break + } + } + return + } + + if jsonOutput { + printJSON(entry) + return + } + + printRuntimeDetail(entry) + }, +} + +var runtimeValidateCmd = &cobra.Command{ + Use: "validate [name]", + Short: "Validate a JS runtime API name", + Long: "Check if a JS global name is documented (e.g. FS, log, Process)", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + name := args[0] + var result *doc.ValidationResult + for _, t := range []doc.EntryType{doc.TypeJSObject, doc.TypeJSClass, doc.TypeJSFunction} { + r := doc.Validate(t, name) + if r.Valid { + result = r + break + } + if result == nil || len(r.Suggestion) > len(result.Suggestion) { + result = r + } + } + + if jsonOutput { + printJSON(result) + return + } + + if result.Valid { + fmt.Printf("✓ %s — %s (type: %s)\n", result.Name, result.Message, result.Entry.Type) + } else { + fmt.Printf("✗ %s — %s (status: %s)\n", result.Name, result.Message, result.Status) + if len(result.Suggestion) > 0 { + fmt.Println(" Did you mean:") + for _, s := range result.Suggestion { + fmt.Printf(" - %s\n", s) + } + } + } + }, +} + +func findRuntime(name string) *doc.Entry { + for _, t := range []doc.EntryType{doc.TypeJSObject, doc.TypeJSClass, doc.TypeJSFunction} { + e, ok := doc.Get(t, name) + if ok { + return e + } + } + return nil +} + +func printRuntimeDetail(e *doc.Entry) { + fmt.Printf("Name: %s\n", e.Name) + fmt.Printf("Type: %s\n", e.Type) + fmt.Printf("Desc: %s\n", e.Desc) + + if len(e.Args) > 0 { + fmt.Println() + fmt.Println("Constructor Arguments:") + for i, a := range e.Args { + req := "required" + if !a.Required { + req = "optional" + } + fmt.Printf(" [%d] %s (%s, %s)\n", i, a.Name, a.Type, req) + if a.Desc != "" { + fmt.Printf(" %s\n", a.Desc) + } + } + } + + if e.Return != nil { + fmt.Println() + fmt.Println("Returns:") + printTypeValue(e.Return, 2) + } + + if len(e.Methods) > 0 { + fmt.Println() + fmt.Printf("Methods (%d):\n", len(e.Methods)) + for _, m := range e.Methods { + ret := formatReturn(m.Return) + fmt.Printf(" .%-25s %s → %s\n", m.Name+formatArgs(m.Args), m.Desc, ret) + if m.Return != nil && len(m.Return.Fields) > 0 { + printTypeFields(m.Return.Fields, 4) + } + } + } +} + +func runtimeTypes() []doc.EntryType { + switch typeFlag { + case "object": + return []doc.EntryType{doc.TypeJSObject} + case "function": + return []doc.EntryType{doc.TypeJSFunction} + case "class": + return []doc.EntryType{doc.TypeJSClass} + default: + return []doc.EntryType{doc.TypeJSObject, doc.TypeJSClass, doc.TypeJSFunction} + } +} diff --git a/cmd/root.go b/cmd/root.go index f9f84358..7b09cf68 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -8,6 +8,7 @@ import ( "github.com/spf13/cobra" "github.com/yaoapp/kun/exception" "github.com/yaoapp/yao/cmd/agent" + yaodoc "github.com/yaoapp/yao/cmd/doc" "github.com/yaoapp/yao/cmd/mcp" "github.com/yaoapp/yao/cmd/robot" "github.com/yaoapp/yao/cmd/sui" @@ -167,6 +168,18 @@ var robotCmd = &cobra.Command{ }, } +var docCmd = &cobra.Command{ + Use: "doc", + Short: "Documentation and API reference", + Long: "Browse and validate documentation for processes, JS runtime APIs, and more", + CompletionOptions: cobra.CompletionOptions{ + DisableDefaultCmd: true, + }, + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + // Command initialize func init() { @@ -192,6 +205,10 @@ func init() { // Robot robotCmd.AddCommand(robot.AddCmd) + // Doc + docCmd.AddCommand(yaodoc.ProcessCmd) + docCmd.AddCommand(yaodoc.RuntimeCmd) + rootCmd.AddCommand( versionCmd, migrateCmd, @@ -210,6 +227,7 @@ func init() { agentCmd, mcpCmd, robotCmd, + docCmd, upgradeCmd, ) // rootCmd.SetHelpCommand(helpCmd) diff --git a/crypto/doc.go b/crypto/doc.go new file mode 100644 index 00000000..16f9c5d5 --- /dev/null +++ b/crypto/doc.go @@ -0,0 +1,11 @@ +package crypto + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/crypto/doc.yml b/crypto/doc.yml new file mode 100644 index 00000000..9cc5a2a5 --- /dev/null +++ b/crypto/doc.yml @@ -0,0 +1,171 @@ +group: crypto +type: process +entries: + - name: Hash + desc: Compute a cryptographic hash of a string value + args: + - name: algorithm + type: string + required: true + desc: "Hash algorithm: MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, MD5SHA1, RIPEMD160, SHA3_224, SHA3_256, SHA3_384, SHA3_512, SHA512_224, SHA512_256, BLAKE2s_256, BLAKE2b_256, BLAKE2b_384, BLAKE2b_512" + - name: value + type: string + required: true + desc: String value to hash + return: + type: string + desc: Hex-encoded hash string + + - name: Hmac + desc: Compute a Keyed-Hash Message Authentication Code (HMAC) + args: + - name: algorithm + type: string + required: true + desc: "Hash algorithm: MD4, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, etc." + - name: value + type: string + required: true + desc: String value to hash + - name: key + type: string + required: true + desc: Secret key for HMAC + - name: encoding + type: string + required: false + desc: "Output encoding: \"base64\" for base64 output (default: hex)" + return: + type: string + desc: HMAC hash string (hex or base64 encoded) + + - name: hmacwith + desc: Compute HMAC with advanced encoding options for key, value, and output + args: + - name: option + type: object + required: true + desc: "Encoding options: {key: \"base64\"|\"hex\", value: \"base64\"|\"hex\", output: \"base64\"|\"hex\", algo: \"SHA256\"}" + - name: value + type: string + required: true + desc: Value to hash (encoding specified in option) + - name: key + type: string + required: true + desc: Secret key (encoding specified in option) + return: + type: string + desc: HMAC hash string with specified output encoding + + - name: rsa2sign + desc: Create an RSA-SHA2 digital signature + args: + - name: privateKey + type: string + required: true + desc: RSA private key in PEM format + - name: algorithm + type: string + required: true + desc: "Hash algorithm: SHA256, SHA384, SHA512, etc." + - name: value + type: string + required: true + desc: Data to sign + - name: encoding + type: string + required: false + desc: "Output encoding: \"base64\" for base64 output (default: hex)" + return: + type: string + desc: Digital signature string (hex or base64 encoded) + + - name: rsa2verify + desc: Verify an RSA-SHA2 digital signature + args: + - name: publicKey + type: string + required: true + desc: RSA public key in PEM format + - name: algorithm + type: string + required: true + desc: "Hash algorithm: SHA256, SHA384, SHA512, etc." + - name: value + type: string + required: true + desc: Original data that was signed + - name: signature + type: string + required: true + desc: Signature to verify (hex or base64 encoded) + - name: encoding + type: string + required: false + desc: "Signature encoding: \"base64\" if signature is base64-encoded (default: hex)" + return: + type: bool + desc: True if signature is valid + + - name: aes256encrypt + desc: Encrypt data using AES-256 algorithm + args: + - name: algorithm + type: string + required: true + desc: "AES mode: \"GCM\"" + - name: key + type: string + required: true + desc: AES-256 encryption key (32 bytes) + - name: nonce + type: string + required: true + desc: Nonce/IV for encryption + - name: text + type: string + required: true + desc: Plaintext to encrypt + - name: additionalData + type: string + required: false + desc: Additional authenticated data (AAD) for GCM mode + - name: encoding + type: string + required: false + desc: "Output encoding: \"base64\" for base64 output (default: hex)" + return: + type: string + desc: Encrypted ciphertext (hex or base64 encoded) + + - name: aes256decrypt + desc: Decrypt data using AES-256 algorithm + args: + - name: algorithm + type: string + required: true + desc: "AES mode: \"GCM\"" + - name: key + type: string + required: true + desc: AES-256 decryption key (32 bytes) + - name: nonce + type: string + required: true + desc: Nonce/IV used during encryption + - name: ciphertext + type: string + required: true + desc: Encrypted data to decrypt (hex or base64 encoded) + - name: additionalData + type: string + required: false + desc: Additional authenticated data (AAD) used during encryption + - name: encoding + type: string + required: false + desc: "Input encoding: \"base64\" if ciphertext is base64-encoded (default: hex)" + return: + type: string + desc: Decrypted plaintext diff --git a/engine/doc.go b/engine/doc.go new file mode 100644 index 00000000..22547cde --- /dev/null +++ b/engine/doc.go @@ -0,0 +1,11 @@ +package engine + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/engine/doc.yml b/engine/doc.yml new file mode 100644 index 00000000..285d6ec3 --- /dev/null +++ b/engine/doc.yml @@ -0,0 +1,92 @@ +group: utils.app +type: process +desc: "Utility and app bootstrap processes for health checks and system inspection" +entries: + # ── utils.app (current) ────────────────────────────────────────── + - name: Ping + desc: Return engine name, version, and application root path + args: [] + return: + type: object + desc: "Object with engine, version, and root fields" + + - name: Inspect + desc: Return detailed system information including version, CUI, build name, config, and external tools + args: [] + return: + type: object + desc: "Object with VERSION, CUI, BUILDNAME, CONFIG, and optionally TOOLS fields" + + # ── xiang.main (deprecated, aliased to utils.app) ─────────────── + - name: Ping + group: xiang.main + desc: "[Deprecated: use utils.app.Ping] Return engine name, version, and application root path" + args: [] + return: + type: object + desc: "Object with engine, version, and root fields" + + - name: Inspect + group: xiang.main + desc: "[Deprecated: use utils.app.Inspect] Return detailed system information" + args: [] + return: + type: object + desc: "Object with VERSION, CUI, BUILDNAME, CONFIG, and optionally TOOLS fields" + + - name: Favicon + group: xiang.main + desc: "[Deprecated] Return the application favicon (currently returns null)" + args: [] + return: + type: "null" + desc: "Always returns null" + + - name: FileContent + group: xiang.main + desc: "[Deprecated] Return file content from storage (currently returns null)" + args: + - name: filename + type: string + required: false + desc: "File path to read (handler is disabled)" + - name: encode + type: bool + required: false + desc: "Whether to base64 encode the content (handler is disabled)" + return: + type: "null" + desc: "Always returns null" + + - name: AppFileContent + group: xiang.main + desc: "[Deprecated] Return application data file content (currently returns null)" + args: + - name: filename + type: string + required: false + desc: "Application data file path to read (handler is disabled)" + - name: encode + type: bool + required: false + desc: "Whether to base64 encode the content (handler is disabled)" + return: + type: "null" + desc: "Always returns null" + + # ── xiang.sys (deprecated aliases) ────────────────────────────── + - name: Ping + group: xiang.sys + desc: "[Deprecated: use utils.app.Ping] Alias of xiang.main.Ping" + args: [] + return: + type: object + desc: "Object with engine, version, and root fields" + + - name: Inspect + group: xiang.sys + desc: "[Deprecated: use utils.app.Inspect] Alias of xiang.main.Inspect" + args: [] + return: + type: object + desc: "Object with VERSION, CUI, BUILDNAME, CONFIG, and optionally TOOLS fields" diff --git a/excel/doc.go b/excel/doc.go new file mode 100644 index 00000000..029dca95 --- /dev/null +++ b/excel/doc.go @@ -0,0 +1,12 @@ +package excel + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/excel/doc.yml b/excel/doc.yml new file mode 100644 index 00000000..abe31026 --- /dev/null +++ b/excel/doc.yml @@ -0,0 +1,678 @@ +group: excel +type: process +entries: + # File operations + - name: open + desc: Open an Excel file and return a handle for subsequent operations + args: + - name: file + type: string + required: true + desc: File path relative to the data directory + - name: writable + type: bool + required: false + desc: "Whether to open in writable mode (default: false)" + return: + type: string + desc: Handle string for referencing the opened file + + - name: close + desc: Close an opened Excel file and release resources + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + return: + type: "null" + desc: Returns null on success + + - name: save + desc: Save the current state of an opened Excel file to disk + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + return: + type: "null" + desc: Returns null on success + + - name: sheets + desc: Get the list of sheet names in an Excel file + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + return: + type: array + desc: Array of sheet name strings + + # Sheet operations + - name: sheet.create + desc: Create a new sheet in an Excel file + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: name + type: string + required: true + desc: Name for the new sheet + return: + type: number + desc: Index of the created sheet + + - name: sheet.read + desc: Read all data from a sheet + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: name + type: string + required: true + desc: Sheet name + return: + type: array + desc: 2D array of sheet data + + - name: sheet.update + desc: Update a sheet with new data (overwrites existing content) + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: name + type: string + required: true + desc: Sheet name + - name: data + type: array + required: true + desc: 2D array of data to write + return: + type: "null" + desc: Returns null on success + + - name: sheet.delete + desc: Delete a sheet from an Excel file + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: name + type: string + required: true + desc: Sheet name to delete + return: + type: "null" + desc: Returns null on success + + - name: sheet.copy + desc: Copy a sheet to a new sheet + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: source + type: string + required: true + desc: Source sheet name + - name: target + type: string + required: true + desc: Target sheet name + return: + type: "null" + desc: Returns null on success + + - name: sheet.list + desc: List all sheets with their metadata + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + return: + type: array + desc: Array of sheet information objects + + - name: sheet.exists + desc: Check if a sheet exists in an Excel file + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: name + type: string + required: true + desc: Sheet name to check + return: + type: bool + desc: True if the sheet exists + + - name: sheet.rows + desc: Read a range of rows from a sheet + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: name + type: string + required: true + desc: Sheet name + - name: start + type: number + required: true + desc: Start row index (0-based) + - name: size + type: number + required: true + desc: Number of rows to read + return: + type: array + desc: 2D array of row data + + - name: sheet.dimension + desc: Get the dimensions (rows and columns count) of a sheet + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: name + type: string + required: true + desc: Sheet name + return: + type: object + desc: "Object with rows and cols counts (e.g. {rows: 100, cols: 10})" + + # Read operations + - name: read.cell + desc: Read the value of a single cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Cell reference (e.g. \"A1\", \"B2\")" + return: + type: string + desc: Cell value as string + + - name: read.row + desc: Read all rows from a sheet + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + return: + type: array + desc: 2D array of all row data + + - name: read.column + desc: Read all columns from a sheet + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + return: + type: array + desc: 2D array of column data + + # Write operations + - name: write.cell + desc: Write a value to a single cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Cell reference (e.g. \"A1\")" + - name: value + type: any + required: true + desc: Value to write + return: + type: "null" + desc: Returns null on success + + - name: write.row + desc: Write values to a row starting from a cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Starting cell reference (e.g. \"A1\")" + - name: values + type: array + required: true + desc: Array of values to write across the row + return: + type: "null" + desc: Returns null on success + + - name: write.column + desc: Write values to a column starting from a cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Starting cell reference (e.g. \"A1\")" + - name: values + type: array + required: true + desc: Array of values to write down the column + return: + type: "null" + desc: Returns null on success + + - name: write.all + desc: Write a 2D array of data starting from a cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Starting cell reference (e.g. \"A1\")" + - name: values + type: array + required: true + desc: 2D array of values (array of row arrays) + return: + type: "null" + desc: Returns null on success + + # Style & formatting + - name: set.style + desc: Apply a style to a cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Cell reference (e.g. \"A1\")" + - name: styleID + type: number + required: true + desc: Style ID to apply + return: + type: "null" + desc: Returns null on success + + - name: set.formula + desc: Set a formula for a cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Cell reference (e.g. \"A1\")" + - name: formula + type: string + required: true + desc: "Excel formula string (e.g. \"=SUM(A1:A10)\")" + return: + type: "null" + desc: Returns null on success + + - name: set.link + desc: Set a hyperlink for a cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Cell reference (e.g. \"A1\")" + - name: link + type: string + required: true + desc: Hyperlink URL + - name: text + type: string + required: true + desc: Link type or display text + return: + type: "null" + desc: Returns null on success + + - name: set.richtext + desc: Set rich text content for a cell + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: cell + type: string + required: true + desc: "Cell reference (e.g. \"A1\")" + - name: richText + type: array + required: true + desc: "Array of rich text run objects: [{text: \"...\"}]" + return: + type: "null" + desc: Returns null on success + + - name: set.comment + desc: Set a comment on a sheet + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: comment + type: object + required: true + desc: Comment data object + return: + type: "null" + desc: Returns null on success + + - name: set.rowheight + desc: Set the height of a row + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: row + type: number + required: true + desc: Row number (1-based) + - name: height + type: number + required: true + desc: Row height in points + return: + type: "null" + desc: Returns null on success + + - name: set.columnwidth + desc: Set the width of columns in a range + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: startCol + type: string + required: true + desc: "Start column letter (e.g. \"A\")" + - name: endCol + type: string + required: true + desc: "End column letter (e.g. \"D\")" + - name: width + type: number + required: true + desc: Column width + return: + type: "null" + desc: Returns null on success + + - name: set.mergecell + desc: Merge a range of cells + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: start + type: string + required: true + desc: "Top-left cell reference (e.g. \"A1\")" + - name: end + type: string + required: true + desc: "Bottom-right cell reference (e.g. \"D4\")" + return: + type: "null" + desc: Returns null on success + + - name: set.unmergecell + desc: Unmerge a range of cells + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + - name: start + type: string + required: true + desc: "Top-left cell reference (e.g. \"A1\")" + - name: end + type: string + required: true + desc: "Bottom-right cell reference (e.g. \"D4\")" + return: + type: "null" + desc: Returns null on success + + # Iterator operations + - name: each.openrow + desc: Open a row iterator for streaming row-by-row reading + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + return: + type: string + desc: Iterator ID for use with nextrow/closerow + + - name: each.closerow + desc: Close a row iterator and release resources + args: + - name: id + type: string + required: true + desc: Iterator ID from each.openrow + return: + type: "null" + desc: Returns null + + - name: each.nextrow + desc: Get the next row from the iterator; returns null when exhausted + args: + - name: id + type: string + required: true + desc: Iterator ID from each.openrow + return: + type: array + desc: Array of cell values for the row, or null if no more rows + + - name: each.opencolumn + desc: Open a column iterator for streaming column-by-column reading + args: + - name: handle + type: string + required: true + desc: File handle from excel.open + - name: sheet + type: string + required: true + desc: Sheet name + return: + type: string + desc: Iterator ID for use with nextcolumn/closecolumn + + - name: each.closecolumn + desc: Close a column iterator and release resources + args: + - name: id + type: string + required: true + desc: Iterator ID from each.opencolumn + return: + type: "null" + desc: Returns null + + - name: each.nextcolumn + desc: Get the next column from the iterator; returns null when exhausted + args: + - name: id + type: string + required: true + desc: Iterator ID from each.opencolumn + return: + type: array + desc: Array of cell values for the column, or null if no more columns + + # Conversion utilities + - name: convert.columnnametonumber + desc: "Convert a column letter name to a number (e.g. \"A\" -> 1, \"Z\" -> 26)" + args: + - name: name + type: string + required: true + desc: "Column letter name (e.g. \"A\", \"AB\")" + return: + type: number + desc: Column number (1-based) + + - name: convert.columnnumbertoname + desc: "Convert a column number to a letter name (e.g. 1 -> \"A\", 26 -> \"Z\")" + args: + - name: number + type: number + required: true + desc: Column number (1-based) + return: + type: string + desc: Column letter name + + - name: convert.cellnametocoordinates + desc: "Convert a cell name to column and row coordinates (e.g. \"B3\" -> [2, 3])" + args: + - name: cell + type: string + required: true + desc: "Cell reference (e.g. \"A1\", \"B3\")" + return: + type: array + desc: "[column, row] coordinates (1-based)" + + - name: convert.coordinatestocellname + desc: "Convert column and row coordinates to a cell name (e.g. 2, 3 -> \"B3\")" + args: + - name: col + type: number + required: true + desc: Column number (1-based) + - name: row + type: number + required: true + desc: Row number (1-based) + return: + type: string + desc: "Cell reference string (e.g. \"B3\")" diff --git a/helper/doc.go b/helper/doc.go new file mode 100644 index 00000000..e0efca6c --- /dev/null +++ b/helper/doc.go @@ -0,0 +1,12 @@ +package helper + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/helper/doc.yml b/helper/doc.yml new file mode 100644 index 00000000..1d590165 --- /dev/null +++ b/helper/doc.yml @@ -0,0 +1,473 @@ +group: xiang.helper +type: process +entries: + # Array operations + - name: ArrayPluck + desc: "[Deprecated: use utils.arr.Pluck] Merge multiple record sets into one by plucking specified columns" + args: + - name: columns + type: array + required: true + desc: Array of column names to pluck + - name: data + type: object + required: true + desc: Map of column names to value arrays + return: + type: array + desc: Merged array of records + + - name: ArraySplit + desc: "[Deprecated: use utils.arr.Split] Split an array of records into columns and values" + args: + - name: records + type: array + required: true + desc: Array of record objects + return: + type: object + desc: "Object with columns (string[]) and values (any[][])" + + - name: ArrayColumn + desc: "[Deprecated: use utils.arr.Column] Extract values of a specified field from an array of records" + args: + - name: records + type: array + required: true + desc: Array of record objects + - name: name + type: string + required: true + desc: Field name to extract + return: + type: array + desc: Array of field values + + - name: ArrayKeep + desc: "[Deprecated: use utils.arr.Keep] Keep only specified keys in each record" + args: + - name: records + type: array + required: true + desc: Array of record objects + - name: columns + type: array + required: true + desc: Array of key names to keep + return: + type: array + desc: Filtered array of records + + - name: ArrayTree + desc: "[Deprecated: use utils.arr.Tree] Convert a flat array of records into a tree structure" + args: + - name: records + type: array + required: true + desc: Array of record objects + - name: setting + type: object + required: true + desc: "Tree settings: {primary, parent, children, etc.}" + return: + type: array + desc: Tree-structured array + + - name: ArrayUnique + desc: "[Deprecated: use utils.arr.Unique] Remove duplicate values from an array" + args: + - name: array + type: array + required: true + desc: Array to deduplicate + return: + type: array + desc: Array with duplicates removed + + - name: ArrayMapSet + desc: "[Deprecated: use utils.arr.MapSet] Set a field value on every map in an array" + args: + - name: records + type: array + required: true + desc: Array of map objects + - name: key + type: string + required: true + desc: Key to set in each map + - name: value + type: any + required: true + desc: Value to set + return: + type: array + desc: Modified array + + - name: ArrayIndexes + desc: "[Deprecated: use utils.arr.Indexes] Return the index numbers of an array" + args: + - name: array + type: array + required: true + desc: Input array + return: + type: array + desc: Array of integer indexes + + - name: ArrayGet + desc: "[Deprecated: use utils.arr.Get] Get an element at a specified index from an array" + args: + - name: array + type: array + required: true + desc: Input array + - name: index + type: number + required: true + desc: Index to retrieve + return: + type: any + desc: Element at the given index, or null if out of range + + # Map operations + - name: MapKeys + desc: "[Deprecated: use utils.map.Keys] Return all keys of a map" + args: + - name: record + type: object + required: true + desc: Input map + return: + type: array + desc: Array of key strings + + - name: MapValues + desc: "[Deprecated: use utils.map.Values] Return all values of a map" + args: + - name: record + type: object + required: true + desc: Input map + return: + type: array + desc: Array of values + + - name: MapGet + desc: "[Deprecated: use utils.map.Get] Get a value by key from a map (supports dot notation)" + args: + - name: record + type: object + required: true + desc: Input map + - name: key + type: string + required: true + desc: Key name (supports dot notation for nested access) + return: + type: any + desc: Value at the given key + + - name: MapSet + desc: "[Deprecated: use utils.map.Set] Set a key-value pair in a map (supports dot notation)" + args: + - name: record + type: object + required: true + desc: Input map + - name: key + type: string + required: true + desc: Key name (supports dot notation for nested access) + - name: value + type: any + required: true + desc: Value to set + return: + type: object + desc: Modified map + + - name: MapDel + desc: "[Deprecated: use utils.map.Del] Delete a key from a map" + args: + - name: record + type: object + required: true + desc: Input map + - name: key + type: string + required: true + desc: Key name to delete + return: + type: object + desc: Modified map + + - name: MapMultiDel + desc: "[Deprecated: use utils.map.DelMany] Delete multiple keys from a map" + args: + - name: record + type: object + required: true + desc: Input map + - name: keys + type: string + required: true + desc: Keys to delete (variadic) + return: + type: object + desc: Modified map + + - name: MapToArray + desc: "[Deprecated: use utils.map.Array] Convert a map to an array of key-value objects" + args: + - name: record + type: object + required: true + desc: Input map + return: + type: array + desc: "Array of {key, value} objects" + + # String operations + - name: StrConcat + desc: "[Deprecated: use utils.str.Concat] Concatenate multiple values into a string" + args: + - name: values + type: any + required: true + desc: Values to concatenate (variadic, minimum 2) + return: + type: string + desc: Concatenated string + + - name: HexToString + desc: "[Deprecated: use utils.str.Hex] Encode a string or byte array to hexadecimal" + args: + - name: input + type: any + required: true + desc: String or byte array to encode + return: + type: string + desc: Hex-encoded string + + # Captcha + - name: Captcha + desc: "[Deprecated: use utils.captcha.Make] Generate a captcha image/audio" + args: + - name: params + type: any + required: true + desc: "URL-style params with width, height, length, type, lang, background" + return: + type: object + desc: "Object with id and content (base64 image/audio data)" + + - name: CaptchaValidate + desc: "[Deprecated: use utils.captcha.Verify] Validate a captcha code" + args: + - name: id + type: string + required: true + desc: Captcha ID + - name: code + type: string + required: true + desc: User-entered captcha code + return: + type: bool + desc: True if valid; throws exception if invalid + + # Password + - name: PasswordValidate + desc: "[Deprecated: use utils.pwd.Verify] Validate a password against a bcrypt hash" + args: + - name: password + type: string + required: true + desc: Plain text password + - name: passwordHash + type: string + required: true + desc: Bcrypt hash to compare against + return: + type: bool + desc: True if password matches; throws exception if invalid + + # JWT + - name: JwtMake + desc: "[Deprecated: use utils.jwt.Make] Generate a JWT token" + args: + - name: id + type: number + required: true + desc: User ID + - name: data + type: object + required: true + desc: Custom claims data + - name: option + type: object + required: false + desc: "Options: {subject, audience, issuer, timeout (seconds), sid, expires_at}" + return: + type: object + desc: "JWT token object with token string and expires_at timestamp" + + - name: JwtValidate + desc: "[Deprecated: use utils.jwt.Verify] Validate and parse a JWT token" + args: + - name: token + type: string + required: true + desc: JWT token string + return: + type: object + desc: "Decoded JWT claims: {id, sid, data, ...standard claims}" + + # Flow control + - name: For + desc: "[Deprecated: use utils.flow.For] Execute a process in a loop from start to end" + args: + - name: from + type: number + required: true + desc: Start index (inclusive) + - name: to + type: number + required: true + desc: End index (exclusive) + - name: process + type: object + required: true + desc: "Process definition: {process: \"name\", args: [\"::key\", \"::value\"]}" + return: + type: "null" + desc: Returns null + + - name: Each + desc: "[Deprecated: use utils.flow.Each] Iterate over a value (array, map, or integer) and execute a process" + args: + - name: data + type: any + required: true + desc: Value to iterate over (array, map, or integer) + - name: process + type: object + required: true + desc: "Process definition: {process: \"name\", args: [\"::key\", \"::value\"]}" + return: + type: "null" + desc: Returns null + + - name: Case + desc: "[Deprecated: use utils.flow.Case] Execute the first process whose conditions are met" + args: + - name: cases + type: object + required: true + desc: "Case objects (variadic): {when: [{...conditions}], process: \"name\", args: [...]}" + return: + type: any + desc: Return value from the matched process, or null if no match + + - name: IF + desc: "[Deprecated: use utils.flow.IF] Conditional execution with optional else branch" + args: + - name: condition + type: object + required: true + desc: "Primary condition: {when: [{...conditions}], process: \"name\", args: [...]}" + - name: else + type: object + required: false + desc: "Else condition: {when: [{...conditions}], process: \"name\", args: [...]}" + return: + type: any + desc: Return value from the executed process, or null + + - name: Throw + desc: "[Deprecated: use utils.flow.Throw] Throw an exception with a message and HTTP status code" + args: + - name: message + type: string + required: true + desc: Error message + - name: code + type: number + required: true + desc: HTTP status code + return: + type: void + desc: Does not return; throws exception + + - name: Return + desc: "[Deprecated: use utils.flow.Return] Return all arguments as-is" + args: + - name: values + type: any + required: false + desc: Values to return (variadic) + return: + type: array + desc: Array of all passed arguments + + # Environment + - name: EnvGet + desc: "[Deprecated: use utils.env.Get] Get an environment variable value" + args: + - name: name + type: string + required: true + desc: Environment variable name + return: + type: string + desc: Environment variable value + + - name: EnvSet + desc: "[Deprecated: use utils.env.Set] Set an environment variable" + args: + - name: name + type: string + required: true + desc: Environment variable name + - name: value + type: string + required: true + desc: Value to set + return: + type: any + desc: Error on failure, null on success + + - name: EnvMultiGet + desc: "[Deprecated: use utils.env.GetMany] Get multiple environment variable values" + args: + - name: names + type: string + required: true + desc: Environment variable names (variadic) + return: + type: object + desc: Map of variable names to their values + + - name: EnvMultiSet + desc: "[Deprecated: use utils.env.SetMany] Set multiple environment variables" + args: + - name: envs + type: object + required: true + desc: Map of variable names to values + return: + type: any + desc: Error on failure, null on success + + # Print + - name: Print + desc: "[Deprecated: use utils.fmt.Print] Print values to stdout (debug dump)" + args: + - name: values + type: any + required: true + desc: Values to print (variadic) + return: + type: "null" + desc: Returns null diff --git a/openai/doc.go b/openai/doc.go new file mode 100644 index 00000000..04005f7b --- /dev/null +++ b/openai/doc.go @@ -0,0 +1,12 @@ +package openai + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/openai/doc.yml b/openai/doc.yml new file mode 100644 index 00000000..125b9d16 --- /dev/null +++ b/openai/doc.yml @@ -0,0 +1,97 @@ +group: openai +type: process +entries: + - name: tiktoken + desc: Count the number of tokens for a given model and input text + args: + - name: model + type: string + required: true + desc: Model name for tokenization (e.g. "gpt-3.5-turbo", "gpt-4") + - name: input + type: string + required: true + desc: Input text to tokenize + return: + type: number + desc: Number of tokens in the input text + + - name: embeddings + desc: Create embedding vectors representing the input text + args: + - name: model + type: string + required: true + desc: AI connector name (e.g. "openai") + - name: input + type: any + required: true + desc: Input text or array of texts to embed + - name: user + type: string + required: false + desc: Unique identifier for the end-user + return: + type: object + desc: Embedding response with vector data + + - name: chat.completions + desc: Create a chat completion response for the given messages + args: + - name: model + type: string + required: true + desc: AI connector name (e.g. "openai") + - name: messages + type: array + required: true + desc: "Array of message objects with role and content fields" + - name: options + type: object + required: false + desc: "Additional options: temperature, max_tokens, etc." + - name: callback + type: function + required: false + desc: Callback function for streaming responses; receives each chunk and returns an int status + return: + type: object + desc: Chat completion response object + + - name: audio.transcriptions + desc: Transcribe audio from base64-encoded data into text + args: + - name: model + type: string + required: true + desc: AI connector name (e.g. "openai.whisper-1") + - name: dataBase64 + type: string + required: true + desc: Base64-encoded audio data + - name: options + type: object + required: false + desc: "Additional options: language, model override, etc." + return: + type: object + desc: "Transcription result (e.g. {\"text\": \"...\"})" + + - name: audio.transcriptionsfile + desc: Transcribe audio from a file path using streaming upload (no base64 overhead) + args: + - name: connector + type: string + required: true + desc: AI connector name (e.g. "openai.whisper-1") + - name: filePath + type: string + required: true + desc: Absolute OS file path to the audio file + - name: options + type: object + required: false + desc: "Additional options: language, model override, etc." + return: + type: object + desc: "Transcription result (e.g. {\"text\": \"...\"})" diff --git a/openapi/job/doc.go b/openapi/job/doc.go new file mode 100644 index 00000000..c4976882 --- /dev/null +++ b/openapi/job/doc.go @@ -0,0 +1,12 @@ +package job + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/openapi/job/doc.yml b/openapi/job/doc.yml new file mode 100644 index 00000000..4a02ee06 --- /dev/null +++ b/openapi/job/doc.yml @@ -0,0 +1,166 @@ +group: job +type: process +entries: + # Job Management + - name: jobs.list + desc: List jobs with pagination and optional query parameters + args: + - name: page + type: number + required: false + desc: "Page number (default: 1)" + - name: pagesize + type: number + required: false + desc: "Number of records per page (default: 20)" + - name: params + type: object + required: false + desc: Query parameters with wheres, orders, etc. + return: + type: object + desc: Paginated job list with data array and pagination info + + - name: jobs.get + desc: Get a specific job by its ID + args: + - name: jobID + type: string + required: true + desc: Job ID to retrieve + return: + type: object + desc: Job instance details including status, schedule, last_run_at, next_run_at, etc. + + - name: jobs.count + desc: Count jobs matching query parameters + args: + - name: params + type: object + required: false + desc: Query parameters with wheres conditions + return: + type: object + desc: "Object with count" + + - name: jobs.stop + desc: Stop a running job + args: + - name: jobID + type: string + required: true + desc: Job ID to stop + return: + type: object + desc: "Object with message and job_id" + + # Execution Management + - name: executions.list + desc: List executions for a specific job + args: + - name: jobID + type: string + required: true + desc: Job ID to list executions for + return: + type: object + desc: "Object with executions array and count" + + - name: executions.get + desc: Get a specific execution by its ID + args: + - name: executionID + type: string + required: true + desc: Execution ID to retrieve + - name: params + type: object + required: false + desc: Optional query parameters + return: + type: object + desc: Execution details including status, progress, started_at, ended_at, duration, etc. + + - name: executions.count + desc: Count executions for a specific job + args: + - name: jobID + type: string + required: true + desc: Job ID to count executions for + - name: params + type: object + required: false + desc: Optional query parameters with wheres conditions + return: + type: object + desc: "Object with count" + + - name: executions.stop + desc: Stop a running execution (stops the parent job) + args: + - name: executionID + type: string + required: true + desc: Execution ID to stop + return: + type: object + desc: "Object with message, execution_id, and job_id" + + # Log Management + - name: logs.list + desc: List logs for a specific job with pagination + args: + - name: jobID + type: string + required: true + desc: Job ID to list logs for + - name: page + type: number + required: false + desc: "Page number (default: 1)" + - name: pagesize + type: number + required: false + desc: "Number of records per page (default: 50)" + - name: params + type: object + required: false + desc: Optional query parameters with wheres conditions (level, execution_id filters) + return: + type: object + desc: Paginated log list with data array and pagination info + + # Category Management + - name: categories.list + desc: List job categories with optional filtering + args: + - name: params + type: object + required: false + desc: Query parameters with wheres conditions (enabled, system filters) + return: + type: object + desc: "Object with categories array and count" + + - name: categories.get + desc: Get a specific job category by its ID + args: + - name: categoryID + type: string + required: true + desc: Category ID to retrieve + return: + type: object + desc: Category details including name, description, enabled status, etc. + + - name: categories.count + desc: Count job categories matching query parameters + args: + - name: params + type: object + required: false + desc: Query parameters with wheres conditions + return: + type: object + desc: "Object with count" diff --git a/openapi/kb/doc.go b/openapi/kb/doc.go new file mode 100644 index 00000000..593d3487 --- /dev/null +++ b/openapi/kb/doc.go @@ -0,0 +1,12 @@ +package kb + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/openapi/kb/doc.yml b/openapi/kb/doc.yml new file mode 100644 index 00000000..21b909e2 --- /dev/null +++ b/openapi/kb/doc.yml @@ -0,0 +1,118 @@ +group: kb +type: process +entries: + # Collection Management + - name: collection.create + desc: Create a new knowledge base collection with embedding configuration + args: + - name: params + type: object + required: true + desc: "Collection parameters: {id, metadata: {name, description}, embedding_provider_id, embedding_option_id, locale, config: {distance, index_type, m, ef_construction, ef_search}}" + return: + type: object + desc: "Object with collection_id and message" + + - name: collection.remove + desc: Remove a collection and all its documents + args: + - name: collectionID + type: string + required: true + desc: Collection ID to remove + return: + type: object + desc: "Object with collection_id, removed status, documents_removed count, and message" + + - name: collection.get + desc: Retrieve a collection by its ID + args: + - name: collectionID + type: string + required: true + desc: Collection ID to retrieve + return: + type: object + desc: Collection details including metadata, embedding config, status, etc. + + - name: collection.exists + desc: Check if a collection exists + args: + - name: collectionID + type: string + required: true + desc: Collection ID to check + return: + type: object + desc: "Object with collection_id and exists (bool)" + + - name: collection.list + desc: List collections with pagination and filtering + args: + - name: filter + type: object + required: false + desc: "Filter parameters: {page, pagesize, keywords, status, embedding_provider_id, system, select, sort}" + return: + type: object + desc: Paginated result with data array, page, pagesize, total, pagecnt, next, prev + + - name: collection.updatemetadata + desc: Update the metadata of an existing collection + args: + - name: collectionID + type: string + required: true + desc: Collection ID to update + - name: params + type: object + required: true + desc: "Update parameters: {metadata: {name, description}}" + return: + type: object + desc: "Object with collection_id and message" + + # Document Management + - name: documents.addfile + desc: Add a document to a collection from an uploaded file + args: + - name: params + type: object + required: true + desc: File upload parameters including collection_id and file data + return: + type: object + desc: Document creation result with document_id + + - name: documents.addtext + desc: Add a document to a collection from raw text content + args: + - name: params + type: object + required: true + desc: Text document parameters including collection_id, content, and metadata + return: + type: object + desc: Document creation result with document_id + + - name: documents.addurl + desc: Add a document to a collection by fetching content from a URL + args: + - name: params + type: object + required: true + desc: URL document parameters including collection_id and URL + return: + type: object + desc: Document creation result with document_id + + - name: documents.getcontents + desc: Retrieve content for one or more documents by their IDs + args: + - name: documentIDs + type: any + required: true + desc: "A single document ID (string) or an array of document IDs" + return: + type: array + desc: Array of objects with document_id, name, content, content_type, etc. diff --git a/openapi/oauth/doc.go b/openapi/oauth/doc.go new file mode 100644 index 00000000..45a9c8f8 --- /dev/null +++ b/openapi/oauth/doc.go @@ -0,0 +1,12 @@ +package oauth + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/openapi/oauth/doc.yml b/openapi/oauth/doc.yml new file mode 100644 index 00000000..bc238338 --- /dev/null +++ b/openapi/oauth/doc.yml @@ -0,0 +1,48 @@ +group: oauth +type: process +entries: + - name: token.Make + desc: Generate an OAuth access token with explicit parameters + args: + - name: clientID + type: string + required: true + desc: OAuth client ID embedded in the token + - name: scope + type: string + required: true + desc: Token scope (space-separated) + - name: subject + type: string + required: true + desc: JWT subject claim + - name: expiresIn + type: number + required: true + desc: Token lifetime in seconds + - name: extraClaims + type: object + required: false + desc: Additional JWT claims (e.g. user_id, team_id) + return: + type: string + desc: The generated access token string + + - name: token.MakeByUser + desc: Generate an OAuth access token for a team member by looking up user and team from the database + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: memberID + type: string + required: true + desc: Member ID (business ID) + - name: expiresIn + type: number + required: false + desc: "Token lifetime in seconds (default: 86400 = 24h)" + return: + type: string + desc: The generated access token string diff --git a/openapi/otp/doc.go b/openapi/otp/doc.go new file mode 100644 index 00000000..f77349c2 --- /dev/null +++ b/openapi/otp/doc.go @@ -0,0 +1,12 @@ +package otp + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/openapi/otp/doc.yml b/openapi/otp/doc.yml new file mode 100644 index 00000000..23b197f9 --- /dev/null +++ b/openapi/otp/doc.yml @@ -0,0 +1,50 @@ +group: otp +type: process +entries: + - name: create + desc: Create a new OTP code with associated payload data for login or verification + args: + - name: params + type: object + required: true + desc: "OTP creation parameters: team_id, member_id, user_id, expires_in, redirect, scope, token_expires_in, consume" + return: + type: string + desc: The generated OTP code + + - name: verify + desc: Verify an OTP code and return its associated payload without consuming it + args: + - name: code + type: string + required: true + desc: The OTP code to verify + return: + type: object + desc: The payload associated with the OTP code (team_id, member_id, user_id, redirect, scope, etc.) + + - name: login + desc: Verify an OTP code and perform login, returning access tokens and redirect URL + args: + - name: code + type: string + required: true + desc: The OTP code to authenticate with + - name: locale + type: string + required: false + desc: Locale for login context (e.g. "en", "zh-CN") + return: + type: object + desc: Login result with access_token, id_token, refresh_token, expires_in, redirect, etc. + + - name: revoke + desc: Revoke an OTP code, making it no longer usable + args: + - name: code + type: string + required: true + desc: The OTP code to revoke + return: + type: "null" + desc: Returns null on success diff --git a/openapi/user/doc.go b/openapi/user/doc.go new file mode 100644 index 00000000..d773f8e1 --- /dev/null +++ b/openapi/user/doc.go @@ -0,0 +1,12 @@ +package user + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/openapi/user/doc.yml b/openapi/user/doc.yml new file mode 100644 index 00000000..670c9b93 --- /dev/null +++ b/openapi/user/doc.yml @@ -0,0 +1,264 @@ +group: user +type: process +entries: + # Profile + - name: profile.get + desc: Get the current user's profile information + args: + - name: options + type: object + required: false + desc: "Optional flags: {team: bool, member: bool, type: bool} to include team, member, or type info" + return: + type: object + desc: User profile data in OIDC format with optional team/member/type info + + - name: profile.update + desc: Update the current user's profile information + args: + - name: data + type: object + required: true + desc: "Profile fields to update (name, given_name, family_name, nickname, picture, gender, locale, theme, metadata, etc.)" + return: + type: object + desc: "Object with user_id and message" + + # Team Management + - name: team.list + desc: List teams owned by the current user with pagination and filtering + args: + - name: params + type: object + required: true + desc: "Query parameters: {status, name, page, pagesize}" + return: + type: object + desc: Paginated team list with data array and pagination info + + - name: team.get + desc: Get details of a specific team the current user is a member of + args: + - name: teamID + type: string + required: true + desc: Team ID to retrieve + return: + type: object + desc: Team details including name, description, logo, owner_id, status, settings + + - name: team.create + desc: Create a new team with the current user as owner + args: + - name: data + type: object + required: true + desc: "Team data: {name, description, settings, ...}" + return: + type: object + desc: "Object with team_id of the created team" + + - name: team.update + desc: Update an existing team owned by the current user + args: + - name: teamID + type: string + required: true + desc: Team ID to update + - name: data + type: object + required: true + desc: "Fields to update: {name, description, settings, ...}" + return: + type: object + desc: "Object with message" + + - name: team.delete + desc: Delete a team owned by the current user (removes all members first) + args: + - name: teamID + type: string + required: true + desc: Team ID to delete + return: + type: object + desc: "Object with message" + + # Team Member Management + - name: member.list + desc: List members of a team with advanced filtering and pagination + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: params + type: object + required: true + desc: "Query parameters: {page, pagesize, status, member_type, role_id, email, display_name, order, fields, locale}" + return: + type: object + desc: Paginated member list with data array and pagination info + + - name: member.get + desc: Get details of a specific team member + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: memberID + type: string + required: true + desc: Member ID (business key) + return: + type: object + desc: Member details including role, status, display_name, robot config, etc. + + - name: member.update + desc: Update a team member (owner only, for role/status changes) + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: memberID + type: string + required: true + desc: Member ID (business key) + - name: data + type: object + required: true + desc: "Fields to update: {role_id, status, settings, last_activity}" + return: + type: object + desc: "Object with message" + + - name: member.profile.get + desc: Get a team member's profile (display_name, bio, avatar, email) + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: userID + type: string + required: true + desc: "User ID of the member (not member_id)" + return: + type: object + desc: Member profile data with user_id, team_id, display_name, bio, avatar, email + + - name: member.profile.update + desc: Update a team member's own profile (display_name, bio, avatar, email) + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: userID + type: string + required: true + desc: "User ID of the member (not member_id)" + - name: data + type: object + required: true + desc: "Profile fields to update: {display_name, bio, avatar, email}" + return: + type: object + desc: "Object with user_id and message" + + - name: member.delete + desc: Remove a member from a team (owner only) + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: memberID + type: string + required: true + desc: Member ID (business key) + return: + type: object + desc: "Object with message" + + # Team Invitation Management + - name: team.invitation.list + desc: List pending invitations for a team with pagination + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: params + type: object + required: true + desc: "Query parameters: {status, page, pagesize}" + return: + type: object + desc: Paginated invitation list with data array and pagination info + + - name: team.invitation.get + desc: Get details of a specific team invitation + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: invitationID + type: string + required: true + desc: Invitation ID (business key) + return: + type: object + desc: Invitation details including status, role, invited_by, expiry, etc. + + - name: team.invitation.create + desc: Create a new team invitation (owner only) + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: data + type: object + required: true + desc: "Invitation data: {user_id, email, member_type, role_id, message, expiry, settings}" + return: + type: object + desc: "Object with invitation_id" + + - name: team.invitation.resend + desc: Resend a pending team invitation with a new token and extended expiry + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: invitationID + type: string + required: true + desc: Invitation ID (business key) + - name: locale + type: string + required: false + desc: "Locale for email template (default: \"en\")" + return: + type: object + desc: "Object with message" + + - name: team.invitation.delete + desc: Cancel a pending team invitation (owner only) + args: + - name: teamID + type: string + required: true + desc: Team ID + - name: invitationID + type: string + required: true + desc: Invitation ID (business key) + return: + type: object + desc: "Object with message" diff --git a/pipe/doc.go b/pipe/doc.go new file mode 100644 index 00000000..352b0de9 --- /dev/null +++ b/pipe/doc.go @@ -0,0 +1,17 @@ +package pipe + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +//go:embed doc_pipes.yml +var docPipesYAML []byte + +func init() { + doc.LoadYAML(docYAML) + doc.LoadYAML(docPipesYAML) +} diff --git a/pipe/doc.yml b/pipe/doc.yml new file mode 100644 index 00000000..9a1d11fd --- /dev/null +++ b/pipe/doc.yml @@ -0,0 +1,96 @@ +group: pipe +type: process +entries: + - name: run + desc: Run a loaded pipeline by its registered ID + args: + - name: pipeId + type: string + required: true + desc: Registered pipeline ID + - name: args + type: any + required: false + desc: "Variable arguments passed to the pipeline execution" + return: + type: any + desc: Pipeline execution result + + - name: create + desc: Create a new pipeline from a DSL string and run it immediately + args: + - name: dsl + type: string + required: true + desc: Pipeline DSL definition as a YAML/JSON string + - name: args + type: any + required: false + desc: "Variable arguments passed to the pipeline execution" + return: + type: any + desc: Pipeline execution result + + - name: createwith + desc: Create a new pipeline from DSL with global data and run it immediately + args: + - name: dsl + type: string + required: true + desc: Pipeline DSL definition as a YAML/JSON string + - name: global + type: object + required: true + desc: Global data map merged with process global context + - name: args + type: any + required: false + desc: "Variable arguments passed to the pipeline execution" + return: + type: any + desc: Pipeline execution result + + - name: resume + desc: Resume a paused pipeline context by its context ID + args: + - name: contextId + type: string + required: true + desc: Pipeline context ID to resume + - name: args + type: any + required: false + desc: "Variable arguments passed to the resumed pipeline" + return: + type: any + desc: Resumed pipeline execution result + + - name: resumewith + desc: Resume a paused pipeline context with additional global data + args: + - name: contextId + type: string + required: true + desc: Pipeline context ID to resume + - name: global + type: object + required: true + desc: Global data map merged with process global context + - name: args + type: any + required: false + desc: "Variable arguments passed to the resumed pipeline" + return: + type: any + desc: Resumed pipeline execution result + + - name: close + desc: Close and clean up a pipeline context + args: + - name: contextId + type: string + required: true + desc: Pipeline context ID to close + return: + type: "null" + desc: Returns null on success diff --git a/pipe/doc_pipes.yml b/pipe/doc_pipes.yml new file mode 100644 index 00000000..758aad5b --- /dev/null +++ b/pipe/doc_pipes.yml @@ -0,0 +1,13 @@ +group: pipes +type: process +entries: + - name: "*" + desc: "Run a loaded pipeline by ID. Called as pipes. with the pipe ID as the process name suffix" + args: + - name: args + type: any + required: false + desc: "Variable arguments passed to the pipeline execution" + return: + type: any + desc: Pipeline execution result diff --git a/rss/doc.go b/rss/doc.go new file mode 100644 index 00000000..9548c8ef --- /dev/null +++ b/rss/doc.go @@ -0,0 +1,11 @@ +package rss + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/rss/doc.yml b/rss/doc.yml new file mode 100644 index 00000000..67497eb8 --- /dev/null +++ b/rss/doc.yml @@ -0,0 +1,66 @@ +group: rss +type: process +desc: "RSS/Atom feed parsing, validation, building, discovery, and fetching processes" +entries: + - name: parse + desc: Parse an RSS 2.0 or Atom 1.0 XML string into a unified Feed object with auto-format detection and podcast metadata extraction + args: + - name: data + type: string + required: true + desc: "Feed XML string to parse" + return: + type: object + desc: "Feed object with format, title, link, description, language, updated, items (array), and podcast (object or null) fields" + + - name: validate + desc: Check whether a string is a valid RSS 2.0 or Atom 1.0 feed + args: + - name: data + type: string + required: true + desc: "Feed XML string to validate" + return: + type: any + desc: "True (bool) if valid; error description string if invalid" + + - name: discover + desc: Extract feed URLs from HTML, Markdown, or plain text content using regex-based detection (no network requests) + args: + - name: text + type: string + required: true + desc: "Text content to scan for feed URLs" + return: + type: array + desc: "Array of FeedLink objects with url, title, and type fields" + + - name: build + desc: Generate an XML feed document from a Feed object + args: + - name: feed + type: object + required: true + desc: "Feed object (same structure as rss.parse output)" + - name: format + type: string + required: false + desc: "Output format: \"rss\" (default) or \"atom\"" + return: + type: string + desc: "XML feed document string" + + - name: fetch + desc: Fetch a remote RSS/Atom feed by URL and return the parsed Feed with HTTP metadata for conditional polling + args: + - name: url + type: string + required: true + desc: "Feed URL to fetch" + - name: options + type: object + required: false + desc: "Fetch options: user_agent (string), timeout (number, seconds), etag (string, for If-None-Match), last_modified (string, for If-Modified-Since)" + return: + type: object + desc: "FetchResult with feed (object or null), status_code (number), etag (string), last_modified (string), and not_modified (bool) fields" diff --git a/seed/doc.go b/seed/doc.go new file mode 100644 index 00000000..44608e2a --- /dev/null +++ b/seed/doc.go @@ -0,0 +1,12 @@ +package seed + +import ( + _ "embed" + + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/seed/doc.yml b/seed/doc.yml new file mode 100644 index 00000000..589ec6c2 --- /dev/null +++ b/seed/doc.yml @@ -0,0 +1,21 @@ +group: seeds +type: process +entries: + - name: import + desc: Import seed data from a file (CSV, XLSX, JSON, JSONC/Yao) into a model table + args: + - name: filename + type: string + required: true + desc: "Seed file name relative to the seeds directory (e.g. \"users.csv\", \"data.xlsx\", \"records.json\")" + - name: modelName + type: string + required: true + desc: Target model name to import data into + - name: options + type: object + required: false + desc: "Import options: {chunk_size: number, duplicate: \"ignore\"|\"error\"|\"update\"|\"abort\", mode: \"batch\"|\"each\"}" + return: + type: object + desc: "Import result: {total, success, failure, ignore, errors: [{row, message, code, data}]}" diff --git a/sitemap/doc.go b/sitemap/doc.go new file mode 100644 index 00000000..0d1c5fcc --- /dev/null +++ b/sitemap/doc.go @@ -0,0 +1,11 @@ +package sitemap + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/sitemap/doc.yml b/sitemap/doc.yml new file mode 100644 index 00000000..073e65d8 --- /dev/null +++ b/sitemap/doc.yml @@ -0,0 +1,103 @@ +group: sitemap +type: process +desc: "Sitemap parsing, validation, discovery, fetching, and streaming build processes" +entries: + - name: parse + desc: Parse a sitemap XML string into a unified ParseResult, auto-detecting urlset or sitemapindex format + args: + - name: data + type: string + required: true + desc: "Sitemap XML string to parse" + return: + type: object + desc: "ParseResult with type (\"urlset\" or \"sitemapindex\"), urls (array of URL objects), and sitemaps (array of SitemapEntry objects)" + + - name: validate + desc: Check whether a string is a valid sitemap XML document + args: + - name: data + type: string + required: true + desc: "Sitemap XML string to validate" + return: + type: any + desc: "True (bool) if valid; error description string if invalid" + + - name: parserobo + desc: Extract sitemap URLs from robots.txt content (pure text parsing, no HTTP) + args: + - name: text + type: string + required: true + desc: "robots.txt content" + return: + type: array + desc: "Array of sitemap URL strings" + + - name: discover + desc: Discover sitemap files for a domain via robots.txt and well-known paths, recursively expanding sitemapindex files + args: + - name: domain + type: string + required: true + desc: "Domain to discover sitemaps for (e.g. \"example.com\")" + - name: options + type: object + required: false + desc: "Options: user_agent (string), timeout (number, seconds)" + return: + type: object + desc: "DiscoverResult with sitemaps (array of SitemapLink objects with url, source, url_count, content_size, encoding, last_modified, etag) and total_urls (number)" + + - name: fetch + desc: Fetch and parse URLs from sitemaps for a domain with pagination support + args: + - name: domain + type: string + required: true + desc: "Domain to fetch sitemaps for (e.g. \"example.com\")" + - name: options + type: object + required: false + desc: "Options: offset (number), limit (number, default/max 50000), user_agent (string), timeout (number, seconds)" + return: + type: object + desc: "FetchResult with urls (array of URL objects with loc, lastmod, changefreq, priority, images, videos, news) and total (number)" + + - name: build.open + desc: Open a new streaming sitemap writer and return a UUID handle + args: + - name: options + type: object + required: true + desc: "Build options: dir (string, output directory path, required), base_url (string, URL prefix for index references, required if multiple files)" + return: + type: string + desc: "UUID handle string for use with build.write and build.close" + + - name: build.write + desc: Write a batch of URLs to an open sitemap writer, automatically splitting at 50,000 URLs per file + args: + - name: handle + type: string + required: true + desc: "UUID handle from build.open" + - name: urls + type: array + required: true + desc: "Array of URL objects with loc (required), lastmod, changefreq, priority, images, videos, and news fields" + return: + type: "null" + desc: "Returns null on success" + + - name: build.close + desc: Finalize the sitemap output, generate a sitemapindex if needed, and clean up the handle + args: + - name: handle + type: string + required: true + desc: "UUID handle from build.open" + return: + type: object + desc: "BuildResult with index (string, sitemap_index.xml path or empty), files (array of file paths), and total (number of URLs written)" diff --git a/sui/api/doc.go b/sui/api/doc.go new file mode 100644 index 00000000..ba1487af --- /dev/null +++ b/sui/api/doc.go @@ -0,0 +1,11 @@ +package api + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/sui/api/doc.yml b/sui/api/doc.yml new file mode 100644 index 00000000..6652c108 --- /dev/null +++ b/sui/api/doc.yml @@ -0,0 +1,772 @@ +group: sui +type: process +entries: + - name: setting + desc: Get the SUI instance settings + args: + - name: instance + type: string + required: true + desc: SUI instance name + return: + type: object + desc: SUI setting object + + - name: render + desc: "[Internal] Render an HTML fragment by route. Do not use in scripts or flows, use template.render instead" + args: + - name: context + type: external + required: true + desc: Gin request context (*gin.Context) + - name: route + type: string + required: true + desc: Page route path + - name: payload + type: object + required: true + desc: "Render payload containing name (render target), data (template data), and option (render options)" + return: + type: string + desc: Rendered HTML string + + - name: run + desc: "[Internal] Execute a page backend script method. Do not use in scripts or flows" + args: + - name: context + type: external + required: true + desc: Gin request context (*gin.Context) + - name: route + type: string + required: true + desc: Page route path + - name: payload + type: object + required: true + desc: "Execution payload with method (string, required) and args (array, optional)" + return: + type: any + desc: Script execution result + + - name: template.get + desc: List all templates in the SUI instance + args: + - name: instance + type: string + required: true + desc: SUI instance name + return: + type: array + desc: Array of template objects + + - name: template.find + desc: Find a template by ID + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + return: + type: object + desc: Template object + + - name: template.asset + desc: Get a template asset file content and MIME type + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: path + type: string + required: true + desc: Asset file path within the template + - name: width + type: number + required: false + desc: Optional image width for resizing + - name: height + type: number + required: false + desc: Optional image height for resizing + return: + type: object + desc: "Object with content (asset data) and type (MIME type)" + + - name: template.assetupload + desc: Upload an asset file to a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: file + type: any + required: true + desc: "File data: *gin.Context (form upload with field 'file') or base64-encoded string" + - name: filename + type: string + required: false + desc: "Filename when uploading as base64 string (default: file.png)" + return: + type: any + desc: "Upload result: object with data and header (form upload), or file path string (base64)" + + - name: template.render + desc: Compile and render a template page to HTML + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: source + type: string + required: true + desc: Page source path + - name: data + type: object + required: true + desc: Template data for rendering + - name: option + type: object + required: false + desc: "Render options with theme, locale, and data fields" + - name: request + type: object + required: false + desc: Override request object for rendering context + return: + type: string + desc: Rendered HTML string + + - name: locale.get + desc: Get available locales for a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + return: + type: array + desc: Array of locale select options, or empty array if none + + - name: theme.get + desc: Get available themes for a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + return: + type: array + desc: Array of theme objects + + - name: block.get + desc: List all blocks in a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + return: + type: array + desc: Array of block objects + + - name: block.find + desc: Get the source code of a block by ID + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: blockId + type: string + required: true + desc: Block ID (trailing .js suffix is stripped) + return: + type: string + desc: Block source code + + - name: block.Media + desc: Get the media asset of a block + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: blockId + type: string + required: true + desc: Block ID (trailing .js suffix is stripped) + return: + type: object + desc: "Object with content (media data) and type (MIME type)" + + - name: block.export + desc: Export block layout items from a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + return: + type: array + desc: Array of block layout items + + - name: component.get + desc: List all components in a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + return: + type: array + desc: Array of component objects + + - name: component.find + desc: Get the source code of a component by ID + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: componentId + type: string + required: true + desc: Component ID (trailing .js suffix is stripped) + return: + type: string + desc: Component source code + + - name: page.tree + desc: Get the page tree under a route + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: false + desc: "Route path (defaults to /index if empty)" + return: + type: object + desc: Page tree structure + + - name: page.get + desc: List all pages in a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + return: + type: array + desc: Array of page objects + + - name: page.save + desc: Save a page source to the given route + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: source + type: any + required: true + desc: "Page source: RequestSource object, *gin.Context, JSON string, or map" + return: + type: "null" + desc: Returns null on success + + - name: page.savetemp + desc: Temporarily save a page source (requires source.uid) + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: source + type: any + required: true + desc: "Page source with uid field required: RequestSource object, *gin.Context, JSON string, or map" + return: + type: "null" + desc: Returns null on success + + - name: page.create + desc: Create a new empty page and optionally save initial source + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: source + type: any + required: false + desc: "Optional initial page source to save" + - name: payload + type: object + required: false + desc: "Optional payload with route (override) and title fields" + return: + type: "null" + desc: Returns null on success + + - name: page.duplicate + desc: Duplicate a page to a new route + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: sourceRoute + type: string + required: true + desc: Source page route to copy from + - name: payload + type: object + required: false + desc: "Object with route (required, target path) and title (optional)" + return: + type: "null" + desc: Returns null on success + + - name: page.rename + desc: Rename (move) a page to a new route + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: sourceRoute + type: string + required: true + desc: Current page route + - name: payload + type: object + required: true + desc: "Object with route field (required, new route path)" + return: + type: "null" + desc: Returns null on success + + - name: page.remove + desc: Remove a page from the template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path to remove + return: + type: "null" + desc: Returns null on success + + - name: page.exist + desc: Check if a page exists at the given route + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path to check + return: + type: bool + desc: True if the page exists + + - name: page.asset + desc: Get the CSS or JS/TS asset content of a page + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: file + type: string + required: true + desc: "Asset file path (.css, .js, or .ts extension)" + return: + type: object + desc: "Object with content (asset data) and type (MIME type)" + + - name: editor.render + desc: Render a page for the editor view + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + return: + type: any + desc: Editor render result + + - name: editor.source + desc: Get page source code by kind for the editor + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: kind + type: string + required: true + desc: "Source kind: page, style, script, or data" + return: + type: any + desc: Source code content for the specified kind + + - name: editor.renderaftersavetemp + desc: Temporarily save page source then render for the editor + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: source + type: any + required: true + desc: Page source to save temporarily (requires uid) + - name: extra + type: any + required: false + desc: Additional arguments passed to the editor render + return: + type: any + desc: Editor render result + + - name: editor.sourceaftersavetemp + desc: Temporarily save page source then get editor source + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: source + type: any + required: true + desc: Page source to save temporarily (requires uid) + - name: extra + type: any + required: false + desc: Additional arguments passed to the editor source + return: + type: any + desc: Source code content for the specified kind + + - name: media.search + desc: Search media assets in a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: driver + type: string + required: true + desc: "Media driver name (e.g., local)" + - name: query + type: any + required: false + desc: "Search query parameters: map or url.Values. Supports page, pagesize, and template fields" + return: + type: any + desc: Media search results + + - name: preview.render + desc: Render a page for preview + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: referer + type: string + required: false + desc: Optional referer URL + return: + type: string + desc: Preview HTML string + + - name: build.all + desc: Build all pages in a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: option + type: object + required: true + desc: "Build options with ssr (bool), asset_root (string), and data (object) fields" + return: + type: any + desc: Array of warnings if any, otherwise null + + - name: build.page + desc: Build a single page in a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: option + type: object + required: true + desc: "Build options with ssr (bool) and asset_root (string) fields" + - name: extra + type: any + required: false + desc: Reserved + - name: data + type: object + required: false + desc: Additional data for the build + return: + type: any + desc: Array of warnings if any, otherwise null + + - name: trans.all + desc: Extract and translate all pages in a template + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: option + type: object + required: true + desc: "Translation options with ssr (bool), asset_root (string), and data (object) fields" + return: + type: any + desc: Array of warnings if any, otherwise null + + - name: trans.page + desc: Extract and translate a single page + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: route + type: string + required: true + desc: Page route path + - name: option + type: object + required: true + desc: "Translation options with ssr (bool) and asset_root (string) fields" + - name: extra + type: any + required: false + desc: Reserved + - name: data + type: object + required: false + desc: Additional data for the translation + return: + type: any + desc: Array of warnings if any, otherwise null + + - name: sync.assetfile + desc: "[Deprecated] Sync a single asset file in a template" + args: + - name: instance + type: string + required: true + desc: SUI instance name + - name: templateId + type: string + required: true + desc: Template ID + - name: filename + type: string + required: true + desc: Asset filename to sync + - name: option + type: object + required: true + desc: "Sync options with ssr (bool), asset_root (string), and data (object) fields" + return: + type: "null" + desc: Returns null on success + + - name: types.QueryParam + desc: "[Deprecated] Convert various input formats to a query parameter structure" + args: + - name: input + type: any + required: true + desc: "Input data: url.Values, map[string][]string, map[string]interface{}, or any serializable value" + return: + type: any + desc: Converted query parameter structure diff --git a/utils/doc.go b/utils/doc.go new file mode 100644 index 00000000..3209ca77 --- /dev/null +++ b/utils/doc.go @@ -0,0 +1,11 @@ +package utils + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/utils/doc.yml b/utils/doc.yml new file mode 100644 index 00000000..f50f0ab9 --- /dev/null +++ b/utils/doc.yml @@ -0,0 +1,377 @@ +group: utils +type: process +entries: + # throw + - name: throw.Forbidden + desc: Throw a 403 Forbidden exception + args: + - name: message + type: string + required: false + desc: "Error message (default: \"Access denied\")" + return: + type: void + desc: Does not return; throws exception + + - name: throw.Unauthorized + desc: Throw a 401 Unauthorized exception + args: + - name: message + type: string + required: false + desc: "Error message (default: \"Authentication required\")" + return: + type: void + desc: Does not return; throws exception + + - name: throw.NotFound + desc: Throw a 404 Not Found exception + args: + - name: message + type: string + required: false + desc: "Error message (default: \"Resource not found\")" + return: + type: void + desc: Does not return; throws exception + + - name: throw.BadRequest + desc: Throw a 400 Bad Request exception + args: + - name: message + type: string + required: false + desc: "Error message (default: \"Bad Request\")" + return: + type: void + desc: Does not return; throws exception + + - name: throw.InternalError + desc: Throw a 500 Internal Server Error exception + args: + - name: message + type: string + required: false + desc: "Error message (default: \"Internal Error\")" + return: + type: void + desc: Does not return; throws exception + + - name: throw.Exception + desc: Throw a custom exception with specified message and HTTP status code + args: + - name: message + type: string + required: true + desc: Error message + - name: code + type: number + required: true + desc: HTTP status code + return: + type: void + desc: Does not return; throws exception + + # fmt + - name: fmt.Printf + desc: Print formatted output to stdout + args: + - name: format + type: string + required: true + desc: Format string (Go fmt style) + - name: args + type: any + required: false + desc: Values to format (variadic) + return: + type: "null" + desc: Returns null + + - name: fmt.ColorPrintf + desc: Print colored formatted output to stdout + args: + - name: color + type: string + required: true + desc: "Color name: red, green, yellow, blue, magenta, cyan, white, black, hired, higreen, etc." + - name: format + type: string + required: true + desc: Format string (Go fmt style) + - name: args + type: any + required: false + desc: Values to format (variadic) + return: + type: "null" + desc: Returns null + + # str + - name: str.Join + desc: Join array elements into a string with a separator + args: + - name: array + type: array + required: true + desc: Array of values to join + - name: separator + type: string + required: true + desc: Separator string + return: + type: string + desc: Joined string + + - name: str.JoinPath + desc: Join path segments into a file path + args: + - name: paths + type: string + required: true + desc: Path segments to join (variadic, minimum 2 segments required) + return: + type: string + desc: Joined file path + + - name: str.UUID + desc: Generate a new UUID v4 string + args: [] + return: + type: string + desc: UUID string (e.g. "550e8400-e29b-41d4-a716-446655440000") + + - name: str.Pinyin + desc: Convert Chinese characters to Pinyin + args: + - name: text + type: string + required: true + desc: Chinese text to convert + - name: options + type: object + required: false + desc: "Options: {tone: bool|\"mark\"|\"number\"|\"none\", heteronym: bool, separator: string}" + return: + type: string + desc: Pinyin string + + # tree + - name: tree.Flatten + desc: Flatten a tree structure into a flat array + args: + - name: array + type: array + required: true + desc: Tree-structured array to flatten + - name: options + type: object + required: false + desc: "Options: {primary: \"id\", children: \"children\", parent: \"parent\"}" + return: + type: array + desc: Flat array with parent references + + # now / time + - name: now.Time + desc: Get the current time as a string + args: [] + return: + type: string + desc: "Current time in HH:MM:SS format (e.g. \"15:04:05\")" + + - name: now.Date + desc: Get the current date as a string + args: [] + return: + type: string + desc: "Current date in YYYY-MM-DD format (e.g. \"2006-01-02\")" + + - name: now.DateTime + desc: Get the current date and time as a string + args: [] + return: + type: string + desc: "Current datetime in YYYY-MM-DD HH:MM:SS format" + + - name: now.Timestamp + desc: Get the current Unix timestamp in seconds + args: [] + return: + type: number + desc: Unix timestamp in seconds + + - name: now.Timestampms + desc: Get the current Unix timestamp in milliseconds + args: [] + return: + type: number + desc: Unix timestamp in milliseconds + + # url + - name: url.ParseQuery + desc: Parse a URL query string into key-value pairs + args: + - name: queryString + type: string + required: true + desc: "URL query string (e.g. \"key1=val1&key2=val2\")" + return: + type: object + desc: Parsed query parameters as map of string to string array + + - name: url.QueryParam + desc: Convert URL values or map to QueryParam object + args: + - name: values + type: any + required: true + desc: "URL values: url.Values, map[string][]string, or map[string]interface{}" + return: + type: object + desc: QueryParam object + + - name: url.ParseURL + desc: Parse a URL string into its components + args: + - name: url + type: string + required: true + desc: URL string to parse + return: + type: object + desc: "Parsed URL with scheme, host, domain, path, port, query, and url fields" + + # json + - name: json.Validate + desc: "[Warning: under development] Validate JSON data against rules" + args: + - name: data + type: object + required: true + desc: JSON data to validate + - name: rules + type: array + required: true + desc: "Validation rules (e.g. [{\"haskey\": \"fieldName\"}])" + return: + type: bool + desc: True if validation passes, false otherwise + + # jsonschema + - name: jsonschema.ValidateSchema + desc: Validate a JSON Schema structure + args: + - name: schema + type: any + required: true + desc: "JSON Schema to validate (map, string, or bytes)" + return: + type: any + desc: "Null if valid, error message string if invalid" + + - name: jsonschema.Validate + desc: Validate data against a JSON Schema + args: + - name: schema + type: any + required: true + desc: "JSON Schema (map, string, or bytes)" + - name: data + type: any + required: true + desc: Data to validate against the schema + return: + type: any + desc: "Null if valid, error message string if invalid" + + # captcha (0.10.5+) + - name: captcha.Generate + desc: Generate a captcha image/audio with customizable options + args: + - name: options + type: object + required: true + desc: "Options: {width, height, length, type, lang, background}" + return: + type: object + desc: "Object with id and content (base64 image/audio)" + + - name: captcha.Validate + desc: Validate a captcha code + args: + - name: id + type: string + required: true + desc: Captcha ID returned by Generate + - name: code + type: string + required: true + desc: User-entered captcha code + return: + type: bool + desc: True if valid; throws exception if invalid + + - name: captcha.Get + desc: Get the captcha code by ID (for testing purposes) + args: + - name: id + type: string + required: true + desc: Captcha ID + return: + type: string + desc: The captcha answer code + + # otp (0.10.5+) + - name: otp.Generate + desc: Generate a one-time password (OTP) code + args: + - name: options + type: object + required: true + desc: "Options: {length: number, expiration: number (seconds), type: string}" + return: + type: object + desc: "Object with id and code" + + - name: otp.Validate + desc: Validate a one-time password (OTP) code + args: + - name: id + type: string + required: true + desc: OTP ID returned by Generate + - name: code + type: string + required: true + desc: OTP code to validate + - name: clear + type: bool + required: false + desc: "Whether to clear the OTP after validation (default: true)" + return: + type: bool + desc: True if valid; throws exception if invalid or expired + + - name: otp.Get + desc: Get the OTP code by ID (for testing purposes) + args: + - name: id + type: string + required: true + desc: OTP ID + return: + type: string + desc: The OTP code + + - name: otp.Delete + desc: Delete an OTP code by ID + args: + - name: id + type: string + required: true + desc: OTP ID to delete + return: + type: "null" + desc: Returns null diff --git a/widgets/app/doc.go b/widgets/app/doc.go new file mode 100644 index 00000000..78ea7bd6 --- /dev/null +++ b/widgets/app/doc.go @@ -0,0 +1,11 @@ +package app + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/widgets/app/doc.yml b/widgets/app/doc.yml new file mode 100644 index 00000000..64f4a0ce --- /dev/null +++ b/widgets/app/doc.yml @@ -0,0 +1,84 @@ +group: yao.app +type: process +desc: "Application widget processes for settings, menus, icons, setup, and services" +entries: + - name: setting + desc: Return the application DSL settings with i18n translation applied + args: + - name: payload + type: object + required: false + desc: "Optional object with sid (session ID), lang (language code e.g. \"en-us\"), and now (unix timestamp)" + return: + type: object + desc: "Application DSL object with name, version, description, theme, lang, menu, optional, sid, logo, and favicon fields" + + - name: xgen + desc: Return the merged Xgen settings including app config, login config, agent config, tools, and knowledge base + args: + - name: payload + type: object + required: false + desc: "Optional object with sid (session ID), lang (language code e.g. \"en-us\"), and now (unix timestamp)" + return: + type: object + desc: "Xgen settings object with name, description, version, yao, cui, theme, lang, mode, apiPrefix, token, optional, login, agent, tools, openapi, kb, logo, favicon, and sid fields" + + - name: menu + desc: Return the application menu list by delegating to the configured menu.process + args: + - name: args + type: any + required: false + desc: "Arguments forwarded to the configured menu process" + return: + type: any + desc: "Menu data returned by the configured menu process" + + - name: icons + desc: Return the content of an application icon file from the icons/ directory + args: + - name: name + type: string + required: true + desc: "Icon filename (e.g. \"app.ico\", \"app.png\")" + return: + type: string + desc: "Icon file content as string" + + - name: setup + desc: Run the application setup process and return home/admin URLs with translated settings + args: + - name: payload + type: object + required: true + desc: "Setup payload object; may include sid (session ID); include 'error' key to trigger a test error" + return: + type: object + desc: "Object with home (string URL), admin (string URL), and setting (translated app DSL)" + + - name: check + desc: Run the application check process for setup validation + args: + - name: payload + type: object + required: true + desc: "Check payload object; include 'error' key to trigger a test error" + return: + type: "null" + desc: "Returns null on success, throws exception on error" + + - name: service + desc: Call a named application service script method with arguments + args: + - name: name + type: string + required: true + desc: "Service script name (resolves to __yao_service. V8 script)" + - name: payload + type: object + required: true + desc: "Object with method (string, required) and args (array, optional) fields" + return: + type: any + desc: "Return value from the service method call" diff --git a/widgets/chart/doc.go b/widgets/chart/doc.go new file mode 100644 index 00000000..beda4dd4 --- /dev/null +++ b/widgets/chart/doc.go @@ -0,0 +1,11 @@ +package chart + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/widgets/chart/doc.yml b/widgets/chart/doc.yml new file mode 100644 index 00000000..f50a54b8 --- /dev/null +++ b/widgets/chart/doc.yml @@ -0,0 +1,62 @@ +group: yao.chart +type: process +entries: + - name: setting + desc: Get the setting configuration of a chart widget + args: + - name: chartId + type: string + required: true + desc: Chart widget ID + return: + type: any + desc: Chart setting from the configured action handler + + - name: xgen + desc: Get the Xgen UI configuration for a chart widget with permission filtering + args: + - name: chartId + type: string + required: true + desc: Chart widget ID + - name: data + type: object + required: false + desc: Additional data for generating the configuration + return: + type: object + desc: Xgen configuration object with permission-based field exclusions + + - name: component + desc: Execute a cloud component query within a chart widget + args: + - name: chartId + type: string + required: true + desc: Chart widget ID + - name: xpath + type: string + required: true + desc: Component XPath (URL-encoded) + - name: method + type: string + required: true + desc: Component method name (URL-encoded) + - name: query + type: object + required: false + desc: Query parameters for the component + return: + type: any + desc: Component query execution result + + - name: data + desc: Get the data for a chart widget + args: + - name: chartId + type: string + required: true + desc: Chart widget ID + return: + type: any + desc: Chart data from the configured action handler diff --git a/widgets/component/doc.go b/widgets/component/doc.go new file mode 100644 index 00000000..e8ae98c2 --- /dev/null +++ b/widgets/component/doc.go @@ -0,0 +1,11 @@ +package component + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/widgets/component/doc.yml b/widgets/component/doc.yml new file mode 100644 index 00000000..bb4c5fe5 --- /dev/null +++ b/widgets/component/doc.yml @@ -0,0 +1,24 @@ +group: yao.component +type: process +entries: + - name: getoptions + desc: Get select options by querying a model or query engine with configurable label/value mapping + args: + - name: params + type: object + required: true + desc: Query parameters map for filtering results + - name: props + type: object + required: true + desc: "Component props containing a query object with engine, from, labelField, valueField, wheres, and other query configuration" + return: + type: array + desc: "Array of option objects with label, value, and optional icon and color fields" + + - name: selectoptions + desc: "[Deprecated] Use yao.component.getoptions instead. Always throws a 400 error" + args: [] + return: + type: void + desc: Never returns; always throws a deprecation error diff --git a/widgets/dashboard/doc.go b/widgets/dashboard/doc.go new file mode 100644 index 00000000..2c074d3d --- /dev/null +++ b/widgets/dashboard/doc.go @@ -0,0 +1,11 @@ +package dashboard + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/widgets/dashboard/doc.yml b/widgets/dashboard/doc.yml new file mode 100644 index 00000000..e1283bf2 --- /dev/null +++ b/widgets/dashboard/doc.yml @@ -0,0 +1,62 @@ +group: yao.dashboard +type: process +entries: + - name: setting + desc: Get the setting configuration of a dashboard widget + args: + - name: dashboardId + type: string + required: true + desc: Dashboard widget ID + return: + type: any + desc: Dashboard setting from the configured action handler + + - name: xgen + desc: Get the Xgen UI configuration for a dashboard widget with permission filtering + args: + - name: dashboardId + type: string + required: true + desc: Dashboard widget ID + - name: data + type: object + required: false + desc: Additional data for generating the configuration + return: + type: object + desc: Xgen configuration object with permission-based field exclusions + + - name: component + desc: Execute a cloud component query within a dashboard widget + args: + - name: dashboardId + type: string + required: true + desc: Dashboard widget ID + - name: xpath + type: string + required: true + desc: Component XPath (URL-encoded) + - name: method + type: string + required: true + desc: Component method name (URL-encoded) + - name: query + type: object + required: false + desc: Query parameters for the component + return: + type: any + desc: Component query execution result + + - name: data + desc: Get the data for a dashboard widget + args: + - name: dashboardId + type: string + required: true + desc: Dashboard widget ID + return: + type: any + desc: Dashboard data from the configured action handler diff --git a/widgets/doc.go b/widgets/doc.go new file mode 100644 index 00000000..d60cd194 --- /dev/null +++ b/widgets/doc.go @@ -0,0 +1,11 @@ +package widgets + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/widgets/doc.yml b/widgets/doc.yml new file mode 100644 index 00000000..cc571d55 --- /dev/null +++ b/widgets/doc.yml @@ -0,0 +1,37 @@ +group: widget +type: process +entries: + - name: apis + desc: Get all loaded widget API definitions + args: [] + return: + type: any + desc: Map of all registered widget APIs + + - name: actions + desc: Get all loaded widget action definitions + args: [] + return: + type: any + desc: Map of all registered widget actions + + - name: models + desc: Get all loaded widget model definitions + args: [] + return: + type: any + desc: Map of all registered widget models + + - name: fields + desc: Get all loaded widget field definitions + args: [] + return: + type: any + desc: Map of all registered widget fields + + - name: filters + desc: Get all loaded widget filter definitions + args: [] + return: + type: any + desc: Map of all registered widget filters diff --git a/widgets/expression/doc.go b/widgets/expression/doc.go new file mode 100644 index 00000000..92d9cb30 --- /dev/null +++ b/widgets/expression/doc.go @@ -0,0 +1,11 @@ +package expression + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/widgets/expression/doc.yml b/widgets/expression/doc.yml new file mode 100644 index 00000000..f7abba58 --- /dev/null +++ b/widgets/expression/doc.yml @@ -0,0 +1,32 @@ +group: yao.expression +type: process +entries: + - name: selectoption + desc: Convert input values into an array of label/value select options + args: + - name: input + type: any + required: true + desc: "Comma-separated string, or array of strings/numbers/maps" + - name: labelField + type: string + required: false + desc: "Field name to use as label when input items are maps (default: name)" + - name: valueField + type: string + required: false + desc: "Field name to use as value when input items are maps (default: id)" + return: + type: array + desc: Array of objects with label and value fields + + - name: trimspace + desc: Trim leading and trailing whitespace from a string + args: + - name: input + type: string + required: true + desc: String to trim + return: + type: string + desc: Trimmed string diff --git a/widgets/login/doc.go b/widgets/login/doc.go new file mode 100644 index 00000000..87fb933b --- /dev/null +++ b/widgets/login/doc.go @@ -0,0 +1,11 @@ +package login + +import ( + _ "embed" + "github.com/yaoapp/gou/doc" +) + +//go:embed doc.yml +var docYAML []byte + +func init() { doc.LoadYAML(docYAML) } diff --git a/widgets/login/doc.yml b/widgets/login/doc.yml new file mode 100644 index 00000000..6f36a4c5 --- /dev/null +++ b/widgets/login/doc.yml @@ -0,0 +1,14 @@ +group: yao.login +type: process +desc: "Login widget processes for user authentication" +entries: + - name: admin + desc: Authenticate an admin user with email or mobile, password, and captcha verification + args: + - name: payload + type: object + required: true + desc: "Login payload with captcha.id (string), captcha.code (string), password (string), and either email (string) or mobile (string); optional sid (string) for session ID" + return: + type: object + desc: "Object with expires_at (number, token expiry unix timestamp), token (string, JWT), user (object with id, name, type, email, mobile, extra, status), and menus (app menu data)"