@tailor-platform/sdk 2.20.0 → 2.22.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.
Files changed (116) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/agent-skills/tailor/SKILL.md +3 -1
  3. package/dist/application-BE4vehXW.mjs +1 -0
  4. package/dist/application-BzO9ywXQ.mjs +199 -0
  5. package/dist/application-BzO9ywXQ.mjs.map +1 -0
  6. package/dist/cli/commands/deploy/app-id-lock.d.mts +31 -0
  7. package/dist/cli/lib.d.mts +2 -2
  8. package/dist/cli/lib.mjs +1 -1
  9. package/dist/cli/lib.mjs.map +1 -1
  10. package/dist/cli/main.d.mts +1 -0
  11. package/dist/cli/main.mjs +42 -42
  12. package/dist/cli/main.mjs.map +1 -1
  13. package/dist/cli/shared/logger.d.mts +9 -0
  14. package/dist/cli/shared/tailordb-namespaces.d.mts +1 -1
  15. package/dist/completion/zsh-worker.zsh +654 -131
  16. package/dist/configure/config/index.d.mts +2 -0
  17. package/dist/configure/index.d.mts +2 -1
  18. package/dist/configure/index.mjs +12 -1
  19. package/dist/configure/index.mjs.map +1 -1
  20. package/dist/configure/services/secrets/index.d.mts +14 -0
  21. package/dist/configure/services/tailordb/schema.d.mts +3 -2
  22. package/dist/configure/types/secret-vault-name.d.mts +32 -0
  23. package/dist/crashreport-CBaRJl5h.mjs +1 -0
  24. package/dist/{crashreport-Cyuz1qiu.mjs → crashreport-DFpRn-LS.mjs} +4 -4
  25. package/dist/{crashreport-Cyuz1qiu.mjs.map → crashreport-DFpRn-LS.mjs.map} +1 -1
  26. package/dist/{date-B7-oyTGE.mjs → date-Dri6Yas-.mjs} +2 -2
  27. package/dist/date-Dri6Yas-.mjs.map +1 -0
  28. package/dist/{errors-BjJnpXkK.mjs → errors-C9zGf4nz.mjs} +2 -2
  29. package/dist/{errors-BjJnpXkK.mjs.map → errors-C9zGf4nz.mjs.map} +1 -1
  30. package/dist/es-builtins-SfvXRVoG.mjs +2 -0
  31. package/dist/{es-builtins-BHCXINQp.mjs.map → es-builtins-SfvXRVoG.mjs.map} +1 -1
  32. package/dist/field-parse-DhnFs9WG.mjs +2 -0
  33. package/dist/field-parse-DhnFs9WG.mjs.map +1 -0
  34. package/dist/{globals-CMHSnj4w.mjs → globals-BCmGX05J.mjs} +2 -2
  35. package/dist/{globals-CMHSnj4w.mjs.map → globals-BCmGX05J.mjs.map} +1 -1
  36. package/dist/guards-yDXyKC9F.mjs +2 -0
  37. package/dist/{guards-ForsrxnH.mjs.map → guards-yDXyKC9F.mjs.map} +1 -1
  38. package/dist/{kysely-type-B_oA8D1k.mjs → kysely-type-C-iyFFH7.mjs} +2 -2
  39. package/dist/{kysely-type-B_oA8D1k.mjs.map → kysely-type-C-iyFFH7.mjs.map} +1 -1
  40. package/dist/logger-Db-YRTwK.mjs +9 -0
  41. package/dist/logger-Db-YRTwK.mjs.map +1 -0
  42. package/dist/manager-8-JOvuLl.mjs +2 -0
  43. package/dist/{manager-qfbUL7ru.mjs.map → manager-8-JOvuLl.mjs.map} +1 -1
  44. package/dist/plugin/builtin/enum-constants/index.mjs +1 -1
  45. package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
  46. package/dist/plugin/builtin/file-utils/index.mjs +1 -1
  47. package/dist/plugin/builtin/file-utils/index.mjs.map +1 -1
  48. package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
  49. package/dist/plugin/index.mjs +1 -1
  50. package/dist/plugin/index.mjs.map +1 -1
  51. package/dist/register-ts-hook-z7ggXQy4.mjs +922 -0
  52. package/dist/register-ts-hook-z7ggXQy4.mjs.map +1 -0
  53. package/dist/registry-BijIDRVA.mjs +2 -0
  54. package/dist/{registry-HlEaGvl5.mjs.map → registry-BijIDRVA.mjs.map} +1 -1
  55. package/dist/repl-editor-DGJBfIt1.mjs +2 -0
  56. package/dist/{repl-editor-BG1aDOfH.mjs.map → repl-editor-DGJBfIt1.mjs.map} +1 -1
  57. package/dist/runtime/field-parse.d.mts +17 -1
  58. package/dist/runtime/index.d.mts +2 -1
  59. package/dist/runtime/index.mjs +1 -1
  60. package/dist/runtime/secretmanager.d.mts +8 -20
  61. package/dist/schema-CRtAmDcl.mjs +2 -0
  62. package/dist/{schema-BKvcWdVf.mjs.map → schema-CRtAmDcl.mjs.map} +1 -1
  63. package/dist/secretmanager-vHQoXdQz.mjs.map +1 -1
  64. package/dist/seed/index.mjs +7 -6
  65. package/dist/seed/index.mjs.map +1 -1
  66. package/dist/service-Bx-7Lz06.mjs +1 -0
  67. package/dist/{service-CuqkHP1r.mjs → service-CL1Bp4It.mjs} +3 -3
  68. package/dist/{service-CuqkHP1r.mjs.map → service-CL1Bp4It.mjs.map} +1 -1
  69. package/dist/{service-B4Gh_bbL.mjs → service-DHVuH7-X.mjs} +2 -2
  70. package/dist/{service-B4Gh_bbL.mjs.map → service-DHVuH7-X.mjs.map} +1 -1
  71. package/dist/service_pb-DNskuJQC.mjs +1 -0
  72. package/dist/service_pb-y2GYIgfs.mjs +2 -0
  73. package/dist/{service_pb-DprmLNsq.mjs.map → service_pb-y2GYIgfs.mjs.map} +1 -1
  74. package/dist/tailordb-ddl-DqInYupv.mjs +7 -0
  75. package/dist/{tailordb-ddl-Fgm2cNvT.mjs.map → tailordb-ddl-DqInYupv.mjs.map} +1 -1
  76. package/dist/utils/test/index.mjs +1 -1
  77. package/dist/utils/test/index.mjs.map +1 -1
  78. package/dist/vitest/environment.mjs +1 -1
  79. package/dist/vitest/environment.mjs.map +1 -1
  80. package/dist/vitest/index.mjs +1 -1
  81. package/dist/vitest/index.mjs.map +1 -1
  82. package/dist/vitest/mocks/file.d.mts +1 -1
  83. package/dist/vitest/setup.mjs +1 -1
  84. package/dist/workspace_resource_pb-D2njwgsE.mjs +2 -0
  85. package/dist/{workspace_resource_pb-BOoRts_z.mjs.map → workspace_resource_pb-D2njwgsE.mjs.map} +1 -1
  86. package/docs/cli-reference.md +22 -12
  87. package/docs/configuration.md +1 -1
  88. package/docs/github-actions.md +90 -24
  89. package/docs/migration/v2.md +70 -5
  90. package/docs/migration/v3.md +64 -0
  91. package/docs/plugin/index.md +1 -1
  92. package/docs/services/resolver.md +21 -0
  93. package/docs/services/secret.md +20 -15
  94. package/package.json +19 -19
  95. package/dist/application-B6NYnrhv.mjs +0 -199
  96. package/dist/application-B6NYnrhv.mjs.map +0 -1
  97. package/dist/application-BlbyGJsd.mjs +0 -1
  98. package/dist/crashreport-CgymxQDu.mjs +0 -1
  99. package/dist/date-B7-oyTGE.mjs.map +0 -1
  100. package/dist/es-builtins-BHCXINQp.mjs +0 -2
  101. package/dist/field-parse-BbNyotv5.mjs +0 -2
  102. package/dist/field-parse-BbNyotv5.mjs.map +0 -1
  103. package/dist/guards-ForsrxnH.mjs +0 -2
  104. package/dist/logger-72hM4JWZ.mjs +0 -9
  105. package/dist/logger-72hM4JWZ.mjs.map +0 -1
  106. package/dist/manager-qfbUL7ru.mjs +0 -2
  107. package/dist/register-ts-hook-FsCX38LQ.mjs +0 -917
  108. package/dist/register-ts-hook-FsCX38LQ.mjs.map +0 -1
  109. package/dist/registry-HlEaGvl5.mjs +0 -2
  110. package/dist/repl-editor-BG1aDOfH.mjs +0 -2
  111. package/dist/schema-BKvcWdVf.mjs +0 -2
  112. package/dist/service-BgrEteZ2.mjs +0 -1
  113. package/dist/service_pb-DKrsO1_u.mjs +0 -1
  114. package/dist/service_pb-DprmLNsq.mjs +0 -2
  115. package/dist/tailordb-ddl-Fgm2cNvT.mjs +0 -7
  116. package/dist/workspace_resource_pb-BOoRts_z.mjs +0 -2
