@tailor-platform/sdk 2.38.0 → 2.39.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 (55) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/dist/{application-Bz80INH4.mjs → application-OeNMQzOC.mjs} +1 -1
  3. package/dist/{application-CeqD1OK-.mjs → application-mNOJx9Y2.mjs} +4 -4
  4. package/dist/{application-CeqD1OK-.mjs.map → application-mNOJx9Y2.mjs.map} +1 -1
  5. package/dist/cli/commands/executor/trigger.d.mts +1 -0
  6. package/dist/cli/commands/generate/seed/bundler.d.mts +7 -5
  7. package/dist/cli/commands/workspace/transform.d.mts +1 -2
  8. package/dist/cli/lib.d.mts +4 -2
  9. package/dist/cli/lib.mjs +1 -1
  10. package/dist/cli/lib.mjs.map +1 -1
  11. package/dist/cli/main.mjs +30 -30
  12. package/dist/cli/main.mjs.map +1 -1
  13. package/dist/cli/shared/build-options.d.mts +13 -0
  14. package/dist/cli/shared/client.d.mts +1 -0
  15. package/dist/cli/shared/script-workflow.d.mts +65 -0
  16. package/dist/cli/shared/seed-chunker.d.mts +3 -3
  17. package/dist/{client-DOQv-BP8.mjs → client-CqiPQgMG.mjs} +2 -2
  18. package/dist/client-CqiPQgMG.mjs.map +1 -0
  19. package/dist/client-DO2_Xz_z.mjs +1 -0
  20. package/dist/completion/zsh-worker.zsh +61 -6
  21. package/dist/configure/index.mjs +1 -1
  22. package/dist/configure/index.mjs.map +1 -1
  23. package/dist/configure/services/auth/types.d.mts +20 -3
  24. package/dist/configure/services/executor/trigger/webhook.d.mts +8 -1
  25. package/dist/{context-OOASEQLA.mjs → context-CYBcQZyO.mjs} +1 -1
  26. package/dist/{context-DSi5kfqr.mjs → context-aAgFGDBD.mjs} +4 -4
  27. package/dist/{context-DSi5kfqr.mjs.map → context-aAgFGDBD.mjs.map} +1 -1
  28. package/dist/{register-ts-hook-CXYYYgCl.mjs → register-ts-hook-CORbtrSN.mjs} +82 -71
  29. package/dist/register-ts-hook-CORbtrSN.mjs.map +1 -0
  30. package/dist/{service-DB-RHn25.mjs → service-Bkz_TB5v.mjs} +2 -2
  31. package/dist/{service-DB-RHn25.mjs.map → service-Bkz_TB5v.mjs.map} +1 -1
  32. package/dist/service-Dffd4how.mjs +1 -0
  33. package/dist/syntax-diagnostic-BQgOV8Fz.mjs +2 -0
  34. package/dist/syntax-diagnostic-BQgOV8Fz.mjs.map +1 -0
  35. package/dist/validation-errors-ChvCG6wT.mjs +3 -0
  36. package/dist/validation-errors-ChvCG6wT.mjs.map +1 -0
  37. package/dist/vitest/index.mjs +1 -1
  38. package/dist/vitest/index.mjs.map +1 -1
  39. package/docs/cli/application.md +3 -3
  40. package/docs/cli/executor.md +13 -17
  41. package/docs/cli/function.md +1 -1
  42. package/docs/cli/workspace.md +2 -3
  43. package/docs/configuration.md +28 -0
  44. package/docs/github-actions.md +82 -15
  45. package/docs/migration/v2.md +5 -3
  46. package/docs/services/auth.md +5 -0
  47. package/docs/services/executor.md +2 -0
  48. package/docs/services/tailordb/migration.md +3 -3
  49. package/package.json +12 -12
  50. package/dist/client-CHXix4LD.mjs +0 -1
  51. package/dist/client-DOQv-BP8.mjs.map +0 -1
  52. package/dist/register-ts-hook-CXYYYgCl.mjs.map +0 -1
  53. package/dist/service-DsAWXbVX.mjs +0 -1
  54. package/dist/validation-errors-DqCeUW4L.mjs +0 -3
  55. package/dist/validation-errors-DqCeUW4L.mjs.map +0 -1
@@ -42,9 +42,9 @@ tailor generate [options]
42
42
 
43
43
  **Options**
44
44
 
45
- | Option | Alias | Description | Required | Default |
46
- | ------------------- | ----- | ----------------------- | -------- | -------------------- |
47
- | `--config <CONFIG>` | `-c` | Path to SDK config file | No | `"tailor.config.ts"` |
45
+ | Option | Alias | Description | Required | Default | Env |
46
+ | ------------------- | ----- | -------------------------- | -------- | -------------------- | -------------------- |
47
+ | `--config <CONFIG>` | `-c` | Path to Tailor config file | No | `"tailor.config.ts"` | `TAILOR_CONFIG_PATH` |
48
48
 
