@tailor-platform/sdk 2.27.0 → 2.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +109 -0
- package/README.md +0 -8
- package/agent-skills/tailor/SKILL.md +4 -2
- package/dist/application-dalGHdrI.mjs +1 -0
- package/dist/application-rWYDAfNU.mjs +200 -0
- package/dist/application-rWYDAfNU.mjs.map +1 -0
- package/dist/cli/cache/bundle-cache.d.mts +1 -0
- package/dist/cli/commands/executor/get.d.mts +2 -1
- package/dist/cli/commands/executor/jobs.d.mts +2 -1
- package/dist/cli/commands/executor/trigger.d.mts +2 -1
- package/dist/cli/commands/function/get.d.mts +2 -1
- package/dist/cli/commands/function/list.d.mts +2 -1
- package/dist/cli/commands/organization/folder/create.d.mts +2 -1
- package/dist/cli/commands/organization/folder/delete.d.mts +2 -1
- package/dist/cli/commands/organization/folder/get.d.mts +2 -1
- package/dist/cli/commands/organization/folder/list.d.mts +2 -1
- package/dist/cli/commands/organization/folder/update.d.mts +2 -1
- package/dist/cli/commands/organization/get.d.mts +2 -1
- package/dist/cli/commands/organization/tree.d.mts +2 -1
- package/dist/cli/commands/organization/update.d.mts +2 -1
- package/dist/cli/commands/show.d.mts +2 -1
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +2 -1
- package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +3 -1
- package/dist/cli/commands/workflow/executions.d.mts +2 -1
- package/dist/cli/commands/workflow/get.d.mts +2 -1
- package/dist/cli/commands/workflow/start.d.mts +2 -1
- package/dist/cli/commands/workspace/app/health.d.mts +2 -1
- package/dist/cli/commands/workspace/app/list.d.mts +2 -1
- package/dist/cli/commands/workspace/create.d.mts +5 -2
- package/dist/cli/commands/workspace/delete.d.mts +2 -1
- package/dist/cli/commands/workspace/get.d.mts +2 -1
- package/dist/cli/commands/workspace/restore.d.mts +2 -1
- package/dist/cli/commands/workspace/user/invite.d.mts +2 -1
- package/dist/cli/commands/workspace/user/list.d.mts +2 -1
- package/dist/cli/commands/workspace/user/remove.d.mts +2 -1
- package/dist/cli/commands/workspace/user/update.d.mts +2 -1
- package/dist/cli/lib.d.mts +1 -1
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.d.mts +7 -0
- package/dist/cli/main.mjs +55 -42
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/query/index.d.mts +2 -1
- package/dist/cli/shared/args.d.mts +4 -2
- package/dist/cli/shared/client.d.mts +6 -1
- package/dist/cli/shared/context.d.mts +2 -1
- package/dist/cli/shared/logger.d.mts +5 -2
- package/dist/cli/shared/readonly-guard.d.mts +2 -1
- package/dist/cli/shared/seed-context.d.mts +5 -0
- package/dist/cli/shared/type-generator.d.mts +2 -1
- package/dist/cli/ts-hook.mjs +15 -11
- package/dist/completion/zsh-worker.zsh +275 -19
- package/dist/configure/config/types.d.mts +80 -1
- package/dist/configure/services/aigateway/types.d.mts +2 -1
- package/dist/configure/services/auth/types.d.mts +2 -1
- package/dist/configure/services/executor/executor.d.mts +2 -1
- package/dist/configure/services/executor/operation.d.mts +2 -1
- package/dist/configure/services/executor/trigger/event.d.mts +2 -1
- package/dist/configure/services/executor/trigger/schedule.d.mts +2 -1
- package/dist/configure/services/http-adapter/http-adapter.d.mts +2 -1
- package/dist/configure/services/idp/permission.d.mts +2 -1
- package/dist/configure/services/idp/types.d.mts +2 -1
- package/dist/configure/services/resolver/permission.d.mts +2 -1
- package/dist/configure/services/resolver/resolver.d.mts +2 -1
- package/dist/configure/services/secrets/types.d.mts +2 -1
- package/dist/configure/services/staticwebsite/types.d.mts +2 -1
- package/dist/configure/services/tailordb/permission.d.mts +2 -1
- package/dist/configure/services/tailordb/schema.d.mts +4 -3
- package/dist/configure/services/tailordb/types.d.mts +12 -1
- package/dist/configure/services/workflow/execution-policy.types.d.mts +2 -1
- package/dist/configure/services/workflow/job.d.mts +2 -1
- package/dist/configure/services/workflow/wait-point.d.mts +2 -1
- package/dist/configure/types/field.types.d.mts +2 -1
- package/dist/configure/types/permission-operand.types.d.mts +2 -1
- package/dist/configure/types/type.d.mts +2 -1
- package/dist/{crashreport-DFpRn-LS.mjs → crashreport-BAG8c7hB.mjs} +4 -4
- package/dist/{crashreport-DFpRn-LS.mjs.map → crashreport-BAG8c7hB.mjs.map} +1 -1
- package/dist/crashreport-BcXuocwI.mjs +1 -0
- package/dist/{errors-CpvSChyL.mjs → errors-D3qpNHR6.mjs} +2 -2
- package/dist/{errors-CpvSChyL.mjs.map → errors-D3qpNHR6.mjs.map} +1 -1
- package/dist/kysely-type-BWMfV301.mjs +48 -0
- package/dist/kysely-type-BWMfV301.mjs.map +1 -0
- package/dist/logger-DuaT2zY3.mjs +9 -0
- package/dist/logger-DuaT2zY3.mjs.map +1 -0
- package/dist/package-json-D1BRkjtr.mjs +1 -0
- package/dist/parser/service/tailordb/types.d.mts +3 -1
- package/dist/plugin/builtin/enum-constants/index.d.mts +2 -1
- package/dist/plugin/builtin/file-utils/index.d.mts +2 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +2 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
- package/dist/plugin/builtin/seed/index.d.mts +11 -1
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/register-ts-hook-CkfKqhJT.mjs +1014 -0
- package/dist/register-ts-hook-CkfKqhJT.mjs.map +1 -0
- package/dist/runtime/aigateway.mjs +1 -1
- package/dist/runtime/authconnection.mjs +1 -1
- package/dist/runtime/context.d.mts +2 -1
- package/dist/runtime/context.mjs +1 -1
- package/dist/runtime/date.d.mts +2 -1
- package/dist/runtime/field-parse.d.mts +2 -1
- package/dist/runtime/file.d.mts +2 -1
- package/dist/runtime/file.mjs +1 -1
- package/dist/runtime/globals.d.mts +2 -1
- package/dist/runtime/iconv.mjs +1 -1
- package/dist/runtime/idp.mjs +1 -1
- package/dist/runtime/logger.mjs +1 -1
- package/dist/runtime/secretmanager.mjs +1 -1
- package/dist/runtime/types.d.mts +2 -1
- package/dist/runtime/workflow.d.mts +2 -1
- package/dist/runtime/workflow.mjs +1 -1
- package/dist/schema-B6hJQWp6.mjs.map +1 -1
- package/dist/seed/index.d.mts +17 -4
- package/dist/seed/index.mjs +6 -6
- package/dist/seed/index.mjs.map +1 -1
- package/dist/seed-C3P_T_Eh.mjs.map +1 -1
- package/dist/{service-Cc7OY0Oh.mjs → service-CETr0AKY.mjs} +3 -3
- package/dist/service-CETr0AKY.mjs.map +1 -0
- package/dist/service-DREWLYxD.mjs +1 -0
- package/dist/{service-DFmt9UJP.mjs → service-b1g22NN9.mjs} +2 -2
- package/dist/{service-DFmt9UJP.mjs.map → service-b1g22NN9.mjs.map} +1 -1
- package/dist/service_pb-Bbu2QSIr.mjs +2 -0
- package/dist/service_pb-Bbu2QSIr.mjs.map +1 -0
- package/dist/service_pb-urxAIYHT.mjs +1 -0
- package/dist/tailor-proto/src/tailor/v1/events_pb.d.mts +53 -1
- package/dist/tailor-proto/src/tailor/v1/events_resource_pb.d.mts +33 -0
- package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +0 -8
- package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +18 -1
- package/dist/tailor-proto/src/tailor/v1/tailordb_resource_pb.d.mts +4 -0
- package/dist/telemetry-DpkFGBmu.mjs +1 -0
- package/dist/{telemetry-Bklv9kQY.mjs → telemetry-Xk7J829P.mjs} +2 -2
- package/dist/{telemetry-Bklv9kQY.mjs.map → telemetry-Xk7J829P.mjs.map} +1 -1
- package/dist/types/tailordb.generated.d.mts +2 -0
- package/dist/vitest/index.mjs +1 -1
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/mock-kysely.d.mts +2 -1
- package/dist/vitest/mocks/aigateway.d.mts +2 -1
- package/dist/vitest/mocks/authconnection.d.mts +2 -1
- package/dist/vitest/mocks/file.d.mts +2 -1
- package/dist/vitest/mocks/iconv.d.mts +2 -1
- package/dist/vitest/mocks/idp.d.mts +2 -1
- package/dist/vitest/mocks/logger.d.mts +2 -1
- package/dist/vitest/mocks/secretmanager.d.mts +2 -1
- package/dist/vitest/mocks/tailordb-pglite.d.mts +2 -1
- package/dist/vitest/mocks/tailordb.d.mts +2 -1
- package/dist/vitest/mocks/workflow.d.mts +3 -1
- package/dist/vitest/pglite-kysely.d.mts +2 -1
- package/dist/vitest/workflow-local.d.mts +2 -1
- package/dist/{workspace_resource_pb-ChWejcj0.mjs → workspace_resource_pb-CaoM2npP.mjs} +2 -2
- package/dist/{workspace_resource_pb-ChWejcj0.mjs.map → workspace_resource_pb-CaoM2npP.mjs.map} +1 -1
- package/docs/cli/application.md +21 -3
- package/docs/cli/data.md +105 -0
- package/docs/cli/secret.md +6 -6
- package/docs/cli/tailordb.md +52 -16
- package/docs/cli/user.md +37 -7
- package/docs/cli/workspace.md +9 -1
- package/docs/cli-reference.md +36 -3
- package/docs/configuration.md +62 -2
- package/docs/github-actions.md +179 -13
- package/docs/multi-environment.md +24 -0
- package/docs/plugin/custom.md +1 -1
- package/docs/services/idp.md +1 -1
- package/docs/services/resolver.md +1 -58
- package/docs/services/tailordb-migration.md +80 -12
- package/docs/services/tailordb.md +17 -4
- package/docs/services/workflow.md +2 -2
- package/docs/testing.md +3 -2
- package/package.json +22 -22
- package/dist/application-DFeuELRo.mjs +0 -200
- package/dist/application-DFeuELRo.mjs.map +0 -1
- package/dist/application-nT_4a5HO.mjs +0 -1
- package/dist/crashreport-CBaRJl5h.mjs +0 -1
- package/dist/kysely-type-RDX59E1j.mjs +0 -48
- package/dist/kysely-type-RDX59E1j.mjs.map +0 -1
- package/dist/logger-Db-YRTwK.mjs +0 -9
- package/dist/logger-Db-YRTwK.mjs.map +0 -1
- package/dist/package-json-CmqhDJ__.mjs +0 -1
- package/dist/register-ts-hook-D6KXrGrB.mjs +0 -1009
- package/dist/register-ts-hook-D6KXrGrB.mjs.map +0 -1
- package/dist/service-Cc7OY0Oh.mjs.map +0 -1
- package/dist/service-sH2MZ4_W.mjs +0 -1
- package/dist/service_pb-Dw2ilc1O.mjs +0 -2
- package/dist/service_pb-Dw2ilc1O.mjs.map +0 -1
- package/dist/service_pb-GDOqfwb6.mjs +0 -1
- package/dist/telemetry-DXHP3VVi.mjs +0 -1
package/docs/github-actions.md
CHANGED
|
@@ -35,7 +35,8 @@ tailor setup ci tag --name my-app-prod \
|
|
|
35
35
|
|
|
36
36
|
After running the command, follow the **Next steps** printed to the terminal:
|
|
37
37
|
run `tailor setup ci env` to get the commands that set the secrets and
|
|
38
|
-
variables each GitHub Environment needs
|
|
38
|
+
variables each GitHub Environment needs, and `tailor setup ci env --check` to
|
|
39
|
+
confirm none is missing (see
|
|
39
40
|
[Setting secrets and variables](#setting-secrets-and-variables)), then commit
|
|
40
41
|
the generated files.
|
|
41
42
|
|
|
@@ -98,7 +99,8 @@ The generated workflow builds one self-contained ERD viewer HTML file for each
|
|
|
98
99
|
owned TailorDB namespace in `tailor.config.ts`. The viewer compares the pull
|
|
99
100
|
request merge result with the base branch, can switch between the current schema
|
|
100
101
|
and highlighted diff, uploads the HTML files as unarchived Actions artifacts,
|
|
101
|
-
and upserts a PR comment with artifact links.
|
|
102
|
+
and upserts a PR comment with artifact links. On GitHub Enterprise Server, also
|
|
103
|
+
pass `--ghes` (see [GitHub Enterprise Server](#github-enterprise-server)).
|
|
102
104
|
|
|
103
105
|
ERD preview does not use Tailor Platform credentials. Fork pull requests still
|
|
104
106
|
build artifacts, but the comment step is skipped because fork tokens cannot
|
|
@@ -194,6 +196,26 @@ the `plan` job as well as `deploy`, because `plan` must enter the environment to
|
|
|
194
196
|
read the variable. (A token-based read that lets `plan` run without entering the
|
|
195
197
|
environment is planned.)
|
|
196
198
|
|
|
199
|
+
## Package manager
|
|
200
|
+
|
|
201
|
+
The generated workflow sets up your package manager, installs dependencies with
|
|
202
|
+
it, and runs `tailor` through it. `setup ci` detects the package manager from the
|
|
203
|
+
lockfile at the repository root (`pnpm-lock.yaml`, `yarn.lock`, `bun.lock`,
|
|
204
|
+
`bun.lockb`, `package-lock.json`, or `npm-shrinkwrap.json`), or, when there is
|
|
205
|
+
none, from the `packageManager` or `devEngines.packageManager` field of the root
|
|
206
|
+
`package.json`. When neither names one, `setup ci` stops instead of guessing.
|
|
207
|
+
|
|
208
|
+
Pass `--package-manager` (`pnpm`, `npm`, `yarn`, or `bun`) to choose it
|
|
209
|
+
yourself, for example to generate the workflow before the lockfile exists:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
tailor setup ci branch --name my-app-stg --package-manager pnpm
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The workflow installs dependencies at the repository root, so commit the
|
|
216
|
+
lockfile there before it runs. `tailor setup update` keeps a package manager
|
|
217
|
+
chosen with `--package-manager` and detects it again otherwise.
|
|
218
|
+
|
|
197
219
|
## Generated files
|
|
198
220
|
|
|
199
221
|
Running a workflow setup subcommand creates or updates:
|
|
@@ -244,8 +266,8 @@ Everything else is yours, and re-running `setup` keeps it:
|
|
|
244
266
|
- **These inputs of managed steps:** `ignore` on `tailor-generate-check` and
|
|
245
267
|
`tailor-drift-check`, `fail-on-drift` on `tailor-drift-check`,
|
|
246
268
|
`install-command` on `tailor-install`, `node-version-file` on
|
|
247
|
-
`tailor-setup`, `label` on `tailor-plan`,
|
|
248
|
-
`tailor-notify`.
|
|
269
|
+
`tailor-setup`, `label` on `tailor-plan`, `ttl` on `tailor-preview-deploy`,
|
|
270
|
+
and `user-mapping` on `tailor-notify`.
|
|
249
271
|
- **Your own jobs in the `needs` of `tailor-result` and
|
|
250
272
|
`tailor-preview-result`**, so they count toward the workflow's result (see
|
|
251
273
|
[Requiring the workflow in branch protection](#requiring-the-workflow-in-branch-protection)).
|
|
@@ -276,6 +298,17 @@ The job is skipped whenever `tailor-preview-deploy` is skipped: when a pull
|
|
|
276
298
|
request is closed, for draft and fork pull requests, and for unlabeled ones with
|
|
277
299
|
`--require-preview-label`.
|
|
278
300
|
|
|
301
|
+
A preview workspace expires 7 days (`ttl: 7d` on `tailor-preview-deploy`) after
|
|
302
|
+
the last push to its pull request. When a pull request is closed,
|
|
303
|
+
`tailor-preview-cleanup` deletes its workspace and also deletes the other
|
|
304
|
+
expired preview workspaces of the same workspace name in the folder
|
|
305
|
+
(`TAILOR_PLATFORM_FOLDER_ID`, or directly under the organization when unset), so
|
|
306
|
+
a workspace whose own cleanup never ran does not stay forever. A pull request
|
|
307
|
+
that stays idle past the `ttl` can have its workspace deleted while it is still
|
|
308
|
+
open; the next push creates a fresh one. Change `ttl` to keep previews longer or
|
|
309
|
+
shorter. Workflows generated before this was added get these settings the next
|
|
310
|
+
time you run `tailor setup update`.
|
|
311
|
+
|
|
279
312
|
Each new preview workflow run for a pull request, such as after a push or when
|
|
280
313
|
the pull request is closed, cancels the run still in progress for it, including
|
|
281
314
|
your jobs, so they do not keep running against a workspace that the new run
|
|
@@ -448,14 +481,18 @@ protection rules no longer guard your deploys.
|
|
|
448
481
|
Environment the generated workflows use, the commands that create the
|
|
449
482
|
environment (only when it does not exist yet) and set its secrets and
|
|
450
483
|
variables. It is read-only, so re-run it whenever you add a target. When the
|
|
451
|
-
`origin` remote points at github.com, the output names that repository
|
|
452
|
-
|
|
453
|
-
|
|
484
|
+
`origin` remote points at github.com, the output names that repository;
|
|
485
|
+
otherwise it names the repository `gh repo view` reports for the current
|
|
486
|
+
directory, with its host on GitHub Enterprise Server. Either way the commands
|
|
487
|
+
work from any directory. When neither names a repository, `gh` resolves it from
|
|
488
|
+
the current directory when you run the commands, and the Terraform output leaves
|
|
489
|
+
it as a placeholder.
|
|
454
490
|
|
|
455
491
|
```bash
|
|
456
492
|
tailor setup ci env # gh CLI commands (default)
|
|
457
493
|
tailor setup ci env --format terraform # Terraform for the integrations/github provider
|
|
458
494
|
tailor setup ci env --environment my-app-stg # only one environment (repeat for several)
|
|
495
|
+
tailor setup ci env --check # check what is registered in GitHub (see below)
|
|
459
496
|
```
|
|
460
497
|
|
|
461
498
|
The list follows what each generated workflow actually reads:
|
|
@@ -497,6 +534,30 @@ protection settings (reviewers, wait timer, branch policy), so importing an
|
|
|
497
534
|
environment keeps the approval gate you configured; remove the `lifecycle` block
|
|
498
535
|
to manage those settings in Terraform instead.
|
|
499
536
|
|
|
537
|
+
### Checking what is registered
|
|
538
|
+
|
|
539
|
+
`tailor setup ci env --check` reads GitHub with `gh` and reports, for each
|
|
540
|
+
environment, which of these entries are registered. It fails when a required
|
|
541
|
+
entry is missing, reports missing optional entries without failing, and prints
|
|
542
|
+
the `gh` commands that set only the missing entries, with where each value comes
|
|
543
|
+
from. It changes nothing, and it checks names only, since GitHub never returns
|
|
544
|
+
secret values.
|
|
545
|
+
|
|
546
|
+
- An entry set on the repository, or on the organization and shared with the
|
|
547
|
+
repository, counts as registered, because the workflow reads it from there when
|
|
548
|
+
the environment does not set it. The report says where each entry was found.
|
|
549
|
+
- An entry registered as the other kind, such as `TAILOR_PLATFORM_WORKSPACE_ID`
|
|
550
|
+
set as a secret, is reported as missing, because the workflow does not read it.
|
|
551
|
+
`TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID` set as a secret still counts, with a
|
|
552
|
+
reminder to move it to a variable.
|
|
553
|
+
- `gh` must be installed and logged in (`gh auth login`) as an account with write
|
|
554
|
+
access to the repository, which listing secrets and variables requires. GitHub
|
|
555
|
+
answers 404 for a private repository the account cannot see, so the check
|
|
556
|
+
reports that as an access problem, not as missing entries.
|
|
557
|
+
|
|
558
|
+
`--environment` narrows the check the same way. `--check` cannot be combined with
|
|
559
|
+
`--format terraform`.
|
|
560
|
+
|
|
500
561
|
## GitHub Environments (approval gate)
|
|
501
562
|
|
|
502
563
|
Both the `plan` and `deploy` jobs are associated with a GitHub Environment — the
|
|
@@ -553,6 +614,67 @@ plan job also enters the environment, allow `refs/pull/*/merge` as well so pull
|
|
|
553
614
|
request plans keep running, and note that dry runs from other branches are then
|
|
554
615
|
rejected too.
|
|
555
616
|
|
|
617
|
+
## Seeding the workspace after deploy
|
|
618
|
+
|
|
619
|
+
Pass `--seed` to `setup ci branch`, `setup ci tag`, or `setup ci preview` to seed
|
|
620
|
+
the workspace with `tailor seed apply` right after each deploy. Add
|
|
621
|
+
`--seed-dataset <name>` (repeatable, implies `--seed`) to apply
|
|
622
|
+
[datasets](https://github.com/tailor-platform/sdk/tree/main/packages/sdk-plugin-seed#datasets)
|
|
623
|
+
on top of the base seed data:
|
|
624
|
+
|
|
625
|
+
```bash
|
|
626
|
+
tailor setup ci branch --seed-dataset stg
|
|
627
|
+
tailor setup ci preview --region us-west --seed-dataset preview
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
The deploy job gains a `tailor-seed` step after the deploy step. Branch targets
|
|
631
|
+
validate seed data before deploy and also in the PR or dry-run plan job; tag
|
|
632
|
+
targets validate it in the plan job before deploy. Both use
|
|
633
|
+
`tailor seed validate --upsert` with the selected datasets to check the `id`
|
|
634
|
+
and required fields that `seed apply --upsert` needs. Preview targets validate
|
|
635
|
+
and apply the data after deploy.
|
|
636
|
+
|
|
637
|
+
| Target | Seeds with | Effect |
|
|
638
|
+
| ----------- | ------------------------------------ | ----------------------------------------------------------------------------- |
|
|
639
|
+
| branch, tag | `tailor seed apply --upsert` | The fields of each committed seed row are written; other rows are kept |
|
|
640
|
+
| preview | `tailor seed apply --truncate --yes` | The preview workspace is emptied, IdP users included, and seeded from scratch |
|
|
641
|
+
|
|
642
|
+
Setup stops unless the config uses `seedPlugin` with `machineUserName`, which
|
|
643
|
+
names the machine user that seeds, and an existing `<distPath>/data/` directory.
|
|
644
|
+
Every `--seed-dataset` must name an entry of
|
|
645
|
+
the `seedPlugin` `datasets` option or a directory under `<distPath>/data/`.
|
|
646
|
+
Commit the dataset directories the workflow seeds: a gitignored dataset such as
|
|
647
|
+
a per-developer `local/` is not in the CI checkout.
|
|
648
|
+
Install `@tailor-platform/sdk-plugin-seed` so the `tailor seed` commands resolve
|
|
649
|
+
in CI. For branch and tag targets, use a version that supports
|
|
650
|
+
`tailor seed validate --upsert`; update the setup and seed plugins together.
|
|
651
|
+
Give every TailorDB seed row an `id` and
|
|
652
|
+
every field its table requires: `--upsert` matches rows by id, so run
|
|
653
|
+
`tailor seed fill` and commit the result.
|
|
654
|
+
Seeding is available for a target that deploys one app.
|
|
655
|
+
|
|
656
|
+
Before enabling it, note that:
|
|
657
|
+
|
|
658
|
+
- Every branch or tag deploy writes the fields of the committed seed rows over
|
|
659
|
+
the workspace, `_User` rows and their passwords included, so an edit to one of
|
|
660
|
+
those fields in the workspace is undone. Each row is updated like any other update: update hooks
|
|
661
|
+
and validation run, `updatedAt` changes, and executors with
|
|
662
|
+
`recordUpdatedTrigger` fire once per seeded row on every deploy.
|
|
663
|
+
- Every preview deploy deletes the data reviewers added to the preview
|
|
664
|
+
workspace. That is every push, and with `--require-preview-label` also every
|
|
665
|
+
label added to the pull request, since each one redeploys the preview.
|
|
666
|
+
- A seed failure fails the deploy job and its notification, although the deploy
|
|
667
|
+
itself went through.
|
|
668
|
+
- The step shares the deploy job's timeout. IdP users take about a second each.
|
|
669
|
+
- Steps you added after the deploy step stay right after it, so they run before
|
|
670
|
+
`tailor-seed`. Move a step below `tailor-seed` when it needs the seeded data,
|
|
671
|
+
and move it again if you regenerate without `--seed` and then with it.
|
|
672
|
+
- `tailor-seed` is an SDK-managed step. To seed another way (a different mode,
|
|
673
|
+
`--skip-idp`, a condition), leave `--seed` off and add your own step.
|
|
674
|
+
|
|
675
|
+
Re-run `setup ci` with the flags each time you regenerate the workflow; `setup
|
|
676
|
+
update` keeps them.
|
|
677
|
+
|
|
556
678
|
## Monorepo setup
|
|
557
679
|
|
|
558
680
|
For a monorepo where your SDK app lives in a subdirectory, pass `--dir`:
|
|
@@ -673,8 +795,9 @@ a branch target deploys only its target branch, so use Option 1 there.
|
|
|
673
795
|
- **Schema and data are not rolled back.** If the older config expects a schema
|
|
674
796
|
state that no longer exists, the plan may show errors. In that case, review
|
|
675
797
|
the diff carefully before proceeding.
|
|
676
|
-
- **Seed data** is not
|
|
677
|
-
|
|
798
|
+
- **Seed data** is not rolled back. Without `--seed`, the pipeline does not
|
|
799
|
+
touch it; with `--seed`, deploying an older commit seeds the rows committed
|
|
800
|
+
there on top of the current data.
|
|
678
801
|
- **Static websites** are not yet integrated into the generated pipeline.
|
|
679
802
|
Static asset rollbacks must be performed manually.
|
|
680
803
|
|
|
@@ -702,6 +825,48 @@ tailor setup ci env
|
|
|
702
825
|
|
|
703
826
|
Commit both workflow files and `.github/tailor.lock`.
|
|
704
827
|
|
|
828
|
+
## GitHub Enterprise Server
|
|
829
|
+
|
|
830
|
+
The generated workflows also run on GitHub Enterprise Server. Prepare the
|
|
831
|
+
server and its runners first:
|
|
832
|
+
|
|
833
|
+
- **Runners:** GitHub Enterprise Server has no GitHub-hosted runners. Change
|
|
834
|
+
`runs-on` on the managed jobs to the labels of your self-hosted runners;
|
|
835
|
+
re-running `setup` keeps it (see
|
|
836
|
+
[Customizing the generated workflow](#customizing-the-generated-workflow)).
|
|
837
|
+
The runners need Actions runner 2.327.1 or later, which runs the Node 24
|
|
838
|
+
actions the workflows use, and `gh` and `jq` on `PATH` (plus `node` with
|
|
839
|
+
`--erd-preview`).
|
|
840
|
+
- **Actions from github.com:** the workflows use `tailor-platform/actions`,
|
|
841
|
+
`actions/checkout`, `actions/setup-node`, `pnpm/action-setup`, and
|
|
842
|
+
`oven-sh/setup-bun` (and `actions/upload-artifact` with `--erd-preview`).
|
|
843
|
+
Make them available on the server with GitHub Connect or `actions-sync`. The
|
|
844
|
+
server ships its own copies of the `actions/*` ones, which may not include
|
|
845
|
+
the pinned versions: update them with `actions-sync`, or, with GitHub
|
|
846
|
+
Connect, delete them from the server's `actions` organization (see GitHub's
|
|
847
|
+
[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)).
|
|
848
|
+
- **Environment settings:** sign `gh` in to the server
|
|
849
|
+
(`gh auth login --hostname <host>`) before you run `tailor setup ci env` in a
|
|
850
|
+
clone of the repository, so that the `gh` commands it prints and its Terraform
|
|
851
|
+
output target the server. When `gh` cannot tell the repository, the output
|
|
852
|
+
says to export `GH_HOST=<host>` before running the `gh` commands, or
|
|
853
|
+
`GITHUB_BASE_URL=https://<host>/` before running Terraform, so that they
|
|
854
|
+
call the server instead of github.com.
|
|
855
|
+
|
|
856
|
+
With `--erd-preview`, also pass `--ghes`:
|
|
857
|
+
|
|
858
|
+
```bash
|
|
859
|
+
tailor setup ci branch --name my-app-stg --erd-preview --ghes
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
GitHub Enterprise Server does not support `actions/upload-artifact` v4 or
|
|
863
|
+
later, which the workflow uses to upload each ERD viewer unzipped. With
|
|
864
|
+
`--ghes`, the workflow uploads it with v3 instead, so each viewer is a zip
|
|
865
|
+
file, and the PR comment links to the workflow run, which lists the artifacts.
|
|
866
|
+
`setup update` keeps `--ghes`; pass it again whenever you re-run
|
|
867
|
+
`setup ci branch`, or the workflow switches back to the upload that GitHub
|
|
868
|
+
Enterprise Server does not support.
|
|
869
|
+
|
|
705
870
|
## Keeping dependencies and actions updated
|
|
706
871
|
|
|
707
872
|
Run this command once from the repository root to add Renovate configuration:
|
|
@@ -781,10 +946,11 @@ It regenerates every workflow recorded in
|
|
|
781
946
|
have to re-type `setup ci branch`, `setup ci tag`, and the rest one by one.
|
|
782
947
|
Your own jobs, steps, and settings are kept (see
|
|
783
948
|
[Customizing the generated workflow](#customizing-the-generated-workflow)). A
|
|
784
|
-
branch that was detected from the repository default branch
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
from the
|
|
949
|
+
branch that was detected from the repository default branch and a
|
|
950
|
+
[package manager](#package-manager) that was detected from the repository root
|
|
951
|
+
are detected again, and the parts that follow your config — the migration drift
|
|
952
|
+
check, seed validation, and ERD preview namespaces — are derived from the
|
|
953
|
+
current `tailor.config.ts`.
|
|
788
954
|
|
|
789
955
|
A target that cannot be regenerated, for example because you edited a managed
|
|
790
956
|
part, does not stop the others: `update` regenerates the rest, then lists the
|
|
@@ -96,3 +96,27 @@ defineStaticWebSite("my-website", {
|
|
|
96
96
|
customDomains: process.env.APP_ENV === "production" ? ["app.example.com"] : undefined,
|
|
97
97
|
});
|
|
98
98
|
```
|
|
99
|
+
|
|
100
|
+
## Seed data per environment and per scenario
|
|
101
|
+
|
|
102
|
+
`seedPlugin` seeds every environment from the JSONL files in `<distPath>/data/`. Rows that only some environments or scenarios need go into **datasets** — directories under `<distPath>/data/` that hold JSONL files for some of the tables — and are applied on top of the base seed data with `tailor seed apply --dataset <name>`:
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
seed/data/
|
|
106
|
+
*.schema.ts, *.jsonl # base seed data, applied everywhere
|
|
107
|
+
cogs/Item.jsonl # scenario: rows only a costing demo needs
|
|
108
|
+
dev/Account.jsonl # environment: the dev variant of a table
|
|
109
|
+
stg/Account.jsonl # environment: the staging variant of the same table
|
|
110
|
+
local/_User.jsonl # per developer, gitignored
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A table whose rows differ per environment lives only in the per-environment datasets, since a row may be defined in only one of the selected files. Name the combinations each environment uses in the `datasets` option of `seedPlugin`, so a deploy pipeline runs `tailor seed apply --dataset preview` instead of repeating the list:
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
seedPlugin({
|
|
117
|
+
distPath: "./seed",
|
|
118
|
+
datasets: { preview: ["cogs", "dev"] },
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The `tailor seed` commands come from the `@tailor-platform/sdk-plugin-seed` CLI plugin; see its [Datasets](https://github.com/tailor-platform/sdk/tree/main/packages/sdk-plugin-seed#datasets) guide for validating, filling, and dumping datasets.
|
package/docs/plugin/custom.md
CHANGED
|
@@ -516,9 +516,9 @@ export default createSoftDeletePlugin();
|
|
|
516
516
|
```typescript
|
|
517
517
|
// plugins/soft-delete/executors/on-delete.ts
|
|
518
518
|
import { createExecutor, recordDeletedTrigger } from "@tailor-platform/sdk";
|
|
519
|
-
import type { TailorAnyDBType } from "@tailor-platform/sdk";
|
|
520
519
|
import { withPluginContext } from "@tailor-platform/sdk/plugin";
|
|
521
520
|
import { getDB } from "generated/tailordb";
|
|
521
|
+
import type { TailorAnyDBType } from "@tailor-platform/sdk";
|
|
522
522
|
|
|
523
523
|
interface SoftDeleteContext {
|
|
524
524
|
sourceTable: TailorAnyDBType;
|
package/docs/services/idp.md
CHANGED
|
@@ -106,7 +106,7 @@ defineIdp("my-idp", {
|
|
|
106
106
|
**Operators:** `"="`, `"!="`, `"in"`, `"not in"`
|
|
107
107
|
|
|
108
108
|
> [!WARNING]
|
|
109
|
-
> A policy of `[{ user: "_loggedIn" }, "=", true]` permits every authenticated user to run the operation against any IdP user. For `read` and `update` this exposes and lets them change other users' login information (such as email addresses), and for `sendPasswordResetEmail` it lets them send reset emails to anyone. Use it only when every user who can sign in to the project is trusted. For an IdP used by external users (such as business partners), restrict each operation to an administrator role as shown above.
|
|
109
|
+
> A policy of `[{ user: "_loggedIn" }, "=", true]` permits every authenticated user to run the operation against any IdP user. For `read` and `update` this exposes and lets them change other users' login information (such as email addresses), and for `sendPasswordResetEmail` it lets them send reset emails to anyone. Use it only when every user who can sign in to the project is trusted. For an IdP used by external users (such as business partners), restrict each operation to an administrator role as shown above. `tailor deploy` warns about each rule whose only condition is `_loggedIn`.
|
|
110
110
|
|
|
111
111
|
**Helper:** `unsafeAllowAllIdPPermission` grants full access without conditions. Intended only for development and testing.
|
|
112
112
|
|
|
@@ -11,64 +11,7 @@ Resolvers provide:
|
|
|
11
11
|
- Access to TailorDB via Kysely query builder
|
|
12
12
|
- User context for authentication/authorization
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
The SDK's Resolver is a simplified version of Tailor Platform's [Pipeline Resolver](https://docs.tailor.tech/guides/resolver).
|
|
17
|
-
|
|
18
|
-
| Pipeline Resolver | SDK Resolver |
|
|
19
|
-
| ---------------------------------------- | --------------------------------- |
|
|
20
|
-
| Multiple steps with different operations | Single `body` function |
|
|
21
|
-
| Declarative step configuration | Imperative TypeScript code |
|
|
22
|
-
| Built-in TailorDB/GraphQL steps | Direct database access via Kysely |
|
|
23
|
-
| CEL expressions for data transformation | Native TypeScript transformations |
|
|
24
|
-
|
|
25
|
-
### Example Comparison
|
|
26
|
-
|
|
27
|
-
**Pipeline Resolver (Tailor Platform native):**
|
|
28
|
-
|
|
29
|
-
```yaml
|
|
30
|
-
steps:
|
|
31
|
-
- name: getUser
|
|
32
|
-
operation: tailordb.query
|
|
33
|
-
params:
|
|
34
|
-
type: User
|
|
35
|
-
filter:
|
|
36
|
-
email: { eq: "{{ input.email }}" }
|
|
37
|
-
- name: updateAge
|
|
38
|
-
operation: tailordb.mutation
|
|
39
|
-
params:
|
|
40
|
-
type: User
|
|
41
|
-
id: "{{ steps.getUser.id }}"
|
|
42
|
-
input:
|
|
43
|
-
age: "{{ steps.getUser.age + 1 }}"
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
**Resolver (SDK):**
|
|
47
|
-
|
|
48
|
-
```typescript
|
|
49
|
-
createResolver({
|
|
50
|
-
name: "incrementUserAge",
|
|
51
|
-
operation: "mutation",
|
|
52
|
-
input: { email: t.string() },
|
|
53
|
-
body: async (context) => {
|
|
54
|
-
const db = getDB("tailordb");
|
|
55
|
-
const user = await db
|
|
56
|
-
.selectFrom("User")
|
|
57
|
-
.selectAll()
|
|
58
|
-
.where("email", "=", context.input.email)
|
|
59
|
-
.executeTakeFirstOrThrow();
|
|
60
|
-
|
|
61
|
-
await db
|
|
62
|
-
.updateTable("User")
|
|
63
|
-
.set({ age: user.age + 1 })
|
|
64
|
-
.where("id", "=", user.id)
|
|
65
|
-
.execute();
|
|
66
|
-
|
|
67
|
-
return { oldAge: user.age, newAge: user.age + 1 };
|
|
68
|
-
},
|
|
69
|
-
output: t.object({ oldAge: t.int(), newAge: t.int() }),
|
|
70
|
-
});
|
|
71
|
-
```
|
|
14
|
+
For the official Tailor Platform documentation, see [Resolver Guide](https://docs.tailor.tech/guides/resolver).
|
|
72
15
|
|
|
73
16
|
## Creating a Resolver
|
|
74
17
|
|
|
@@ -419,13 +419,13 @@ A script with a single step runs like a `main` script: one job and one transacti
|
|
|
419
419
|
Because steps commit separately, a failure does not undo the steps that already completed:
|
|
420
420
|
|
|
421
421
|
- If the first step fails before any other step has completed, the migration fails like a `main` script: the pre-migration schema changes are rolled back.
|
|
422
|
-
- If a step fails after another step has completed, `tailor deploy` stops and leaves the migration **in progress**. The pre-migration schema stays in place
|
|
422
|
+
- If a step fails after another step has completed, `tailor deploy` stops and leaves the migration **in progress**. The pre-migration schema stays in place and the checkpoint is not advanced. With [maintenance mode](#maintenance-mode) on, the namespace's tables stay in it, as while the migration runs: GraphQL create, update, and delete operations, bulk upsert, and record events remain disabled, while `read` keeps its setting. `tailor tailordb migration status` reports the migration as in progress.
|
|
423
423
|
- If `tailor deploy` cannot confirm whether the steps started, for example because the connection dropped while starting them, the migration also stays in progress. Run `tailor deploy` again; it checks whether the steps ran before continuing.
|
|
424
424
|
- Fix the failing step and run `tailor deploy` again. The deploy resumes the migration: completed steps do not run again, and the failed step and the steps after it run with the updated script. A completed step is treated like an applied migration — editing it afterwards does not run it again.
|
|
425
425
|
- If the steps changed since the earlier run, or that run is no longer available, every step runs again from the beginning. See [Editing steps of a migration in progress](#editing-steps-of-a-migration-in-progress).
|
|
426
426
|
- If every step completed but the post-migration schema changes fail (for example, a field the migration makes required still has empty values), the migration also stays in progress with its pre-migration schema, and the next deploy retries those schema changes without running the steps again.
|
|
427
427
|
- To run a completed step again (because it had a bug, or to fix rows the post-migration schema changes reject), change the steps: rename that step and update the `dependsOn` lists that name it, or add a step that fixes the rows. Every step then runs again from the beginning, so this relies on every step being safe to run again; to keep the other completed steps from running again, skip them as described below.
|
|
428
|
-
- While a migration is in progress, `migration set`, `migration sync`, and `migration rebaseline` refuse to run, and `migration test` refuses to use that workspace as its source. Finish the migration with `tailor deploy` first. The one exception is `migration set <N>` with the in-progress migration's own number: it marks that migration as completed and clears its in-progress record. Use it only when the migration's schema changes are already applied, for example after the deploy reported that the checkpoint write could not be confirmed.
|
|
428
|
+
- While a migration is in progress, `migration set`, `migration sync`, and `migration rebaseline` refuse to run, and `migration test` refuses to use that workspace as its source. Finish the migration with `tailor deploy` first, or settle it with `migration resolve` (see [Settling a migration that stays in progress](#settling-a-migration-that-stays-in-progress)). The one exception is `migration set <N>` with the in-progress migration's own number: it marks that migration as completed and clears its in-progress record. Use it only when the migration's schema changes are already applied, for example after the deploy reported that the checkpoint write could not be confirmed.
|
|
429
429
|
|
|
430
430
|
#### Editing steps of a migration in progress
|
|
431
431
|
|
|
@@ -448,7 +448,16 @@ tailor deploy --migration-skip-steps main-db/backfillUser,main-db/backfillInvoic
|
|
|
448
448
|
- The option applies to the migration an earlier deploy left in progress. Deploy fails before changing anything when an entry names a step that did not succeed, a step the migration does not define, a namespace without a migration in progress, or a namespace that no deployed config defines. It also fails when the earlier run's step results cannot be read, because then it cannot confirm which steps succeeded; deploy again to retry.
|
|
449
449
|
- It takes effect for the deploy you pass it to. If that run fails, the next `tailor deploy` resumes it as usual, and the skipped steps stay completed without passing the option again.
|
|
450
450
|
|
|
451
|
-
Write every step so that running it again is safe: besides the cases above, a step can run a second time when a deploy is interrupted right after it commits. Use `where` clauses that skip rows a step already migrated, as in the example. Maintenance mode blocks GraphQL writes
|
|
451
|
+
Write every step so that running it again is safe: besides the cases above, a step can run a second time when a deploy is interrupted right after it commits. Use `where` clauses that skip rows a step already migrated, as in the example. Rows written while a migration is in progress are not seen by steps that already completed. [Maintenance mode](#maintenance-mode) blocks GraphQL writes but not the writes your resolvers, executors, or workflows make through Kysely, and without it GraphQL clients can write too, so stop such writers until the migration finishes or write steps that tolerate them.
|
|
452
|
+
|
|
453
|
+
### Settling a migration that stays in progress
|
|
454
|
+
|
|
455
|
+
When you do not want to resume the migration with another deploy — you abandoned it, or you repaired the data by hand — settle it with `tailor tailordb migration resolve`. Pass exactly one of two options:
|
|
456
|
+
|
|
457
|
+
- `--rollback` sends the schema of the migration before the failed one, clears the in-progress record, and leaves the checkpoint where it was. The next `tailor deploy` runs the failed migration again from its first step, so every step must be safe to run again. Data changes made by steps that already completed are not undone, and tables that exist only in the failed migration's schema are deleted with their data.
|
|
458
|
+
- `--complete` sends the schema of the failed migration itself, clears the in-progress record, and moves the checkpoint to that migration, without running its `migrate.ts` again. Repair the data first, for example with `tailor query`, and make sure no record lacks a value for a field the migration makes required: the update is rejected while such a record exists, and the migration stays in progress.
|
|
459
|
+
|
|
460
|
+
Tables that the failed migration removes are deleted with their data under `--complete`. The command refuses to run while an execution of the failed migration is still running; wait for it to finish first. Both options take the namespace's tables out of [maintenance mode](#maintenance-mode) and remove the temporary resources of the failed run. The command shows what it will change and asks for confirmation (`--yes` skips it). As with `migration sync`, the local migration history must reproduce the current table definitions, so settle the migration before you change the tables. If sending the schema stops partway, run the same command again.
|
|
452
461
|
|
|
453
462
|
## Supported Schema Changes
|
|
454
463
|
|
|
@@ -677,6 +686,65 @@ For each pending migration:
|
|
|
677
686
|
|
|
678
687
|
This split is what allows existing rows to be backfilled before the database starts rejecting nulls, and what lets `migrate.ts` traverse foreign-key fields that the same migration removes.
|
|
679
688
|
|
|
689
|
+
### Maintenance mode
|
|
690
|
+
|
|
691
|
+
`maintenanceMode` in `defineConfig` decides whether `tailor deploy` puts each namespace with pending migrations into maintenance mode while it applies them. A table in maintenance mode accepts no GraphQL `create`, `update`, `delete`, or bulk upsert operation and publishes no record events; its `read` setting is left as it is.
|
|
692
|
+
|
|
693
|
+
| Value | Maintenance mode |
|
|
694
|
+
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
695
|
+
| `false` | None. Nothing is restricted while migrations run. |
|
|
696
|
+
| `"migration"` (default) | From before the first pending migration runs until the last one completes. |
|
|
697
|
+
| `"deploy"` | From before the first pending migration runs until the deploy has applied every other change, including resolvers, executors, and workflows, and has removed the resources it deletes. |
|
|
698
|
+
|
|
699
|
+
A deploy without pending migrations never enters maintenance mode. When `maintenanceMode` is unset, it behaves as `"migration"`, preserving the existing deployment behavior. The value is read from the config like any other, so it can differ per environment (see [Multi-Environment Configuration](../multi-environment.md#varying-config-values-per-environment)):
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
export default defineConfig({
|
|
703
|
+
name: "my-app",
|
|
704
|
+
maintenanceMode: process.env.APP_ENV === "production" ? "deploy" : false,
|
|
705
|
+
});
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
**Without maintenance mode**, the SDK does not guarantee what requests that run during the migration observe. A table can still have its [pre-migration shape](#per-migration-phases), with new required fields optional and removed fields present; a client can write rows after `migrate.ts` has already read the table; and the records `migrate.ts` writes publish events to the executors of the previous deploy, which were written for the old shape. Use it only where clients and executors tolerate that.
|
|
709
|
+
|
|
710
|
+
**`"migration"` vs `"deploy"`**: the new resolvers and executors are deployed after the migrations. With `"migration"`, the migrated tables accept requests and publish events again while the resolvers and executors of the previous deploy are still in place. `"deploy"` keeps the tables in maintenance mode until they are replaced.
|
|
711
|
+
|
|
712
|
+
Maintenance mode restricts GraphQL writes and record events only. Resolvers, executors (including scheduled and webhook triggers), and workflows keep running, and the writes they make through Kysely are not blocked.
|
|
713
|
+
|
|
714
|
+
**When a deploy stops early:**
|
|
715
|
+
|
|
716
|
+
- If a migration fails, the tables leave maintenance mode before the error is reported: they return to the settings of the last checkpoint that completed. A migration that did not reach its checkpoint returns existing tables to their previous settings and keeps the tables it created in maintenance mode until a later deploy applies it. The settings are not restored if the checkpoint number or migration history changed concurrently, or if checkpoint ownership cannot be verified. A table left behind by a failed post-checkpoint deletion also stays in maintenance mode for manual recovery.
|
|
717
|
+
- A [multi-step migration](#splitting-a-migration-into-steps) left in progress keeps its tables in maintenance mode until a deploy completes it.
|
|
718
|
+
- With `"deploy"`, if a later part of the deploy fails, the tables leave maintenance mode before the error is reported. When the deploy ends maintenance mode, it leaves the tables of a namespace unchanged if that namespace's checkpoint number or migration history changed concurrently, or if checkpoint ownership cannot be verified, and reports it.
|
|
719
|
+
- If the deploy process is interrupted after a namespace's migrations completed but before maintenance mode ended, that namespace's tables stay in maintenance mode until a later `tailor deploy` releases them when it applies its TailorDB changes, before it replaces resolvers and executors. A namespace whose migrations had not all completed is not released this way: the next deploy resumes a multi-step migration left in progress, and otherwise reports remote schema drift (see [Failure Recovery](#failure-recovery)).
|
|
720
|
+
|
|
721
|
+
#### Keeping maintenance mode short
|
|
722
|
+
|
|
723
|
+
Maintenance mode lasts for the whole migration job, including the time the platform takes to start it, which can far exceed the time `migrate.ts` itself needs. Keep in `migrate.ts` only the work that must be done before the post-migration schema is applied, and move the rest into a workflow that you start after the deploy (for example with [`tailor workflow start`](../cli/workflow.md#workflow-start)).
|
|
724
|
+
|
|
725
|
+
- **Must stay in `migrate.ts`**: anything the post-migration schema enforces or removes — filling a field that becomes required, resolving duplicates before a unique index, converting values for a field type change, and copying data out of a field or table that the migration renames or removes.
|
|
726
|
+
- **Can move to a workflow**: work the post-migration schema does not depend on, such as filling an optional field, recomputing derived values, or cleaning up rows. Requests that run before the workflow finishes see the data in its unfixed state.
|
|
727
|
+
|
|
728
|
+
### Time spent in maintenance mode
|
|
729
|
+
|
|
730
|
+
When [maintenance mode](#maintenance-mode) is on, `tailor deploy` reports how long the migrating namespaces' tables were restricted, split into phases. With `"deploy"`, the window also includes the remaining deployment changes and ends when their restrictions are lifted. No maintenance report is emitted with `maintenanceMode: false`.
|
|
731
|
+
|
|
732
|
+
| Phase | Covers |
|
|
733
|
+
| ------------------ | ---------------------------------------------------------------------------------------- |
|
|
734
|
+
| `restrict` | Putting the tables into maintenance mode |
|
|
735
|
+
| `pre-migration` | Pre-migration schema changes |
|
|
736
|
+
| `job setup` | Bundling `migrate.ts` and registering it as a job |
|
|
737
|
+
| `waiting to start` | Time when the platform has accepted the job but none of its code runs yet |
|
|
738
|
+
| `running` | Time when the script runs |
|
|
739
|
+
| `job cleanup` | Collecting the script's logs and removing its job, unless its steps run as separate jobs |
|
|
740
|
+
| `post-migration` | Post-migration schema changes, the checkpoint update, and cleanup |
|
|
741
|
+
| `remaining deploy` | With `"deploy"`, applying the remaining deployment changes while tables stay restricted |
|
|
742
|
+
| `restore` | Taking the tables out of maintenance mode |
|
|
743
|
+
|
|
744
|
+
Phases that repeat across several migrations are added up. The report is printed only after the migrations succeed and the tables leave maintenance mode; when a migration fails, deploy reports the error instead (see [Failure Recovery](#failure-recovery)). When deploy resumes a migration that an earlier deploy left in progress, the tables were already in maintenance mode before it started, and the report covers only this deploy. A job can be reported as started on the platform well before its code runs, so deploy tells waiting from running by a line every job of a migration logs before your script: `[tailor-sdk] migration script started`. You may see that line in function execution logs; deploy leaves it out of the logs it prints. A script that exports [`steps`](#splitting-a-migration-into-steps) waits for each step's job to start, and that time counts as `waiting to start` too. Time when deploy cannot tell whether the script is running — because the run or a running job's logs could not be read, or because an older SDK version started the run and it never logs the line — is reported as `waiting to start or running` instead.
|
|
745
|
+
|
|
746
|
+
Deploy checks the run every few seconds, so a boundary between `waiting to start` and `running` can be off by that much. With `--json`, the same breakdown is in `tailordbMaintenance` (see [Deploy JSON result](../cli/application.md#deploy)). Add `--verbose` to also print how long each phase took and every change in the job's status.
|
|
747
|
+
|
|
680
748
|
### Schema verification
|
|
681
749
|
|
|
682
750
|
Before running migrations, `apply` performs two checks:
|
|
@@ -716,14 +784,14 @@ tailor deploy --no-schema-check
|
|
|
716
784
|
### Example output
|
|
717
785
|
|
|
718
786
|
```
|
|
719
|
-
ℹ
|
|
720
|
-
ℹ Executing 2 pending migration(s)...
|
|
721
|
-
ℹ Using machine user: admin-machine-user for namespace 'tailordb'
|
|
787
|
+
ℹ Executing 1 data migration(s)...
|
|
722
788
|
|
|
723
|
-
|
|
724
|
-
|
|
789
|
+
ℹ Using machine user: admin-machine-user for namespace 'tailordb'
|
|
790
|
+
10:42:31 AM ℹ Migration tailordb/0002 started running after waiting 15m02s for its job to start.
|
|
791
|
+
✓ Migration tailordb/0002 completed successfully (waiting to start 15m02s, running 1m41s)
|
|
725
792
|
|
|
726
|
-
✔ All migrations completed successfully.
|
|
793
|
+
✔ All data migrations completed successfully.
|
|
794
|
+
ℹ Tables of namespace tailordb were in maintenance mode for 16m56s (restrict 1.2s, pre-migration 3.4s, job setup 2.1s, waiting to start 15m02s, running 1m41s, job cleanup 0.8s, post-migration 4.0s, restore 1.1s).
|
|
727
795
|
✔ Successfully applied changes.
|
|
728
796
|
```
|
|
729
797
|
|
|
@@ -825,7 +893,7 @@ A script that exports `steps` follows different rules once one of its steps has
|
|
|
825
893
|
|
|
826
894
|
The rollback is best-effort per table; if reverting a table fails, a warning is logged and the original migration error is still reported. The next deploy then stops with remote schema drift on that table. Run `tailor tailordb migration validate` to see which tables differ, return the namespace to its checkpoint with `tailor tailordb migration sync <N>`, where `<N>` is the checkpoint `tailor tailordb migration status` reports, and deploy again. `sync` deletes the tables and fields that are not in that migration's snapshot, together with any rows the failed migration wrote to them; the next deploy runs the failed migration again.
|
|
827
895
|
|
|
828
|
-
If `tailor deploy` cannot tell whether a `main` script ran, for example because the connection dropped while it started or waited for the script, it does not roll anything back: the pre-migration schema changes stay, the namespace's tables stay in maintenance mode, and the deploy reports that it could not confirm the outcome. A later deploy refuses to run the migration while that run is still executing. Run `tailor workflow executions --workflow-name <name>` with the workflow name the error reports until the execution has finished or none is listed. If it succeeded, run `tailor tailordb migration sync <N>` with the migration's own number; otherwise run `tailor tailordb migration sync <N-1>`. Then deploy again. Do not deploy before running sync, even with `--no-schema-check` to skip the drift check: the deploy may run the `main` script again even if the execution succeeded.
|
|
896
|
+
If `tailor deploy` cannot tell whether a `main` script ran, for example because the connection dropped while it started or waited for the script, it does not roll anything back: the pre-migration schema changes stay, the namespace's tables stay in [maintenance mode](#maintenance-mode) if it is on, and the deploy reports that it could not confirm the outcome. A later deploy refuses to run the migration while that run is still executing. Run `tailor workflow executions --workflow-name <name>` with the workflow name the error reports until the execution has finished or none is listed. If it succeeded, run `tailor tailordb migration sync <N>` with the migration's own number; otherwise run `tailor tailordb migration sync <N-1>`. Then deploy again. Do not deploy before running sync, even with `--no-schema-check` to skip the drift check: the deploy may run the `main` script again even if the execution succeeded.
|
|
829
897
|
|
|
830
898
|
`migration sync` refuses to run while a migration is in progress. When a steps migration's post-migration schema changes fail and the deploy cannot return its tables to the pre-migration schema, it logs a warning, and the next deploy stops with remote schema drift on those tables. Run `tailor tailordb migration validate` from a checkout of the deployed migration history. If the only issue it reports is that drift, run `tailor deploy --no-schema-check`: the deploy applies the pre-migration schema again, skips the completed steps unless the steps changed, and retries the post-migration schema changes. `--no-schema-check` skips the schema checks of every namespace, so do not use it while `validate` reports any other issue.
|
|
831
899
|
|
|
@@ -917,8 +985,8 @@ When `migrate.ts` already exists (the usual case for breaking changes, where `mi
|
|
|
917
985
|
// migrations/0005/migrate.test.ts
|
|
918
986
|
import { createKyselyMock } from "@tailor-platform/sdk/vitest";
|
|
919
987
|
import { describe, expect, test } from "vitest";
|
|
920
|
-
import type { Database } from "./db";
|
|
921
988
|
import { main } from "./migrate";
|
|
989
|
+
import type { Database } from "./db";
|
|
922
990
|
|
|
923
991
|
describe("0005 add required email", () => {
|
|
924
992
|
test("backfills null emails", async () => {
|
|
@@ -954,9 +1022,9 @@ The generated `db.pglite.ts` exports the `CREATE TABLE` script for the same sche
|
|
|
954
1022
|
import { PGlite } from "@electric-sql/pglite";
|
|
955
1023
|
import { createKyselyPGlite, type Unmigrated } from "@tailor-platform/sdk/vitest";
|
|
956
1024
|
import { afterAll, beforeAll, describe, expect, test } from "vitest";
|
|
957
|
-
import type { Database } from "./db";
|
|
958
1025
|
import { pgliteSchema } from "./db.pglite";
|
|
959
1026
|
import { main } from "./migrate";
|
|
1027
|
+
import type { Database } from "./db";
|
|
960
1028
|
|
|
961
1029
|
const pglite = new PGlite();
|
|
962
1030
|
const db = createKyselyPGlite<Unmigrated<Database>>(pglite);
|
|
@@ -431,16 +431,29 @@ db.string().vector();
|
|
|
431
431
|
|
|
432
432
|
```typescript
|
|
433
433
|
db.int().serial({
|
|
434
|
-
start:
|
|
434
|
+
start: 1,
|
|
435
435
|
maxValue: 100,
|
|
436
436
|
});
|
|
437
437
|
|
|
438
438
|
db.string().serial({
|
|
439
|
-
start:
|
|
439
|
+
start: 1,
|
|
440
440
|
format: "CUST_%d",
|
|
441
441
|
});
|
|
442
442
|
```
|
|
443
443
|
|
|
444
|
+
A serial field cannot be used inside a `db.object()` field.
|
|
445
|
+
|
|
446
|
+
> **Preview:** The `gapless` option is a preview feature. Its behavior and configuration may change before general availability.
|
|
447
|
+
|
|
448
|
+
Set `gapless: true` to number records without gaps. A number is used only by a create that commits, so a create that fails leaves no hole. Numbered creates of the table run one at a time, so use it only when contiguous numbering is required. See the [TailorDB Serial documentation](https://docs.tailor.tech/guides/tailordb/fields#serial) for what the gapless guarantee covers.
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
db.int().serial({
|
|
452
|
+
start: 1,
|
|
453
|
+
gapless: true,
|
|
454
|
+
});
|
|
455
|
+
```
|
|
456
|
+
|
|
444
457
|
### Common Fields
|
|
445
458
|
|
|
446
459
|
```typescript
|
|
@@ -522,7 +535,7 @@ db.table("User", {
|
|
|
522
535
|
- When not specified, `deploy` sets it from the executors taking part in the same run: `true` while one of them uses this table with `recordCreatedTrigger`, `recordUpdatedTrigger`, or `recordDeletedTrigger`, and `false` once none does. Removing the last such trigger turns publishing back off on the next `deploy`
|
|
523
536
|
- When explicitly set to `false` while an executor taking part in the same run uses this table, `deploy` fails
|
|
524
537
|
- An executor declared with `disabled: true` never runs, so it does not count as using the table
|
|
525
|
-
- While a `deploy` applies pending migrations, every table in the migrating namespace is restricted: the GraphQL create, update, and delete operations and bulk upsert are disabled, and the table's `read` setting is not switched off for the migration (a table the migration creates uses its configured setting), so nothing writes an intermediate schema and readable tables are not shut down. Record event publishing is also switched off so a migration script's writes do not reach executors from the previous deploy. After success, the configured settings take effect. If a later migration fails, settings from the last confirmed checkpoint are restored; an uncommitted migration restores existing tables' prior settings and leaves its newly created tables restricted until a successful retry. A table that already refuses create, update, delete, and bulk upsert and publishes no record events is left as it is. Restoration is skipped if the checkpoint number or migration history changed concurrently, or if checkpoint ownership cannot be verified; the deploy then reports the namespace whose tables stay restricted and points to `tailor tailordb migration status --namespace <namespace>`. When a failed migration or a failed restoration leaves tables restricted, the deploy lists their names, and deploying again releases them once the migration completes. A table that a failed rollback could not delete or revert is the exception: the deploy also lists it, but the next deploy stops with remote schema drift until you delete or repair that table by hand. A table left behind by a failed post-checkpoint deletion also remains read-only for manual recovery, and the deploy does not list it by name
|
|
538
|
+
- While a `deploy` applies pending migrations with [maintenance mode](./tailordb-migration.md#maintenance-mode) on, every table in the migrating namespace is restricted: the GraphQL create, update, and delete operations and bulk upsert are disabled, and the table's `read` setting is not switched off for the migration (a table the migration creates uses its configured setting), so nothing writes an intermediate schema and readable tables are not shut down. Record event publishing is also switched off so a migration script's writes do not reach executors from the previous deploy. With `maintenanceMode: false`, these restrictions are not applied. After success, the configured settings take effect. If a later migration fails, settings from the last confirmed checkpoint are restored; an uncommitted migration restores existing tables' prior settings and leaves its newly created tables restricted until a successful retry. A table that already refuses create, update, delete, and bulk upsert and publishes no record events is left as it is. Restoration is skipped if the checkpoint number or migration history changed concurrently, or if checkpoint ownership cannot be verified; the deploy then reports the namespace whose tables stay restricted and points to `tailor tailordb migration status --namespace <namespace>`. When a failed migration or a failed restoration leaves tables restricted, the deploy lists their names, and deploying again releases them once the migration completes. A table that a failed rollback could not delete or revert is the exception: the deploy also lists it, but the next deploy stops with remote schema drift until you delete or repair that table by hand. A table left behind by a failed post-checkpoint deletion also remains read-only for manual recovery, and the deploy does not list it by name
|
|
526
539
|
|
|
527
540
|
**Use cases:**
|
|
528
541
|
|
|
@@ -567,7 +580,7 @@ db.table("User", {
|
|
|
567
580
|
|
|
568
581
|
Control which GraphQL operations (`create`, `update`, `delete`, `read`) are exposed for a table. All operations are enabled by default.
|
|
569
582
|
|
|
570
|
-
While a `deploy` applies pending migrations, the GraphQL `create`, `update`, and `delete` operations and bulk upsert are switched off across the migrating namespace, so nothing writes an intermediate schema. The `read` operation is not switched off: it keeps the setting the table has when the restrictions begin.
|
|
583
|
+
While a `deploy` applies pending migrations with [maintenance mode](./tailordb-migration.md#maintenance-mode) on, the GraphQL `create`, `update`, and `delete` operations and bulk upsert are switched off across the migrating namespace, so nothing writes an intermediate schema. The `read` operation is not switched off: it keeps the setting the table has when the restrictions begin. With or without maintenance mode, a table that a migration touches follows that migration's schema from its first phase on, so a migration that changes `read` changes it before its script runs; a table no migration touches keeps its setting. A table the migration creates uses its configured `read` setting from the start. After success, the configured operations take effect. If a later migration fails while maintenance mode is on, operations from the last confirmed checkpoint are restored; an uncommitted migration restores existing tables' prior operations and leaves its newly created tables restricted until a successful retry. A table that already refuses create, update, delete, and bulk upsert and publishes no record events is left as it is. Restoration is skipped if the checkpoint number or migration history changed concurrently; the deploy then reports the namespace whose tables stay restricted, and deploying again releases them once the migration completes.
|
|
571
584
|
|
|
572
585
|
```typescript
|
|
573
586
|
db.table("Order", {
|
|
@@ -488,9 +488,9 @@ Pass the runtime key through the `executionPolicyKey` option on `job.start()`. F
|
|
|
488
488
|
|
|
489
489
|
```typescript
|
|
490
490
|
import { createWorkflowJob } from "@tailor-platform/sdk";
|
|
491
|
-
import { executionPolicies } from "./policies";
|
|
492
|
-
import { sendNotification } from "./jobs/send-notification";
|
|
493
491
|
import { fetchTenant } from "./jobs/fetch-tenant";
|
|
492
|
+
import { sendNotification } from "./jobs/send-notification";
|
|
493
|
+
import { executionPolicies } from "./policies";
|
|
494
494
|
|
|
495
495
|
export const mainJob = createWorkflowJob({
|
|
496
496
|
name: "main-job",
|