@@ -12,12 +12,12 @@ tailor <command> [options]
12
12
 
13
13
  <a id="global-options"></a>
14
14
 
15
- | Option | Alias | Description | Required | Default |
16
- | ------------------------------------------- | ----- | --------------------------------------------------- | -------- | ------- |
17
- | `--env-file <ENV_FILE>` | `-e` | Path to the environment file (error if not found) | No | - |
18
- | `--env-file-if-exists <ENV_FILE_IF_EXISTS>` | - | Path to the environment file (ignored if not found) | No | - |
19
- | `--verbose` | - | Enable verbose logging | No | `false` |
20
- | `--json` | `-j` | Output as JSON | No | `false` |
15
+ | Option | Alias | Description | Required | Default | Env |
16
+ | ------------------------------------------- | ----- | --------------------------------------------------- | -------- | ------- | -------------------- |
17
+ | `--env-file <ENV_FILE>` | `-e` | Path to the environment file (error if not found) | No | - | - |
18
+ | `--env-file-if-exists <ENV_FILE_IF_EXISTS>` | - | Path to the environment file (ignored if not found) | No | - | - |
19
+ | `--verbose` | - | Enable verbose logging | No | `false` | - |
20
+ | `--json` | `-j` | Output as JSON | No | `false` | `TAILOR_JSON_OUTPUT` |
21
21
 
