diff --git a/docs/sdk/cli-reference.md b/docs/sdk/cli-reference.md index 27f7975..c5444c0 100644 --- a/docs/sdk/cli-reference.md +++ b/docs/sdk/cli-reference.md @@ -53,14 +53,20 @@ tailor-sdk apply --env-file .env --env-file .env.production You can use environment variables to configure workspace and authentication: -| Variable | Description | -| --------------------------------- | --------------------------------------------------------------------------- | -| `TAILOR_PLATFORM_WORKSPACE_ID` | Workspace ID for deployment commands | -| `TAILOR_PLATFORM_TOKEN` | Authentication token (alternative to `login`) | -| `TAILOR_TOKEN` | **Deprecated.** Use `TAILOR_PLATFORM_TOKEN` instead | -| `TAILOR_PLATFORM_PROFILE` | Workspace profile name | -| `TAILOR_PLATFORM_SDK_CONFIG_PATH` | Path to SDK config file | -| `VISUAL` / `EDITOR` | Preferred editor for commands that open files (e.g., `vim`, `code`, `nano`) | +| Variable | Description | +| -------------------------------------------- | --------------------------------------------------------------------------- | +| `TAILOR_PLATFORM_WORKSPACE_ID` | Workspace ID for deployment commands | +| `TAILOR_PLATFORM_ORGANIZATION_ID` | Organization ID for organization commands | +| `TAILOR_PLATFORM_FOLDER_ID` | Folder ID for folder commands | +| `TAILOR_PLATFORM_TOKEN` | Authentication token (alternative to `login`) | +| `TAILOR_TOKEN` | **Deprecated.** Use `TAILOR_PLATFORM_TOKEN` instead | +| `TAILOR_PLATFORM_PROFILE` | Workspace profile name | +| `TAILOR_PLATFORM_SDK_CONFIG_PATH` | Path to SDK config file | +| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID` | Client ID for `login --machineuser` | +| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET` | Client secret for `login --machineuser` | +| `VISUAL` / `EDITOR` | Preferred editor for commands that open files (e.g., `vim`, `code`, `nano`) | +| `TAILOR_CRASH_REPORTS_LOCAL` | Local crash log writing: `on` (default) or `off` | +| `TAILOR_CRASH_REPORTS_REMOTE` | Automatic crash report submission: `off` (default) or `on` | ### Authentication Token Priority @@ -125,9 +131,25 @@ Commands for authentication and user management. | [user pat delete](cli/user.md#user-pat-delete) | Delete a personal access token | | [user pat update](cli/user.md#user-pat-update) | Update a personal access token | -### [Workspace Commands](cli/workspace) +### Workspace & Organization Commands -Commands for managing workspaces and profiles. +Commands for managing workspaces, profiles, organizations, and folders. + +**[Organization Commands](cli/organization)** + +| Command | Description | +| ------------------------------------------------------------------------------ | ----------------------------------------------- | +| [organization list](cli/organization.md#organization-list) | List organizations you belong to | +| [organization get](cli/organization.md#organization-get) | Show detailed information about an organization | +| [organization update](cli/organization.md#organization-update) | Update an organization's name | +| [organization tree](cli/organization.md#organization-tree) | Display organization folder hierarchy as a tree | +| [organization folder list](cli/organization.md#organization-folder-list) | List folders in an organization | +| [organization folder get](cli/organization.md#organization-folder-get) | Show detailed information about a folder | +| [organization folder create](cli/organization.md#organization-folder-create) | Create a new folder in an organization | +| [organization folder update](cli/organization.md#organization-folder-update) | Update a folder's name | +| [organization folder delete](cli/organization.md#organization-folder-delete) | Delete a folder from an organization | + +**[Workspace Commands](cli/workspace)** | Command | Description | | ------------------------------------------------------- | ---------------------- | @@ -203,6 +225,23 @@ Commands for managing and deploying static websites. | [staticwebsite list](cli/staticwebsite.md#staticwebsite-list) | List static websites in a workspace | | [staticwebsite get](cli/staticwebsite.md#staticwebsite-get) | Get details of a static website | +### [Crash Report Commands](cli/crash-report) + +Commands for managing crash reports. + +| Command | Description | +| ------------------------------------------------------------ | --------------------------------------------- | +| [crash-report list](cli/crash-report.md#crash-report-list) | List local crash report files | +| [crash-report send](cli/crash-report.md#crash-report-send) | Submit a crash report to help improve the SDK | + +### [Setup Commands](cli/setup) + +Commands for setting up project infrastructure. + +| Command | Description | +| ------------------------------------------- | ----------------------------------------------- | +| [setup github](cli/setup.md#setup-github) | Generate GitHub Actions workflow for deployment | + ### [Completion](cli/completion) Generate shell completion scripts for bash, zsh, and fish. diff --git a/docs/sdk/cli/crash-report.md b/docs/sdk/cli/crash-report.md new file mode 100644 index 0000000..d8716d3 --- /dev/null +++ b/docs/sdk/cli/crash-report.md @@ -0,0 +1,107 @@ +# Crash Report Commands + +Commands for managing crash reports. + + + +## crash-report + + + + + +Manage crash reports. + + + + + +**Usage** + +``` +tailor-sdk crash-report [command] +``` + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + + +**Commands** + +| Command | Description | +| ----------------------------------------- | ---------------------------------------------- | +| [`crash-report send`](#crash-report-send) | Submit a crash report to help improve the SDK. | +| [`crash-report list`](#crash-report-list) | List local crash report files. | + + + + +### crash-report list + + + + + +List local crash report files. + + + + + +**Usage** + +``` +tailor-sdk crash-report list +``` + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + + +### crash-report send + + + + + +Submit a crash report to help improve the SDK. + + + + + +**Usage** + +``` +tailor-sdk crash-report send [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | +| --------------- | ----- | ----------------------------- | -------- | ------- | +| `--file ` | - | Path to the crash report file | Yes | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + diff --git a/docs/sdk/cli/function.md b/docs/sdk/cli/function.md index 60dbbfc..5503914 100644 --- a/docs/sdk/cli/function.md +++ b/docs/sdk/cli/function.md @@ -164,7 +164,7 @@ $ tailor-sdk function test-run workflows/sample.ts --name validate-order **Run a pre-bundled .js file directly** ```bash -$ tailor-sdk function test-run .tailor-sdk/resolvers/add.js --arg '{"input":{"a":1,"b":2}}' +$ tailor-sdk function test-run build/resolvers/add.js --arg '{"input":{"a":1,"b":2}}' ``` diff --git a/docs/sdk/cli/organization.md b/docs/sdk/cli/organization.md new file mode 100644 index 0000000..478bc09 --- /dev/null +++ b/docs/sdk/cli/organization.md @@ -0,0 +1,426 @@ + + +## organization + + + + + +Manage Tailor Platform organizations. + + + + + +**Usage** + +``` +tailor-sdk organization [command] +``` + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + + +**Commands** + +| Command | Description | +| --------------------------------------------- | ------------------------------------------------ | +| [`organization folder`](#organization-folder) | Manage organization folders. | +| [`organization get`](#organization-get) | Show detailed information about an organization. | +| [`organization list`](#organization-list) | List organizations you belong to. | +| [`organization tree`](#organization-tree) | Display organization folder hierarchy as a tree. | +| [`organization update`](#organization-update) | Update an organization's name. | + + + + +### organization folder + + + + + +Manage organization folders. + + + + + +**Usage** + +``` +tailor-sdk organization folder [command] +``` + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + + +**Commands** + +| Command | Description | +| ----------------------------------------------------------- | ----------------------------------------- | +| [`organization folder create`](#organization-folder-create) | Create a new folder in an organization. | +| [`organization folder delete`](#organization-folder-delete) | Delete a folder from an organization. | +| [`organization folder get`](#organization-folder-get) | Show detailed information about a folder. | +| [`organization folder list`](#organization-folder-list) | List folders in an organization. | +| [`organization folder update`](#organization-folder-update) | Update a folder's name. | + + + + +#### organization folder create + + + + + +Create a new folder in an organization. + + + + + +**Usage** + +``` +tailor-sdk organization folder create [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| --------------------------------------- | ----- | ---------------- | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID | Yes | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | +| `--parent-folder-id ` | - | Parent folder ID | No | - | - | +| `--name ` | `-n` | Folder name | Yes | - | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +#### organization folder delete + + + + + +Delete a folder from an organization. + + + + + +**Usage** + +``` +tailor-sdk organization folder delete [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| ------------------------------------- | ----- | ------------------------- | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID | Yes | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | +| `--folder-id ` | `-f` | Folder ID | Yes | - | `TAILOR_PLATFORM_FOLDER_ID` | +| `--yes` | `-y` | Skip confirmation prompts | No | `false` | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +#### organization folder get + + + + + +Show detailed information about a folder. + + + + + +**Usage** + +``` +tailor-sdk organization folder get [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| ------------------------------------- | ----- | --------------- | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID | Yes | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | +| `--folder-id ` | `-f` | Folder ID | Yes | - | `TAILOR_PLATFORM_FOLDER_ID` | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +#### organization folder list + + + + + +List folders in an organization. + + + + + +**Usage** + +``` +tailor-sdk organization folder list [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| --------------------------------------- | ----- | ------------------------------------ | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID | Yes | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | +| `--parent-folder-id ` | - | Parent folder ID to list children of | No | - | - | +| `--limit ` | `-l` | Maximum number of folders to list | No | - | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +#### organization folder update + + + + + +Update a folder's name. + + + + + +**Usage** + +``` +tailor-sdk organization folder update [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| ------------------------------------- | ----- | --------------- | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID | Yes | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | +| `--folder-id ` | `-f` | Folder ID | Yes | - | `TAILOR_PLATFORM_FOLDER_ID` | +| `--name ` | `-n` | New folder name | Yes | - | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +### organization get + + + + + +Show detailed information about an organization. + + + + + +**Usage** + +``` +tailor-sdk organization get [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| ------------------------------------- | ----- | --------------- | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID | Yes | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +### organization list + + + + + +List organizations you belong to. + + + + + +**Usage** + +``` +tailor-sdk organization list [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | +| ----------------- | ----- | --------------------------------------- | -------- | ------- | +| `--limit ` | `-l` | Maximum number of organizations to list | No | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +### organization tree + + + + + +Display organization folder hierarchy as a tree. + + + + + +**Usage** + +``` +tailor-sdk organization tree [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| ------------------------------------- | ----- | ------------------------------------- | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID (show all if omitted) | No | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | +| `--depth ` | `-d` | Maximum folder depth to display | No | - | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +### organization update + + + + + +Update an organization's name. + + + + + +**Usage** + +``` +tailor-sdk organization update [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | Env | +| ------------------------------------- | ----- | --------------------- | -------- | ------- | --------------------------------- | +| `--organization-id ` | `-o` | Organization ID | Yes | - | `TAILOR_PLATFORM_ORGANIZATION_ID` | +| `--name ` | `-n` | New organization name | Yes | - | - | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + diff --git a/docs/sdk/cli/secret.md b/docs/sdk/cli/secret.md index c97e3a1..dd1395f 100644 --- a/docs/sdk/cli/secret.md +++ b/docs/sdk/cli/secret.md @@ -243,13 +243,14 @@ tailor-sdk secret create [options] **Options** -| Option | Alias | Description | Required | Default | Env | -| ------------------------------- | ----- | ----------------- | -------- | ------- | ------------------------------ | -| `--workspace-id ` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` | -| `--profile ` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` | -| `--vault-name ` | `-V` | Vault name | Yes | - | - | -| `--name ` | `-n` | Secret name | Yes | - | - | -| `--value ` | `-v` | Secret value | Yes | - | - | +| Option | Alias | Description | Required | Default | Env | +| ------------------------------- | ----- | ------------------------- | -------- | ------- | ------------------------------ | +| `--workspace-id ` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` | +| `--profile ` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` | +| `--vault-name ` | `-V` | Vault name | Yes | - | - | +| `--name ` | `-n` | Secret name | Yes | - | - | +| `--value ` | `-v` | Secret value | Yes | - | - | +| `--yes` | `-y` | Skip confirmation prompts | No | `false` | - | @@ -284,13 +285,14 @@ tailor-sdk secret update [options] **Options** -| Option | Alias | Description | Required | Default | Env | -| ------------------------------- | ----- | ----------------- | -------- | ------- | ------------------------------ | -| `--workspace-id ` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` | -| `--profile ` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` | -| `--vault-name ` | `-V` | Vault name | Yes | - | - | -| `--name ` | `-n` | Secret name | Yes | - | - | -| `--value ` | `-v` | Secret value | Yes | - | - | +| Option | Alias | Description | Required | Default | Env | +| ------------------------------- | ----- | ------------------------- | -------- | ------- | ------------------------------ | +| `--workspace-id ` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` | +| `--profile ` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` | +| `--vault-name ` | `-V` | Vault name | Yes | - | - | +| `--name ` | `-n` | Secret name | Yes | - | - | +| `--value ` | `-v` | Secret value | Yes | - | - | +| `--yes` | `-y` | Skip confirmation prompts | No | `false` | - | diff --git a/docs/sdk/cli/setup.md b/docs/sdk/cli/setup.md new file mode 100644 index 0000000..772cdbf --- /dev/null +++ b/docs/sdk/cli/setup.md @@ -0,0 +1,82 @@ +# Setup Commands + +Commands for setting up project infrastructure. + + + +## setup + + + + + +Set up project infrastructure. + + + + + +**Usage** + +``` +tailor-sdk setup [command] +``` + + + + + +**Commands** + +| Command | Description | +| ------------------------------- | ------------------------------------------------------- | +| [`setup github`](#setup-github) | Generate GitHub Actions workflow for deployment. (beta) | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + + + +### setup github + + + + + +Generate GitHub Actions workflow for deployment. (beta) + + + + + +**Usage** + +``` +tailor-sdk setup github [options] +``` + + + + + +**Options** + +| Option | Alias | Description | Required | Default | +| --------------------------------------- | ----- | ----------------------------------- | -------- | ------- | +| `--workspace-name ` | `-n` | Workspace name | Yes | - | +| `--workspace-region ` | `-r` | Workspace region | Yes | - | +| `--organization-id ` | `-o` | Organization ID | Yes | - | +| `--folder-id ` | `-f` | Folder ID | Yes | - | +| `--dir ` | `-d` | App directory (for monorepo setups) | No | `"."` | + + + + + +See [Global Options](../cli-reference.md#global-options) for options available to all commands. + + diff --git a/docs/sdk/cli/user.md b/docs/sdk/cli/user.md index ce315d7..32ead06 100644 --- a/docs/sdk/cli/user.md +++ b/docs/sdk/cli/user.md @@ -19,11 +19,31 @@ Login to Tailor Platform. **Usage** ``` -tailor-sdk login +tailor-sdk login [options] ``` + + +**Options** + +> One of the following option groups is required: + +**User Login:** + +_no options_ + +**Machine User Login:** + +| Option | Alias | Description | Required | Default | Env | +| --------------------------------- | ----- | --------------------------------- | -------- | ------- | -------------------------------------------- | +| `--machineuser ` | - | Login as a platform machine user. | Yes | - | - | +| `--client-id ` | - | Client ID | Yes | - | `TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID` | +| `--client-secret ` | - | Client secret | No | - | `TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET` | + + + See [Global Options](../cli-reference.md#global-options) for options available to all commands. @@ -148,13 +168,6 @@ tailor-sdk user list - -**Options** - -| Option | Alias | Description | Required | Default | -| -------- | ----- | -------------- | -------- | ------- | -| `--json` | `-j` | Output as JSON | No | `false` | - @@ -222,13 +235,6 @@ tailor-sdk user pat [command] - -**Options** - -| Option | Alias | Description | Required | Default | -| -------- | ----- | -------------- | -------- | ------- | -| `--json` | `-j` | Output as JSON | No | `false` | - @@ -272,13 +278,6 @@ tailor-sdk user pat list - -**Options** - -| Option | Alias | Description | Required | Default | -| -------- | ----- | -------------- | -------- | ------- | -| `--json` | `-j` | Output as JSON | No | `false` | - diff --git a/docs/sdk/cli/workspace.md b/docs/sdk/cli/workspace.md index 44e556b..acd0dd2 100644 --- a/docs/sdk/cli/workspace.md +++ b/docs/sdk/cli/workspace.md @@ -274,13 +274,6 @@ tailor-sdk profile list - -**Options** - -| Option | Alias | Description | Required | Default | -| -------- | ----- | -------------- | -------- | ------- | -| `--json` | `-j` | Output as JSON | No | `false` | - diff --git a/docs/sdk/configuration.md b/docs/sdk/configuration.md index 668d489..e357c9d 100644 --- a/docs/sdk/configuration.md +++ b/docs/sdk/configuration.md @@ -145,6 +145,25 @@ export default defineConfig({ }); ``` +### Secret Manager + +Configure secrets using `defineSecretManager()`. See [Secret Manager](services/secret) for full documentation. + +```typescript +import { defineSecretManager } from "@tailor-platform/sdk"; + +export const secrets = defineSecretManager({ + "api-keys": { + "stripe-secret-key": process.env.STRIPE_SECRET_KEY!, + "sendgrid-api-key": process.env.SENDGRID_API_KEY!, + }, +}); + +export default defineConfig({ + secrets, +}); +``` + ### Environment Variables Define environment variables that can be accessed in resolvers, executors, and workflows: diff --git a/docs/sdk/quickstart.md b/docs/sdk/quickstart.md index 7da5bce..d182214 100644 --- a/docs/sdk/quickstart.md +++ b/docs/sdk/quickstart.md @@ -14,12 +14,18 @@ Contact us [here](https://www.tailor.tech/demo) to get started. The SDK requires Node.js 22 or later. Install Node.js via your package manager by following the official Node.js instructions. +Alternatively, you can use Bun as the runtime. + +> **Note:** Bun has a known issue with HTTP/2 connections that may cause intermittent failures during `apply` or `generate` commands ([bun#14249](https://github.com/oven-sh/bun/issues/14249), [bun#26719](https://github.com/oven-sh/bun/issues/26719)). If you encounter a connection error, retry the command. + ### Create an Example App The following command creates a new project with the required configuration files and example code. ```bash npm create @tailor-platform/sdk -- --template hello-world example-app +# Or with Bun: +# bun create @tailor-platform/sdk --template hello-world example-app ``` Before deploying your app, you need to create a workspace: @@ -29,6 +35,10 @@ npx tailor-sdk login npx tailor-sdk workspace create --name --region npx tailor-sdk workspace list +# Or with Bun: +# bunx tailor-sdk login +# bunx tailor-sdk workspace create --name --region + # OR # Create a new workspace using Tailor Platform Console # https://console.tailor.tech/ @@ -41,6 +51,8 @@ Run the apply command to deploy your project: ```bash cd example-app npm run deploy -- --workspace-id +# Or with Bun: +# bun run deploy --workspace-id ``` You can now open the GraphQL Playground and execute the `hello` query: @@ -53,7 +65,7 @@ query { } ``` -### Hello World Example +## Hello World Example Here's a simple query resolver from the hello-world template: diff --git a/docs/sdk/services/auth.md b/docs/sdk/services/auth.md index b362140..19cac71 100644 --- a/docs/sdk/services/auth.md +++ b/docs/sdk/services/auth.md @@ -341,6 +341,39 @@ idProvider: idp.provider("my-provider", "my-client"), See [IdP](idp) for configuring identity providers. +## Before Login Hook + +Run custom logic before a user logs in. This is useful for JIT (Just-In-Time) user provisioning — automatically creating or updating user records when a user authenticates for the first time. + +```typescript +import { defineAuth } from "@tailor-platform/sdk"; +import { user } from "./tailordb/user"; + +export const auth = defineAuth("my-auth", { + userProfile: { + type: user, + usernameField: "email", + }, + machineUsers: { + "hook-invoker": { + attributes: { role: "ADMIN" }, + }, + }, + hooks: { + beforeLogin: { + handler: async ({ claims, idpConfigName }) => { + // Provision or update user based on IdP claims + }, + invoker: "hook-invoker", + }, + }, +}); +``` + +**handler**: An async function that receives `{ claims, idpConfigName }` and is called before each login. `claims` contains the token claims from the identity provider, and `idpConfigName` is the name of the IdP configuration used for authentication. + +**invoker**: The machine user whose permissions are used to execute the hook. Must reference a machine user defined in the same auth configuration. + ## CLI Commands Manage Auth resources using the CLI: diff --git a/docs/sdk/services/executor.md b/docs/sdk/services/executor.md index 69582fe..7b08da8 100644 --- a/docs/sdk/services/executor.md +++ b/docs/sdk/services/executor.md @@ -99,6 +99,30 @@ resolverExecutedTrigger({ }); ``` +### IdP User Triggers + +Fire when IdP users are created, updated, or deleted: + +- `idpUserCreatedTrigger()`: Fires when a new IdP user is created +- `idpUserUpdatedTrigger()`: Fires when an IdP user is updated +- `idpUserDeletedTrigger()`: Fires when an IdP user is deleted + +```typescript +idpUserCreatedTrigger(); +``` + +### Auth Access Token Triggers + +Fire on auth access token lifecycle events: + +- `authAccessTokenIssuedTrigger()`: Fires when a new access token is issued +- `authAccessTokenRefreshedTrigger()`: Fires when an access token is refreshed +- `authAccessTokenRevokedTrigger()`: Fires when an access token is revoked + +```typescript +authAccessTokenIssuedTrigger(); +``` + ## Operation Types ### Function Operation @@ -401,3 +425,25 @@ export default createExecutor({ }, }); ``` + +### IdP User Event Payload + +IdP user triggers receive user context: + +```typescript +interface IdpUserContext { + namespaceName: string; // IdP namespace name + userId: string; // The affected user ID +} +``` + +### Auth Access Token Event Payload + +Auth access token triggers receive token context: + +```typescript +interface AuthAccessTokenContext { + namespaceName: string; // Auth namespace name + userId: string; // The user associated with the token +} +``` diff --git a/docs/sdk/services/resolver.md b/docs/sdk/services/resolver.md index 889d400..b85079d 100644 --- a/docs/sdk/services/resolver.md +++ b/docs/sdk/services/resolver.md @@ -120,6 +120,65 @@ createResolver({ }); ``` +### Custom Type Name (`typeName`) + +Enum and nested object fields in input/output schemas generate protobuf type names automatically (e.g., `{ResolverName}{FieldName}`). Use `typeName()` to set a custom name: + +```typescript +createResolver({ + name: "createOrder", + operation: "mutation", + input: { + address: t + .object({ + street: t.string(), + city: t.string(), + zip: t.string(), + }) + .typeName("ShippingAddress"), + status: t.enum(["pending", "confirmed", "shipped"]).typeName("OrderStatus"), + }, + // ... +}); +``` + +**Constraints:** + +- Only available on `enum()` and `object()` fields — calling on scalar types is a compile error +- Cannot be called twice on the same field +- Can be chained with `description()` + +This is useful when the same logical type appears in multiple resolvers or when you want a predictable, human-readable name in the generated GraphQL schema. + +**Warning:** Do not set `typeName` to an existing TailorDB type name on an `object()` that contains enum or nested fields. Child fields without an explicit `typeName` auto-generate names using `{parentTypeName}{FieldName}`, which can collide with the TailorDB type's own enum/nested type names. + +```typescript +// Collision — "Item" + "status" auto-generates "ItemStatus", +// which collides with the TailorDB Item type's status enum +output: t + .object({ + id: t.uuid(), + status: t.enum(["ACTIVE", "INACTIVE"]), + }) + .typeName("Item"), + +// OK — use a distinct name that won't collide +output: t + .object({ + id: t.uuid(), + status: t.enum(["ACTIVE", "INACTIVE"]), + }) + .typeName("DeactivateItemOutput"), + +// OK — explicitly set typeName on child enum too +output: t + .object({ + id: t.uuid(), + status: t.enum(["ACTIVE", "INACTIVE"]).typeName("DeactivateItemStatus"), + }) + .typeName("Item"), +``` + ## Input Validation Add validation rules to input fields using the `validate` method: @@ -275,3 +334,35 @@ createResolver({ // ... }); ``` + +## Authentication + +Specify an `authInvoker` to execute the resolver with machine user credentials: + +```typescript +import { defineAuth, createResolver, t } from "@tailor-platform/sdk"; + +const auth = defineAuth("my-auth", { + // ... auth configuration + machineUsers: { + "batch-processor": { + attributes: { role: "ADMIN" }, + }, + }, +}); + +export default createResolver({ + name: "adminQuery", + operation: "query", + output: t.object({ result: t.string() }), + body: async () => { + // Executes as "batch-processor" machine user + return { result: "ok" }; + }, + authInvoker: auth.invoker("batch-processor"), +}); +``` + +The `authInvoker` option accepts the return value of `auth.invoker()`, which specifies the auth namespace and machine user name. + +**Note:** `authInvoker` controls the permissions for database operations and other platform actions, but the `user` object passed to the `body` function still reflects the original caller who invoked the resolver. diff --git a/docs/sdk/services/secret.md b/docs/sdk/services/secret.md index 1e2c336..4f602f1 100644 --- a/docs/sdk/services/secret.md +++ b/docs/sdk/services/secret.md @@ -32,8 +32,85 @@ workspace/ Secrets are key-value pairs stored within a vault. Secret values are encrypted at rest and only accessible at runtime by authorized services. +## Managing Secrets + +There are two ways to manage secrets: declaratively via `defineSecretManager()` in `tailor.config.ts`, or imperatively via the [CLI](#cli-management). Management is scoped per vault — **do not mix both approaches for the same vault**. When a vault is defined in config, the config becomes the source of truth: any secrets in that vault not present in the config will be deleted on `tailor-sdk apply`. + +### Declarative Configuration + +Define your secrets in `tailor.config.ts` using `defineSecretManager()`. Each key is a vault name, and its value is a record of secret names to their values. These values are deployed to each vault on `tailor-sdk apply`. + +Since secret values should not be committed to source control, use environment variables: + +```typescript +import { defineConfig, defineSecretManager } from "@tailor-platform/sdk"; + +export const secrets = defineSecretManager({ + "api-keys": { + "stripe-secret-key": process.env.STRIPE_SECRET_KEY!, + "sendgrid-api-key": process.env.SENDGRID_API_KEY!, + }, + database: { + "analytics-connection-string": process.env.ANALYTICS_DB_URL!, + }, +}); + +export default defineConfig({ + name: "my-app", + secrets, + // ...other config +}); +``` + +The exported `secrets` object provides type-safe `get()` and `getAll()` methods for runtime access from resolvers, executors, and workflows. + ## Using Secrets +### Runtime Access with `get()` / `getAll()` + +Use the `secrets` object exported from `tailor.config.ts` to retrieve secret values at runtime. The vault and secret names are fully type-checked based on the `defineSecretManager()` configuration. + +#### `get(vault, secret)` + +Retrieves a single secret value. + +```typescript +import { createResolver } from "@tailor-platform/sdk"; +import { secrets } from "../tailor.config"; + +export default createResolver({ + name: "call-stripe", + // ... + operation: async ({ input }) => { + const apiKey = await secrets.get("api-keys", "stripe-secret-key"); + // Use apiKey to call the Stripe API + }, +}); +``` + +#### `getAll(vault, secrets)` + +Retrieves multiple secret values at once from the same vault. + +```typescript +import { createResolver } from "@tailor-platform/sdk"; +import { secrets } from "../tailor.config"; + +export default createResolver({ + name: "send-notification", + // ... + operation: async ({ input }) => { + const [apiKey, webhookSecret] = await secrets.getAll("api-keys", [ + "sendgrid-api-key", + "stripe-secret-key", + ]); + // Use the retrieved secrets + }, +}); +``` + +Both methods return `Promise` (or an array of them for `getAll`). + ### In Webhook Operations Reference secrets in webhook headers using the vault/key syntax: @@ -71,6 +148,10 @@ At runtime, these references are replaced with the actual secret values. ## CLI Management +Use the CLI to manage vaults that are **not** defined in `defineSecretManager()`. If you attempt to modify a vault that is managed by the config, the CLI will show a warning and ask for confirmation. Once confirmed, the CLI releases the vault's ownership label so it is no longer managed by config. + +After ownership is released, the next `tailor-sdk apply` will treat the vault as an unmanaged resource and prompt for confirmation before taking any action on it. + ### Create a Vault ```bash diff --git a/docs/sdk/services/tailordb.md b/docs/sdk/services/tailordb.md index 9677c2c..316f0c3 100644 --- a/docs/sdk/services/tailordb.md +++ b/docs/sdk/services/tailordb.md @@ -243,10 +243,10 @@ export const customer = db }); ``` -**⚠️ Important:** Field-level and type-level hooks cannot coexist on the same field. TypeScript will prevent this at compile time: +**Important:** Field-level and type-level hooks cannot coexist on the same field. TypeScript will prevent this at compile time: ```typescript -// ❌ Compile error - cannot set hooks on the same field twice +// Compile error - cannot set hooks on the same field twice export const user = db .type("User", { name: db.string().hooks({ create: ({ data }) => data.firstName }), // Field-level @@ -255,7 +255,7 @@ export const user = db name: { create: ({ data }) => data.lastName }, // Type-level - ERROR }); -// ✅ Correct - set hooks on different fields +// OK - set hooks on different fields export const user = db .type("User", { firstName: db.string().hooks({ create: () => "John" }), // Field-level on firstName @@ -306,10 +306,10 @@ export const user = db }); ``` -**⚠️ Important:** Field-level and type-level validation cannot coexist on the same field. TypeScript will prevent this at compile time: +**Important:** Field-level and type-level validation cannot coexist on the same field. TypeScript will prevent this at compile time: ```typescript -// ❌ Compile error - cannot set validation on the same field twice +// Compile error - cannot set validation on the same field twice export const user = db .type("User", { name: db.string().validate(({ value }) => value.length > 0), // Field-level @@ -318,7 +318,7 @@ export const user = db name: [({ value }) => value.length < 100, "Too long"], // Type-level - ERROR }); -// ✅ Correct - set validation on different fields +// OK - set validation on different fields export const user = db .type("User", { name: db.string().validate(({ value }) => value.length > 0), // Field-level on name @@ -449,6 +449,78 @@ db.type("User", { }); ``` +### Field Extraction (`pickFields` / `omitFields`) + +Extract subsets of fields from a `TailorDBType` for reuse in resolvers, executors, seed schemas, etc. + +#### `pickFields(keys, options)` + +Select specific fields and optionally modify their properties: + +```typescript +const user = db.type("User", { + id: db.uuid(), + name: db.string(), + email: db.string().unique(), + ...db.fields.timestamps(), +}); + +// Pick id and createdAt, making them optional +user.pickFields(["id", "createdAt"], { optional: true }); +``` + +Available options: + +| Option | Effect | +| ---------- | ------------------------------------- | +| `optional` | Makes the selected fields optional | +| `array` | Makes the selected fields array types | + +#### `omitFields(keys)` + +Return all fields except the specified ones: + +```typescript +// All fields except id and createdAt +user.omitFields(["id", "createdAt"]); +``` + +#### Common Pattern: Input Schema Composition + +The typical use case is combining `pickFields` and `omitFields` with spread syntax to build input schemas where identifiers are optional but other fields remain required: + +```typescript +import { createResolver, t } from "@tailor-platform/sdk"; +import { user } from "../tailordb/user"; + +export default createResolver({ + name: "createUser", + operation: "mutation", + input: { + // id/createdAt are optional (auto-generated), other fields are required + ...user.pickFields(["id", "createdAt"], { optional: true }), + ...user.omitFields(["id", "createdAt"]), + }, + output: t.object({ id: t.uuid() }), + body: async (context) => { + // ... + return { id: "..." }; + }, +}); +``` + +This is also used in seed data schemas: + +```typescript +import { t } from "@tailor-platform/sdk"; +import { invoice } from "../../tailordb/invoice"; + +const schemaType = t.object({ + ...invoice.pickFields(["id", "createdAt"], { optional: true }), + ...invoice.omitFields(["id", "createdAt", "invoiceNumber", "sequentialId"]), +}); +``` + ### Permissions Configure Permission and GQLPermission. For details, see the [TailorDB Permission documentation](/guides/tailordb/permission).