@tailor-platform/sdk 2.24.0 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/dist/application-ChqHuhZW.mjs +1 -0
- package/dist/{application-CfqvzV3I.mjs → application-DS0XKBtK.mjs} +4 -4
- package/dist/application-DS0XKBtK.mjs.map +1 -0
- package/dist/cli/commands/deploy/deployment-target.d.mts +1 -0
- package/dist/cli/commands/machineuser/list.d.mts +1 -0
- package/dist/cli/commands/show.d.mts +13 -1
- package/dist/cli/lib.d.mts +2 -2
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +46 -46
- package/dist/cli/main.mjs.map +1 -1
- package/dist/completion/zsh-worker.zsh +3 -3
- package/dist/configure/index.d.mts +2 -2
- package/dist/configure/index.mjs.map +1 -1
- package/dist/plugin/index.mjs +1 -1
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/plugin/types.d.mts +97 -0
- package/dist/register-ts-hook-DPAW0Z4M.mjs +924 -0
- package/dist/register-ts-hook-DPAW0Z4M.mjs.map +1 -0
- package/docs/cli/application.md +23 -0
- package/docs/cli/secret.md +24 -16
- package/docs/cli-reference.md +25 -13
- package/docs/github-actions.md +69 -4
- package/docs/plugin/custom.md +76 -1
- package/docs/plugin/frontend.md +124 -0
- package/docs/plugin/index.md +24 -2
- package/docs/services/auth.md +2 -0
- package/docs/services/secret.md +5 -4
- package/docs/services/staticwebsite.md +2 -0
- package/docs/services/tailordb-migration.md +1 -1
- package/package.json +5 -5
- package/dist/application-BDqze-wy.mjs +0 -1
- package/dist/application-CfqvzV3I.mjs.map +0 -1
- package/dist/register-ts-hook-CVlI9Jzl.mjs +0 -922
- package/dist/register-ts-hook-CVlI9Jzl.mjs.map +0 -1
package/docs/cli/application.md
CHANGED
|
@@ -74,6 +74,29 @@ tailor deploy [options]
|
|
|
74
74
|
| `--clean-cache` | - | Clean the bundle cache before building | No | - | - |
|
|
75
75
|
|
|
76
76
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
77
|
+
**JSON result:**
|
|
78
|
+
|
|
79
|
+
After a successful `tailor deploy --json`, stdout includes `status: "applied"`,
|
|
80
|
+
`summary`, `workspaceId`, and `applications` in config order. Each entry includes
|
|
81
|
+
the config's `name`, `configPath`, and, when configured, `id`, plus `aiGateways`
|
|
82
|
+
and `staticWebsites` keyed by site name. Endpoint `url` and `domain` are included
|
|
83
|
+
when a Platform Application with that name exists. If Auth is configured, `auth`
|
|
84
|
+
includes its `namespace` and `oauth2Clients` with each client's `name` and public `clientId`.
|
|
85
|
+
Client secrets are excluded. These fields are returned even when no deploy plugin
|
|
86
|
+
is registered or no resources changed.
|
|
87
|
+
|
|
88
|
+
Plugins that return outputs add entries under `deployedHooks`. For example, the
|
|
89
|
+
frontend plugin provides upload results in `deployedHooks[].outputs.frontends`.
|
|
90
|
+
|
|
91
|
+
```sh
|
|
92
|
+
tailor deploy --json > deploy-result.json
|
|
93
|
+
jq '.applications[] | {name, url, staticWebsites, auth}' deploy-result.json
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Dry-run and build-only deployments do not return deployed application information.
|
|
97
|
+
If resources were applied but loading the JSON result fails, the command reports
|
|
98
|
+
`DEPLOY_RESULT_LOAD_FAILED`; fix the error and run `tailor deploy` again.
|
|
99
|
+
|
|
77
100
|
**Workspace Selection:**
|
|
78
101
|
|
|
79
102
|
After validating the configuration file, `deploy` resolves a workspace before bundling the
|
package/docs/cli/secret.md
CHANGED
|
@@ -36,17 +36,21 @@ tailor secret create [options]
|
|
|
36
36
|
|
|
37
37
|
**Options**
|
|
38
38
|
|
|
39
|
-
| Option | Alias | Description
|
|
40
|
-
| ------------------------------- | ----- |
|
|
41
|
-
| `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID
|
|
42
|
-
| `--profile <PROFILE>` | `-p` | Workspace profile
|
|
43
|
-
| `--vault-name <VAULT_NAME>` | `-V` | Vault name
|
|
44
|
-
| `--name <NAME>` | `-n` | Secret name
|
|
45
|
-
| `--value <VALUE>` | `-v` | Secret value
|
|
46
|
-
| `--yes` | `-y` | Skip confirmation prompts
|
|
39
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
40
|
+
| ------------------------------- | ----- | ---------------------------------------------------- | -------- | ------- | ------------------------------ |
|
|
41
|
+
| `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` |
|
|
42
|
+
| `--profile <PROFILE>` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` |
|
|
43
|
+
| `--vault-name <VAULT_NAME>` | `-V` | Vault name | Yes | - | - |
|
|
44
|
+
| `--name <NAME>` | `-n` | Secret name | Yes | - | - |
|
|
45
|
+
| `--value <VALUE>` | `-v` | Secret value (read from standard input when omitted) | No | - | - |
|
|
46
|
+
| `--yes` | `-y` | Skip confirmation prompts | No | `false` | - |
|
|
47
47
|
|
|
48
48
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
49
49
|
|
|
50
|
+
**Notes**
|
|
51
|
+
|
|
52
|
+
Pass the value with `--value`, or omit `--value` and pipe the value in to keep it out of shell history and process listings, for example `printf '%s' "$STRIPE_KEY" | tailor secret create --vault-name api-keys --name stripe-secret-key`. A piped value can be up to 128 KiB, and one trailing newline is removed from it. In a vault managed by `defineSecretManager()`, the command asks for confirmation before releasing the vault from the config, which needs an interactive terminal, so pass `--yes` when piping the value.
|
|
53
|
+
|
|
50
54
|
### secret delete
|
|
51
55
|
|
|
52
56
|
Delete a secret in a vault.
|
|
@@ -103,17 +107,21 @@ tailor secret update [options]
|
|
|
103
107
|
|
|
104
108
|
**Options**
|
|
105
109
|
|
|
106
|
-
| Option | Alias | Description
|
|
107
|
-
| ------------------------------- | ----- |
|
|
108
|
-
| `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID
|
|
109
|
-
| `--profile <PROFILE>` | `-p` | Workspace profile
|
|
110
|
-
| `--vault-name <VAULT_NAME>` | `-V` | Vault name
|
|
111
|
-
| `--name <NAME>` | `-n` | Secret name
|
|
112
|
-
| `--value <VALUE>` | `-v` | Secret value
|
|
113
|
-
| `--yes` | `-y` | Skip confirmation prompts
|
|
110
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
111
|
+
| ------------------------------- | ----- | ---------------------------------------------------- | -------- | ------- | ------------------------------ |
|
|
112
|
+
| `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` |
|
|
113
|
+
| `--profile <PROFILE>` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` |
|
|
114
|
+
| `--vault-name <VAULT_NAME>` | `-V` | Vault name | Yes | - | - |
|
|
115
|
+
| `--name <NAME>` | `-n` | Secret name | Yes | - | - |
|
|
116
|
+
| `--value <VALUE>` | `-v` | Secret value (read from standard input when omitted) | No | - | - |
|
|
117
|
+
| `--yes` | `-y` | Skip confirmation prompts | No | `false` | - |
|
|
114
118
|
|
|
115
119
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
116
120
|
|
|
121
|
+
**Notes**
|
|
122
|
+
|
|
123
|
+
Pass the value with `--value`, or omit `--value` and pipe the value in to keep it out of shell history and process listings, for example `printf '%s' "$STRIPE_KEY" | tailor secret update --vault-name api-keys --name stripe-secret-key`. A piped value can be up to 128 KiB, and one trailing newline is removed from it. In a vault managed by `defineSecretManager()`, the command asks for confirmation before releasing the vault from the config, which needs an interactive terminal, so pass `--yes` when piping the value.
|
|
124
|
+
|
|
117
125
|
### secret vault
|
|
118
126
|
|
|
119
127
|
Manage Secret Manager vaults.
|
package/docs/cli-reference.md
CHANGED
|
@@ -31,8 +31,16 @@ For commands that return structured results, passing `--json` writes one parseab
|
|
|
31
31
|
to stdout on success. Empty successful result sets are emitted as JSON values such as `[]`, not as
|
|
32
32
|
human-readable text or empty stdout.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
Many commands that change state print a JSON object describing the outcome. Its `changed` field is
|
|
35
|
+
`true` when the command did work and `false` when it did nothing, for example because the requested
|
|
36
|
+
state was already in place. The other fields identify what the command acted on and report details of
|
|
37
|
+
the outcome. Other state-changing commands print a result without `changed`, or do not report a
|
|
38
|
+
result yet and leave stdout empty even when `--json` is passed.
|
|
39
|
+
|
|
40
|
+
List commands return at most `--limit` items. When more exist, the list is followed by a notice on
|
|
41
|
+
stderr, `More results exist beyond --limit N. Raise --limit to see more.`, so `--json` output stays a
|
|
42
|
+
plain array of the listed items. Log listings such as `executor jobs`, `function logs`, and
|
|
43
|
+
`workflow executions` default to `--limit 50`; pass `--limit 0` to list everything.
|
|
36
44
|
|
|
37
45
|
Set `TAILOR_JSON_OUTPUT=true` (or `1`) to default every command to JSON without passing `--json`
|
|
38
46
|
each time. This is intended for agents, scripts, and CI steps that parse CLI output. An explicit
|
|
@@ -42,11 +50,13 @@ keep table output. Other values are rejected. JSON mode also disables interactiv
|
|
|
42
50
|
variable per invocation or per job rather than exporting it from a shell profile; a command that
|
|
43
51
|
needed a prompt names what selected JSON when it refuses.
|
|
44
52
|
|
|
45
|
-
Errors, warnings, progress, and diagnostic messages are written to stderr.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
53
|
+
Errors, warnings, progress, and diagnostic messages are written to stderr. A command failure under
|
|
54
|
+
`--json` or `TAILOR_JSON_OUTPUT` emits a JSON error envelope to stderr, including a failure while
|
|
55
|
+
parsing arguments: an unknown option or subcommand, or an option value that fails validation, is
|
|
56
|
+
reported as `INVALID_ARGUMENTS`. Failures you can act on — an invalid or missing option, a resource
|
|
57
|
+
that does not exist, an invalid configuration, or an unmet precondition — carry a stable `error.code`
|
|
58
|
+
such as `PROFILE_NOT_FOUND`, `TAILORDB_NAMESPACE_NOT_FOUND`, or `MIGRATION_SCRIPT_REQUIRED`. Where a
|
|
59
|
+
remediation exists, the envelope also includes
|
|
50
60
|
`error.suggestion`, `error.help` (the `--help` invocation for the failing command), `error.next` (a
|
|
51
61
|
runnable command), or `error.context`. `UNEXPECTED_ERROR` marks failures without a dedicated code,
|
|
52
62
|
including SDK-internal errors. Diagnostic lines may precede the error envelope, and stdout is not
|
|
@@ -75,9 +85,11 @@ Use `--verbose` to include debug diagnostics and error stack traces. `DEBUG=true
|
|
|
75
85
|
sets `RUNNER_DEBUG=1` when debug logging is enabled, so the same command automatically includes
|
|
76
86
|
these details in a debug run. These settings do not enable JSON output; pass `--json` separately.
|
|
77
87
|
|
|
78
|
-
Capture the original failure's stderr and exit code before retrying.
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
Capture the original failure's stderr and exit code before retrying. Failures before the CLI starts,
|
|
89
|
+
a rejected `--json` or `TAILOR_JSON_OUTPUT` value, argument errors in the bundled CLI plugins, and
|
|
90
|
+
the install hint for a CLI plugin that is not installed may still produce plain text when JSON output
|
|
91
|
+
is requested. A failed deployment may have already
|
|
92
|
+
applied changes, so inspect its output before deciding to run it again.
|
|
81
93
|
|
|
82
94
|
### GitHub Actions Annotations
|
|
83
95
|
|
|
@@ -95,9 +107,9 @@ without reporting through the CLI's error path, such as one relaying a failed re
|
|
|
95
107
|
writes no annotation.
|
|
96
108
|
|
|
97
109
|
Set `TAILOR_GITHUB_ACTIONS_ANNOTATIONS=false` (also `off`, `no`, or `0`) to turn annotations off.
|
|
98
|
-
Passing `--json` also suppresses them, so a workflow step that parses
|
|
99
|
-
error envelope on stderr
|
|
100
|
-
|
|
110
|
+
Passing `--json` or setting `TAILOR_JSON_OUTPUT` also suppresses them, so a workflow step that parses
|
|
111
|
+
JSON output gets only the error envelope on stderr, even when the command fails during argument
|
|
112
|
+
parsing.
|
|
101
113
|
|
|
102
114
|
An annotation does not by itself fail a step: the step still fails on the CLI's exit code, which
|
|
103
115
|
is unchanged. Workflows that already echo their own `::error::` around the CLI keep working;
|
package/docs/github-actions.md
CHANGED
|
@@ -199,6 +199,14 @@ Running a workflow setup subcommand creates or updates:
|
|
|
199
199
|
The workflow file. The `name:` field is set to `Tailor (<workspace-name>)` so
|
|
200
200
|
you can distinguish multiple workspaces in the Actions UI.
|
|
201
201
|
|
|
202
|
+
Every checkout in the workflow sets `persist-credentials: false`, so the GitHub
|
|
203
|
+
token is not left in `.git/config` while the job installs and runs your
|
|
204
|
+
project's code. The tag guard step passes the job token only to its
|
|
205
|
+
`git fetch`, and the plan step passes it to its `git fetch` and to the step that
|
|
206
|
+
posts the plan comment on the pull request; neither writes it to `.git/config`.
|
|
207
|
+
If installing your dependencies fetches git repositories
|
|
208
|
+
that require authentication, configure the credentials in your own step.
|
|
209
|
+
|
|
202
210
|
See [Customizing the generated workflow](#customizing-the-generated-workflow)
|
|
203
211
|
for what you can edit.
|
|
204
212
|
|
|
@@ -218,7 +226,12 @@ them. Everything else is yours, and re-running `setup` keeps it:
|
|
|
218
226
|
managed job with `needs: tailor-deploy`.
|
|
219
227
|
- **Your own top-level keys**, such as a workflow-level `env:` or `defaults:`.
|
|
220
228
|
- **Runtime settings of managed jobs:** `runs-on`, `timeout-minutes`,
|
|
221
|
-
`container`, and `env`.
|
|
229
|
+
`container`, and `env`. On a managed job generated without an
|
|
230
|
+
`environment:` (such as `tailor-tag-guard` or `tailor-erd-preview`), you can
|
|
231
|
+
also add one, for example so a step you added there can read that GitHub
|
|
232
|
+
Environment's secrets. The `environment:` of `tailor-plan`, `tailor-deploy`,
|
|
233
|
+
and the preview jobs comes from `--environment`, so change it with that
|
|
234
|
+
option instead.
|
|
222
235
|
- **These inputs of managed steps:** `ignore` on `tailor-generate-check` and
|
|
223
236
|
`tailor-drift-check`, `fail-on-drift` on `tailor-drift-check`,
|
|
224
237
|
`install-command` on `tailor-install`, `node-version-file` on
|
|
@@ -479,9 +492,61 @@ For a monorepo where your SDK app lives in a subdirectory, pass `--dir`:
|
|
|
479
492
|
tailor setup ci branch --name my-app --dir apps/backend
|
|
480
493
|
```
|
|
481
494
|
|
|
482
|
-
The
|
|
483
|
-
|
|
484
|
-
|
|
495
|
+
The `working-directory` for SDK commands is set accordingly, and the workflow
|
|
496
|
+
only plans and deploys when that subdirectory changes. The workflow itself
|
|
497
|
+
starts on every pull request and push: a `tailor-changes` job checks whether
|
|
498
|
+
the change touches `apps/backend/**`, and the plan, deploy, and ERD preview jobs
|
|
499
|
+
are skipped when it does not. A skipped job reports success, so you can make
|
|
500
|
+
these checks required in branch protection; a workflow that a `paths` trigger
|
|
501
|
+
filter never started would leave them pending instead. If the `tailor-changes` job
|
|
502
|
+
itself fails (for example, on a GitHub API error), the plan, deploy, and ERD
|
|
503
|
+
preview jobs fail too instead of being skipped, so a required check blocks
|
|
504
|
+
merging and nothing is deployed. Re-run the failed jobs once the cause is gone.
|
|
505
|
+
|
|
506
|
+
### Deploying several apps together
|
|
507
|
+
|
|
508
|
+
To deploy several apps to the same workspace from one workflow, repeat `--dir`
|
|
509
|
+
and pass `--name` for the workflow:
|
|
510
|
+
|
|
511
|
+
```bash
|
|
512
|
+
tailor setup ci branch --name erp --dir apps/erp/backend --dir apps/users/backend
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
`setup ci branch`, `setup ci tag`, and `setup ci preview` accept repeated
|
|
516
|
+
`--dir`. The workflow plans and deploys every app's `tailor.config.ts` in one
|
|
517
|
+
[multi-config deploy](./cli/application.md#deploy) from the repository root, so
|
|
518
|
+
an app can reference resources of another app with `external: true`. Add
|
|
519
|
+
`@tailor-platform/sdk` to the root `package.json` so the `tailor` CLI resolves
|
|
520
|
+
there; setup stops until it is declared. The generate check runs for each app
|
|
521
|
+
directory, as do seed validation and the migration drift check on branch and tag
|
|
522
|
+
workflows, and a change under any app directory runs the workflow's jobs.
|
|
523
|
+
|
|
524
|
+
With `--erd-preview`, each TailorDB namespace is previewed from the app that
|
|
525
|
+
owns it. A namespace may be owned by only one app; the others reference it with
|
|
526
|
+
`external: true`.
|
|
527
|
+
|
|
528
|
+
With more than one app, the preview comment does not link an application URL.
|
|
529
|
+
|
|
530
|
+
### Running on changes outside the app directories
|
|
531
|
+
|
|
532
|
+
When the apps depend on code outside their directories, such as a frontend or
|
|
533
|
+
shared packages, add those paths with `--paths` on `setup ci branch` or
|
|
534
|
+
`setup ci preview`. Repeat it for each pattern:
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
tailor setup ci preview --name erp --region asia-northeast \
|
|
538
|
+
--dir apps/erp/backend --dir apps/users/backend \
|
|
539
|
+
--paths "apps/*/frontend/**" --paths "modules/**" --paths pnpm-lock.yaml
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
The patterns are checked after the app directories, in order, and the last
|
|
543
|
+
pattern that matches a changed file decides whether it counts. `*` matches
|
|
544
|
+
within one path segment, `**` matches any number of segments, and a pattern
|
|
545
|
+
starting with `!` excludes matching paths, so it can also exclude files inside
|
|
546
|
+
an app directory, for example `--paths '!apps/erp/backend/**/*.md'`. Other glob
|
|
547
|
+
characters (`?`, `+`, `[ ]`, `{ }`, `( )`, and `\`) are not supported, and
|
|
548
|
+
`setup ci` rejects a pattern that contains them. An app at the repository root already
|
|
549
|
+
runs on every change, so `--paths` is not accepted with `--dir .`.
|
|
485
550
|
|
|
486
551
|
## Rollback
|
|
487
552
|
|
package/docs/plugin/custom.md
CHANGED
|
@@ -6,7 +6,7 @@ Create your own plugins by implementing the `Plugin` interface.
|
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
9
|
-
**Plugins must use default export**:
|
|
9
|
+
**Plugins with definition-time hooks must use default export**:
|
|
10
10
|
|
|
11
11
|
```typescript
|
|
12
12
|
// plugin.ts
|
|
@@ -48,6 +48,9 @@ interface Plugin<TableConfig = unknown, PluginConfig = unknown> {
|
|
|
48
48
|
onExecutorReady?(
|
|
49
49
|
context: ExecutorReadyContext<PluginConfig>,
|
|
50
50
|
): GeneratorResult | Promise<GeneratorResult>;
|
|
51
|
+
onDeployed?(
|
|
52
|
+
context: DeployedContext<PluginConfig>,
|
|
53
|
+
): void | DeployedHookResult | Promise<void | DeployedHookResult>;
|
|
51
54
|
}
|
|
52
55
|
```
|
|
53
56
|
|
|
@@ -254,6 +257,78 @@ onExecutorReady(ctx) {
|
|
|
254
257
|
},
|
|
255
258
|
```
|
|
256
259
|
|
|
260
|
+
### onDeployed
|
|
261
|
+
|
|
262
|
+
Runs once after every application in the deploy has been applied, including when
|
|
263
|
+
there are no resource changes. Hooks run sequentially in config order, then in
|
|
264
|
+
`definePlugins()` registration order. No `importPath` or table attachment is required.
|
|
265
|
+
|
|
266
|
+
Use `ctx.application` for the registering application's ID, URL, domain, AI
|
|
267
|
+
Gateway URLs, static websites, and public OAuth client IDs. `ctx.application.id`
|
|
268
|
+
is the `id` from `defineConfig()` and is `undefined` when the config has none.
|
|
269
|
+
`ctx.applications` contains all applications in a multi-config deploy with the
|
|
270
|
+
same fields. OAuth client secrets are never included.
|
|
271
|
+
|
|
272
|
+
`ctx.configPath` is the absolute path of the registering config. `ctx.workspaceId`
|
|
273
|
+
and `ctx.pluginConfig` identify the deployment workspace and the plugin's options.
|
|
274
|
+
Use `ctx.logger.info`, `warn`, and `success` for diagnostics; they write to stderr
|
|
275
|
+
and preserve deploy's JSON stdout.
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { definePlugins, type Plugin } from "@tailor-platform/sdk";
|
|
279
|
+
|
|
280
|
+
const deployedInfo: Plugin = {
|
|
281
|
+
id: "@example/deployed-info",
|
|
282
|
+
description: "Reports the deployed application URL",
|
|
283
|
+
onDeployed(ctx) {
|
|
284
|
+
const url = ctx.application.url;
|
|
285
|
+
if (!url) return;
|
|
286
|
+
ctx.logger.success(`Application ready: ${url}`);
|
|
287
|
+
return { outputs: { url } };
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
|
|
291
|
+
export const plugins = definePlugins(deployedInfo);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
To publish assets, look up the site with `ctx.application.staticWebsites[name]`
|
|
295
|
+
and await its `publish(dir)` with an absolute directory path. Only websites
|
|
296
|
+
declared in the registering config appear there; any other name is `undefined`,
|
|
297
|
+
so check the site before publishing. Websites of other configs are listed under
|
|
298
|
+
`ctx.applications` with their `name` and `url` only, so a plugin can read their
|
|
299
|
+
URLs but cannot publish to them. The result contains `url` and `skippedFiles`; report skipped
|
|
300
|
+
files so users can correct files that could not be uploaded.
|
|
301
|
+
|
|
302
|
+
To run a shell command such as a build, await `ctx.exec(command, { workingDir, env })`.
|
|
303
|
+
It rejects when the command exits with a non-zero code. By default the command's
|
|
304
|
+
stdout and stderr both go to stderr so `tailor deploy --json` stdout stays parseable;
|
|
305
|
+
pass `output: "capture"` to receive them as `stdout` and `stderr` instead, or
|
|
306
|
+
`output: "ignore"` to discard them. Use `ctx.exec` rather than importing
|
|
307
|
+
`node:child_process` in the plugin: `tailor.config.ts` is also bundled into
|
|
308
|
+
functions that run on the Tailor Platform, such as auth hooks, and a plugin module
|
|
309
|
+
that imports Node.js-only modules makes that bundle fail.
|
|
310
|
+
|
|
311
|
+
Return JSON-serializable `outputs` to include a result in `deployedHooks` under
|
|
312
|
+
`tailor deploy --json`. Each entry identifies the application and plugin. This
|
|
313
|
+
key is omitted when no hook supplies outputs. `outputs` must be a plain object whose
|
|
314
|
+
values are only strings, finite numbers, booleans, `null`, arrays, and plain objects;
|
|
315
|
+
any other value, such as `undefined`, a function, or a `Date`, fails the hook.
|
|
316
|
+
Output values may be typed with an `interface`. The type checker rejects a
|
|
317
|
+
`Date`, function, `Map`, or other non-JSON value placed directly in `outputs` or in
|
|
318
|
+
an object or array literal, but a `Date` or class instance nested inside an
|
|
319
|
+
interface-typed value is caught only when `tailor deploy` runs the hook.
|
|
320
|
+
|
|
321
|
+
A failed hook stops later hooks with `DEPLOYED_HOOK_FAILED`. The same error is
|
|
322
|
+
reported when the deployed information passed to hooks cannot be loaded. Platform
|
|
323
|
+
resources have already been applied and are not rolled back. The error lists any hooks
|
|
324
|
+
that did not run, with the application each belongs to. Fix the hook and run `tailor deploy` again; hooks run again even
|
|
325
|
+
if there are no resource changes.
|
|
326
|
+
|
|
327
|
+
Hooks do not run during dry-run, build-only, or migration test deployments.
|
|
328
|
+
Dry-run lists the pending hooks; with `--json`, they appear under
|
|
329
|
+
`pendingDeployedHooks` as `{ application, pluginId }` entries. Calling `deploy()` from the programmatic CLI
|
|
330
|
+
API runs hooks under the same conditions as `tailor deploy`.
|
|
331
|
+
|
|
257
332
|
## Hook Scheduling Rules
|
|
258
333
|
|
|
259
334
|
Each generation-time hook runs at its own pipeline phase, regardless of what other hooks the same plugin implements:
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Frontend Plugin
|
|
2
|
+
|
|
3
|
+
`frontendPlugin` builds frontend assets and uploads them to Static Websites after
|
|
4
|
+
`tailor deploy` applies your application. It can provide deployed URLs and public
|
|
5
|
+
OAuth client IDs as build environment variables.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pnpm add -D @tailor-platform/sdk-plugin-frontend
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Use an SDK version that supports `onDeployed` hooks. When testing a PR before
|
|
14
|
+
that SDK release, install both the SDK and frontend plugin from the same
|
|
15
|
+
`pkg.pr.new` commit.
|
|
16
|
+
|
|
17
|
+
## Monorepo example
|
|
18
|
+
|
|
19
|
+
Given this layout:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
apps/
|
|
23
|
+
backend/
|
|
24
|
+
tailor.config.ts
|
|
25
|
+
web/
|
|
26
|
+
package.json
|
|
27
|
+
dist/
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Register the plugin in `apps/backend/tailor.config.ts`:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { defineConfig, definePlugins, defineStaticWebSite } from "@tailor-platform/sdk";
|
|
34
|
+
import { frontendPlugin } from "@tailor-platform/sdk-plugin-frontend";
|
|
35
|
+
|
|
36
|
+
const website = defineStaticWebSite("my-frontend", { description: "Web app" });
|
|
37
|
+
|
|
38
|
+
export default defineConfig({
|
|
39
|
+
name: "my-app",
|
|
40
|
+
staticWebsites: [website],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const plugins = definePlugins(
|
|
44
|
+
frontendPlugin({
|
|
45
|
+
site: website,
|
|
46
|
+
workingDir: "../web",
|
|
47
|
+
build: "pnpm run build",
|
|
48
|
+
distDir: "dist",
|
|
49
|
+
env: ({ site, application }) => ({
|
|
50
|
+
...(application.url ? { VITE_TAILOR_APP_URL: application.url } : {}),
|
|
51
|
+
VITE_SITE_URL: site.url,
|
|
52
|
+
VITE_OAUTH2_CLIENT_ID:
|
|
53
|
+
application.auth?.oauth2Clients.find((client) => client.name === "web")?.clientId ?? "",
|
|
54
|
+
}),
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Run `tailor deploy --config apps/backend/tailor.config.ts` from the repository
|
|
60
|
+
root. `workingDir` is where `build` runs, relative to the config's directory, so
|
|
61
|
+
this example builds in `apps/web`. `distDir` is the directory your build writes
|
|
62
|
+
its assets to, relative to `workingDir`, so this example publishes `apps/web/dist`.
|
|
63
|
+
Set it to match your build tool's output setting; the plugin does not change where
|
|
64
|
+
the build writes. Omitting `workingDir` uses the config's directory. Absolute paths are
|
|
65
|
+
also accepted.
|
|
66
|
+
|
|
67
|
+
`site` accepts either a `defineStaticWebSite()` result or a site name. The site
|
|
68
|
+
must be declared in `staticWebsites` of the same config that registers
|
|
69
|
+
`frontendPlugin`. With multiple configs, register each frontend in the config that
|
|
70
|
+
declares its site; a site from another config fails before the build starts. The
|
|
71
|
+
`env` callback can still read the URLs of other configs' sites from `applications`.
|
|
72
|
+
|
|
73
|
+
## Build environment
|
|
74
|
+
|
|
75
|
+
`env` is an optional function that returns environment variables, synchronously
|
|
76
|
+
or asynchronously. Its values override matching variables inherited from the
|
|
77
|
+
parent process. Choose variable names for your frontend framework; the plugin
|
|
78
|
+
does not add a prefix.
|
|
79
|
+
|
|
80
|
+
The callback receives the destination `site`, the registering `application`, all
|
|
81
|
+
`applications` in the deploy, and `workspaceId`. Each application lists its static
|
|
82
|
+
websites by name under `staticWebsites`, so `application.staticWebsites.admin?.url`
|
|
83
|
+
reads another site of the same config.
|
|
84
|
+
Only public OAuth client IDs are provided. Values embedded into browser assets
|
|
85
|
+
are visible to visitors, so supply only values intended for public use.
|
|
86
|
+
|
|
87
|
+
Build commands run in a shell. Their stdout and stderr both go to stderr, keeping
|
|
88
|
+
`tailor deploy --json` stdout available for the JSON result. Builds have no timeout.
|
|
89
|
+
|
|
90
|
+
## Upload existing assets
|
|
91
|
+
|
|
92
|
+
Omit `build` to upload an existing directory:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
export const plugins = definePlugins(
|
|
96
|
+
frontendPlugin({ site: "my-frontend", workingDir: "../web", distDir: "dist" }),
|
|
97
|
+
);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
For multiple frontends, pass each one as another argument, as in
|
|
101
|
+
`frontendPlugin(web, admin)`; register the plugin only once. Each site may appear
|
|
102
|
+
only once. Frontends are built and uploaded sequentially, in argument order. At
|
|
103
|
+
least one frontend is required, and each `distDir` must be non-empty. A `build` that is empty or only whitespace is rejected; omit `build` instead to publish without building.
|
|
104
|
+
|
|
105
|
+
## Deploy behavior and failures
|
|
106
|
+
|
|
107
|
+
The plugin runs even if no platform resources changed. It does not run during
|
|
108
|
+
dry-run, build-only, generation, or migration test deployments. Dry-run lists the
|
|
109
|
+
plugin as a pending deploy hook.
|
|
110
|
+
|
|
111
|
+
An unknown site, a site declared in another config, failed build, missing output directory, or failed upload stops
|
|
112
|
+
later frontends and deploy hooks. Platform resources have already been applied;
|
|
113
|
+
fix the error and run `tailor deploy` again. Successfully uploaded frontends are
|
|
114
|
+
not rolled back. Skipped upload files produce warnings and are listed in the result.
|
|
115
|
+
|
|
116
|
+
With `--json`, the result contains a `deployedHooks` entry for
|
|
117
|
+
`@tailor-platform/frontend`. Its `outputs.frontends` array contains each site's
|
|
118
|
+
`site`, published `url`, and `skippedFiles`.
|
|
119
|
+
|
|
120
|
+
The same deploy result includes `workspaceId` and `applications`, including each
|
|
121
|
+
config's Static Website URLs, AI Gateway URLs, and public OAuth client IDs. The
|
|
122
|
+
application endpoint URL and domain are present when a Platform Application with
|
|
123
|
+
the config's name exists. Read these directly from `tailor deploy --json`; a
|
|
124
|
+
separate `show` command is not required.
|
package/docs/plugin/index.md
CHANGED
|
@@ -115,7 +115,7 @@ e.g. `@example/soft-delete` → `example-soft-delete`), such as:
|
|
|
115
115
|
|
|
116
116
|
## Plugin Lifecycle
|
|
117
117
|
|
|
118
|
-
Plugins have
|
|
118
|
+
Plugins have definition-time, generation-time, and deploy-time hooks. The generation lifecycle is:
|
|
119
119
|
|
|
120
120
|
```
|
|
121
121
|
tailor generate
|
|
@@ -156,7 +156,29 @@ These hooks produce TailorDB tables, resolvers, and executors that become part o
|
|
|
156
156
|
|
|
157
157
|
These hooks receive all finalized data and produce output files (TypeScript code, etc.). No `importPath` required.
|
|
158
158
|
|
|
159
|
-
|
|
159
|
+
### Deploy-time hooks
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
tailor deploy
|
|
163
|
+
│
|
|
164
|
+
├─ Build and review resource changes
|
|
165
|
+
├─ Apply all applications and services
|
|
166
|
+
└─ onDeployed ← each registered plugin, in config order
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Hook | Available data | Can do |
|
|
170
|
+
| ------------ | ---------------------------------------------------------------- | ---------------------------------------- |
|
|
171
|
+
| `onDeployed` | Deployed application URLs, website URLs, public OAuth client IDs | Build assets and publish static websites |
|
|
172
|
+
|
|
173
|
+
Deploy hooks run even when there are no resource changes. They do not run during
|
|
174
|
+
`tailor generate`, dry-run, build-only, or migration test deployments. Dry-run lists
|
|
175
|
+
which hooks would run. A deploy-only plugin needs neither `importPath` nor table attachments.
|
|
176
|
+
|
|
177
|
+
A plugin can implement hooks from any combination of phases.
|
|
178
|
+
|
|
179
|
+
## Deploying Frontends
|
|
180
|
+
|
|
181
|
+
See [Frontend Plugin](./frontend.md) to build frontends and upload them to static websites as part of `tailor deploy`.
|
|
160
182
|
|
|
161
183
|
## Creating Custom Plugins
|
|
162
184
|
|
package/docs/services/auth.md
CHANGED
|
@@ -351,6 +351,8 @@ Get OAuth2 client credentials using the CLI:
|
|
|
351
351
|
tailor oauth2client get <name>
|
|
352
352
|
```
|
|
353
353
|
|
|
354
|
+
`tailor show` also lists the client ID, without the secret, of each OAuth2 client defined in `oauth2Clients` once it has been deployed. If your credentials cannot list OAuth2 clients, as with the workspace viewer role, it warns and reports `oauth2Clients` as `null`.
|
|
355
|
+
|
|
354
356
|
## Identity Provider
|
|
355
357
|
|
|
356
358
|
Connect to an external identity provider:
|
package/docs/services/secret.md
CHANGED
|
@@ -197,13 +197,14 @@ tailor secret create \
|
|
|
197
197
|
--name stripe-secret-key \
|
|
198
198
|
--value sk_live_xxxxx
|
|
199
199
|
|
|
200
|
-
# Update a secret
|
|
201
|
-
tailor secret update \
|
|
200
|
+
# Update a secret, reading the value from standard input
|
|
201
|
+
printf '%s' "$STRIPE_SECRET_KEY" | tailor secret update \
|
|
202
202
|
--vault-name api-keys \
|
|
203
|
-
--name stripe-secret-key
|
|
204
|
-
--value sk_live_yyyyy
|
|
203
|
+
--name stripe-secret-key
|
|
205
204
|
```
|
|
206
205
|
|
|
206
|
+
A value passed with `--value` can show up in your shell history and in process listings. Without `--value`, the command reads the value from standard input instead, accepting up to 128 KiB and removing one trailing newline.
|
|
207
|
+
|
|
207
208
|
### List Secrets
|
|
208
209
|
|
|
209
210
|
```bash
|
|
@@ -130,6 +130,8 @@ export default defineConfig({
|
|
|
130
130
|
|
|
131
131
|
Resolver, executor, workflow job, and auth before-login hook code, and TailorDB migration scripts, that read [`env`](../configuration.md#environment-variables) receive the deployed URL, even when the same deploy both creates the website and reads its URL — one `deploy` call resolves it, with no second, manually-triggered `deploy` needed. If the referenced website does not exist at all, the CLI warns and leaves the unresolved reference in place. If the reference still can't be resolved after this deploy's rebuild, the deploy fails instead of shipping the unresolved reference. This platform lookup only happens during `deploy`; `function run` passes the literal `<name>:url` string unchanged, since it never talks to the platform to resolve it.
|
|
132
132
|
|
|
133
|
+
The deployed URL is also shown by `tailor show`, which lists the URL of each static website defined in `staticWebsites` once it has been deployed.
|
|
134
|
+
|
|
133
135
|
## Complete Example
|
|
134
136
|
|
|
135
137
|
```typescript
|
|
@@ -240,7 +240,7 @@ This writes a numbered migration with an empty `diff.json`, a `migrate.ts` skele
|
|
|
240
240
|
|
|
241
241
|
The command requires a clean state: if the namespace has schema changes that are not yet in migration files, generate the schema migration first. With multiple namespaces, pass `--namespace` to name the target. `--data-only` cannot be combined with `--init`, `--rename`, `--drop`, or `--expand-contract`.
|
|
242
242
|
|
|
243
|
-
A data-only migration runs in **every** workspace the history is applied to, including freshly created ones. Write the script so it is safe against tables with no matching rows (a set-based `UPDATE` with a `WHERE` clause is naturally a no-op on an empty table). For a fix that should run in a single environment only, or that is too large for one transaction, run it outside the migration history instead.
|
|
243
|
+
A data-only migration runs in **every** workspace the history is applied to, including freshly created ones. Write the script so it is safe against tables with no matching rows (a set-based `UPDATE` with a `WHERE` clause is naturally a no-op on an empty table). For a fix that should run in a single environment only, or that is too large for one transaction, run it outside the migration history instead, for example as a one-off script scaffolded with [`tailor function script`](../cli/function.md#function-script) and executed against a single workspace with [`tailor function run`](../cli/function.md#function-run).
|
|
244
244
|
|
|
245
245
|
## Configuration
|
|
246
246
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
"@opentelemetry/resources": "2.11.0",
|
|
165
165
|
"@opentelemetry/sdk-trace-node": "2.11.0",
|
|
166
166
|
"@opentelemetry/semantic-conventions": "1.43.0",
|
|
167
|
-
"@oxc-project/types": "0.
|
|
167
|
+
"@oxc-project/types": "0.152.0",
|
|
168
168
|
"@politty/zod": "0.3.0",
|
|
169
169
|
"@secretlint/core": "13.0.6",
|
|
170
170
|
"@secretlint/secretlint-rule-preset-recommend": "13.0.6",
|
|
@@ -191,7 +191,7 @@
|
|
|
191
191
|
"pathe": "2.0.3",
|
|
192
192
|
"pgsql-ast-parser": "12.0.2",
|
|
193
193
|
"pkg-types": "2.3.3",
|
|
194
|
-
"rolldown": "1.2.
|
|
194
|
+
"rolldown": "1.2.12",
|
|
195
195
|
"semver": "7.8.5",
|
|
196
196
|
"sql-highlight": "6.1.0",
|
|
197
197
|
"std-env": "4.2.0",
|
|
@@ -213,8 +213,8 @@
|
|
|
213
213
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
214
214
|
"@vitest/coverage-v8": "5.0.1",
|
|
215
215
|
"eslint-plugin-zod": "4.14.2",
|
|
216
|
-
"oxfmt": "0.
|
|
217
|
-
"oxlint": "1.
|
|
216
|
+
"oxfmt": "0.71.0",
|
|
217
|
+
"oxlint": "1.86.0",
|
|
218
218
|
"oxlint-tsgolint": "7.0.2003",
|
|
219
219
|
"sonda": "0.14.0",
|
|
220
220
|
"tsdown": "0.23.0",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e,t}from"./application-CfqvzV3I.mjs";export{t as defineApplication,e as generatePluginFilesIfNeeded};
|