@tailor-platform/sdk 2.35.0 → 2.37.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 (135) hide show
  1. package/CHANGELOG.md +108 -0
  2. package/dist/{application-Bj2MtL-d.mjs → application-83WVdH85.mjs} +1 -1
  3. package/dist/{application-DIsQSnj3.mjs → application-Cida-j1g.mjs} +36 -36
  4. package/dist/application-Cida-j1g.mjs.map +1 -0
  5. package/dist/cli/commands/deploy/deploy.d.mts +6 -1
  6. package/dist/cli/commands/deploy/tailordb/migration-validation.d.mts +1 -0
  7. package/dist/cli/commands/executor/jobs.d.mts +3 -0
  8. package/dist/cli/commands/tailordb/migrate/bundler.d.mts +3 -0
  9. package/dist/cli/commands/tailordb/migrate/config.d.mts +4 -0
  10. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +10 -0
  11. package/dist/cli/commands/tailordb/migrate/generate.d.mts +28 -2
  12. package/dist/cli/commands/tailordb/migrate/hints.d.mts +1 -0
  13. package/dist/cli/commands/tailordb/migrate/remote-state.d.mts +3 -0
  14. package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +3 -1
  15. package/dist/cli/commands/tailordb/migrate/snapshot-comparison.d.mts +4 -0
  16. package/dist/cli/commands/tailordb/migrate/snapshot-files.d.mts +44 -6
  17. package/dist/cli/commands/tailordb/migrate/snapshot-local.d.mts +2 -0
  18. package/dist/cli/commands/tailordb/migrate/snapshot-migrations.d.mts +2 -0
  19. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +8 -0
  20. package/dist/cli/commands/tailordb/migrate/types.d.mts +2 -0
  21. package/dist/cli/commands/workspace/create.d.mts +5 -3
  22. package/dist/cli/lib.d.mts +2 -2
  23. package/dist/cli/lib.mjs +1 -1
  24. package/dist/cli/lib.mjs.map +1 -1
  25. package/dist/cli/main.mjs +52 -51
  26. package/dist/cli/main.mjs.map +1 -1
  27. package/dist/cli/shared/client.d.mts +26 -0
  28. package/dist/cli/shared/function-execution.d.mts +2 -0
  29. package/dist/cli/shared/prompt.d.mts +9 -4
  30. package/dist/completion/zsh-worker.zsh +21 -13
  31. package/dist/configure/config/index.d.mts +2 -0
  32. package/dist/configure/config/types.d.mts +2 -0
  33. package/dist/configure/index.mjs.map +1 -1
  34. package/dist/configure/services/executor/trigger/webhook.d.mts +1 -0
  35. package/dist/configure/services/tailordb/schema.d.mts +7 -2
  36. package/dist/configure/services/tailordb/types.d.mts +3 -0
  37. package/dist/crashreport-C2AcQNTe.mjs +1 -0
  38. package/dist/{crashreport-DGU6lwiX.mjs → crashreport-D_wf4GZh.mjs} +4 -4
  39. package/dist/{crashreport-DGU6lwiX.mjs.map → crashreport-D_wf4GZh.mjs.map} +1 -1
  40. package/dist/date-representation-Cr7W7Pn2.mjs.map +1 -1
  41. package/dist/{errors-BXmGBX-7.mjs → errors-Dmdnq0zi.mjs} +2 -2
  42. package/dist/errors-Dmdnq0zi.mjs.map +1 -0
  43. package/dist/{kysely-type-B0ri1-Xs.mjs → kysely-type-DVL90_oX.mjs} +6 -6
  44. package/dist/kysely-type-DVL90_oX.mjs.map +1 -0
  45. package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
  46. package/dist/plugin/builtin/seed/seed-type-processor.d.mts +4 -3
  47. package/dist/plugin/get-generated-table.d.mts +4 -0
  48. package/dist/plugin/index.mjs.map +1 -1
  49. package/dist/plugin/types.d.mts +55 -3
  50. package/dist/plugin/with-context.d.mts +16 -0
  51. package/dist/register-ts-hook-Ht4zCseV.mjs +1115 -0
  52. package/dist/register-ts-hook-Ht4zCseV.mjs.map +1 -0
  53. package/dist/schema-BU1aIQ63.mjs.map +1 -1
  54. package/dist/{secret-file-BxZ-J_Nz.mjs → secret-file-DiuEcLFP.mjs} +2 -2
  55. package/dist/{secret-file-BxZ-J_Nz.mjs.map → secret-file-DiuEcLFP.mjs.map} +1 -1
  56. package/dist/service-CZ0EdD2-.mjs +10 -0
  57. package/dist/service-CZ0EdD2-.mjs.map +1 -0
  58. package/dist/service-DDrbdyd-.mjs +2 -0
  59. package/dist/{service-CaGmqg0r.mjs.map → service-DDrbdyd-.mjs.map} +1 -1
  60. package/dist/service-WhSyhaho.mjs +1 -0
  61. package/dist/service_pb-BMHhVot2.mjs +1 -0
  62. package/dist/service_pb-BxMSK0gg.mjs +2 -0
  63. package/dist/service_pb-BxMSK0gg.mjs.map +1 -0
  64. package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +3 -3
  65. package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +92 -0
  66. package/dist/tailor-proto/src/tailor/v1/notification_pb.d.mts +176 -0
  67. package/dist/tailor-proto/src/tailor/v1/notification_resource_pb.d.mts +172 -0
  68. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +78 -0
  69. package/dist/types/app-config.generated.d.mts +1 -1
  70. package/dist/types/auth-connection.generated.d.mts +2 -2
  71. package/dist/types/auth.generated.d.mts +13 -13
  72. package/dist/types/executor.generated.d.mts +25 -25
  73. package/dist/types/field.generated.d.mts +2 -2
  74. package/dist/types/http-adapter.generated.d.mts +4 -4
  75. package/dist/types/idp.generated.d.mts +272 -272
  76. package/dist/types/resolver.generated.d.mts +10 -10
  77. package/dist/types/tailordb.generated.d.mts +84 -80
  78. package/dist/types/workflow.generated.d.mts +2 -2
  79. package/dist/vitest/date-representation.d.mts +2 -0
  80. package/dist/vitest/environment.d.mts +1 -0
  81. package/dist/vitest/environment.mjs.map +1 -1
  82. package/dist/vitest/index.mjs +1 -1
  83. package/dist/vitest/index.mjs.map +1 -1
  84. package/dist/vitest/migration-steps.d.mts +13 -2
  85. package/dist/vitest/mock-kysely.d.mts +12 -2
  86. package/dist/vitest/mocks/aigateway.d.mts +7 -1
  87. package/dist/vitest/mocks/authconnection.d.mts +7 -1
  88. package/dist/vitest/mocks/file.d.mts +7 -1
  89. package/dist/vitest/mocks/iconv.d.mts +7 -1
  90. package/dist/vitest/mocks/idp.d.mts +7 -1
  91. package/dist/vitest/mocks/logger.d.mts +7 -1
  92. package/dist/vitest/mocks/secretmanager.d.mts +7 -1
  93. package/dist/vitest/mocks/tailordb-pglite.d.mts +12 -2
  94. package/dist/vitest/mocks/tailordb.d.mts +22 -4
  95. package/dist/vitest/mocks/workflow.d.mts +2 -1
  96. package/dist/vitest/pglite-kysely.d.mts +23 -2
  97. package/dist/vitest/pglite-temporal.d.mts +5 -1
  98. package/dist/vitest/workflow-local.d.mts +7 -0
  99. package/dist/{workspace_resource_pb-C4CkoYww.mjs → workspace_resource_pb-7smKERdZ.mjs} +2 -2
  100. package/dist/workspace_resource_pb-7smKERdZ.mjs.map +1 -0
  101. package/docs/cli/application.md +52 -22
  102. package/docs/cli/executor.md +2 -0
  103. package/docs/cli/function.md +3 -1
  104. package/docs/cli/tailordb.md +31 -23
  105. package/docs/cli/user.md +1 -1
  106. package/docs/cli/workflow.md +2 -0
  107. package/docs/cli/workspace.md +20 -18
  108. package/docs/cli-reference.md +10 -7
  109. package/docs/configuration.md +2 -2
  110. package/docs/data-clone.md +1 -1
  111. package/docs/github-actions.md +104 -15
  112. package/docs/plugin/custom.md +4 -4
  113. package/docs/runtime.md +1 -1
  114. package/docs/services/auth.md +2 -0
  115. package/docs/services/executor.md +12 -5
  116. package/docs/services/idp.md +2 -0
  117. package/docs/services/tailordb/index.md +12 -3
  118. package/docs/services/tailordb/migration.md +90 -38
  119. package/docs/services/workflow.md +1 -1
  120. package/docs/testing.md +9 -9
  121. package/package.json +22 -22
  122. package/dist/application-DIsQSnj3.mjs.map +0 -1
  123. package/dist/crashreport-WsYAWARW.mjs +0 -1
  124. package/dist/errors-BXmGBX-7.mjs.map +0 -1
  125. package/dist/kysely-type-B0ri1-Xs.mjs.map +0 -1
  126. package/dist/register-ts-hook-CQ7shKO5.mjs +0 -1055
  127. package/dist/register-ts-hook-CQ7shKO5.mjs.map +0 -1
  128. package/dist/service-CaGmqg0r.mjs +0 -2
  129. package/dist/service-DEq_hdht.mjs +0 -1
  130. package/dist/service-eeXdVrDK.mjs +0 -8
  131. package/dist/service-eeXdVrDK.mjs.map +0 -1
  132. package/dist/service_pb-6EkMfdOb.mjs +0 -2
  133. package/dist/service_pb-6EkMfdOb.mjs.map +0 -1
  134. package/dist/service_pb-CsJKokDl.mjs +0 -1
  135. package/dist/workspace_resource_pb-C4CkoYww.mjs.map +0 -1
