From beba59ea9e75af8c6511ff355fa276633daea021 Mon Sep 17 00:00:00 2001 From: jackchuka Date: Mon, 16 Mar 2026 21:02:26 +0900 Subject: [PATCH 1/3] docs: add built-in interfaces reference page for Function service Add a centralized reference page documenting all built-in interfaces available as global variables in Functions (Resolvers, Workflows, Executors): tailor.idp.Client, tailor.secretmanager, tailor.authconnection, tailor.iconv, tailor.workflow, tailordb.Client, and tailordb.file. Also updates the Function overview page to link to the new reference. Addresses tailor-professional-service/knowledge#63 --- .vitepress/config/constants.ts | 3 +- docs/guides/function/builtin-interfaces.md | 263 +++++++++++++++++++++ docs/guides/function/overview.md | 3 + 3 files changed, 267 insertions(+), 2 deletions(-) create mode 100644 docs/guides/function/builtin-interfaces.md diff --git a/.vitepress/config/constants.ts b/.vitepress/config/constants.ts index 814675c..fc56d32 100644 --- a/.vitepress/config/constants.ts +++ b/.vitepress/config/constants.ts @@ -88,8 +88,7 @@ export const defaultSidebarOrder: string[] = ["overview", "quickstart"]; // Section-specific overrides (only if you need different ordering for a specific section) export const sidebarItemOrder: Record = { - // Add section-specific overrides here if needed - // Example: 'guides': ['overview', 'quickstart', 'tailordb', ...] + function: ["overview", "builtin-interfaces"], "app-shell": [ "api", "authentication", diff --git a/docs/guides/function/builtin-interfaces.md b/docs/guides/function/builtin-interfaces.md new file mode 100644 index 0000000..a68b7d4 --- /dev/null +++ b/docs/guides/function/builtin-interfaces.md @@ -0,0 +1,263 @@ +--- +doc_type: guide +--- + +# Built-in interfaces + +Functions (Resolvers, Workflows, Executors) have access to built-in interfaces as global variables. +These provide direct access to platform services without external HTTP calls or token management. + +All interfaces are typed via `@tailor-platform/function-types` — install the package to get full TypeScript support. + +## Overview + +| Interface | Description | +| --- | --- | +| [`tailor.idp.Client`](#tailor-idp-client) | Create, update, delete IdP users and send password reset emails | +| [`tailor.secretmanager`](#tailor-secretmanager) | Retrieve secrets from vaults | +| [`tailor.authconnection`](#tailor-authconnection) | Get access tokens for external auth connections | +| [`tailor.iconv`](#tailor-iconv) | Convert between character encodings | +| [`tailor.workflow`](#tailor-workflow) | Trigger workflows and job functions | +| [`tailordb.Client`](#tailordb-client) | Execute SQL queries against TailorDB | +| [`tailordb.file`](#tailordb-file) | Upload, download, and manage files in TailorDB | + +## `tailor.idp.Client` + +Manage Built-in IdP users directly from your function. No external HTTP calls or machine user tokens needed. + +See also: [Managing IdP Users in Functions](/guides/function/managing-idp-users) + +```typescript +const client = new tailor.idp.Client({ namespace: "my-namespace" }); + +// Create a user +const user = await client.createUser({ name: "user@example.com", password: "secret" }); + +// List users with filtering +const { users, totalCount } = await client.users({ + first: 10, + query: { names: ["user@example.com"] }, +}); + +// Get, update, delete +const user = await client.user(userId); +await client.updateUser({ id: userId, name: "new@example.com" }); +await client.deleteUser(userId); + +// Send password reset email +await client.sendPasswordResetEmail({ + userId: user.id, + redirectUri: "https://app.example.com/reset", +}); +``` + +### Methods + +| Method | Returns | Description | +| --- | --- | --- | +| `users(options?)` | `Promise` | List users with optional filtering and pagination | +| `user(userId)` | `Promise` | Get a user by ID | +| `createUser(input)` | `Promise` | Create a new user | +| `updateUser(input)` | `Promise` | Update an existing user | +| `deleteUser(userId)` | `Promise` | Delete a user by ID | +| `sendPasswordResetEmail(input)` | `Promise` | Send a password reset email | + +## `tailor.secretmanager` + +Retrieve secrets stored in Tailor Platform vaults. + +```typescript +// Get a single secret +const apiKey = await tailor.secretmanager.getSecret("my-vault", "API_KEY"); + +// Get multiple secrets at once +const secrets = await tailor.secretmanager.getSecrets("my-vault", [ + "API_KEY", + "API_SECRET", +] as const); +// secrets.API_KEY, secrets.API_SECRET +``` + +### Functions + +| Function | Returns | Description | +| --- | --- | --- | +| `getSecret(vault, name)` | `Promise` | Get a single secret. Returns `undefined` if not found | +| `getSecrets(vault, names)` | `Promise>>` | Get multiple secrets. Missing keys are omitted | + +## `tailor.authconnection` + +Get access tokens for configured external auth connections (e.g., OAuth providers). + +```typescript +const token = await tailor.authconnection.getConnectionToken("my-google-connection"); +// Use token to call external APIs +``` + +### Functions + +| Function | Returns | Description | +| --- | --- | --- | +| `getConnectionToken(connectionName)` | `Promise` | Get the access token for a named auth connection | + +## `tailor.iconv` + +Convert between character encodings. Useful for processing files in non-UTF-8 encodings (e.g., Shift_JIS CSV files). + +```typescript +// Convert Shift_JIS buffer to UTF-8 string +const text = tailor.iconv.decode(shiftJisBuffer, "Shift_JIS"); + +// Encode a string to Shift_JIS +const encoded = tailor.iconv.encode("こんにちは", "Shift_JIS"); + +// Convert between encodings +const result = tailor.iconv.convert(buffer, "EUC-JP", "UTF-8"); + +// List supported encodings +const encodings = tailor.iconv.encodings(); +``` + +### Functions + +| Function | Returns | Description | +| --- | --- | --- | +| `convert(str, fromEncoding, toEncoding)` | `string \| Uint8Array` | Convert between encodings. Returns `string` when target is UTF-8 | +| `decode(buffer, encoding)` | `string` | Decode a buffer to a UTF-8 string | +| `encode(str, encoding)` | `string \| Uint8Array` | Encode a string to the specified encoding | +| `encodings()` | `string[]` | List all supported encodings | + +The `Iconv` class is also available for node-iconv compatibility: + +```typescript +const converter = new tailor.iconv.Iconv("Shift_JIS", "UTF-8"); +const result = converter.convert(inputBuffer); +``` + +## `tailor.workflow` + +Trigger workflows and job functions from within a function. + +```typescript +// Trigger a workflow +const executionId = await tailor.workflow.triggerWorkflow("processOrder", { + orderId: "order-123", +}); + +// Trigger with a specific machine user +const executionId = await tailor.workflow.triggerWorkflow( + "processOrder", + { orderId: "order-123" }, + { + authInvoker: { + namespace: "my-namespace", + machineUserName: "workflow-runner", + }, + }, +); + +// Trigger a job function +const result = await tailor.workflow.triggerJobFunction("calculateTax", { + amount: 1000, +}); +``` + +### Functions + +| Function | Returns | Description | +| --- | --- | --- | +| `triggerWorkflow(name, args?, options?)` | `Promise` | Trigger a workflow. Returns the execution ID | +| `triggerJobFunction(name, args?)` | `any` | Trigger a job function and return its result | + +## `tailordb.Client` + +Execute SQL queries directly against TailorDB. For ORM-style access, consider using `@tailor-platform/function-kysely-tailordb`. + +See also: [Accessing TailorDB](/guides/function/accessing-tailordb) + +```typescript +const db = new tailordb.Client({ namespace: "my-namespace" }); +await db.connect(); + +try { + const result = await db.queryObject<{ id: string; name: string }>( + "SELECT id, name FROM users WHERE active = $1", + [true], + ); + console.log(result.rows); // [{ id: "...", name: "..." }, ...] +} finally { + await db.end(); +} +``` + +### Methods + +| Method | Returns | Description | +| --- | --- | --- | +| `connect()` | `Promise` | Open the database connection | +| `end()` | `Promise` | Close the database connection | +| `queryObject(sql, args?)` | `Promise>` | Execute a SQL query with parameterized arguments | + +## `tailordb.file` + +Upload, download, and manage files attached to TailorDB records. + +```typescript +// Upload a file +const { metadata } = await tailordb.file.upload( + "my-namespace", + "Document", + "attachment", + recordId, + fileData, + { contentType: "application/pdf" }, +); + +// Download a file +const { data, metadata } = await tailordb.file.download( + "my-namespace", + "Document", + "attachment", + recordId, +); + +// Download as Base64 (for embedding in JSON responses) +const { data: base64 } = await tailordb.file.downloadAsBase64( + "my-namespace", + "Document", + "attachment", + recordId, +); + +// Stream large files (>10MB) +const stream = await tailordb.file.openDownloadStream( + "my-namespace", + "Document", + "attachment", + recordId, +); +for await (const chunk of stream) { + if (chunk.type === "chunk") { + // process chunk.data + } +} + +// Get metadata without downloading +const meta = await tailordb.file.getMetadata("my-namespace", "Document", "attachment", recordId); + +// Delete a file +await tailordb.file.delete("my-namespace", "Document", "attachment", recordId); +``` + +### Methods + +All methods take `(namespace, typeName, fieldName, recordId)` as the first four arguments. + +| Method | Returns | Description | +| --- | --- | --- | +| `upload(..., data, options?)` | `Promise` | Upload a file | +| `download(...)` | `Promise` | Download a file as `Uint8Array`. Throws if >10MB | +| `downloadAsBase64(...)` | `Promise` | Download as Base64 string. Throws if >10MB | +| `delete(...)` | `Promise` | Delete a file | +| `getMetadata(...)` | `Promise` | Get file metadata without downloading | +| `openDownloadStream(...)` | `Promise` | Stream large files in chunks | diff --git a/docs/guides/function/overview.md b/docs/guides/function/overview.md index 29116ba..f6e9327 100644 --- a/docs/guides/function/overview.md +++ b/docs/guides/function/overview.md @@ -14,12 +14,14 @@ With Function service, you can: - Send HTTP requests to 3rd party applications - Access and execute SQL queries to Tailor DB +- Manage IdP users, secrets, files, and workflows via [built-in interfaces](/guides/function/builtin-interfaces) - Process data transformations - Implement custom business logic with npm packages To keep the this guide simple, we'll focus on a basic example of writing a function that returns a greeting message. For more advanced use cases, you can refer to these sections: +- [Built-in interfaces](/guides/function/builtin-interfaces) — all platform APIs available as global variables - [Sending HTTP request](/guides/function/sending-request) - [Accessing Tailor DB](/guides/function/accessing-tailordb) @@ -192,6 +194,7 @@ export default createExecutor({ For more advanced use cases, you can refer to these sections: +- [Built-in interfaces](/guides/function/builtin-interfaces) — all platform APIs available as global variables (IdP, secrets, files, workflows, etc.) - [Sending HTTP request](/guides/function/sending-request) - [Accessing Tailor DB](/guides/function/accessing-tailordb) From 5bd1ed2603e7249b72e86a92a078e14fd13609e5 Mon Sep 17 00:00:00 2001 From: jackchuka Date: Tue, 17 Mar 2026 00:08:19 +0900 Subject: [PATCH 2/3] fix(config): resolve sidebar and nav ordering for nested sections Sidebar ordering only checked the top-level section name (e.g., "guides") against sidebarItemOrder, ignoring subdirectory-specific orders like "function". Now checks current directory name first. Nav links for sections without index.md used alphabetical sort, landing on the wrong page. Now respects sidebarItemOrder and defaultSidebarOrder to pick the correct first page. Also links @tailor-platform/function-types to its GitHub source. --- .vitepress/config/nav.ts | 16 +++++++++++----- .vitepress/config/sidebar.ts | 6 ++++-- docs/guides/function/builtin-interfaces.md | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/.vitepress/config/nav.ts b/.vitepress/config/nav.ts index a771791..2ee67bd 100644 --- a/.vitepress/config/nav.ts +++ b/.vitepress/config/nav.ts @@ -2,7 +2,7 @@ import type { DefaultTheme } from "vitepress"; import fs from "node:fs"; import path from "node:path"; import { toTitle } from "./utils.js"; -import { navGroups, navItemOrder } from "./constants.js"; +import { navGroups, navItemOrder, sidebarItemOrder, defaultSidebarOrder } from "./constants.js"; // Generate grouped nav items with organized dropdown structure export function generateNav(docsDir: string): DefaultTheme.NavItem[] { @@ -38,10 +38,16 @@ export function generateNav(docsDir: string): DefaultTheme.NavItem[] { const subFiles = fs .readdirSync(path.join(sectionPath, e.name)) .filter((f) => f.endsWith(".md") && !f.startsWith(".")) - .sort(); - - if (subFiles.length > 0) { - link = `/${section}/${e.name}/${subFiles[0].replace(/\.md$/, "")}`; + .map((f) => f.replace(/\.md$/, "")); + + // Use sidebarItemOrder, then defaultSidebarOrder, then alphabetical + const order = sidebarItemOrder[e.name] || defaultSidebarOrder; + const firstOrdered = order.find((item) => subFiles.includes(item)); + if (firstOrdered) { + link = `/${section}/${e.name}/${firstOrdered}`; + } else if (subFiles.length > 0) { + subFiles.sort(); + link = `/${section}/${e.name}/${subFiles[0]}`; } } diff --git a/.vitepress/config/sidebar.ts b/.vitepress/config/sidebar.ts index c8215dc..69ba1e4 100644 --- a/.vitepress/config/sidebar.ts +++ b/.vitepress/config/sidebar.ts @@ -25,9 +25,11 @@ export function generateSidebar( const entries = fs.readdirSync(fullPath, { withFileTypes: true }); - // Get section name for custom ordering + // Get custom ordering: check current directory name first, then top-level section + const currentDirName = path.basename(dir); const sectionName = dir.split(path.sep)[0]; - const customOrder = sidebarItemOrder[sectionName] || defaultSidebarOrder; + const customOrder = + sidebarItemOrder[currentDirName] || sidebarItemOrder[sectionName] || defaultSidebarOrder; // Get markdown files (excluding index.md) const files = entries diff --git a/docs/guides/function/builtin-interfaces.md b/docs/guides/function/builtin-interfaces.md index a68b7d4..7c52f0d 100644 --- a/docs/guides/function/builtin-interfaces.md +++ b/docs/guides/function/builtin-interfaces.md @@ -7,7 +7,7 @@ doc_type: guide Functions (Resolvers, Workflows, Executors) have access to built-in interfaces as global variables. These provide direct access to platform services without external HTTP calls or token management. -All interfaces are typed via `@tailor-platform/function-types` — install the package to get full TypeScript support. +All interfaces are typed via [`@tailor-platform/function-types`](https://github.com/tailor-platform/function/tree/main/packages/types) — install the package to get full TypeScript support. ## Overview From c7519878de6306cd2503cb3ca2c3474bebf2bcaa Mon Sep 17 00:00:00 2001 From: Anukiran Date: Mon, 16 Mar 2026 11:56:39 -0500 Subject: [PATCH 3/3] update section heading --- docs/guides/function/builtin-interfaces.md | 64 +++++++++++----------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/docs/guides/function/builtin-interfaces.md b/docs/guides/function/builtin-interfaces.md index 7c52f0d..06b7c7a 100644 --- a/docs/guides/function/builtin-interfaces.md +++ b/docs/guides/function/builtin-interfaces.md @@ -11,21 +11,23 @@ All interfaces are typed via [`@tailor-platform/function-types`](https://github. ## Overview -| Interface | Description | +| Service | Description | | --- | --- | -| [`tailor.idp.Client`](#tailor-idp-client) | Create, update, delete IdP users and send password reset emails | -| [`tailor.secretmanager`](#tailor-secretmanager) | Retrieve secrets from vaults | -| [`tailor.authconnection`](#tailor-authconnection) | Get access tokens for external auth connections | -| [`tailor.iconv`](#tailor-iconv) | Convert between character encodings | -| [`tailor.workflow`](#tailor-workflow) | Trigger workflows and job functions | -| [`tailordb.Client`](#tailordb-client) | Execute SQL queries against TailorDB | -| [`tailordb.file`](#tailordb-file) | Upload, download, and manage files in TailorDB | +| [IdP Client](#idp-client) | Create, update, delete IdP users and send password reset emails | +| [Secret Manager](#secret-manager) | Retrieve secrets from vaults | +| [Auth Connection](#auth-connection) | Get access tokens for external auth connections | +| [Character Encoding](#character-encoding) | Convert between character encodings (iconv) | +| [Workflow](#workflow) | Trigger workflows and job functions | +| [TailorDB Client](#tailordb-client) | Execute SQL queries against TailorDB | +| [TailorDB File](#tailordb-file) | Upload, download, and manage files in TailorDB | -## `tailor.idp.Client` +## IdP Client + +**Interface**: `tailor.idp.Client` Manage Built-in IdP users directly from your function. No external HTTP calls or machine user tokens needed. -See also: [Managing IdP Users in Functions](/guides/function/managing-idp-users) +**See also**: [Managing IdP Users in Functions](/guides/function/managing-idp-users) ```typescript const client = new tailor.idp.Client({ namespace: "my-namespace" }); @@ -51,8 +53,6 @@ await client.sendPasswordResetEmail({ }); ``` -### Methods - | Method | Returns | Description | | --- | --- | --- | | `users(options?)` | `Promise` | List users with optional filtering and pagination | @@ -62,7 +62,9 @@ await client.sendPasswordResetEmail({ | `deleteUser(userId)` | `Promise` | Delete a user by ID | | `sendPasswordResetEmail(input)` | `Promise` | Send a password reset email | -## `tailor.secretmanager` +## Secret Manager + +**Interface**: `tailor.secretmanager` Retrieve secrets stored in Tailor Platform vaults. @@ -78,14 +80,14 @@ const secrets = await tailor.secretmanager.getSecrets("my-vault", [ // secrets.API_KEY, secrets.API_SECRET ``` -### Functions - | Function | Returns | Description | | --- | --- | --- | | `getSecret(vault, name)` | `Promise` | Get a single secret. Returns `undefined` if not found | | `getSecrets(vault, names)` | `Promise>>` | Get multiple secrets. Missing keys are omitted | -## `tailor.authconnection` +## Auth Connection + +**Interface**: `tailor.authconnection` Get access tokens for configured external auth connections (e.g., OAuth providers). @@ -94,13 +96,13 @@ const token = await tailor.authconnection.getConnectionToken("my-google-connecti // Use token to call external APIs ``` -### Functions - | Function | Returns | Description | | --- | --- | --- | | `getConnectionToken(connectionName)` | `Promise` | Get the access token for a named auth connection | -## `tailor.iconv` +## Character Encoding + +**Interface**: `tailor.iconv` Convert between character encodings. Useful for processing files in non-UTF-8 encodings (e.g., Shift_JIS CSV files). @@ -118,8 +120,6 @@ const result = tailor.iconv.convert(buffer, "EUC-JP", "UTF-8"); const encodings = tailor.iconv.encodings(); ``` -### Functions - | Function | Returns | Description | | --- | --- | --- | | `convert(str, fromEncoding, toEncoding)` | `string \| Uint8Array` | Convert between encodings. Returns `string` when target is UTF-8 | @@ -134,7 +134,9 @@ const converter = new tailor.iconv.Iconv("Shift_JIS", "UTF-8"); const result = converter.convert(inputBuffer); ``` -## `tailor.workflow` +## Workflow + +**Interface**: `tailor.workflow` Trigger workflows and job functions from within a function. @@ -162,18 +164,18 @@ const result = await tailor.workflow.triggerJobFunction("calculateTax", { }); ``` -### Functions - | Function | Returns | Description | | --- | --- | --- | | `triggerWorkflow(name, args?, options?)` | `Promise` | Trigger a workflow. Returns the execution ID | | `triggerJobFunction(name, args?)` | `any` | Trigger a job function and return its result | -## `tailordb.Client` +## TailorDB Client + +**Interface**: `tailordb.Client` Execute SQL queries directly against TailorDB. For ORM-style access, consider using `@tailor-platform/function-kysely-tailordb`. -See also: [Accessing TailorDB](/guides/function/accessing-tailordb) +**See also**: [Accessing TailorDB](/guides/function/accessing-tailordb) ```typescript const db = new tailordb.Client({ namespace: "my-namespace" }); @@ -190,15 +192,15 @@ try { } ``` -### Methods - | Method | Returns | Description | | --- | --- | --- | | `connect()` | `Promise` | Open the database connection | | `end()` | `Promise` | Close the database connection | | `queryObject(sql, args?)` | `Promise>` | Execute a SQL query with parameterized arguments | -## `tailordb.file` +## TailorDB File + +**Interface**: `tailordb.file` Upload, download, and manage files attached to TailorDB records. @@ -249,9 +251,7 @@ const meta = await tailordb.file.getMetadata("my-namespace", "Document", "attach await tailordb.file.delete("my-namespace", "Document", "attachment", recordId); ``` -### Methods - -All methods take `(namespace, typeName, fieldName, recordId)` as the first four arguments. +**Note**: All methods take `(namespace, typeName, fieldName, recordId)` as the first four arguments. | Method | Returns | Description | | --- | --- | --- |