@tailor-platform/sdk 2.26.0 → 2.28.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 +144 -0
- package/agent-skills/tailor/SKILL.md +4 -2
- package/dist/application-CgJLyJaF.mjs +200 -0
- package/dist/application-CgJLyJaF.mjs.map +1 -0
- package/dist/application-CvmKh5WT.mjs +1 -0
- package/dist/cli/commands/deploy/deploy.d.mts +2 -0
- package/dist/cli/commands/deploy/tailordb/migration-validation.d.mts +2 -1
- 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/bundler.d.mts +4 -6
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +8 -1
- package/dist/cli/commands/tailordb/migrate/remote-state.d.mts +1 -0
- 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 +3 -3
- package/dist/cli/lib.mjs +1 -1
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.d.mts +2 -0
- package/dist/cli/main.mjs +68 -55
- 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/shared/workspace-name.d.mts +2 -0
- package/dist/completion/zsh-worker.zsh +220 -19
- package/dist/configure/config/types.d.mts +34 -1
- package/dist/configure/index.d.mts +6 -6
- package/dist/configure/index.mjs +1 -1
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/aigateway/types.d.mts +2 -1
- package/dist/configure/services/auth/types.d.mts +8 -2
- 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 +3 -2
- package/dist/configure/services/executor/trigger/schedule.d.mts +2 -1
- package/dist/configure/services/executor/trigger/webhook.d.mts +1 -1
- package/dist/configure/services/http-adapter/http-adapter.d.mts +2 -1
- package/dist/configure/services/idp/permission.d.mts +4 -3
- 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 +3 -2
- 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 +5 -4
- package/dist/configure/services/tailordb/types.d.mts +13 -2
- package/dist/configure/services/workflow/execution-policy.types.d.mts +2 -1
- package/dist/configure/services/workflow/job.d.mts +3 -2
- package/dist/configure/services/workflow/wait-point.d.mts +2 -1
- package/dist/configure/types/field.types.d.mts +50 -12
- package/dist/configure/types/permission-operand.types.d.mts +2 -1
- package/dist/configure/types/type.d.mts +3 -2
- 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/date-CgP7gMG_.mjs +2 -0
- package/dist/date-CgP7gMG_.mjs.map +1 -0
- package/dist/{secretmanager-5olfnI1b.mjs → date-representation-Cr7W7Pn2.mjs} +2 -2
- package/dist/date-representation-Cr7W7Pn2.mjs.map +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/{field-parse-DhnFs9WG.mjs → field-parse-C41e3UAF.mjs} +2 -2
- package/dist/{field-parse-DhnFs9WG.mjs.map → field-parse-C41e3UAF.mjs.map} +1 -1
- package/dist/idp-G_ojPBB5.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/{manager-8-JOvuLl.mjs → manager-Bk-7vkwd.mjs} +2 -2
- package/dist/{manager-8-JOvuLl.mjs.map → manager-Bk-7vkwd.mjs.map} +1 -1
- package/dist/migration-steps-C6F3zNdQ.mjs +3 -0
- package/dist/migration-steps-C6F3zNdQ.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/plugin/index.mjs +1 -1
- package/dist/register-ts-hook-yxshv0LV.mjs +1013 -0
- package/dist/register-ts-hook-yxshv0LV.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.d.mts +6 -0
- package/dist/runtime/idp.mjs +1 -1
- package/dist/runtime/index.mjs +1 -1
- package/dist/runtime/logger.mjs +1 -1
- package/dist/runtime/secretmanager.mjs +1 -1
- package/dist/runtime/types.d.mts +7 -1
- package/dist/runtime/workflow.d.mts +2 -1
- package/dist/runtime/workflow.mjs +1 -1
- package/dist/{schema-CRtAmDcl.mjs → schema-B6hJQWp6.mjs} +2 -2
- package/dist/schema-B6hJQWp6.mjs.map +1 -0
- package/dist/seed/index.d.mts +19 -4
- package/dist/seed/index.mjs +7 -9
- package/dist/seed/index.mjs.map +1 -1
- package/dist/seed-C3P_T_Eh.mjs.map +1 -1
- package/dist/service-CETr0AKY.mjs +7 -0
- 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/field.generated.d.mts +2 -2
- package/dist/types/tailordb.generated.d.mts +2 -0
- package/dist/utils/test/index.mjs +1 -1
- package/dist/vitest/date-representation.d.mts +23 -0
- package/dist/vitest/index.d.mts +3 -1
- package/dist/vitest/index.mjs +1 -1
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/migration-steps.d.mts +45 -0
- 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 +3 -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/setup.d.mts +3 -1
- package/dist/vitest/setup.mjs +1 -1
- package/dist/vitest/setup.mjs.map +1 -1
- package/dist/vitest/workflow-local.d.mts +2 -1
- package/dist/{workspace_resource_pb-CxR_6fyN.mjs → workspace_resource_pb-CaoM2npP.mjs} +2 -2
- package/dist/workspace_resource_pb-CaoM2npP.mjs.map +1 -0
- package/docs/cli/application.md +37 -16
- package/docs/cli/data.md +105 -0
- package/docs/cli/function.md +2 -0
- package/docs/cli/secret.md +6 -6
- package/docs/cli/tailordb.md +18 -16
- package/docs/cli/user.md +37 -7
- package/docs/cli/workspace.md +10 -2
- package/docs/cli-reference.md +25 -3
- package/docs/configuration.md +28 -6
- package/docs/github-actions.md +212 -63
- package/docs/multi-environment.md +24 -0
- package/docs/plugin/custom.md +2 -1
- package/docs/services/auth.md +20 -0
- package/docs/services/executor.md +2 -2
- package/docs/services/idp.md +6 -1
- package/docs/services/resolver.md +3 -1
- package/docs/services/staticwebsite.md +5 -5
- package/docs/services/tailordb-migration.md +222 -41
- package/docs/services/tailordb.md +17 -4
- package/docs/testing.md +4 -0
- package/package.json +18 -18
- package/dist/application-ChqHuhZW.mjs +0 -1
- package/dist/application-DS0XKBtK.mjs +0 -200
- package/dist/application-DS0XKBtK.mjs.map +0 -1
- package/dist/crashreport-CBaRJl5h.mjs +0 -1
- package/dist/date-Dri6Yas-.mjs +0 -2
- package/dist/date-Dri6Yas-.mjs.map +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-BuwkLuxC.mjs +0 -925
- package/dist/register-ts-hook-BuwkLuxC.mjs.map +0 -1
- package/dist/schema-CRtAmDcl.mjs.map +0 -1
- package/dist/secretmanager-5olfnI1b.mjs.map +0 -1
- package/dist/service-Bx-7Lz06.mjs +0 -1
- package/dist/service-CL1Bp4It.mjs +0 -7
- package/dist/service-CL1Bp4It.mjs.map +0 -1
- package/dist/service_pb-ZClWtj1X.mjs +0 -2
- package/dist/service_pb-ZClWtj1X.mjs.map +0 -1
- package/dist/service_pb-dB3RrGeh.mjs +0 -1
- package/dist/telemetry-DXHP3VVi.mjs +0 -1
- package/dist/workspace_resource_pb-CxR_6fyN.mjs.map +0 -1
package/docs/github-actions.md
CHANGED
|
@@ -153,6 +153,10 @@ or end with a hyphen. It is used for the generated file name, the workflow
|
|
|
153
153
|
select which workspace gets deployed (see
|
|
154
154
|
[Targeting a workspace](#targeting-a-workspace)).
|
|
155
155
|
|
|
156
|
+
For a preview target, the name can be at most 50 characters: each pull request
|
|
157
|
+
gets its own workspace named `<name>-pr-<number>`, which must fit in 63
|
|
158
|
+
characters.
|
|
159
|
+
|
|
156
160
|
## Targeting a workspace
|
|
157
161
|
|
|
158
162
|
The generated `plan` and `deploy` jobs target a workspace by **id**, read from
|
|
@@ -190,6 +194,26 @@ the `plan` job as well as `deploy`, because `plan` must enter the environment to
|
|
|
190
194
|
read the variable. (A token-based read that lets `plan` run without entering the
|
|
191
195
|
environment is planned.)
|
|
192
196
|
|
|
197
|
+
## Package manager
|
|
198
|
+
|
|
199
|
+
The generated workflow sets up your package manager, installs dependencies with
|
|
200
|
+
it, and runs `tailor` through it. `setup ci` detects the package manager from the
|
|
201
|
+
lockfile at the repository root (`pnpm-lock.yaml`, `yarn.lock`, `bun.lock`,
|
|
202
|
+
`bun.lockb`, `package-lock.json`, or `npm-shrinkwrap.json`), or, when there is
|
|
203
|
+
none, from the `packageManager` or `devEngines.packageManager` field of the root
|
|
204
|
+
`package.json`. When neither names one, `setup ci` stops instead of guessing.
|
|
205
|
+
|
|
206
|
+
Pass `--package-manager` (`pnpm`, `npm`, `yarn`, or `bun`) to choose it
|
|
207
|
+
yourself, for example to generate the workflow before the lockfile exists:
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
tailor setup ci branch --name my-app-stg --package-manager pnpm
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
The workflow installs dependencies at the repository root, so commit the
|
|
214
|
+
lockfile there before it runs. `tailor setup update` keeps a package manager
|
|
215
|
+
chosen with `--package-manager` and detects it again otherwise.
|
|
216
|
+
|
|
193
217
|
## Generated files
|
|
194
218
|
|
|
195
219
|
Running a workflow setup subcommand creates or updates:
|
|
@@ -213,9 +237,8 @@ for what you can edit.
|
|
|
213
237
|
### Customizing the generated workflow
|
|
214
238
|
|
|
215
239
|
The SDK owns the jobs and steps whose `id` starts with `tailor-`, and the
|
|
216
|
-
top-level
|
|
217
|
-
|
|
218
|
-
them. Everything else is yours, and re-running `setup` keeps it:
|
|
240
|
+
top-level `name:`, `on:`, and `permissions:`. Do not edit or rename them.
|
|
241
|
+
Everything else is yours, and re-running `setup` keeps it:
|
|
219
242
|
|
|
220
243
|
- **Your own jobs and steps.** Add them anywhere, with an `id` (if any) that
|
|
221
244
|
does not start with `tailor-`: the prefix is reserved for the SDK, even in a
|
|
@@ -225,19 +248,27 @@ them. Everything else is yours, and re-running `setup` keeps it:
|
|
|
225
248
|
(such as `playwright install`) _after_ it. A job of your own can depend on a
|
|
226
249
|
managed job with `needs: tailor-deploy`.
|
|
227
250
|
- **Your own top-level keys**, such as a workflow-level `env:` or `defaults:`.
|
|
251
|
+
- **The top-level `concurrency:` of a preview workflow.** The SDK writes a
|
|
252
|
+
default, and re-running `setup` keeps your edits to it. If you delete it,
|
|
253
|
+
re-running `setup` adds the default back.
|
|
228
254
|
- **Runtime settings of managed jobs:** `runs-on`, `timeout-minutes`,
|
|
229
|
-
`container`, and `env`.
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
255
|
+
`container`, and `env`. If every managed job that re-running `setup` keeps
|
|
256
|
+
uses the same `runs-on` you set, such as self-hosted runners, a managed job
|
|
257
|
+
it adds (for example, the ERD preview jobs when you add `--erd-preview`)
|
|
258
|
+
uses it too; otherwise, set the new job's `runs-on` yourself. On a managed
|
|
259
|
+
job generated without an `environment:` (such as `tailor-tag-guard` or
|
|
260
|
+
`tailor-erd-preview`), you can also add one, for example so a step you added
|
|
261
|
+
there can read that GitHub Environment's secrets. The `environment:` of
|
|
262
|
+
`tailor-plan`, `tailor-deploy`, and the preview jobs comes from
|
|
263
|
+
`--environment`, so change it with that option instead.
|
|
235
264
|
- **These inputs of managed steps:** `ignore` on `tailor-generate-check` and
|
|
236
265
|
`tailor-drift-check`, `fail-on-drift` on `tailor-drift-check`,
|
|
237
266
|
`install-command` on `tailor-install`, `node-version-file` on
|
|
238
267
|
`tailor-setup`, `label` on `tailor-plan`, and `user-mapping` on
|
|
239
|
-
`tailor-notify
|
|
240
|
-
- **
|
|
268
|
+
`tailor-notify`.
|
|
269
|
+
- **Your own jobs in the `needs` of `tailor-result` and
|
|
270
|
+
`tailor-preview-result`**, so they count toward the workflow's result (see
|
|
271
|
+
[Requiring the workflow in branch protection](#requiring-the-workflow-in-branch-protection)).
|
|
241
272
|
|
|
242
273
|
In a preview workflow, the `tailor-preview-deploy` job exposes the per-PR
|
|
243
274
|
workspace as the outputs `workspace-id`, `workspace-name`, and `app-url`, so a
|
|
@@ -250,7 +281,7 @@ deploy-assets:
|
|
|
250
281
|
environment: my-app
|
|
251
282
|
env:
|
|
252
283
|
TAILOR_PLATFORM_WORKSPACE_ID: ${{ needs.tailor-preview-deploy.outputs.workspace-id }}
|
|
253
|
-
TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
|
|
284
|
+
TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID: ${{ vars.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID || secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID }}
|
|
254
285
|
TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET: ${{ secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET }}
|
|
255
286
|
steps:
|
|
256
287
|
# checkout, dependency installation, and your tailor commands
|
|
@@ -265,6 +296,14 @@ The job is skipped whenever `tailor-preview-deploy` is skipped: when a pull
|
|
|
265
296
|
request is closed, for draft and fork pull requests, and for unlabeled ones with
|
|
266
297
|
`--require-preview-label`.
|
|
267
298
|
|
|
299
|
+
Each new preview workflow run for a pull request, such as after a push or when
|
|
300
|
+
the pull request is closed, cancels the run still in progress for it, including
|
|
301
|
+
your jobs, so they do not keep running against a workspace that the new run
|
|
302
|
+
may redeploy or delete. Events on a pull request that stays closed, such as a
|
|
303
|
+
label added after merging, do not cancel anything. A job with `if: always()`
|
|
304
|
+
still runs when its run is cancelled, and the new run waits for it to finish;
|
|
305
|
+
use `if: ${{ !cancelled() }}` instead so it stops with the run.
|
|
306
|
+
|
|
268
307
|
Likewise, the `tailor-deploy` job of a branch or tag workflow exposes the
|
|
269
308
|
deployed workspace as the outputs `workspace-id` and `app-url` to a job with
|
|
270
309
|
`needs: tailor-deploy`. Reading them does not require the target's GitHub
|
|
@@ -299,6 +338,48 @@ Files generated by an older SDK version are compared as a whole, so the first
|
|
|
299
338
|
re-run after upgrading stops if you edited the file in any way. Re-run once with
|
|
300
339
|
`--force` to switch it to this model; your own jobs and steps are kept.
|
|
301
340
|
|
|
341
|
+
### Requiring the workflow in branch protection
|
|
342
|
+
|
|
343
|
+
Branch and preview workflows end with a job that reports the result of the
|
|
344
|
+
whole workflow: `tailor-result` in a branch workflow and
|
|
345
|
+
`tailor-preview-result` in a preview workflow. Its check is named after the
|
|
346
|
+
workspace, such as `tailor-result (my-app)`, so each workflow in the repository
|
|
347
|
+
has its own. Require that one check in branch protection instead of listing
|
|
348
|
+
the jobs one by one.
|
|
349
|
+
|
|
350
|
+
The job runs after every other SDK-managed job of the workflow, even when one
|
|
351
|
+
fails or the run is cancelled. It fails when a job in its `needs` failed or was
|
|
352
|
+
cancelled, and passes when they succeeded or were skipped, for example when the
|
|
353
|
+
preview deploy is skipped for a fork pull request. When a newer run cancels a
|
|
354
|
+
job of an older one, such as the preview deploy of a commit you pushed over,
|
|
355
|
+
the older run's check fails; the newer run reports its own.
|
|
356
|
+
|
|
357
|
+
To make jobs of your own count, add them to its `needs`. A matrix job is listed
|
|
358
|
+
once by its job id, however many combinations it expands to:
|
|
359
|
+
|
|
360
|
+
```yaml
|
|
361
|
+
tailor-preview-result:
|
|
362
|
+
name: tailor-preview-result (my-app)
|
|
363
|
+
needs:
|
|
364
|
+
- tailor-preview-deploy
|
|
365
|
+
- tailor-preview-cleanup
|
|
366
|
+
- seed
|
|
367
|
+
- e2e
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Re-running `setup` keeps the jobs you add there and updates the `tailor-`
|
|
371
|
+
entries to the jobs the SDK generates. A job skipped because a job it needs
|
|
372
|
+
failed also counts as passing, so list every job of yours whose failure should
|
|
373
|
+
block merging, not only the last one: above, `seed` is listed because `e2e`
|
|
374
|
+
needs it.
|
|
375
|
+
|
|
376
|
+
With `--require-preview-label`, the preview workflow does not start when a pull
|
|
377
|
+
request is opened, so its check is not reported until the pull request is
|
|
378
|
+
labeled, reopened, or pushed to. A draft pull request skips the preview deploy,
|
|
379
|
+
and marking it ready for review does not start the workflow, so the check that
|
|
380
|
+
passed while it was a draft stays until the next push. Tag workflows have no
|
|
381
|
+
such job: they run on tags, not on pull requests.
|
|
382
|
+
|
|
302
383
|
### `.github/tailor.lock`
|
|
303
384
|
|
|
304
385
|
A machine-owned JSON file that tracks which files the SDK manages, the inputs
|
|
@@ -353,23 +434,33 @@ the move.
|
|
|
353
434
|
|
|
354
435
|
## Secrets
|
|
355
436
|
|
|
356
|
-
The generated workflow requires
|
|
437
|
+
The generated workflow requires one secret (the optional Slack token is listed in
|
|
357
438
|
[Setting secrets and variables](#setting-secrets-and-variables)):
|
|
358
439
|
|
|
359
440
|
| Secret | Description |
|
|
360
441
|
| -------------------------------------------- | -------------------------- |
|
|
361
|
-
| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID` | Machine user client ID |
|
|
362
442
|
| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET` | Machine user client secret |
|
|
363
443
|
|
|
364
|
-
|
|
365
|
-
|
|
444
|
+
The machine user client ID is a variable, not a secret: it cannot authenticate
|
|
445
|
+
without the client secret. The generated workflow reads
|
|
446
|
+
`vars.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID` and falls back to
|
|
447
|
+
`secrets.TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID`, so a repository that already
|
|
448
|
+
stores the client ID as a secret keeps working unchanged. Storing the client ID
|
|
449
|
+
as a secret is deprecated, and the fallback will be removed in a future release,
|
|
450
|
+
so move it to a variable (`gh variable set TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID`)
|
|
451
|
+
and delete the secret.
|
|
452
|
+
|
|
453
|
+
Set the client secret as a secret and the client ID as a variable on the target
|
|
454
|
+
GitHub Environment (the `--environment` value, or the workspace name when
|
|
455
|
+
omitted); `tailor setup ci env` prints the commands (see
|
|
366
456
|
[Setting secrets and variables](#setting-secrets-and-variables)).
|
|
367
457
|
|
|
368
458
|
Setting them at the environment level isolates each target's credentials and
|
|
369
459
|
keeps them alongside that environment's `TAILOR_PLATFORM_WORKSPACE_ID`
|
|
370
|
-
variable. You can also set
|
|
371
|
-
|
|
372
|
-
|
|
460
|
+
variable. You can also set the client secret as a repository-level secret and the
|
|
461
|
+
client ID as a repository-level variable if every target shares one machine user,
|
|
462
|
+
but then any workflow on any branch can read them, so the environment's
|
|
463
|
+
protection rules no longer guard your deploys.
|
|
373
464
|
|
|
374
465
|
### Setting secrets and variables
|
|
375
466
|
|
|
@@ -389,24 +480,23 @@ tailor setup ci env --environment my-app-stg # only one environment (repeat for
|
|
|
389
480
|
|
|
390
481
|
The list follows what each generated workflow actually reads:
|
|
391
482
|
|
|
392
|
-
| Name | Kind | Targets
|
|
393
|
-
| -------------------------------------------- | -------- |
|
|
394
|
-
| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID` |
|
|
395
|
-
| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET` | secret | all
|
|
396
|
-
| `TAILOR_PLATFORM_WORKSPACE_ID` | variable | branch, tag
|
|
397
|
-
| `TAILOR_PLATFORM_ORGANIZATION_ID` | variable | preview
|
|
398
|
-
| `TAILOR_PLATFORM_FOLDER_ID` | variable | preview
|
|
399
|
-
| `TAILOR_PLATFORM_FAIL_ON_DRIFT` | variable | all
|
|
400
|
-
| `TAILOR_SLACK_BOT_TOKEN` | secret | branch, tag
|
|
401
|
-
| `TAILOR_SLACK_CHANNEL_ID` | variable | branch, tag
|
|
402
|
-
| `TAILOR_SLACK_USER_MAPPING` | variable | branch, tag
|
|
483
|
+
| Name | Kind | Targets | Required | Where the value comes from |
|
|
484
|
+
| -------------------------------------------- | -------- | ----------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
485
|
+
| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_ID` | variable | all | yes | Client ID of the platform machine user CI signs in as (an existing secret of the same name still works as a deprecated fallback); it needs an editor or admin role on the organization or folder that holds the workspace. An organization or folder admin creates one in the Tailor Console and grants it a role; without the required permission you cannot view or create machine users |
|
|
486
|
+
| `TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET` | secret | all | yes | Client secret of the same platform machine user |
|
|
487
|
+
| `TAILOR_PLATFORM_WORKSPACE_ID` | variable | branch, tag | yes | `id` printed by `tailor workspace create`, or listed by `tailor workspace list` |
|
|
488
|
+
| `TAILOR_PLATFORM_ORGANIZATION_ID` | variable | preview | yes | Organization to create the per-PR workspaces in (a machine user cannot create a workspace without one): `organizationId` listed by `tailor organization list` |
|
|
489
|
+
| `TAILOR_PLATFORM_FOLDER_ID` | variable | preview | no | Folder to create the per-PR workspaces in: `id` listed by `tailor organization folder list -o <organization id>`. When unset they go directly under the organization, which needs the machine user's role on the organization itself |
|
|
490
|
+
| `TAILOR_PLATFORM_FAIL_ON_DRIFT` | variable | all | no | `true` to fail the drift check when it finds drift |
|
|
491
|
+
| `TAILOR_SLACK_BOT_TOKEN` | secret | branch, tag | no | Bot User OAuth Token (`xoxb-...`) of a Slack app with the `chat:write` scope |
|
|
492
|
+
| `TAILOR_SLACK_CHANNEL_ID` | variable | branch, tag | no | Channel ID (`C...`) from the channel details in Slack; invite the bot to the channel |
|
|
493
|
+
| `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 |
|
|
403
494
|
|
|
404
495
|
See [Account management](https://docs.tailor.tech/administration/account-management)
|
|
405
496
|
for how organizations, folders, workspaces, and machine users relate.
|
|
406
497
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
together to enable Slack deploy notifications.
|
|
498
|
+
Set `TAILOR_SLACK_BOT_TOKEN` and `TAILOR_SLACK_CHANNEL_ID` together to enable
|
|
499
|
+
Slack deploy notifications.
|
|
410
500
|
|
|
411
501
|
The `gh` output creates an environment only when GitHub reports it missing and
|
|
412
502
|
leaves optional entries commented out. Run the commands one at a time: each
|
|
@@ -463,8 +553,7 @@ dispatches, so you can deploy any commit regardless of branch membership.
|
|
|
463
553
|
|
|
464
554
|
### Restricting manual deploys
|
|
465
555
|
|
|
466
|
-
Pass `--restrict-dispatch` to `setup ci branch
|
|
467
|
-
`setup ci coordinate` to limit what a manual dispatch with `dry-run` off can
|
|
556
|
+
Pass `--restrict-dispatch` to `setup ci branch` or `setup ci tag` to limit what a manual dispatch with `dry-run` off can
|
|
468
557
|
deploy:
|
|
469
558
|
|
|
470
559
|
- **Branch target:** only the target branch. Dispatching another branch skips
|
|
@@ -484,6 +573,67 @@ plan job also enters the environment, allow `refs/pull/*/merge` as well so pull
|
|
|
484
573
|
request plans keep running, and note that dry runs from other branches are then
|
|
485
574
|
rejected too.
|
|
486
575
|
|
|
576
|
+
## Seeding the workspace after deploy
|
|
577
|
+
|
|
578
|
+
Pass `--seed` to `setup ci branch`, `setup ci tag`, or `setup ci preview` to seed
|
|
579
|
+
the workspace with `tailor seed apply` right after each deploy. Add
|
|
580
|
+
`--seed-dataset <name>` (repeatable, implies `--seed`) to apply
|
|
581
|
+
[datasets](https://github.com/tailor-platform/sdk/tree/main/packages/sdk-plugin-seed#datasets)
|
|
582
|
+
on top of the base seed data:
|
|
583
|
+
|
|
584
|
+
```bash
|
|
585
|
+
tailor setup ci branch --seed-dataset stg
|
|
586
|
+
tailor setup ci preview --region us-west --seed-dataset preview
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
The deploy job gains a `tailor-seed` step after the deploy step. Branch targets
|
|
590
|
+
validate seed data before deploy and also in the PR or dry-run plan job; tag
|
|
591
|
+
targets validate it in the plan job before deploy. Both use
|
|
592
|
+
`tailor seed validate --upsert` with the selected datasets to check the `id`
|
|
593
|
+
and required fields that `seed apply --upsert` needs. Preview targets validate
|
|
594
|
+
and apply the data after deploy.
|
|
595
|
+
|
|
596
|
+
| Target | Seeds with | Effect |
|
|
597
|
+
| ----------- | ------------------------------------ | ----------------------------------------------------------------------------- |
|
|
598
|
+
| branch, tag | `tailor seed apply --upsert` | The fields of each committed seed row are written; other rows are kept |
|
|
599
|
+
| preview | `tailor seed apply --truncate --yes` | The preview workspace is emptied, IdP users included, and seeded from scratch |
|
|
600
|
+
|
|
601
|
+
Setup stops unless the config uses `seedPlugin` with `machineUserName`, which
|
|
602
|
+
names the machine user that seeds, and an existing `<distPath>/data/` directory.
|
|
603
|
+
Every `--seed-dataset` must name an entry of
|
|
604
|
+
the `seedPlugin` `datasets` option or a directory under `<distPath>/data/`.
|
|
605
|
+
Commit the dataset directories the workflow seeds: a gitignored dataset such as
|
|
606
|
+
a per-developer `local/` is not in the CI checkout.
|
|
607
|
+
Install `@tailor-platform/sdk-plugin-seed` so the `tailor seed` commands resolve
|
|
608
|
+
in CI. For branch and tag targets, use a version that supports
|
|
609
|
+
`tailor seed validate --upsert`; update the setup and seed plugins together.
|
|
610
|
+
Give every TailorDB seed row an `id` and
|
|
611
|
+
every field its table requires: `--upsert` matches rows by id, so run
|
|
612
|
+
`tailor seed fill` and commit the result.
|
|
613
|
+
Seeding is available for a target that deploys one app.
|
|
614
|
+
|
|
615
|
+
Before enabling it, note that:
|
|
616
|
+
|
|
617
|
+
- Every branch or tag deploy writes the fields of the committed seed rows over
|
|
618
|
+
the workspace, `_User` rows and their passwords included, so an edit to one of
|
|
619
|
+
those fields in the workspace is undone. Each row is updated like any other update: update hooks
|
|
620
|
+
and validation run, `updatedAt` changes, and executors with
|
|
621
|
+
`recordUpdatedTrigger` fire once per seeded row on every deploy.
|
|
622
|
+
- Every preview deploy deletes the data reviewers added to the preview
|
|
623
|
+
workspace. That is every push, and with `--require-preview-label` also every
|
|
624
|
+
label added to the pull request, since each one redeploys the preview.
|
|
625
|
+
- A seed failure fails the deploy job and its notification, although the deploy
|
|
626
|
+
itself went through.
|
|
627
|
+
- The step shares the deploy job's timeout. IdP users take about a second each.
|
|
628
|
+
- Steps you added after the deploy step stay right after it, so they run before
|
|
629
|
+
`tailor-seed`. Move a step below `tailor-seed` when it needs the seeded data,
|
|
630
|
+
and move it again if you regenerate without `--seed` and then with it.
|
|
631
|
+
- `tailor-seed` is an SDK-managed step. To seed another way (a different mode,
|
|
632
|
+
`--skip-idp`, a condition), leave `--seed` off and add your own step.
|
|
633
|
+
|
|
634
|
+
Re-run `setup ci` with the flags each time you regenerate the workflow; `setup
|
|
635
|
+
update` keeps them.
|
|
636
|
+
|
|
487
637
|
## Monorepo setup
|
|
488
638
|
|
|
489
639
|
For a monorepo where your SDK app lives in a subdirectory, pass `--dir`:
|
|
@@ -493,12 +643,14 @@ tailor setup ci branch --name my-app --dir apps/backend
|
|
|
493
643
|
```
|
|
494
644
|
|
|
495
645
|
The `working-directory` for SDK commands is set accordingly, and the workflow
|
|
496
|
-
only plans and deploys when that subdirectory
|
|
497
|
-
starts on every pull request and push: a
|
|
498
|
-
the change touches `apps/backend
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
646
|
+
only plans and deploys when that subdirectory or the generated workflow file
|
|
647
|
+
changes. The workflow itself starts on every pull request and push: a
|
|
648
|
+
`tailor-changes` job checks whether the change touches `apps/backend/**` or the
|
|
649
|
+
generated workflow file itself, and the plan, deploy, and ERD preview jobs are
|
|
650
|
+
skipped when it does not. A skipped job reports success, so you can require the
|
|
651
|
+
workflow's [result check](#requiring-the-workflow-in-branch-protection) in
|
|
652
|
+
branch protection; a workflow that a `paths` trigger filter never started would
|
|
653
|
+
leave it pending instead. If the `tailor-changes` job
|
|
502
654
|
itself fails (for example, on a GitHub API error), the plan, deploy, and ERD
|
|
503
655
|
preview jobs fail too instead of being skipped, so a required check blocks
|
|
504
656
|
merging and nothing is deployed. Re-run the failed jobs once the cause is gone.
|
|
@@ -539,8 +691,13 @@ tailor setup ci preview --name erp --region asia-northeast \
|
|
|
539
691
|
--paths "apps/*/frontend/**" --paths "modules/**" --paths pnpm-lock.yaml
|
|
540
692
|
```
|
|
541
693
|
|
|
542
|
-
The patterns are checked after the app directories
|
|
543
|
-
pattern that matches a changed file decides whether
|
|
694
|
+
The patterns are checked after the app directories and the generated workflow
|
|
695
|
+
file, in order, and the last pattern that matches a changed file decides whether
|
|
696
|
+
it counts. A change to the workflow file alone runs the generated plan, deploy,
|
|
697
|
+
and preview jobs, and with them any job of yours that needs them, in the pull
|
|
698
|
+
request or push that makes the change; to skip the jobs for such a change,
|
|
699
|
+
exclude the file, for example `--paths '!.github/workflows/tailor-erp.yml'`
|
|
700
|
+
(`tailor-erp-preview.yml` for the preview workflow). `*` matches
|
|
544
701
|
within one path segment, `**` matches any number of segments, and a pattern
|
|
545
702
|
starting with `!` excludes matching paths, so it can also exclude files inside
|
|
546
703
|
an app directory, for example `--paths '!apps/erp/backend/**/*.md'`. Other glob
|
|
@@ -597,8 +754,9 @@ a branch target deploys only its target branch, so use Option 1 there.
|
|
|
597
754
|
- **Schema and data are not rolled back.** If the older config expects a schema
|
|
598
755
|
state that no longer exists, the plan may show errors. In that case, review
|
|
599
756
|
the diff carefully before proceeding.
|
|
600
|
-
- **Seed data** is not
|
|
601
|
-
|
|
757
|
+
- **Seed data** is not rolled back. Without `--seed`, the pipeline does not
|
|
758
|
+
touch it; with `--seed`, deploying an older commit seeds the rows committed
|
|
759
|
+
there on top of the current data.
|
|
602
760
|
- **Static websites** are not yet integrated into the generated pipeline.
|
|
603
761
|
Static asset rollbacks must be performed manually.
|
|
604
762
|
|
|
@@ -675,14 +833,12 @@ finding names a stable rule key for future suppression. Run
|
|
|
675
833
|
[`tailor setup update`](#updating-the-generated-workflow) to regenerate the
|
|
676
834
|
targets it reports.
|
|
677
835
|
|
|
678
|
-
Workflows generated by `setup ci branch`, `setup ci tag`, `setup ci preview
|
|
679
|
-
|
|
836
|
+
Workflows generated by `setup ci branch`, `setup ci tag`, and `setup ci preview`
|
|
837
|
+
self-audit: each contains a `tailor-drift-check` step that
|
|
680
838
|
runs the check in CI. Preview workflows run it alongside each preview deploy,
|
|
681
839
|
so pull requests that deploy no preview (drafts, fork PRs, and unlabeled PRs
|
|
682
840
|
in label-triggered mode) skip the check. A single run audits every target
|
|
683
|
-
recorded in `.github/tailor.lock
|
|
684
|
-
`setup ci action` are covered by their coordinator's step and do not carry one
|
|
685
|
-
of their own.
|
|
841
|
+
recorded in `.github/tailor.lock`.
|
|
686
842
|
|
|
687
843
|
Drift findings are advisory by default. Set the repository variable
|
|
688
844
|
`TAILOR_PLATFORM_FAIL_ON_DRIFT` to `true` to make unsuppressed findings fail
|
|
@@ -702,28 +858,21 @@ pick up template improvements:
|
|
|
702
858
|
tailor setup update
|
|
703
859
|
```
|
|
704
860
|
|
|
705
|
-
It regenerates every workflow
|
|
861
|
+
It regenerates every workflow recorded in
|
|
706
862
|
`.github/tailor.lock` with the flags each one was generated with, so you do not
|
|
707
863
|
have to re-type `setup ci branch`, `setup ci tag`, and the rest one by one.
|
|
708
864
|
Your own jobs, steps, and settings are kept (see
|
|
709
865
|
[Customizing the generated workflow](#customizing-the-generated-workflow)). A
|
|
710
|
-
branch that was detected from the repository default branch
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
from the
|
|
866
|
+
branch that was detected from the repository default branch and a
|
|
867
|
+
[package manager](#package-manager) that was detected from the repository root
|
|
868
|
+
are detected again, and the parts that follow your config — the migration drift
|
|
869
|
+
check, seed validation, and ERD preview namespaces — are derived from the
|
|
870
|
+
current `tailor.config.ts`.
|
|
714
871
|
|
|
715
872
|
A target that cannot be regenerated, for example because you edited a managed
|
|
716
873
|
part, does not stop the others: `update` regenerates the rest, then lists the
|
|
717
874
|
targets it could not update and exits non-zero. Revert the edit, or run
|
|
718
875
|
`tailor setup update --force` to reset the managed parts of every target.
|
|
719
876
|
|
|
720
|
-
Coordinators generated by an older plugin version did not record how their
|
|
721
|
-
`--action` values were grouped, so `update` lists them instead of guessing
|
|
722
|
-
which apps deploy together. Re-run `tailor setup ci coordinate` once with all
|
|
723
|
-
of its original flags and its original `--action` groups. The message `update`
|
|
724
|
-
prints fills in the recorded flags (`--tag`, `--branch`, `--environment`,
|
|
725
|
-
`--restrict-dispatch`), so you only add the `--action` values. Later updates
|
|
726
|
-
pick the grouping up from the lock.
|
|
727
|
-
|
|
728
877
|
To change a flag for one target, re-run its `setup ci` subcommand with the new
|
|
729
878
|
flags. `.github/tailor.lock` records them, and later updates reuse them.
|
|
@@ -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
|
@@ -272,7 +272,8 @@ same fields. OAuth client secrets are never included.
|
|
|
272
272
|
`ctx.configPath` is the absolute path of the registering config. `ctx.workspaceId`
|
|
273
273
|
and `ctx.pluginConfig` identify the deployment workspace and the plugin's options.
|
|
274
274
|
Use `ctx.logger.info`, `warn`, and `success` for diagnostics; they write to stderr
|
|
275
|
-
and preserve deploy's JSON stdout.
|
|
275
|
+
and preserve deploy's JSON stdout. A hook that writes to stdout itself, such as
|
|
276
|
+
with `console.log`, makes `tailor deploy --json` output unparseable.
|
|
276
277
|
|
|
277
278
|
```typescript
|
|
278
279
|
import { definePlugins, type Plugin } from "@tailor-platform/sdk";
|
package/docs/services/auth.md
CHANGED
|
@@ -526,6 +526,26 @@ hooks: {
|
|
|
526
526
|
}
|
|
527
527
|
```
|
|
528
528
|
|
|
529
|
+
### Password age claim
|
|
530
|
+
|
|
531
|
+
For a user with a Built-in IdP password, `claims.password_updated_at` holds when the password was last set, in seconds since the Unix epoch. It is `undefined` for users without a password. Throw from the handler to reject a sign-in whose password is older than your policy allows.
|
|
532
|
+
|
|
533
|
+
```typescript
|
|
534
|
+
const MAX_PASSWORD_AGE_SECONDS = 90 * 24 * 60 * 60;
|
|
535
|
+
|
|
536
|
+
hooks: {
|
|
537
|
+
beforeLogin: {
|
|
538
|
+
handler: async ({ claims }) => {
|
|
539
|
+
const updatedAt = claims.password_updated_at;
|
|
540
|
+
if (updatedAt !== undefined && Date.now() / 1000 - updatedAt > MAX_PASSWORD_AGE_SECONDS) {
|
|
541
|
+
throw new Error("Password expired");
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
invoker: "hook-invoker",
|
|
545
|
+
},
|
|
546
|
+
}
|
|
547
|
+
```
|
|
548
|
+
|
|
529
549
|
## CLI Commands
|
|
530
550
|
|
|
531
551
|
Manage Auth resources using the CLI:
|
|
@@ -278,7 +278,7 @@ Executor callbacks receive the trigger args, including `env` from `defineConfig(
|
|
|
278
278
|
|
|
279
279
|
### Job Function Operation
|
|
280
280
|
|
|
281
|
-
For
|
|
281
|
+
For work that needs more than the 60-second `function` limit, use `jobFunction`, which can run for up to 5 minutes. See [Job Function Operation](https://docs.tailor.tech/guides/executor/job-function-operation) for details.
|
|
282
282
|
|
|
283
283
|
```typescript
|
|
284
284
|
import { createExecutor, scheduleTrigger } from "@tailor-platform/sdk";
|
|
@@ -292,7 +292,7 @@ export default createExecutor({
|
|
|
292
292
|
kind: "jobFunction",
|
|
293
293
|
body: async () => {
|
|
294
294
|
const db = getDB("tailordb");
|
|
295
|
-
//
|
|
295
|
+
// Report generation logic (runs up to 5 minutes)
|
|
296
296
|
const records = await db.selectFrom("Order").selectAll().execute();
|
|
297
297
|
// Process records...
|
|
298
298
|
},
|
package/docs/services/idp.md
CHANGED
|
@@ -105,6 +105,9 @@ defineIdp("my-idp", {
|
|
|
105
105
|
|
|
106
106
|
**Operators:** `"="`, `"!="`, `"in"`, `"not in"`
|
|
107
107
|
|
|
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. `tailor deploy` warns about each rule whose only condition is `_loggedIn`.
|
|
110
|
+
|
|
108
111
|
**Helper:** `unsafeAllowAllIdPPermission` grants full access without conditions. Intended only for development and testing.
|
|
109
112
|
|
|
110
113
|
```typescript
|
|
@@ -161,6 +164,8 @@ defineIdp("my-idp", {
|
|
|
161
164
|
- `passwordMinLength` - Minimum password length. Must be between 6 and 30. Default `6`.
|
|
162
165
|
- `passwordMaxLength` - Maximum password length. Must be between 6 and 4096. Default `4096`.
|
|
163
166
|
|
|
167
|
+
**Password expiration:** the IdP does not expire passwords on its own, but it records when each user's password was last set so you can enforce your own policy. The `User` records returned by `idp.Client` expose it as `passwordUpdatedAt` (an ISO 8601 string, or `null` for users without a password), for example to find expired passwords in a scheduled executor. To block sign-in with an expired password, read `claims.password_updated_at` in the Auth `beforeLogin` hook (see [Auth](./auth.md#password-age-claim)).
|
|
168
|
+
|
|
164
169
|
**Email domains and social login:**
|
|
165
170
|
|
|
166
171
|
- `allowedEmailDomains` - Restrict registration to these email domains. Each entry is a hostname (`example.com`), matched exactly and case-insensitively, so `example.com` does not cover `sub.example.com`. Up to 100 entries.
|
|
@@ -189,7 +194,7 @@ defineIdp("my-idp", {
|
|
|
189
194
|
read: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
190
195
|
update: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
191
196
|
delete: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
192
|
-
sendPasswordResetEmail: [{ conditions: [[{ user: "
|
|
197
|
+
sendPasswordResetEmail: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
193
198
|
unenrollMfa: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
194
199
|
},
|
|
195
200
|
});
|
|
@@ -141,7 +141,7 @@ GraphQL still accepts and returns `YYYY-MM-DD` strings. The SDK converts input t
|
|
|
141
141
|
|
|
142
142
|
This option also works in nested objects and with `array: true` or `optional: true`. Input must be a valid calendar date, and output must be a valid `Date` with a 4-digit UTC year (0000-9999). Both deployed resolvers and `tailor function run` perform these conversions.
|
|
143
143
|
|
|
144
|
-
A resolver bundle only includes the conversion code for the representations (`as: "date"` or `as: "temporal"`) its `input` and `output` use. To parse other values with such fields inside `body`, for example an external API response, use `parseDateFields` instead of `.parse()`. It takes the same arguments and returns the same result as `.parse()`. Calling `.parse()` on a field whose representation the bundle leaves out throws an error that points to `parseDateFields`.
|
|
144
|
+
A resolver bundle only includes the conversion code for the representations (`as: "date"` or `as: "temporal"`) its `input` and `output` use; with [`defaultDateRepresentation: "temporal"`](../configuration.md#application-settings), the Temporal conversion is always included. To parse other values with such fields inside `body`, for example an external API response, use `parseDateFields` instead of `.parse()`. It takes the same arguments and returns the same result as `.parse()`. Calling `.parse()` on a field whose representation the bundle leaves out throws an error that points to `parseDateFields`.
|
|
145
145
|
|
|
146
146
|
```typescript
|
|
147
147
|
import { parseDateFields } from "@tailor-platform/sdk/runtime";
|
|
@@ -204,6 +204,8 @@ createResolver({
|
|
|
204
204
|
|
|
205
205
|
All three field types support `array`, `optional`, nested objects, and input validators with the selected representation. Both deployed resolvers and `tailor function run` convert input and output. Executors using `resolverExecutedTrigger` receive date, datetime, and time results as strings.
|
|
206
206
|
|
|
207
|
+
To use Temporal values without writing `as: "temporal"` on every field, set [`defaultDateRepresentation: "temporal"`](../configuration.md#application-settings) in `defineConfig()`. Fields that omit `as` then use `Temporal.PlainDate`, `Temporal.Instant`, and `Temporal.PlainTime`, and `as: "string"` opts a single field back to strings. `defaultDateRepresentation: "date"` does the same for `Date` values. Run `tailor generate` after changing the setting so `tailor.d.ts` updates the field types.
|
|
208
|
+
|
|
207
209
|
The SDK supplies Temporal types, so existing projects can use `as: "temporal"` without changing `compilerOptions.lib`. To construct values or name their types, import `Temporal` from the SDK:
|
|
208
210
|
|
|
209
211
|
```typescript
|
|
@@ -145,11 +145,11 @@ const website = defineStaticWebSite("my-frontend", {
|
|
|
145
145
|
const idp = defineIdp("my-idp", {
|
|
146
146
|
clients: ["default-client"],
|
|
147
147
|
permission: {
|
|
148
|
-
create: [{ conditions: [[{ user: "
|
|
149
|
-
read: [{ conditions: [[{ user: "
|
|
150
|
-
update: [{ conditions: [[{ user: "
|
|
151
|
-
delete: [{ conditions: [[{ user: "
|
|
152
|
-
sendPasswordResetEmail: [{ conditions: [[{ user: "
|
|
148
|
+
create: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
149
|
+
read: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
150
|
+
update: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
151
|
+
delete: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
152
|
+
sendPasswordResetEmail: [{ conditions: [[{ user: "role" }, "=", "ADMIN"]], permit: true }],
|
|
153
153
|
},
|
|
154
154
|
});
|
|
155
155
|
|