22
22
  ### Progress and Detailed Logs
23
23
 
@@ -34,6 +34,14 @@ human-readable text or empty stdout.
34
34
  Commands that only perform side effects and do not define a structured result may leave stdout empty
35
35
  even when `--json` is passed.
36
36
 
37
+ Set `TAILOR_JSON_OUTPUT=true` (or `1`) to default every command to JSON without passing `--json`
38
+ each time. This is intended for agents, scripts, and CI steps that parse CLI output. An explicit
39
+ flag always wins, so `--json=false` forces table output even when the variable is enabled. The values
40
+ `true`, `True`, `TRUE`, `t`, `T`, and `1` enable JSON; `false`, `False`, `FALSE`, `f`, `F`, and `0`
41
+ keep table output. Other values are rejected. JSON mode also disables interactive prompts, so set the
42
+ variable per invocation or per job rather than exporting it from a shell profile; a command that
43
+ needed a prompt names what selected JSON when it refuses.
44
+
37
45
  Errors, warnings, progress, and diagnostic messages are written to stderr. After argument parsing,
38
46
  a command failure under `--json` emits a JSON error envelope to stderr. Failures you can act on — an
39
47
  invalid or missing option, a resource that does not exist, an invalid configuration, or an unmet
@@ -96,14 +104,15 @@ is unchanged. Workflows that already echo their own `::error::` around the CLI k
96
104
  those messages describe the workflow's own checks, which can fail even when the CLI succeeds.
97
105
 
98
106
  When the failure has a known source, the annotation carries it: `seed validate` reports the
99
- offending JSONL file and line, and a rejected config reports its file — or, when the config or a
100
- file it imports cannot be parsed, that file and the line it failed on. Locations are written
101
- relative to `GITHUB_WORKSPACE`; a file outside it is annotated without a location rather than with
102
- a path the runner cannot resolve.
107
+ offending JSONL file and line, including a line that is not valid JSON, and a rejected config
108
+ reports its file — or, when the config or a file it imports cannot be parsed, that file and the line
109
+ it failed on. Locations are written relative to `GITHUB_WORKSPACE`; a file outside it is annotated
110
+ without a location rather than with a path the runner cannot resolve.
103
111
 
104
112
  For a JSONL file containing a blank line, the annotation's line and the line printed in the report
105
113
  text differ: the annotation counts every line in the file, while the printed line counts only the
106
- records. The annotation points at the row as an editor numbers it.
114
+ records. The annotation points at the row as an editor numbers it. A line that is not valid JSON is
115
+ printed with the line an editor shows, so both agree.
107
116
 
108
117
  `generate` and `deploy` do not group their per-service progress.
109
118
 
@@ -225,7 +234,8 @@ Resolution rules:
225
234
  then forwarded, so when the same flag appears on both sides the later one wins. A flag the host
226
235
  does not define — including one only some commands declare, such as `--profile` — still has to be
227
236
  typed after the plugin's own subcommand. `--help` and `--version` are answered by the host CLI and
228
- never dispatch a plugin.
237
+ never dispatch a plugin. Setting `TAILOR_JSON_OUTPUT=true` also works, which plugins inherit from
238
+ the environment.
229
239
 
230
240
  Because resolution is based on `node_modules/.bin` and `PATH`, any package manager that populates