49
49
  See [Global Options](../cli-reference.md#global-options) for options available to all commands.
50
50
 
@@ -172,16 +172,16 @@ tailor executor trigger [options] <executor-name>
172
172
 
173
173
  **Options**
174
174
 
175
- | Option | Alias | Description | Required | Default | Env |
176
- | ------------------------------- | ----- | ---------------------------------------------------------------------------------- | -------- | ------- | ------------------------------ |
177
- | `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` |
178
- | `--profile <PROFILE>` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` |
179
- | `--data <DATA>` | `-d` | Request body (JSON string) | No | - | - |
180
- | `--header <HEADER>` | `-H` | Request header (format: 'Key: Value', can be specified multiple times) | No | - | - |
181
- | `--wait` | `-W` | Wait for job completion and downstream execution (workflow/function) if applicable | No | `false` | - |
182
- | `--interval <INTERVAL>` | `-i` | Polling interval when using --wait (e.g., '3s', '500ms', '1m') | No | `"3s"` | - |
183
- | `--timeout <TIMEOUT>` | `-t` | Maximum time to wait when using --wait (e.g., '30s', '5m') | No | `"5m"` | - |
184
- | `--logs` | `-l` | Display function execution logs after completion (requires --wait) | No | `false` | - |
175
+ | Option | Alias | Description | Required | Default | Env |
176
+ | ------------------------------- | ----- | ------------------------------------------------------------------------------------------------------- | -------- | ------- | ------------------------------ |
177
+ | `--workspace-id <WORKSPACE_ID>` | `-w` | Workspace ID | No | - | `TAILOR_PLATFORM_WORKSPACE_ID` |
178
+ | `--profile <PROFILE>` | `-p` | Workspace profile | No | - | `TAILOR_PLATFORM_PROFILE` |
179
+ | `--data <DATA>` | `-d` | Request body (JSON string) | No | - | - |
180
+ | `--header <HEADER>` | `-H` | Ignored, as the executor receives empty headers (format: 'Key: Value', can be specified multiple times) | No | - | - |
181
+ | `--wait` | `-W` | Wait for job completion and downstream execution (workflow/function) if applicable | No | `false` | - |
182
+ | `--interval <INTERVAL>` | `-i` | Polling interval when using --wait (e.g., '3s', '500ms', '1m') | No | `"3s"` | - |
183
+ | `--timeout <TIMEOUT>` | `-t` | Maximum time to wait when using --wait (e.g., '30s', '5m') | No | `"5m"` | - |
184
+ | `--logs` | `-l` | Display function execution logs after completion (requires --wait) | No | `false` | - |
185
185
 
186
186
  **Examples**
187
187
 
@@ -197,12 +197,6 @@ $ tailor executor trigger my-executor
197
197
  $ tailor executor trigger my-executor -d '{"message": "hello"}'
198
198
  ```
199
199
 
200
- **Trigger with data and headers**
201
-
202
- ```bash
203
- $ tailor executor trigger my-executor -d '{"message": "hello"}' -H "X-Custom: value" -H "X-Another: value2"
204
- ```
205
-
206
200
  **Trigger and wait for completion**
207
201
 
208
202
  ```bash
@@ -271,7 +265,9 @@ if (result.timedOut) {
271
265
  Only executors with `INCOMING_WEBHOOK` or `SCHEDULE` trigger types can be triggered manually.
272
266
  Executors with `EVENT` trigger types (such as `recordCreated`, `recordUpdated`, `recordDeleted`) cannot be triggered manually.
273
267
 
274
- The `--data` and `--header` options are only available for `INCOMING_WEBHOOK` trigger type.
268
+ The `--data` and `--header` options are accepted only for `INCOMING_WEBHOOK` trigger type.
269
+
270
+ The executor receives the `--data` JSON as `body`, with empty `headers` and no `rawBody`. `--header` values are not passed to the executor. To test an executor that reads headers or verifies a signature over `rawBody`, send the request to its webhook URL, which `executor webhook list` shows.
275
271
 
276
272
  **Downstream Execution Tracking**
277
273
 
@@ -172,7 +172,7 @@ tailor function run [options] <file>
172
172
  | `--name <NAME>` | `-n` | Workflow job name to run (matches the `name` field of createWorkflowJob) | No | - | - |
173
173
  | `--arg <ARG>` | `-a` | JSON argument to pass to the function | No | - | - |
174
174
  | `--machine-user <MACHINE_USER>` | `-m` | Machine user name for authentication. Falls back to the active profile's default machine user. | No | - | `TAILOR_PLATFORM_MACHINE_USER_NAME` |
175
- | `--config <CONFIG>` | `-c` | Path to SDK config file | No | `"tailor.config.ts"` | - |
175
+ | `--config <CONFIG>` | `-c` | Path to Tailor config file | No | `"tailor.config.ts"` | `TAILOR_CONFIG_PATH` |
176
176
  | `--allow-schema-drift` | - | Run a scaffolded script even when its schema snapshot no longer matches | No | `false` | - |
177
177
 
178
178
  See [Global Options](../cli-reference.md#global-options) for options available to all commands.
@@ -201,10 +201,9 @@ tailor workspace prune [options]
201
201
  | --------------------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------- | ------------------------- |
202
202
  | `--name <NAME>` | - | Select workspaces whose whole name matches this regular expression (repeatable) | No | - | - |
203
203
  | `--older-than <OLDER_THAN>` | - | Minimum age since creation, such as 30m, 24h, or 7d. 0s disables the age check and requires a location. Required unless --expired is given | No | - | - |
204
- | `--expired` | - | Select workspaces whose own --ttl expiry has passed, instead of by name and age. Requires --organization-root, --folder-id, or --personal | No | `false` | - |
204
+ | `--expired` | - | Select workspaces whose own --ttl expiry has passed, instead of by name and age. Requires --organization-root or --folder-id | No | `false` | - |
205
205
  | `--organization-root <ORGANIZATION_ID>` | - | Consider the workspaces directly under this organization, excluding those in its folders (repeatable) | No | - | - |
206
206
  | `--folder-id <FOLDER_ID>` | - | Consider the workspaces in this folder (repeatable) | No | - | - |
207
- | `--personal` | - | Consider the workspaces belonging to no organization and no folder | No | `false` | - |
208
207
  | `--exclude <EXCLUDE>` | - | Keep a workspace with this exact name even when it matches (repeatable) | No | - | - |
209
208
  | `--limit <LIMIT>` | - | Abort when more workspaces match than this, without deleting anything. 0 removes the cap | No | `20` | - |
210
209
  | `--dry-run` | - | List the workspaces that would be deleted without deleting them | No | `false` | - |
@@ -219,7 +218,7 @@ Use this to reclaim workspaces left behind by CI runs, preview deployments, or i
219
218
 
220
219
  With --expired the workspaces select themselves instead: each one is deleted only once the --ttl expiry it recorded at creation has passed, so callers need no --name or --older-than. A workspace that records no expiry is never deleted this way, and neither is one whose recorded expiry cannot be read. Because that expiry is recorded on the workspace rather than derived from its name, anything able to write the workspace's metadata can bring its deletion forward -- and writing a workspace's metadata is a lesser permission than deleting it. --expired therefore requires at least one location, and --name still applies on top.
221
220
 
222
- Every workspace lives in exactly one location, and the location options name them explicitly: --organization-root selects the workspaces directly under an organization and none inside its folders, --folder-id selects the workspaces in one folder, and --personal selects the workspaces belonging to no organization and no folder. Each option can be given more than once, they combine as a union, and none of them is read from the environment or from the default organization/folder set by `user update` -- a sweep covers exactly the locations spelled out on the command line. Selecting --personal is a deliberate choice to accept, for every organization-less workspace visible to this login, the expiry that anyone able to write a workspace's metadata may have recorded. Without any location option, a --name / --older-than sweep considers every visible workspace.
221
+ Every workspace lives in exactly one location, and the location options name them explicitly: --organization-root selects the workspaces directly under an organization and none inside its folders, and --folder-id selects the workspaces in one folder. Each option can be given more than once, they combine as a union, and none of them is read from the environment or from the default organization/folder set by `user update` -- a sweep covers exactly the locations spelled out on the command line. Without any location option, a --name / --older-than sweep considers every visible workspace.
223
222
 
224
223
  Without a location option, prune warns before listing workspaces that every workspace visible to this login is a candidate for the name and age filters, even with --yes or --dry-run. The default organization/folder set by `tailor user update` is not used.
225
224
 
@@ -265,6 +265,34 @@ When using external resources:
265
265
  - Destructive operations like `tailordb truncate` (and `tailor seed apply --truncate`) automatically exclude external resources to prevent accidental data loss in shared resources
266
266
  - Subscribing an executor to an external resource's events requires the config that owns the resource in the same `deploy`. Publishing is then enabled automatically, and `deploy` records the dependency so a later deploy without that config asks for confirmation instead of silently turning publishing off
267
267
 
268
+ #### Referencing another app's Auth with `asExternal()`
269
+
270
+ When the other app is in the same repository, import its `defineAuth` result and call `asExternal()` instead of writing the name by hand.
271
+
272
+ ```typescript
273
+ // core/auth.ts
274
+ export const auth = defineAuth("core-auth", {
275
+ machineUsers: { portal: { attributes: { role: "STAFF" } } },
276
+ // ...
277
+ });
278
+ ```
279
+
280
+ ```typescript
281
+ // portal/tailor.config.ts
282
+ import { auth as coreAuth } from "../core/auth";
283
+
284
+ export default defineConfig({
285
+ name: "portal",
286
+ auth: coreAuth.asExternal(),
287
+ });
288
+ ```
289
+
290
+ - The reference follows renames of the Auth service and of its machine users.
291
+ - The machine user names reach the generated `tailor.d.ts`, so a misspelled `invoker` is a type error in the referencing app, including when it is written as an expression such as `flag ? "portal" : "other"`.
292
+ - Only the name and the machine users are taken over. Hooks, OAuth2 clients, and the rest of the definition stay with the app that owns the Auth service, so this project does not deploy them a second time.
293
+ - Put the `defineAuth` call in its own file, as above. Importing the other app's `tailor.config.ts` also runs the rest of that file.
294
+ - An Auth service defined in another repository cannot be imported. Reference it with `{ name: "...", external: true }`; `invoker` then accepts any string.
295
+
268
296
  ### Built-in IdP
269
297
 
270
298
  Configure the Built-in IdP service using `defineIdp()`. See [IdP](./services/idp.md) for full documentation.
@@ -333,14 +333,24 @@ pull request is closed no longer runs, because that workflow no longer starts
333
333
  then; move it into the cleanup workflow. `setup` warns about each job of yours
334
334
  in the preview workflow whose `if` contains an `== 'closed'` comparison.
335
335
 
336
- Fork pull requests are skipped. Every other pull request gets a preview, draft
337
- pull requests included. `--require` narrows that to one of:
336
+ #### Pull requests that get a preview
337
+
338
+ Fork pull requests are skipped, and so are events on a closed pull request,
339
+ such as a label added after merging. Every other pull request gets a preview,
340
+ draft pull requests included. `--require` narrows that to one of:
338
341
 
339
342
  - `--require ready` skips draft pull requests. The preview is deployed when the
340
343
  draft is marked ready for review.
341
344
  - `--require label` deploys only pull requests labeled `tailor:preview`. A
342
345
  labeled draft deploys too, because the label asks for the preview.
343
346
 
347
+ With app directories other than the repository root (`--dir`), a pull request
348
+ gets no preview either when none of its changed files counts. A file counts
349
+ when it is under an app directory, is the generated workflow file, or matches a
350
+ `--paths` pattern, and the last pattern that matches it does not start with `!`
351
+ (see
352
+ [Running on changes outside the app directories](#running-on-changes-outside-the-app-directories)).
353
+
344
354
  When `tailor setup update` regenerates a preview target generated before
345
355
  `--require` existed, it reads the target as `--require ready`, or as
346
356
  `--require label` if it required the label. The first keeps skipping drafts; the
@@ -362,7 +372,8 @@ tailor setup ci autofix --dir apps/erp --dir apps/users # run tailor generate i
362
372
  It writes `.github/workflows/tailor-autofix.yml`, which runs `tailor generate`
363
373
  on every pull request and, when that changes files, commits them to the pull
364
374
  request branch as `chore: run tailor generate`. Only the changes
365
- `tailor generate` makes are committed: files that earlier steps leave in the
375
+ `tailor generate` makes, and with `--codemod deterministic` those of
376
+ `tailor upgrade`, are committed: files that earlier steps leave in the
366
377
  checkout, such as an `.npmrc`, are not. The deploy workflows keep their check,
367
378
  which fails on the commit that needed the fix and passes on the fix commit.
368
379
 
@@ -387,9 +398,10 @@ right away.
387
398
  - **A branch that moved on:** if someone pushes to the branch while the
388
399
  workflow runs, it does not commit; the run for the new commit regenerates the
389
400
  files.
390
- - **Output that keeps changing:** if `tailor generate` changes files again
391
- right after the fix commit, the workflow fails instead of committing again.
392
- Check that running it twice in a row changes nothing.
401
+ - **Output that keeps changing:** if `tailor generate` (or, with
402
+ `--codemod deterministic`, `tailor upgrade`) changes files again right after
403
+ the fix commit, the workflow fails instead of committing again. Check that
404
+ running it twice in a row changes nothing.
393
405
  - **Approval rules:** the fix commit becomes the most recent push to the pull
394
406
  request, and a bot pushed it. A branch protection rule that requires the most
395
407
  recent push to be approved by someone other than its pusher is then satisfied
@@ -414,6 +426,60 @@ right away.
414
426
  To stop committing, delete the workflow with
415
427
  `tailor setup delete .github/workflows/tailor-autofix.yml`.
416
428
 
429
+ ### Applying codemods on SDK upgrades
430
+
431
+ A pull request that upgrades `@tailor-platform/sdk`, such as one from Renovate,
432
+ may need the codemods that [`tailor upgrade`](./cli/upgrade.md) runs. Pass
433
+ `--codemod` to have the autofix workflow handle them; without it, the
434
+ workflow runs only `tailor generate`:
435
+
436
+ ```bash
437
+ tailor setup ci autofix --codemod error # fail the pull request until they are applied
438
+ tailor setup ci autofix --codemod deterministic # commit what they rewrite
439
+ ```
440
+
441
+ | `--codemod` | On a pull request that upgrades the SDK | Check fails |
442
+ | --------------- | ------------------------------------------------------------------------------------------------------------------------ | ----------- |
443
+ | `warn` | Runs `tailor upgrade --dry-run` and reports the files it would rewrite and the changes it leaves for review, as warnings | No |
444
+ | `error` | Reports the same as errors, and fails the `tailor-codemod-result` job | Yes |
445
+ | `deterministic` | Commits what `tailor upgrade` rewrites together with what `tailor generate` changes, and reports the rest as warnings | No |
446
+
447
+ - **Which upgrade:** for each `--dir`, the workflow upgrades from the SDK
448
+ version that the lockfile at the repository root resolves on the pull
449
+ request's base branch to the version the pull request installs. When the
450
+ base branch has no lockfile of that name, such as when the pull request
451
+ switches package managers, it upgrades from 2.37.0, the oldest version
452
+ `tailor setup ci autofix` supports. A pull request that keeps the version,
453
+ or keeps the SDK linked from a workspace (such as with `workspace:*`), runs
454
+ no codemod.
455
+ - **Reports:** the files left for you get annotations, and the job summary
456
+ lists every file, with the migration prompt of each change left for review.
457
+ Hand the prompt to an AI coding assistant, or follow it yourself.
458
+ - **Required check:** with `error`, require the `tailor-codemod-result` check
459
+ to block the merge. The workflow still commits what `tailor generate`
460
+ changes. `tailor-codemod-result` also fails when the `tailor-autofix` job
461
+ fails or is cancelled, and is skipped, which counts as passing, when that
462
+ job succeeds with nothing left.
463
+ - **Reviews keep matching:** a change left for review is found by the code it
464
+ touches, and some codemods ask for a review of the whole app, so a review
465
+ can still be reported after you finish the migration. With `error`, such a
466
+ pull request keeps failing until the base branch has the new version.
467
+ - **Workflow files:** GitHub refuses a change to `.github/workflows` from the
468
+ workflow token or from an App without the Workflows permission, so
469
+ `deterministic` leaves those files out of the fix commit and reports them.
470
+ Run `tailor upgrade --from <base version>` and commit them yourself.
471
+ - **Warnings** that `tailor upgrade` prints for code that may still need a
472
+ manual migration stay warnings with every value.
473
+ - **Lockfile:** bun needs the text `bun.lock`, not `bun.lockb`. A `yarn.lock`
474
+ does not record which app uses which version, so when the base branch has
475
+ several SDK versions and the pull request changes them, the workflow fails and
476
+ you run `tailor upgrade` yourself. Yarn 1 leaves workspace packages out of
477
+ `yarn.lock`, so the workflow also fails for an app that takes the SDK from a
478
+ workspace there.
479
+ - **Skipped pull requests:** fork and Dependabot pull requests skip the whole
480
+ workflow (except fork pull requests with `autofix-ci`), so `error` does not
481
+ check them, and a skipped check counts as passing.
482
+
417
483
  ## Targeting a workspace
418
484
 
419
485
  The generated `plan` and `deploy` jobs target a workspace by **id**, read from
@@ -558,9 +624,8 @@ A job that runs `tailor` against the workspace needs the machine-user
558
624
  (the `--environment` value, or the workspace name when omitted) as above. A job
559
625
  that only uses `app-url`, such as end-to-end tests, does not.
560
626
 
561
- The job is skipped whenever `tailor-preview-deploy` is skipped: for fork pull
562
- requests, for draft pull requests with `--require ready`, and for unlabeled
563
- ones with `--require label`.
627
+ The job is skipped whenever `tailor-preview-deploy` is skipped (see
628
+ [Pull requests that get a preview](#pull-requests-that-get-a-preview)).
564
629
 
565
630
  A preview workspace expires 7 days (`ttl: 7d` on `tailor-preview-deploy`) after
566
631
  the last push to its pull request. When a pull request is closed,
@@ -999,8 +1064,10 @@ Before enabling it, note that:
999
1064
  and validation run, `updatedAt` changes, and executors with
1000
1065
  `recordUpdatedTrigger` fire once per seeded row on every deploy.
1001
1066
  - Every preview deploy deletes the data reviewers added to the preview
1002
- workspace. That is every push, and with `--require label` also every
1003
- label added to the pull request, since each one redeploys the preview.
1067
+ workspace. That is every push to a pull request that
1068
+ [gets a preview](#pull-requests-that-get-a-preview), and with
1069
+ `--require label` also every label added to it, since each one redeploys the
1070
+ preview.
1004
1071
  - A seed failure fails the deploy job and its notification, although the deploy
1005
1072
  itself went through.
1006
1073
  - The step shares the deploy job's timeout. IdP users take about a second each.
@@ -1262,10 +1329,10 @@ workflows it reports.
1262
1329
 
1263
1330
  Workflows generated by `setup ci branch`, `setup ci tag`, and `setup ci preview`
1264
1331
  self-audit: each contains a `tailor-drift-check` step that
1265
- runs the check in CI. Preview workflows run it alongside each preview deploy,
1266
- so pull requests that deploy no preview (drafts with `--require ready`, fork
1267
- PRs, and unlabeled PRs with `--require label`) skip the check. A single run audits every workflow
1268
- recorded in `.github/tailor.lock`.
1332
+ runs the check in CI. Preview workflows run it in `tailor-preview-deploy`, so
1333
+ the check is skipped whenever that job is (see
1334
+ [Pull requests that get a preview](#pull-requests-that-get-a-preview)). A single
1335
+ run audits every workflow recorded in `.github/tailor.lock`.
1269
1336
 
1270
1337
  Drift findings are advisory by default. Set the repository variable
1271
1338
  `TAILOR_PLATFORM_FAIL_ON_DRIFT` to `true` to make unsuppressed findings fail
@@ -1612,7 +1612,7 @@ See the SDK testing guide for the full environment setup.
1612
1612
 
1613
1613
  **Migration:** Manual
1614
1614
 
1615
- The name-keyed option types exported from `@tailor-platform/sdk/cli` — `GetWorkflowOptions`, `StartWorkflowOptions`, `ListWorkflowExecutionsOptions`, `GetExecutorOptions`, `TriggerExecutorOptions`, `ListExecutorJobsOptions`, `GetExecutorJobOptions`, `WatchExecutorJobOptions` — are removed in v2, together with the function overloads that accepted them. Pass the workflow or executor definition itself instead: `{ workflow: myWorkflow, invoker: "admin" }` / `{ executor: myExecutor }`, matching the `*TypedOptions` shape that types `arg` and `payload` from the definition. No codemod ships for this migration: rewriting a name string into a definition requires importing the module that defines the workflow or executor, which a source-local transform cannot resolve.
1615
+ The name-keyed option types exported from `@tailor-platform/sdk/cli` — `GetWorkflowOptions`, `StartWorkflowOptions`, `ListWorkflowExecutionsOptions`, `GetExecutorOptions`, `TriggerExecutorOptions`, `ListExecutorJobsOptions`, `GetExecutorJobOptions`, `WatchExecutorJobOptions` — are removed in v2, together with the function overloads that accepted them. Pass the workflow or executor definition itself instead: `{ workflow: myWorkflow, invoker: "admin" }` / `{ executor: myExecutor }`, matching the `*TypedOptions` shape that types `arg` from the definition and accepts `payload` only for an executor with an incoming webhook trigger. No codemod ships for this migration: rewriting a name string into a definition requires importing the module that defines the workflow or executor, which a source-local transform cannot resolve.
1616
1616
 
1617
1617
  Before:
1618
1618
 
@@ -1662,8 +1662,10 @@ flagged call site:
1662
1662
  invoker, typed against the machine users declared in tailor.config.ts.
1663
1663
  4. Replace imported option types with the *TypedOptions equivalent
1664
1664
  (e.g. GetWorkflowOptions → GetWorkflowTypedOptions<typeof myWorkflow>).
1665
- Note that arg (startWorkflow) and payload (triggerExecutor) are now typed
1666
- from the definition, so a mistyped argument becomes a type error.
1665
+ Note that arg (startWorkflow) is now typed from the definition, so a
1666
+ mistyped argument becomes a type error. Passing payload to
1667
+ triggerExecutor is a type error unless the executor has an incoming
1668
+ webhook trigger.
1667
1669
 
1668
1670
  When the name is only known at runtime (read from argv or an environment
1669
1671
  variable), the CLI command itself — `tailor workflow start <name>` /
@@ -26,6 +26,7 @@ Configure Auth service using `defineAuth()`:
26
26
 
27
27
  - **One auth per application**: Each application can have exactly one Auth service
28
28
  - **Configuration location**: Define in `tailor.config.ts` using `defineAuth()` and reference directly in the config's `auth` field
29
+ - **Referencing another app's auth**: When another app in the same repository defines the auth, reference it with `asExternal()`. See [Referencing another app's Auth with `asExternal()`](../configuration.md#referencing-another-apps-auth-with-asexternal)
29
30
  - **`userProfile` and `machineUserAttributes` are mutually exclusive**: Specifying both fails at deploy/generate time with ``Specify either `userProfile` or `machineUserAttributes`, not both.``
30
31
 
31
32
  ```typescript
@@ -314,6 +315,10 @@ export default createResolver({
314
315
 
315
316
  Type narrowing is provided by the generated `tailor.d.ts` (the `MachineUserNameRegistry` interface). Run `tailor generate` (or `deploy`) after defining new machine users to refresh it.
316
317
 
318
+ `tailor deploy` checks the string `invoker` of every resolver and executor against the machine users of the Auth service it resolves to, and stops with `INVOKER_MACHINE_USER_NOT_FOUND` when the name does not exist. The `invoker` passed to `workflow.start()` is not checked at deploy time. When a config deployed in the same run defines the Auth service, the machine users it lists are the ones checked, because deploy removes the machine users it no longer lists. When the Auth service is only referenced as external, the machine users that exist in the workspace are checked.
319
+
320
+ When the Auth service is an external one (`auth: { name: "...", external: true }`), the machine users are not in your config, so `tailor.d.ts` cannot narrow the invoker type and any string passes type checking. For resolvers and executors, the deploy-time check is what catches a misspelled name in that case.
321
+
317
322
  ## OAuth 2.0 Clients
318
323
 
319
324
  Configure OAuth 2.0 clients for third-party applications:
@@ -543,6 +543,8 @@ export default createExecutor({
543
543
 
544
544
  The webhook URL is public, so verify the signature over the unparsed request body before trusting `body`. `rawBody` is delivered base64-encoded; decode it to the original bytes before computing the signature.
545
545
 
546
+ When an executor is triggered manually with [`tailor executor trigger`](../cli/executor.md#executor-trigger) or `triggerExecutor` from `@tailor-platform/sdk/cli`, it receives empty `headers`, even when `--header` is given, and no `rawBody`. To test an executor that reads headers or verifies a signature, send a request to its webhook URL, which [`tailor executor webhook list`](../cli/executor.md#executor-webhook-list) shows.
547
+
546
548
  **With custom response:**
547
549
 
548
550
  ```typescript
@@ -670,7 +670,7 @@ The command performs the following sequence:
670
670
  6. Optionally runs an assertion script against the migrated data.
671
671
  7. Deletes an automatically-created workspace after success or failure.
672
672
 
673
- Right after creating an automatically-created workspace (step 2), the command records a 24-hour expiry on it. If the run is interrupted before step 7 — for example, a CI job is cancelled or reaches its time limit — the command cannot delete the workspace, so it stays. Once the 24 hours have passed, `tailor workspace prune --expired` (with a location option such as `--organization-root`, `--folder-id`, or `--personal`) deletes it. A workspace given with `--target-workspace-id` is not given an expiry. If recording the expiry fails, the command warns and continues the test.
673
+ Right after creating an automatically-created workspace (step 2), the command records a 24-hour expiry on it. If the run is interrupted before step 7 — for example, a CI job is cancelled or reaches its time limit — the command cannot delete the workspace, so it stays. Once the 24 hours have passed, `tailor workspace prune --expired` (with a location option such as `--organization-root` or `--folder-id`) deletes it. A workspace given with `--target-workspace-id` is not given an expiry. If recording the expiry fails, the command warns and continues the test.
674
674
 
675
675
  Both the pre-migration and final TailorDB schemas come from committed migration snapshots. Ungenerated changes in the current table definitions are not included in the rehearsal.
676
676
 
@@ -846,7 +846,7 @@ To bypass both checks during deploy (not recommended outside of recovery scenari
846
846
  tailor deploy --no-schema-check
847
847
  ```
848
848
 
849
- With pending migrations, each migration still applies its own table definitions in its [phases](#per-migration-phases), so `migrate.ts` sees the schema it was written for. Local table definitions that differ from the last pending migration are applied after every pending migration has completed, and the deploy lists those tables. With [maintenance mode](#maintenance-mode) on, existing tables stay in it until their local definitions are applied. If one of them cannot be applied, for example a unique constraint on a field whose records hold duplicate values, the deploy fails with `MIGRATION_LOCAL_DEFINITIONS_FAILED`: the migrations stay applied, tables already created for their local definitions remain, and the existing tables keep the definitions of the last migration and leave maintenance mode.
849
+ With pending migrations, each migration still applies its own table definitions in its [phases](#per-migration-phases), so `migrate.ts` sees the schema it was written for. Local table definitions that differ from the last pending migration are applied after every pending migration has completed, and the deploy lists those tables. Tables that the local definitions no longer have are deleted after that in the same deploy, even when no migration removes them. With [maintenance mode](#maintenance-mode) on, existing tables stay in it until their local definitions are applied. If one of them cannot be applied, for example a unique constraint on a field whose records hold duplicate values, the deploy fails with `MIGRATION_LOCAL_DEFINITIONS_FAILED`: the migrations stay applied, tables already created for their local definitions remain, the existing tables keep the definitions of the last migration and leave maintenance mode, and tables that no migration removes are not deleted.
850
850
 
851
851
  `--no-schema-check` does not bypass the check that the remote migration checkpoint is in the local migration history. See ["Remote migration checkpoint is not in the local migration history" error](#remote-migration-checkpoint-is-not-in-the-local-migration-history-error).
852
852
 
@@ -970,7 +970,7 @@ Before a migration's script starts, `tailor deploy` checks that the namespace's
970
970
 
971
971
  The checkpoint is advanced only after the reversible post-migration schema updates succeed. If the checkpoint write reports an error, the SDK reads it back: a matching value is treated as committed. Any other observed value leaves the post-migration schema unchanged rather than risk rolling back a concurrent deployment; a value beyond the current migration confirms a concurrent deploy, while an older or missing value means the checkpoint must be repaired before retrying, unless the value is the previous checkpoint and the multi-step migration is still recorded as in progress, which the next deploy resumes. If read-back also fails, the SDK likewise leaves the post-migration schema unchanged; verify the remote checkpoint before retrying.
972
972
 
973
- Removed tables are deleted only after the checkpoint is committed. The deploy records with the checkpoint that these deletions are still to run, and clears the record once they finish. If that cleanup fails or the deploy is interrupted, the checkpoint remains at the new migration, and the next deploy finishes the cleanup: it lists the tables that migration removed among the tables to delete, and deletes them and their GQL permissions with their data before it runs any pending migration. `tailor tailordb migration validate` reports them as tables the next deploy deletes. To delete them without deploying, run `tailor tailordb migration sync <N>` with the committed migration as `<N>` (when the cleanup fails, the deploy error's suggestion names the command). A same-named remote table is still reported as remote schema drift when no unfinished cleanup is recorded, for example a table created again after the cleanup completed or one left by an SDK version that did not record the cleanup, and when a later migration adds the table back; delete it with `migration sync <N>` or by hand, and then deploy again. A deploy with `--no-schema-check` does not finish the cleanup of a namespace that has pending migrations, and once those migrations commit, the leftover tables are reported as drift as well.
973
+ Removed tables are deleted only after the checkpoint is committed. The deploy records with the checkpoint that these deletions are still to run, and clears the record once they finish. If that cleanup fails or the deploy is interrupted, the checkpoint remains at the new migration, and the next deploy finishes the cleanup: it lists the tables that migration removed among the tables to delete, and deletes them and their GQL permissions with their data before it runs any pending migration. `tailor tailordb migration validate` reports them as tables the next deploy deletes. To delete them without deploying, run `tailor tailordb migration sync <N>` with the committed migration as `<N>` (when the cleanup fails, the deploy error's suggestion names the command). A same-named remote table is still reported as remote schema drift when no unfinished cleanup is recorded, for example a table created again after the cleanup completed or one left by an SDK version that did not record the cleanup, and when a later migration adds the table back; delete it with `migration sync <N>` or by hand, and then deploy again. A deploy with `--no-schema-check` does not finish the cleanup first: when the namespace has pending migrations, it deletes the leftover tables that the local definitions no longer have after those migrations complete (see [Schema verification](#schema-verification)).
974
974
 
975
975
  With `--no-schema-check`, local table definitions that the pending migrations do not include are applied after every migration has committed (see [Schema verification](#schema-verification)). If one of them cannot be applied, the deploy fails with `MIGRATION_LOCAL_DEFINITIONS_FAILED`: the migrations stay committed, the existing tables go back to the definitions of the last migration, and tables already created for their local definitions remain. Fix the cause and deploy again. When existing records refuse the definition, for example a unique constraint on a field whose records hold duplicate values, run `tailor tailordb migration generate` to add the change in a migration whose script updates those records, then deploy again; the error's suggestion names the command.
976
976
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk",
3
- "version": "2.38.0",
3
+ "version": "2.39.0",
4
4
  "description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -161,8 +161,8 @@
161
161
  "@badgateway/oauth2-client": "3.3.1",
162
162
  "@bufbuild/protobuf": "2.16.0",
163
163
  "@bufbuild/protovalidate": "1.3.0",
164
- "@connectrpc/connect": "2.2.0",
165
- "@connectrpc/connect-node": "2.2.0",
164
+ "@connectrpc/connect": "2.3.0",
165
+ "@connectrpc/connect-node": "2.3.0",
166
166
  "@enlumine/graphql": "0.2.0",
167
167
  "@enlumine/sql": "0.2.0",
168
168
  "@enlumine/terminal": "0.2.0",
@@ -175,9 +175,9 @@
175
175
  "@opentelemetry/exporter-trace-otlp-proto": "0.300.0",
176
176
  "@opentelemetry/resources": "3.0.0",
177
177
  "@opentelemetry/sdk-trace": "3.0.0",
178
- "@opentelemetry/semantic-conventions": "1.43.0",
179
- "@oxc-project/types": "0.156.0",
180
- "@politty/zod": "0.6.3",
178
+ "@opentelemetry/semantic-conventions": "1.44.0",
179
+ "@oxc-project/types": "0.157.0",
180
+ "@politty/zod": "0.7.1",
181
181
  "@secretlint/core": "13.1.0",
182
182
  "@secretlint/secretlint-rule-preset-recommend": "13.1.0",
183
183
  "@standard-schema/spec": "1.1.0",
@@ -190,19 +190,19 @@
190
190
  "find-up-simple": "1.0.1",
191
191
  "get-east-asian-width": "1.7.0",
192
192
  "get-tsconfig": "4.14.3",
193
- "globals": "17.13.0",
193
+ "globals": "17.14.0",
194
194
  "inflection": "3.0.2",
195
- "kysely": "0.29.7",
195
+ "kysely": "0.29.8",
196
196
  "lines-db": "0.18.1",
197
197
  "mime-types": "3.0.2",
198
198
  "open": "11.0.4",
199
- "oxc-parser": "0.156.0",
199
+ "oxc-parser": "0.157.0",
200
200
  "p-limit": "7.3.3",
201
201
  "pathe": "2.0.3",
202
202
  "pgsql-ast-parser": "12.0.2",
203
203
  "pkg-types": "2.4.0",
204
204
  "rolldown": "1.2.15",
205
- "semver": "7.8.5",
205
+ "semver": "7.8.6",
206
206
  "std-env": "4.3.0",
207
207
  "temporal-polyfill": "1.0.6",
208
208
  "temporal-spec": "1.0.1",
@@ -219,7 +219,7 @@
219
219
  "@types/mime-types": "3.0.1",
220
220
  "@types/node": "26.6.6",
221
221
  "@types/semver": "7.8.0",
222
- "@vitest/coverage-v8": "5.0.5",
222
+ "@vitest/coverage-v8": "5.1.0",
223
223
  "eslint-plugin-zod": "5.2.2",
224
224
  "graphql": "17.0.2",
225
225
  "oxfmt": "0.75.0",
@@ -230,7 +230,7 @@
230
230
  "tsrs": "0.16.0-ts7.1.0-dev.20260929",
231
231
  "tsx": "4.23.15",
232
232
  "typescript": "6.0.3",
233
- "vitest": "5.0.5",
233
+ "vitest": "5.1.0",
234
234
  "zinfer": "0.5.2"
235
235
  },
236
236
  "peerDependencies": {
@@ -1 +0,0 @@
1
- import{A as e,C as t,D as n,E as r,F as i,I as a,M as o,N as s,O as c,P as l,S as u,T as d,_ as f,a as p,b as m,c as h,d as g,f as _,g as v,h as y,i as b,j as x,k as S,l as C,m as w,n as T,o as E,p as D,r as O,s as k,t as A,u as j,v as M,w as N,x as P,y as F}from"./client-DOQv-BP8.mjs";import{t as I}from"./user-agent-vdHYF3QL.mjs";export{A as MAX_PAGE_SIZE,T as POOLED_UPLOAD_METHODS,O as RETRY_SAFE_CREATE_METHODS,b as UPLOAD_POOL_MAX_CONNECTIONS,p as closeConnectionPool,E as concurrencyLimitInterceptor,k as createPooledStreamTransport,h as createTransport,C as defaultConsoleBaseUrl,j as defaultPlatformBaseUrl,g as errorHandlingInterceptor,_ as fetchAll,D as fetchAllTolerant,w as fetchMachineUserToken,y as fetchPaged,v as fetchPlatformMachineUserToken,f as fetchUserInfo,M as findAccessTokenSource,F as getConsoleBaseUrl,m as getEffectivePlatformConfig,P as getOAuth2ClientId,u as getOrNull,t as getPlatformBaseUrl,N as hasStaticWebsiteUrlPlaceholder,d as initOAuth2Client,r as initOperatorClient,n as isDefaultPlatform,c as isNotFoundError,S as normalizeBaseUrl,e as parseMethodName,x as registerAccessTokenSource,o as rememberPlatformConfigForToken,s as resolveStaticWebsiteUrls,l as resolveStaticWebsiteUrlsInEnv,i as retryInterceptor,a as staticWebsiteNameFromPlaceholder,I as userAgent};