@@ -1,11 +1,12 @@
1
1
  ---
2
- description: "Generate GitHub Actions deploy workflows and Renovate configuration for your app with tailor setup, including approval gates, secrets, monorepos, and rollback."
2
+ description: "Generate GitHub Actions deploy workflows, a workflow that commits generated files to pull requests, and Renovate configuration for your app with tailor setup, including approval gates, secrets, monorepos, and rollback."
3
3
  ---
4
4
 
5
- # GitHub Actions Integration
5
+ # GitHub Actions Integration (Beta)
6
6
 
7
7
  `tailor setup` generates GitHub repository automation for your Tailor Platform
8
- application, including deploy workflows and Renovate configuration.
8
+ application, including deploy workflows, a workflow that commits generated
9
+ files to pull requests, and Renovate configuration.
9
10
 
10
11
  > **Beta:** This command is under active development. CLI flags, the generated
11
12
  > workflow, and the `.github/tailor.lock` schema may change before general
@@ -272,6 +273,73 @@ When `tailor setup update` regenerates a preview target generated before
272
273
  second now also deploys a labeled draft. To deploy drafts as well, run
273
274
  `tailor setup ci preview` again without `--require`.
274
275
 
276
+ ## Committing generated files to pull requests
277
+
278
+ Each deploy workflow checks that the files `tailor generate` writes, such as
279
+ seed data and enum constants, are committed, and fails when they are out of
280
+ date. To have CI commit them instead, generate the autofix workflow:
281
+
282
+ ```bash
283
+ tailor setup ci autofix # commit with the workflow token
284
+ tailor setup ci autofix --provider github-app # commit with your GitHub App
285
+ tailor setup ci autofix --dir apps/erp --dir apps/users # run tailor generate in each app
286
+ ```
287
+
288
+ It writes `.github/workflows/tailor-autofix.yml`, which runs `tailor generate`
289
+ on every pull request and, when that changes files, commits them to the pull
290
+ request branch as `chore: run tailor generate`. Only the changes
291
+ `tailor generate` makes are committed: files that earlier steps leave in the
292
+ checkout, such as an `.npmrc`, are not. The deploy workflows keep their check,
293
+ which fails on the commit that needed the fix and passes on the fix commit.
294
+
295
+ `--provider` chooses what makes the commit:
296
+
297
+ | Provider | Commits as | Checks on the fix commit | Setup |
298
+ | ------------------------ | --------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
299
+ | `github-token` (default) | `github-actions[bot]`, with the workflow token | Wait until someone with write access selects **Approve workflows to run** on the pull request | None |
300
+ | `github-app` | Your GitHub App | Run automatically | Create a GitHub App with the Contents read and write permission, install it on the repository, and set `TAILOR_AUTOFIX_APP_CLIENT_ID` and `TAILOR_AUTOFIX_APP_PRIVATE_KEY` (see [Setting secrets and variables](#setting-secrets-and-variables)) |
301
+ | `autofix-ci` | The [autofix.ci](https://autofix.ci) GitHub App | Run automatically | Install the autofix.ci App on the repository |
302
+ | `securefix` | Your [securefix](https://github.com/csm-actions/securefix-action) server workflow | Run automatically | Set up the securefix server repository and its GitHub Apps, pass the server repository's name with `--securefix-server-repository`, and set the client App's `TAILOR_AUTOFIX_APP_CLIENT_ID` and `TAILOR_AUTOFIX_APP_PRIVATE_KEY` |
303
+
304
+ GitHub does not start workflows on its own for a commit pushed with the workflow
305
+ token, so with `github-token` the pull request shows that its workflows are
306
+ awaiting approval after each fix commit. Use another provider to have them run
307
+ right away.
308
+
309
+ - **Fork and Dependabot pull requests** get no write token or secrets, so the
310
+ autofix workflow skips them, except with `autofix-ci`, whose App commits to
311
+ fork pull requests. Their authors run `tailor generate` and commit the result
312
+ as before.
313
+ - **A branch that moved on:** if someone pushes to the branch while the
314
+ workflow runs, it does not commit; the run for the new commit regenerates the
315
+ files.
316
+ - **Output that keeps changing:** if `tailor generate` changes files again
317
+ right after the fix commit, the workflow fails instead of committing again.
318
+ Check that running it twice in a row changes nothing.
319
+ - **Approval rules:** the fix commit becomes the most recent push to the pull
320
+ request, and a bot pushed it. A branch protection rule that requires the most
321
+ recent push to be approved by someone other than its pusher is then satisfied
322
+ by an approval from anyone else, including whoever pushed the commit before
323
+ it.
324
+ - **Renovate** stops updating a pull request that has commits from someone
325
+ else. Add the fix commits' author email to `gitIgnoredAuthors` in your
326
+ Renovate configuration, such as
327
+ `41898282+github-actions[bot]@users.noreply.github.com` for `github-token`.
328
+ - **Secrets:** with `github-app`, every workflow in the repository can read the
329
+ App's private key, which can write to the repository. Give the App only the
330
+ Contents permission and install it only where it commits. `securefix` keeps
331
+ the key that writes in the server repository instead.
332
+ - **Dependabot** stops rebasing a pull request that has commits from someone
333
+ else, which happens when `autofix-ci` commits to one of its pull requests.
334
+ - With `autofix-ci` and `securefix`, the workflow is named `autofix.ci` and
335
+ `securefix`, the names those services accept requests from by default. With
336
+ `autofix-ci`, it also gives git its read-only token after `tailor generate`
337
+ finishes, because autofix.ci fetches the pull request head itself.
338
+ - GitHub Enterprise Server is not supported.
339
+
340
+ To stop committing, delete the workflow with
341
+ `tailor setup delete .github/workflows/tailor-autofix.yml`.
342
+
275
343
  ## Targeting a workspace
276
344
 
277
345
  The generated `plan` and `deploy` jobs target a workspace by **id**, read from
@@ -349,6 +417,12 @@ that require authentication, configure the credentials in your own step.
349
417
  See [Customizing the generated workflow](#customizing-the-generated-workflow)
350
418
  for what you can edit.
351
419
 
420
+ ### `.github/workflows/tailor-autofix.yml`
421
+
422
+ The workflow `setup ci autofix` generates (see
423
+ [Committing generated files to pull requests](#committing-generated-files-to-pull-requests)).
424
+ You can customize it the same way.
425
+
352
426
  ### Customizing the generated workflow
353
427
 
354
428
  The SDK owns the jobs and steps whose `id` starts with `tailor-`, and the
@@ -593,7 +667,8 @@ protection rules no longer guard your deploys.
593
667
  `tailor setup ci env` reads `.github/tailor.lock` and prints, for every GitHub
594
668
  Environment the generated workflows use, the commands that create the
595
669
  environment (only when it does not exist yet) and set its secrets and
596
- variables. It is read-only, so re-run it whenever you add a target. When the
670
+ variables, followed by the repository secrets and variables the autofix
671
+ workflow needs. It is read-only, so re-run it whenever you add a target. When the
597
672
  `origin` remote points at github.com, the output names that repository;
598
673
  otherwise it names the repository `gh repo view` reports for the current
599
674
  directory, with its host on GitHub Enterprise Server. Either way the commands
@@ -622,6 +697,12 @@ The list follows what each generated workflow actually reads:
622
697
  | `TAILOR_SLACK_BOT_TOKEN` | secret | branch, tag | no | Bot User OAuth Token (`xoxb-...`) of a Slack app with the `chat:write` scope |
623
698
  | `TAILOR_SLACK_CHANNEL_ID` | variable | branch, tag | no | Channel ID (`C...`) from the channel details in Slack; invite the bot to the channel |
624
699
  | `TAILOR_SLACK_USER_MAPPING` | variable | branch, tag | no | JSON object mapping GitHub usernames to Slack member IDs (for example `{"alice":"U0123456"}`) so notifications mention the actor; read only after you uncomment the `user-mapping` input of the `tailor-notify` step |
700
+ | `TAILOR_AUTOFIX_APP_CLIENT_ID` | variable | autofix (`github-app`, `securefix`) | yes | Client ID of the GitHub App that commits for the autofix workflow (with `securefix`, the securefix client App), from the App's settings page |
701
+ | `TAILOR_AUTOFIX_APP_PRIVATE_KEY` | secret | autofix (`github-app`, `securefix`) | yes | Private key of the same App, generated on its settings page; pass the `.pem` file on standard input (`gh secret set TAILOR_AUTOFIX_APP_PRIVATE_KEY < key.pem`) |
702
+
703
+ The autofix workflow uses no GitHub Environment, so its two entries are set on
704
+ the repository; the output lists them under the repository instead of an
705
+ environment.
625
706
 
626
707
  See [Account management](https://docs.tailor.tech/administration/account-management)
627
708
  for how organizations, folders, workspaces, and machine users relate.
@@ -651,7 +732,8 @@ to manage those settings in Terraform instead.
651
732
  ### Checking what is registered
652
733
 
653
734
  `tailor setup ci env --check` reads GitHub with `gh` and reports, for each
654
- environment, which of these entries are registered. It fails when a required
735
+ environment and for the repository entries of the autofix workflow, which of
736
+ these entries are registered. It fails when a required
655
737
  entry is missing, reports missing optional entries without failing, and prints
656
738
  the `gh` commands that set only the missing entries, with where each value comes
657
739
  from. It changes nothing, and it checks names only, since GitHub never returns
@@ -669,8 +751,8 @@ secret values.
669
751
  answers 404 for a private repository the account cannot see, so the check
670
752
  reports that as an access problem, not as missing entries.
671
753
 
672
- `--environment` narrows the check the same way. `--check` cannot be combined with
673
- `--format terraform`.
754
+ `--environment` narrows the check the same way, leaving out the repository
755
+ entries. `--check` cannot be combined with `--format terraform`.
674
756
 
675
757
  ## GitHub Environments (approval gate)
676
758
 
@@ -965,6 +1047,7 @@ server and its runners first:
965
1047
  the pinned versions: update them with `actions-sync`, or, with GitHub
966
1048
  Connect, delete them from the server's `actions` organization (see GitHub's
967
1049
  [Using the latest version of the official bundled actions](https://docs.github.com/en/enterprise-server@latest/admin/managing-github-actions-for-your-enterprise/managing-access-to-actions-from-githubcom/using-the-latest-version-of-the-official-bundled-actions)).
1050
+ - **Autofix workflow:** `tailor setup ci autofix` is not supported.
968
1051
  - **Environment settings:** sign `gh` in to the server
969
1052
  (`gh auth login --hostname <host>`) before you run `tailor setup ci env` in a
970
1053
  clone of the repository, so that the `gh` commands it prints and its Terraform
@@ -1031,24 +1114,30 @@ writing anything. It reports when a workflow file is missing or its SDK-managed
1031
1114
  parts were edited by hand, a job or step of yours uses the reserved `tailor-`
1032
1115
  prefix, a newer template is available, `tailor.config.ts` is no longer under the recorded
1033
1116
  `--dir`, or the repository default branch no longer matches a branch target's
1034
- trigger. It exits non-zero when it finds drift, so you can run it in CI. Each
1117
+ trigger. It audits the autofix workflow the same way, along with each app
1118
+ directory it runs `tailor generate` in. It also reports a `.github/tailor-sdk.lock` left by an older setup,
1119
+ with the files it generated that `.github/tailor.lock` does not track, since
1120
+ the workflows among them still run, and prints the `git rm` command that
1121
+ removes them.
1122
+ It exits non-zero when it finds drift, so you can run it in CI. Each
1035
1123
  finding names a stable rule key for future suppression. Run
1036
1124
  [`tailor setup update`](#updating-the-generated-workflow) to regenerate the
1037
- targets it reports.
1125
+ workflows it reports.
1038
1126
 
1039
1127
  Workflows generated by `setup ci branch`, `setup ci tag`, and `setup ci preview`
1040
1128
  self-audit: each contains a `tailor-drift-check` step that
1041
1129
  runs the check in CI. Preview workflows run it alongside each preview deploy,
1042
1130
  so pull requests that deploy no preview (drafts with `--require ready`, fork
1043
- PRs, and unlabeled PRs with `--require label`) skip the check. A single run audits every target
1131
+ PRs, and unlabeled PRs with `--require label`) skip the check. A single run audits every workflow
1044
1132
  recorded in `.github/tailor.lock`.
1045
1133
 
1046
1134
  Drift findings are advisory by default. Set the repository variable
1047
1135
  `TAILOR_PLATFORM_FAIL_ON_DRIFT` to `true` to make unsuppressed findings fail
1048
1136
  the job. Execution and configuration errors fail regardless of this variable.
1049
1137
 
1050
- `check` compares only the generated files, `.github/tailor.lock`, and the
1051
- config; it does not read the GitHub Environment secrets and variables, so it
1138
+ `check` compares only the generated files, `.github/tailor.lock` (and a
1139
+ leftover `.github/tailor-sdk.lock`), and the config; it does not read the
1140
+ GitHub Environment secrets and variables, so it
1052
1141
  runs the same on your own machine and in CI. Run `tailor setup ci env` to list
1053
1142
  what each environment needs.
1054
1143
 
@@ -1072,10 +1161,10 @@ are detected again, and the parts that follow your config — the migration drif
1072
1161
  check, seed validation, and ERD preview namespaces — are derived from the
1073
1162
  current `tailor.config.ts`.
1074
1163
 
1075
- A target that cannot be regenerated, for example because you edited a managed
1164
+ A workflow that cannot be regenerated, for example because you edited a managed
1076
1165
  part, does not stop the others: `update` regenerates the rest, then lists the
1077
- targets it could not update and exits non-zero. Revert the edit, or run
1078
- `tailor setup update --force` to reset the managed parts of every target.
1166
+ workflows it could not update and exits non-zero. Revert the edit, or run
1167
+ `tailor setup update --force` to reset the managed parts of every workflow.
1079
1168
 
1080
1169
  To change a flag for one target, re-run its `setup ci` subcommand with the new
1081
1170
  flags. `.github/tailor.lock` records them, and later updates reuse them.
@@ -204,10 +204,10 @@ onNamespaceLoaded(context) {
204
204
 
205
205
  **Returns** (`GeneratorResult`):
206
206
 
207
- | Field | Type | Description |
208
- | -------- | ------------------------------------------------------ | ------------------------ |
209
- | `files` | `Array<{ path, content, skipIfExists?, executable? }>` | Files to write to disk |
210
- | `errors` | `string[]?` | Error messages to report |
207
+ | Field | Type | Description |
208
+ | -------- | ----------------------------------------- | ------------------------ |
209
+ | `files` | `Array<{ path, content, skipIfExists? }>` | Files to write to disk |
210
+ | `errors` | `string[]?` | Error messages to report |
211
211
 
212
212
  **Use cases**:
213
213
 
package/docs/runtime.md CHANGED
@@ -133,7 +133,7 @@ The runtime entry re-exports the following namespaces. Detailed signatures, para
133
133
  - `aigateway` — AI Gateway URL resolution (`get`)
134
134
  - `logger` — structured logging with severity and attributes; the message is written to standard output, the full entry with its attributes is exported over OpenTelemetry where the attributes are queryable (`debug`, `info`, `warn`, `error`, `setAttributes`)
135
135
 
136
- ## Testing
136
+ ## Testing (Beta)
137
137
 
138
138
  `@tailor-platform/sdk/vitest` ships mock controllers for every runtime namespace. Pair them with the `tailor-runtime` Vitest environment so your unit tests run against the same wrappers your production code does. Each controller is a factory — acquire it with a `using` declaration and its state is reset automatically when the test scope exits (no `beforeEach(() => mock.reset())` needed). Requires TypeScript ≥ 5.2 and a runtime with `Symbol.dispose` (Node ≥ 20.4; the SDK targets Node ≥ 22).
139
139
 
@@ -334,6 +334,8 @@ oauth2Clients: {
334
334
  },
335
335
  ```
336
336
 
337
+ Client names must be 3 to 63 lowercase letters, digits, or hyphens, starting and ending with a letter or digit.
338
+
337
339
  **redirectURIs**: Allowed redirect URIs after authentication.
338
340
 
339
341
  **description**: Optional description of the client.
@@ -505,7 +505,7 @@ interface WebhookContext<T = unknown> {
505
505
  body: T; // Parsed request body
506
506
  headers: Record<string, string>; // Request headers
507
507
  method: "POST" | "GET" | "PUT" | "DELETE"; // HTTP method
508
- rawBody: string; // Raw request body as string
508
+ rawBody: string; // Raw request body, base64-encoded
509
509
  }
510
510
  ```
511
511
 
@@ -513,11 +513,12 @@ interface WebhookContext<T = unknown> {
513
513
 
514
514
  ```typescript
515
515
  import { createExecutor, incomingWebhookTrigger } from "@tailor-platform/sdk";
516
+ import { secretmanager } from "@tailor-platform/sdk/runtime";
516
517
 
517
- interface StripeWebhook {
518
+ type StripeWebhook = {
518
519
  type: string;
519
520
  data: { object: { id: string; amount: number } };
520
- }
521
+ };
521
522
 
522
523
  export default createExecutor({
523
524
  name: "stripe-webhook",
@@ -527,8 +528,12 @@ export default createExecutor({
527
528
  }>(),
528
529
  operation: {
529
530
  kind: "function",
530
- body: async ({ body, headers }) => {
531
- const signature = headers["stripe-signature"];
531
+ body: async ({ body, headers, rawBody }) => {
532
+ const secret = await secretmanager.getSecret("api-keys", "stripe-webhook-secret");
533
+ // Implement verifyStripeSignature following https://docs.stripe.com/webhooks?verify=verify-manually#verify-manually
534
+ if (!(await verifyStripeSignature(headers["stripe-signature"], rawBody, secret))) {
535
+ throw new Error("Invalid Stripe signature");
536
+ }
532
537
  console.log(`Received ${body.type} event`);
533
538
  // Process webhook...
534
539
  },
@@ -536,6 +541,8 @@ export default createExecutor({
536
541
  });
537
542
  ```
538
543
 
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
+
539
546
  **With custom response:**
540
547
 
541
548
  ```typescript
@@ -133,6 +133,8 @@ defineIdp("my-idp", {
133
133
  });
134
134
  ```
135
135
 
136
+ Client names must be 3 to 63 lowercase letters, digits, or hyphens, starting and ending with a letter or digit.
137
+
136
138
  ### userAuthPolicy
137
139
 
138
140
  User authentication policy. Controls password requirements, the identifier used for login, allowed email domains, and social login providers. Every field is optional. The boolean options default to disabled, and the password length fields default to a minimum of 6 and a maximum of 4096.
@@ -177,7 +177,11 @@ db.string().unique();
177
177
 
178
178
  `.unique()` and `.index()` also work on a field inside a `db.object()` that is not an array: with `.unique()` the value must be unique across rows, while `.index()` only indexes it and still allows duplicates. Inside an array of objects (`db.object(..., { array: true })`) the platform does not reject duplicate values, so both are rejected there with an error, as on an array field.
179
179
 
180
- A project whose `db.object()` field already uses `.unique()` or `.index()` was deployed with the setting stored as off, so its next `tailor deploy` stops with `MIGRATION_REMOTE_DRIFT`, and `tailor tailordb migration validate` fails the same way. `tailor tailordb migration generate` reports no differences. Run `tailor deploy --no-schema-check` once to apply the setting. If stored rows already hold duplicate values for a field that gains `.unique()`, that deploy fails and the schema stays unchanged until the duplicates are resolved.
180
+ `.unique()` and `.index()` cannot be set on a `db.object()` field itself, whether it is a table field or a member of another `db.object()`, because the platform cannot index an object value.
181
+
182
+ A project that already uses `.unique()` or `.index()` on a field inside a `db.object()` was deployed with the setting stored as off, so its next `tailor deploy` stops with `MIGRATION_REMOTE_DRIFT`, and `tailor tailordb migration validate` fails the same way. `tailor tailordb migration generate` reports no differences. Run `tailor deploy --no-schema-check` once to apply the setting. If stored rows already hold duplicate values for a field that gains `.unique()`, that deploy fails and the schema stays unchanged until the duplicates are resolved.
183
+
184
+ A project that sets `.unique()` or `.index()` on a member that is itself a `db.object()` now fails with an error naming the field. Remove the modifier. Then, in a namespace with `migration.directory`, run `tailor tailordb migration generate` and `tailor deploy --no-schema-check` once; later deploys need no flag.
181
185
 
182
186
  ### Relations
183
187
 
@@ -239,7 +243,7 @@ const order = db.table("Order", {
239
243
  });
240
244
  ```
241
245
 
242
- A relation inside `db.object()` that points at its own table is not yet handled by `tailor seed apply` or by the data copy a table rename generates. Both write rows in batches, and the platform rejects a row whose parent is in the same or a later batch.
246
+ A relation inside `db.object()` can point at its own table, for example `links.parentID` on `Node`. `tailor seed apply` inserts a row before the rows that point at it, in whatever order the seed data lists them, and follows every element of an array. This needs a unique `id` on every row, and a reference must match the referenced value exactly, including letter case. Otherwise the rows can be inserted in the order the file lists them. The data copy that a table rename generates inserts such references as null and restores them once every row exists.
243
247
 
244
248
  Create relations against different fields using `toward.key`:
245
249
 
@@ -259,6 +263,11 @@ const userProfile = db.table("UserProfile", {
259
263
  `userEmail` does not end in `ID`, `Id`, or `id`, so this example specifies the forward relation
260
264
  name with `toward.as`.
261
265
 
266
+ A relation field must have the same type as the field it points at: `db.uuid()` for the default
267
+ `id`, and the type of the `toward.key` field otherwise. The SDK rejects a relation whose types
268
+ differ, such as a `db.string()` field related to `id`. A custom `toward.key` must be unique,
269
+ through `.unique()` or a one-to-one relation.
270
+
262
271
  Customize relation names using `toward.as` / `backward` options:
263
272
 
264
273
  ```typescript
@@ -769,7 +778,7 @@ db.table("User", {
769
778
 
770
779
  **Warning**: Do not use `unsafeAllowAllTypePermission` or `unsafeAllowAllGqlPermission` in production environments as they effectively disable authorization checks.
771
780
 
772
- ## Migrations
781
+ ## Migrations (Beta)
773
782
 
774
783
  When you change a TailorDB table definition, the SDK can generate a migration that captures the diff and, for breaking changes, runs a data transformation script during `tailor deploy`. See the [TailorDB Migrations guide](./migration.md) for the full workflow, configuration, supported change types, team coordination, and troubleshooting.
775
784