231
241
  `node_modules/.bin` works for project-local plugins — npm, pnpm (its content-addressable store is
@@ -403,7 +403,7 @@ export default defineConfig({
403
403
 
404
404
  ### Plugins
405
405
 
406
- Configure plugins using `definePlugins()`. Plugins must be exported as a named export.
406
+ Configure plugins using `definePlugins()`, exported as `export const plugins`.
407
407
 
408
408
  ```typescript
409
409
  import { definePlugins } from "@tailor-platform/sdk";
@@ -68,7 +68,9 @@ What it does:
68
68
  applies the config; it does not re-run the PR plan.
69
69
  - On **`workflow_dispatch`** with `dry-run: true`: runs plan only (useful for
70
70
  rollback verification — see [Rollback](#rollback)). With `dry-run: false`
71
- (default) it deploys, like a push.
71
+ (default) it deploys the selected branch, like a push. Pass
72
+ `--restrict-dispatch` to deploy only the target branch this way (see
73
+ [Restricting manual deploys](#restricting-manual-deploys)).
72
74
 
73
75
  Fork pull requests cannot read repository secrets. For forks, the plan step is
74
76
  automatically skipped; `generate-check` and other non-secret checks still run.
@@ -129,7 +131,9 @@ What it does:
129
131
  before the deploy job starts.
130
132
  - On **`workflow_dispatch`**: the `tailor-tag-guard` result is ignored — the
131
133
  plan job runs regardless of branch reachability (useful for rolling back to
132
- any tag). `dry-run: true` stops before the deploy job.
134
+ any tag). `dry-run: true` stops before the deploy job. With
135
+ `--restrict-dispatch`, the deploy job runs only for a tag that passes the
136
+ guard (see [Restricting manual deploys](#restricting-manual-deploys)).
133
137
 
134
138
  ### Choosing `--branch` for the tag target
135
139
 
@@ -190,20 +194,53 @@ Running a workflow setup subcommand creates or updates:
190
194
  The workflow file. The `name:` field is set to `Tailor (<workspace-name>)` so
191
195
  you can distinguish multiple workspaces in the Actions UI.
192
196
 
193
- Jobs and steps whose `id` starts with `tailor-` are managed by the SDK. Do not
194
- edit or rename them — the SDK tracks them by id.
195
-
196
- You can add your own jobs and steps around the managed ones. To add
197
- project-specific setup (such as private registry authentication or a system
198
- dependency), add a step _before_ the managed `tailor-setup` step. For
199
- post-install extras (such as `playwright install`), add a step _after_ it.
200
-
201
- Note that re-running `setup` currently regenerates the whole file: if
202
- the file differs from what the SDK last wrote — whether you edited a managed
203
- step or added your own — the command stops and reports the conflict. Pass
204
- `--force` to discard your edits and regenerate from the current template, then
205
- re-apply your own steps. (Preserving user-added steps across regeneration is
206
- planned.)
197
+ See [Customizing the generated workflow](#customizing-the-generated-workflow)
198
+ for what you can edit.
199
+
200
+ ### Customizing the generated workflow
201
+
202
+ The SDK owns the jobs and steps whose `id` starts with `tailor-`, and the
203
+ top-level keys it writes (`name:`, `on:`, and `permissions:` in a workflow; the
204
+ metadata, inputs, and outputs of a composite action). Do not edit or rename
205
+ them. Everything else is yours, and re-running `setup` keeps it:
206
+
207
+ - **Your own jobs and steps.** Add them anywhere, without the `tailor-` prefix.
208
+ A step you add inside a managed job stays right after the managed step it
209
+ followed. For example, add private registry authentication or a system
210
+ dependency _before_ the managed `tailor-setup` step, and post-install extras
211
+ (such as `playwright install`) _after_ it. A job of your own can depend on a
212
+ managed job with `needs: tailor-deploy`.
213
+ - **Your own top-level keys**, such as a workflow-level `env:` or `defaults:`.
214
+ - **Runtime settings of managed jobs:** `runs-on`, `timeout-minutes`,
215
+ `container`, and `env`.
216
+ - **These inputs of managed steps:** `ignore` on `tailor-generate-check` and
217
+ `tailor-drift-check`, `fail-on-drift` on `tailor-drift-check`,
218
+ `install-command` on `tailor-install`, `node-version-file` on
219
+ `tailor-setup`, `label` on `tailor-plan`, and `user-mapping` on
220
+ `tailor-notify` and on a coordinator's steps that call an app action.
221
+ - **The `run:` command of the `build-site` step** in a composite action.
222
+
223
+ Comments above your own jobs and steps and at the end of the file are kept too.
224
+ Comments inside managed jobs and steps, and edits to the header comment, are
225
+ not kept.
226
+
227
+ `setup check` reports an edit to a managed part, and re-running `setup` stops
228
+ on it. Revert the edit, or pass `--force` to reset the managed parts to the
229
+ current template; `--force` still keeps your own jobs, steps, and settings.
230
+ A managed job or step you renamed counts as your own, so `--force` adds the
231
+ managed one back next to it; rename it back instead of forcing. To start over
232
+ from a clean template, delete the file and re-run `setup`.
233
+
234
+ When a template update removes a managed job that contains steps of yours, or
235
+ a job of yours `needs` a removed job, `setup` stops and names them. Move those
236
+ steps into a job of your own (or update the `needs`) and re-run. `--force` drops
237
+ steps left inside a removed job. It also stops when a new template version adds
238
+ a managed job or step whose id you already use; rename yours, or pass `--force`
239
+ to let the managed one replace it.
240
+
241
+ Files generated by an older SDK version are compared as a whole, so the first
242
+ re-run after upgrading stops if you edited the file in any way. Re-run once with
243
+ `--force` to switch it to this model; your own jobs and steps are kept.
207
244
 
208
245
  ### `.github/tailor.lock`
209
246
 
@@ -277,7 +314,8 @@ gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET --env my-app-stg
277
314
  Setting them at the environment level isolates each target's credentials and
278
315
  keeps them alongside that environment's `TAILOR_PLATFORM_WORKSPACE_ID`
279
316
  variable. You can also set them as repository-level secrets if every target
280
- shares one machine user.
317
+ shares one machine user, but then any workflow on any branch can read them, so
318
+ the environment's protection rules no longer guard your deploys.
281
319
 
282
320
  ## GitHub Environments (approval gate)
283
321
 
@@ -309,8 +347,32 @@ or an out-of-band deploy. With `dry-run` off, a branch-target dispatch goes
309
347
  straight to deploy (like a push), while a tag-target dispatch runs plan first
310
348
  and then deploys.
311
349
 
312
- For tag targets, you can select any branch or tag when dispatching manually. The tag-guard check is skipped for manual dispatches, so
313
- you can deploy any commit regardless of branch membership.
350
+ By default you can select any branch or tag when dispatching manually, and it
351
+ deploys that ref. For tag targets, the tag-guard check is skipped for manual
352
+ dispatches, so you can deploy any commit regardless of branch membership.
353
+
354
+ ### Restricting manual deploys
355
+
356
+ Pass `--restrict-dispatch` to `setup ci branch`, `setup ci tag`, or
357
+ `setup ci coordinate` to limit what a manual dispatch with `dry-run` off can
358
+ deploy:
359
+
360
+ - **Branch target:** only the target branch. Dispatching another branch skips
361
+ the deploy job.
362
+ - **Tag target:** only a tag. With `--branch`, the tag must also pass the
363
+ reachability guard. The tag does not have to match `--tag-pattern`.
364
+
365
+ Dry runs stay available from any ref. Re-run `setup` with the flag each time you
366
+ regenerate the workflow; it is not carried over from the previous run.
367
+
368
+ The flag guards against deploying the wrong ref by mistake. It is not an access
369
+ control: a manual dispatch runs the workflow file from the selected ref, so
370
+ anyone who can push a branch can remove the check there. To enforce which refs
371
+ can deploy, configure **Deployment branches and tags** on the target's GitHub
372
+ Environment and keep the machine-user secrets on that environment. Because the
373
+ plan job also enters the environment, allow `refs/pull/*/merge` as well so pull
374
+ request plans keep running, and note that dry runs from other branches are then
375
+ rejected too.
314
376
 
315
377
  ## Monorepo setup
316
378
 
@@ -365,6 +427,8 @@ git push origin v1.2.4
365
427
 
366
428
  For tag targets, the tag-guard step is bypassed on manual dispatch, so you can
367
429
  dispatch from any ref. Environment approval (if configured) applies as usual.
430
+ With `--restrict-dispatch`, step 4 deploys only a tag that passes the guard, and
431
+ a branch target deploys only its target branch, so use Option 1 there.
368
432
 
369
433
  ### Rollback limitations
370
434
 
@@ -445,7 +509,8 @@ subcommand.
445
509
 
446
510
  `tailor setup check` audits the workflows recorded in
447
511
  `.github/tailor.lock` against your current config and repository, without
448
- writing anything. It reports when a workflow file is missing or hand-edited, a
512
+ writing anything. It reports when a workflow file is missing or its SDK-managed
513
+ parts were edited by hand, a
449
514
  newer template is available, `tailor.config.ts` is no longer under the recorded
450
515
  `--dir`, or the repository default branch no longer matches a branch target's
451
516
  trigger. It exits non-zero when it finds drift, so you can run it in CI. Each
@@ -474,10 +539,11 @@ itself at runtime.
474
539
  ## Updating the generated workflow
475
540
 
476
541
  When you upgrade the SDK, re-run the relevant workflow setup subcommand with
477
- the same flags to pick up template improvements. If the SDK detects that you
478
- have hand-edited a managed section, it stops and asks you to use `--force` to
479
- overwrite your edits, or to move your customizations into your own steps before
480
- regenerating.
542
+ the same flags to pick up template improvements. Your own jobs, steps, and
543
+ settings are kept (see
544
+ [Customizing the generated workflow](#customizing-the-generated-workflow)). If
545
+ you edited a managed part, the command stops; revert the edit or pass `--force`
546
+ to reset it.
481
547
 
482
548
  The `.github/tailor.lock` file records the flags used at generation time,
483
549
  so you can check what arguments were used previously.
@@ -84,18 +84,83 @@ After:
84
84
  import { definePlugins } from "@tailor-platform/sdk";
85
85
  import { kyselyTypePlugin } from "@tailor-platform/sdk/plugin/kysely-type";
86
86
 
87
- export const generators = definePlugins(kyselyTypePlugin({ distPath: "db.ts" }));
87
+ export const plugins = definePlugins(kyselyTypePlugin({ distPath: "db.ts" }));
88
88
  ```
89
89
 
90
90
  <details>
91
91
  <summary>Prompt for an AI agent (to finish the cases the codemod could not migrate)</summary>
92
92
 
93
93
  ```text
94
- defineGenerators() is replaced by definePlugins() in v2. The codemod rewrites the
95
- known plugin tuples (kysely-type, enum-constants, file-utils, seed). For any
96
- remaining defineGenerators([...]) the codemod left in place — a plugin it does not
94
+ defineGenerators() is replaced by definePlugins() in v2, exported as `plugins` — the
95
+ only export name the SDK reads plugins from. The codemod rewrites the known plugin
96
+ tuples (kysely-type, enum-constants, file-utils, seed) and renames the export variable
97
+ to `plugins` (left alone when the file already binds `plugins` to something else). For
98
+ any remaining defineGenerators([...]) the codemod left in place — a plugin it does not
97
99
  know, or a non-tuple/spread form — convert it to definePlugins(pluginFn(config)),
98
- importing the matching plugin from its @tailor-platform/sdk/plugin/<name> subpath.
100
+ importing the matching plugin from its @tailor-platform/sdk/plugin/<name> subpath, and
101
+ assign the result to `export const plugins`.
102
+ Merge any remaining exported plugin arrays into `plugins`, including bindings
103
+ exported separately with `export { ... }`, and update their importing files.
104
+ Only tailor.config module exports are renamed automatically; preserve helper-module
105
+ exports and expose their plugins under the canonical config export manually.
106
+ ```
107
+
108
+ </details>
109
+
110
+ ## generator/generators → plugins export rename
111
+
112
+ **Migration:** Partially automatic
113
+
114
+ Rename the plugin config export (and its imports) from generator/generators to plugins
115
+
116
+ Before:
117
+
118
+ ```ts
119
+ import { definePlugins } from "@tailor-platform/sdk";
120
+ import myPlugin from "./plugins/my-plugin";
121
+
122
+ export const generators = definePlugins(myPlugin());
123
+ ```
124
+
125
+ After:
126
+
127
+ ```ts
128
+ import { definePlugins } from "@tailor-platform/sdk";
129
+ import myPlugin from "./plugins/my-plugin";
130
+
131
+ export const plugins = definePlugins(myPlugin());
132
+ ```
133
+
134
+ Also updates other files that import the export by its old name.
135
+
136
+ Before:
137
+
138
+ ```ts
139
+ import { generator } from "./tailor.config";
140
+ ```
141
+
142
+ After:
143
+
144
+ ```ts
145
+ import { plugins } from "./tailor.config";
146
+ ```
147
+
148
+ <details>
149
+ <summary>Prompt for an AI agent (to finish the cases the codemod could not migrate)</summary>
150
+
151
+ ```text
152
+ The SDK only reads plugins from an export named `plugins`; `generator`/`generators` is
153
+ already `definePlugins()` but under the old name. This codemod renames the export (and
154
+ any `import { generator[s] } from ".../tailor.config"` elsewhere) to `plugins`. It
155
+ leaves a file untouched when it already binds `plugins` to something else, or when a
156
+ bare (unaliased) import's local usages cannot be safely told apart from an unrelated
157
+ same-named binding in that file — rename those by hand to `plugins`.
158
+ Multiple arrays or bindings exported separately with `export { ... }` need manual
159
+ consolidation into the `plugins` export; update their importing files as well.
160
+ Only tailor.config module exports are renamed automatically. Review aliased SDK
161
+ factory calls and helper-module re-exports manually, preserving the helper API.
162
+ Indirect config exports, namespace/dynamic imports, and wildcard re-exports are
163
+ conservatively reported for review; keep unrelated values and canonical references unchanged.
99
164
  ```
100
165
 
101
166
  </details>
@@ -165,3 +165,67 @@ Do not change unrelated upload APIs or already explicit encodings.
165
165
  ```
166
166
 
167
167
  </details>
168
+
169
+ ## secrets.get()/getAll() (defineSecretManager) removed — use secretmanager from @tailor-platform/sdk/runtime
170
+
171
+ **Migration:** Manual
172
+
173
+ The `get()`/`getAll()` methods on the object `defineSecretManager()` returns are removed in v3. Importing that object into a resolver, executor, or workflow file bundles the raw values passed to `defineSecretManager()` into that function's deployed code, which fails to build once any value comes from `process.env`. `secretmanager.getSecret()`/`getSecrets()` from `@tailor-platform/sdk/runtime` read the same secrets without importing the config object.
174
+
175
+ Before:
176
+
177
+ ```ts
178
+ import { secrets } from "../tailor.config";
179
+
180
+ const apiKey = await secrets.get("api-keys", "stripe-secret-key");
181
+ ```
182
+
183
+ After:
184
+
185
+ ```ts
186
+ import { secretmanager } from "@tailor-platform/sdk/runtime";
187
+
188
+ const apiKey = await secretmanager.getSecret("api-keys", "stripe-secret-key");
189
+ ```
190
+
191
+ Before:
192
+
193
+ ```ts
194
+ import { secrets } from "../tailor.config";
195
+
196
+ const [apiKey, webhookSecret] = await secrets.getAll("api-keys", [
197
+ "sendgrid-api-key",
198
+ "stripe-secret-key",
199
+ ]);
200
+ ```
201
+
202
+ After:
203
+
204
+ ```ts
205
+ import { secretmanager } from "@tailor-platform/sdk/runtime";
206
+
207
+ const { "sendgrid-api-key": apiKey, "stripe-secret-key": webhookSecret } =
208
+ await secretmanager.getSecrets("api-keys", ["sendgrid-api-key", "stripe-secret-key"]);
209
+ ```
210
+
211
+ <details>
212
+ <summary>Prompt for an AI agent (to perform this migration)</summary>
213
+
214
+ ```text
215
+ `secrets.get()`/`getAll()` on the object `defineSecretManager()` returns are removed in v3.
216
+ Replace the import with `import { secretmanager } from "@tailor-platform/sdk/runtime";` and
217
+ call `secretmanager.getSecret(vault, name)` in place of `secrets.get(vault, name)`.
218
+
219
+ `getAll()` needs more than a rename: `secrets.getAll(vault, names)` returned an array of
220
+ values in the same order as `names`, while `secretmanager.getSecrets(vault, names)` returns
221
+ a partial record keyed by each requested name (a name with no value is omitted instead of
222
+ being `undefined` at its index). Rewrite positional destructuring (`const [a, b] = await
223
+ secrets.getAll(v, ["A", "B"])`) into keyed destructuring (`const { A: a, B: b } = await
224
+ secretmanager.getSecrets(v, ["A", "B"])`).
225
+
226
+ Also review: a `secrets` object re-exported or re-assigned to another name before use, and a
227
+ file that already imports something else named `secretmanager` (rename one of the two on
228
+ conflict).
229
+ ```
230
+
231
+ </details>
@@ -33,7 +33,7 @@ export default defineConfig({
33
33
  });
34
34
  ```
35
35
 
36
- **Important**: The `plugins` export must be a named export (not default).
36
+ **Important**: `definePlugins()` must be assigned to a named export called exactly `plugins` (not default, and not any other name).
37
37
 
38
38
  ### Attaching Plugins to Tables
39
39
 
@@ -141,6 +141,27 @@ GraphQL still accepts and returns `YYYY-MM-DD` strings. The SDK converts input t
141
141
 
142
142
  This option also works in nested objects and with `array: true` or `optional: true`. Input must be a valid calendar date, and output must be a valid `Date` with a 4-digit UTC year (0000-9999). Both deployed resolvers and `tailor function run` perform these conversions.
143
143
 
144
+ A resolver bundle only includes the conversion code for the representations (`as: "date"` or `as: "temporal"`) its `input` and `output` use. To parse other values with such fields inside `body`, for example an external API response, use `parseDateFields` instead of `.parse()`. It takes the same arguments and returns the same result as `.parse()`. Calling `.parse()` on a field whose representation the bundle leaves out throws an error that points to `parseDateFields`.
145
+
146
+ ```typescript
147
+ import { parseDateFields } from "@tailor-platform/sdk/runtime";
148
+
149
+ const payload = t.object({ due: t.date({ as: "date" }) });
150
+
151
+ createResolver({
152
+ name: "importDueDate",
153
+ operation: "mutation",
154
+ input: { id: t.string() },
155
+ body: async ({ input }) => {
156
+ const response = await fetchDueDate(input.id);
157
+ const result = parseDateFields(payload, { value: response, data: response, invoker: null });
158
+ if (result.issues) throw new Error(result.issues[0].message);
159
+ return result.value.due.toISOString();
160
+ },
161
+ output: t.string(),
162
+ });
163
+ ```
164
+
144
165
  An executor subscribing to the resolver with `resolverExecutedTrigger` receives the event as JSON, so `result` holds the `YYYY-MM-DD` string rather than a `Date`.
145
166
 
146
167
  Use `t.date({ as: "temporal" })` to work with the [`Temporal.PlainDate`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal/PlainDate) value instead:
@@ -62,7 +62,7 @@ export default defineConfig({
62
62
  });
63
63
  ```
64
64
 
65
- The exported `secrets` object provides type-safe `get()` and `getAll()` methods for runtime access from resolvers, executors, and workflows.
65
+ The exported `secrets` object also carries the values you passed in, so import it only where you build your `tailor.config.ts` config (the file itself, or a helper module you import into it) — never from a resolver, executor, or workflow file. This `secrets` object's `get()`/`getAll()` methods are deprecated for the same reason and will be removed in a future major version; to read a secret at runtime, use the `secretmanager` API described below instead.
66
66
 
67
67
  ### Skipping Secrets with Missing Values
68
68
 
@@ -91,50 +91,55 @@ This allows you to set secret values once (e.g., via local `tailor deploy` or th
91
91
 
92
92
  ## Using Secrets
93
93
 
94
- ### Runtime Access with `get()` / `getAll()`
94
+ ### Runtime Access with `secretmanager`
95
95
 
96
- 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.
96
+ Read secret values at runtime with the `secretmanager` API from `@tailor-platform/sdk/runtime`, the same module you use for other platform runtime APIs (`idp`, `workflow`, `authconnection`, etc.). Pass the vault and secret names as strings. Once `tailor generate`/`tailor deploy` has run, vault names are autocompleted from `defineSecretManager()` (any other string still works, since vaults can also be managed imperatively via the CLI — see [Managing Secrets](#managing-secrets)), and inside a declared vault, secret names are checked against that vault's configuration.
97
97
 
98
- #### `get(vault, secret)`
98
+ #### `getSecret(vault, name)`
99
99
 
100
100
  Retrieves a single secret value.
101
101
 
102
102
  ```typescript
103
103
  import { createResolver } from "@tailor-platform/sdk";
104
- import { secrets } from "../tailor.config";
104
+ import { secretmanager } from "@tailor-platform/sdk/runtime";
105
105
 
106
106
  export default createResolver({
107
107
  name: "call-stripe",
108
+ operation: "query",
108
109
  // ...
109
- operation: async ({ input }) => {
110
- const apiKey = await secrets.get("api-keys", "stripe-secret-key");
110
+ body: async ({ input }) => {
111
+ const apiKey = await secretmanager.getSecret("api-keys", "stripe-secret-key");
111
112
  // Use apiKey to call the Stripe API
113
+
114
+ // await secretmanager.getSecret("api-keys", "unknown-key"); // Type error — "api-keys" only has "stripe-secret-key" and "sendgrid-api-key"
115
+ // await secretmanager.getSecret("cli-managed-vault", "anything"); // Fine — "cli-managed-vault" isn't declared in defineSecretManager(), so its secret names aren't checked
112
116
  },
113
117
  });
114
118
  ```
115
119
 
116
- #### `getAll(vault, secrets)`
120
+ #### `getSecrets(vault, names)`
117
121
 
118
122
  Retrieves multiple secret values at once from the same vault.
119
123
 
120
124
  ```typescript
121
125
  import { createResolver } from "@tailor-platform/sdk";
122
- import { secrets } from "../tailor.config";
126
+ import { secretmanager } from "@tailor-platform/sdk/runtime";
123
127
 
124
128
  export default createResolver({
125
129
  name: "send-notification",
130
+ operation: "query",
126
131
  // ...
127
- operation: async ({ input }) => {
128
- const [apiKey, webhookSecret] = await secrets.getAll("api-keys", [
129
- "sendgrid-api-key",
130
- "stripe-secret-key",
131
- ]);
132
+ body: async ({ input }) => {
133
+ const { "sendgrid-api-key": apiKey, "stripe-secret-key": webhookSecret } =
134
+ await secretmanager.getSecrets("api-keys", ["sendgrid-api-key", "stripe-secret-key"]);
132
135
  // Use the retrieved secrets
133
136
  },
134
137
  });
135
138
  ```
136
139
 
137
- Both methods return `Promise<string | undefined>` (or an array of them for `getAll`).
140
+ `getSecret` returns `Promise<string | undefined>`; `getSecrets` returns a `Promise` of a partial record keyed by the requested names, omitting any name that has no value.
141
+
142
+ Import `secretmanager` directly in resolver, executor, and workflow files — never the `secrets` object from `tailor.config.ts` (see [Declarative Configuration](#declarative-configuration) above).
138
143
 
139
144
  ### In Webhook Operations
140
145
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk",
3
- "version": "2.20.0",
3
+ "version": "2.22.0",
4
4
  "description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -152,7 +152,7 @@
152
152
  "@0no-co/graphql.web": "1.3.4",
153
153
  "@badgateway/oauth2-client": "3.3.1",
154
154
  "@bufbuild/protobuf": "2.15.0",
155
- "@bufbuild/protovalidate": "1.2.0",
155
+ "@bufbuild/protovalidate": "1.3.0",
156
156
  "@connectrpc/connect": "2.2.0",
157
157
  "@connectrpc/connect-node": "2.2.0",
158
158
  "@inquirer/core": "12.0.3",
@@ -164,41 +164,41 @@
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.149.0",
168
- "@politty/zod": "0.2.1",
167
+ "@oxc-project/types": "0.151.0",
168
+ "@politty/zod": "0.3.0",
169
169
  "@secretlint/core": "13.0.5",
170
170
  "@secretlint/secretlint-rule-preset-recommend": "13.0.5",
171
171
  "@standard-schema/spec": "1.1.0",
172
172
  "@tailor-platform/function-kysely-tailordb": "0.1.3",
173
- "@toiroakr/lines-db": "0.12.7",
173
+ "@toiroakr/lines-db": "0.13.0",
174
174
  "@toiroakr/read-multiline": "0.4.1",
175
175
  "@urql/core": "6.0.3",
176
- "amaro": "1.1.11",
176
+ "amaro": "1.2.1",
177
177
  "confbox": "0.3.1",
178
178
  "date-fns": "4.4.0",
179
179
  "es-toolkit": "1.52.0",
180
180
  "find-up-simple": "1.0.1",
181
- "get-east-asian-width": "1.6.0",
181
+ "get-east-asian-width": "1.7.0",
182
182
  "get-tsconfig": "4.14.3",
183
183
  "globals": "17.12.0",
184
184
  "graphql": "17.0.2",
185
185
  "inflection": "3.0.2",
186
- "kysely": "0.29.5",
186
+ "kysely": "0.29.6",
187
187
  "mime-types": "3.0.2",
188
188
  "open": "11.0.4",
189
- "oxc-parser": "0.149.0",
190
- "p-limit": "7.3.2",
189
+ "oxc-parser": "0.151.0",
190
+ "p-limit": "7.3.3",
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.8",
194
+ "rolldown": "1.2.9",
195
195
  "semver": "7.8.5",
196
196
  "sql-highlight": "6.1.0",
197
197
  "std-env": "4.2.0",
198
198
  "temporal-polyfill": "1.0.5",
199
199
  "temporal-spec": "1.0.1",
200
200
  "ts-cron-validator": "1.1.5",
201
- "type-fest": "5.9.0",
201
+ "type-fest": "5.10.0",
202
202
  "xdg-basedir": "5.1.0",
203
203
  "zod": "4.6.5"
204
204
  },
@@ -208,18 +208,18 @@
208
208
  "@tailor-platform/shared": "^0.0.0",
209
209
  "@tailor-platform/tailor-proto": "^0.0.1",
210
210
  "@types/mime-types": "3.0.1",
211
- "@types/node": "24.13.4",
211
+ "@types/node": "24.13.6",
212
212
  "@types/semver": "7.8.0",
213
213
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
214
- "@vitest/coverage-v8": "5.0.0",
215
- "eslint-plugin-zod": "4.13.1",
216
- "oxfmt": "0.67.0",
217
- "oxlint": "1.82.0",
218
- "oxlint-tsgolint": "7.0.2001",
214
+ "@vitest/coverage-v8": "5.0.1",
215
+ "eslint-plugin-zod": "4.14.2",
216
+ "oxfmt": "0.70.0",
217
+ "oxlint": "1.85.0",
218
+ "oxlint-tsgolint": "7.0.2002",
219
219
  "sonda": "0.14.0",
220
220
  "tsdown": "0.23.0",
221
221
  "typescript": "6.0.3",
222
- "vitest": "5.0.0",
222
+ "vitest": "5.0.1",
223
223
  "zinfer": "0.4.7"
224
224
  },
225
225
  "peerDependencies": {