@tailor-platform/sdk 2.1.0 → 2.3.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 +199 -0
- package/{dist/cli/index.mjs → bin/tailor.mjs} +1 -1
- package/dist/application-BZfk4HKm.mjs +3 -0
- package/dist/{application-D77KJFKD.mjs → application-F-nl107y.mjs} +121 -27
- package/dist/application-F-nl107y.mjs.map +1 -0
- package/dist/cli/commands/deploy/tailordb/index.d.mts +2 -1
- package/dist/cli/commands/deploy/types.d.mts +2 -1
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +52 -22
- package/dist/cli/commands/tailordb/migrate/file-state.d.mts +1 -0
- package/dist/cli/commands/tailordb/migrate/generate.d.mts +6 -0
- package/dist/cli/commands/tailordb/migrate/rename-detection.d.mts +22 -0
- package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +2 -2
- package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +9 -2
- package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +30 -9
- package/dist/cli/lib.d.mts +4 -4
- package/dist/cli/lib.mjs +3 -482
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +1151 -208
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/ts-hook.mjs +52 -7
- package/dist/completion/zsh-worker.zsh +167 -4
- package/dist/configure/index.d.mts +3 -3
- package/dist/configure/index.mjs +90 -23
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/index.d.mts +3 -2
- package/dist/configure/services/tailordb/index.d.mts +2 -1
- package/dist/configure/services/tailordb/schema.d.mts +46 -46
- package/dist/configure/services/tailordb/types.d.mts +30 -4
- package/dist/configure/services/workflow/index.d.mts +2 -2
- package/dist/configure/services/workflow/wait-point.d.mts +72 -13
- package/dist/{crashreport-B5LqCTfF.mjs → crashreport-CIIfLnoO.mjs} +2 -2
- package/dist/{crashreport-B5LqCTfF.mjs.map → crashreport-CIIfLnoO.mjs.map} +1 -1
- package/dist/{crashreport-eI7ty7ok.mjs → crashreport-CINZ5dVN.mjs} +1 -1
- package/dist/errors-BVb6vYGy.mjs +89 -0
- package/dist/errors-BVb6vYGy.mjs.map +1 -0
- package/dist/kysely/index.d.mts +53 -5
- package/dist/kysely/index.mjs +7 -2
- package/dist/kysely/index.mjs.map +1 -1
- package/dist/{logger-CXQq9YIp.mjs → logger-DSdExfor.mjs} +83 -42
- package/dist/logger-DSdExfor.mjs.map +1 -0
- package/dist/plugin/builtin/seed/index.mjs +1 -1
- package/dist/{register-ts-hook-BU18uU44.mjs → register-ts-hook-ClI226n2.mjs} +3541 -703
- package/dist/register-ts-hook-ClI226n2.mjs.map +1 -0
- package/dist/schema--xYWRGfe.mjs.map +1 -1
- package/dist/seed/index.d.mts +52 -3
- package/dist/seed/index.mjs +200 -44
- package/dist/seed/index.mjs.map +1 -1
- package/dist/{seed-B-yckgQY.mjs → seed-xqM9WIHP.mjs} +8 -8
- package/dist/seed-xqM9WIHP.mjs.map +1 -0
- package/dist/{service-k1xy_A5G.mjs → service-C_WpbKHu.mjs} +39 -5
- package/dist/service-C_WpbKHu.mjs.map +1 -0
- package/dist/service-D1RCdzIL.mjs +3 -0
- package/dist/{service-B5WynBHQ.mjs → service-hZskxZmg.mjs} +3 -3
- package/dist/{service-B5WynBHQ.mjs.map → service-hZskxZmg.mjs.map} +1 -1
- package/dist/{service_pb-D5--My_M.mjs → service_pb-BEWj1pOV.mjs} +2 -2
- package/dist/{service_pb-D5--My_M.mjs.map → service_pb-BEWj1pOV.mjs.map} +1 -1
- package/dist/{service_pb-i8CmnQP4.mjs → service_pb-BjlhvK9E.mjs} +1 -1
- package/dist/utils/test/index.d.mts +6 -3
- package/dist/utils/test/index.mjs +25 -13
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/index.d.mts +2 -1
- package/dist/vitest/index.mjs +167 -3
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/mocks/workflow.d.mts +13 -1
- package/dist/vitest/pglite-kysely.d.mts +43 -0
- package/dist/wait-point-invoker-__oE88_P.mjs +148 -0
- package/dist/wait-point-invoker-__oE88_P.mjs.map +1 -0
- package/dist/wait-point-registry-TL99zotw.mjs +47 -0
- package/dist/wait-point-registry-TL99zotw.mjs.map +1 -0
- package/dist/{workspace_resource_pb-DXnO2AT-.mjs → workspace_resource_pb-HNIL_Vfj.mjs} +10 -2
- package/dist/{workspace_resource_pb-DXnO2AT-.mjs.map → workspace_resource_pb-HNIL_Vfj.mjs.map} +1 -1
- package/docs/cli/setup.md +14 -1
- package/docs/cli/tailordb.md +96 -28
- package/docs/cli-reference.md +15 -12
- package/docs/configuration.md +1 -1
- package/docs/github-actions.md +73 -28
- package/docs/migration/v2.md +55 -1
- package/docs/plugin/custom.md +48 -48
- package/docs/plugin/index.md +24 -24
- package/docs/services/auth.md +10 -10
- package/docs/services/executor.md +1 -1
- package/docs/services/resolver.md +2 -2
- package/docs/services/tailordb-migration.md +485 -84
- package/docs/services/tailordb.md +28 -28
- package/docs/services/workflow.md +52 -2
- package/docs/testing.md +14 -0
- package/package.json +12 -7
- package/dist/application-Af1zIqSI.mjs +0 -3
- package/dist/application-D77KJFKD.mjs.map +0 -1
- package/dist/errors-D7583Zz7.mjs +0 -58
- package/dist/errors-D7583Zz7.mjs.map +0 -1
- package/dist/logger-CXQq9YIp.mjs.map +0 -1
- package/dist/register-ts-hook-BU18uU44.mjs.map +0 -1
- package/dist/seed-B-yckgQY.mjs.map +0 -1
- package/dist/service-M7OYziQP.mjs +0 -3
- package/dist/service-k1xy_A5G.mjs.map +0 -1
- package/dist/test-env-key-D7UkZp99.mjs +0 -75
- package/dist/test-env-key-D7UkZp99.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,204 @@
|
|
|
1
1
|
# @tailor-platform/sdk
|
|
2
2
|
|
|
3
|
+
## 2.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#2041](https://github.com/tailor-platform/sdk/pull/2041) [`0d2d542`](https://github.com/tailor-platform/sdk/commit/0d2d5420935a5f1f43f367f58837943fb49ad2dc) Thanks [@dqn](https://github.com/dqn)! - Add `tailor setup renovate` to generate a Renovate config that extends Tailor's shared preset without overwriting existing or customized configuration.
|
|
8
|
+
|
|
9
|
+
- [#2043](https://github.com/tailor-platform/sdk/pull/2043) [`2524e2f`](https://github.com/tailor-platform/sdk/commit/2524e2f0fff830c3ae8978d3136d6a7f0d22e0fe) Thanks [@dqn](https://github.com/dqn)! - Allow generated GitHub workflows to fail on unsuppressed setup drift when the `TAILOR_PLATFORM_FAIL_ON_DRIFT` repository variable is set to `true`. Execution and configuration errors in the drift check now fail regardless of this variable. Re-run the relevant `tailor setup` command after upgrading to regenerate the workflow.
|
|
10
|
+
|
|
11
|
+
- [#2035](https://github.com/tailor-platform/sdk/pull/2035) [`a928959`](https://github.com/tailor-platform/sdk/commit/a9289591359449da4157eb98a28c4beef14bc121) Thanks [@dqn](https://github.com/dqn)! - Convert a TailorDB field to a type that cannot be applied in place without writing the migrations by hand. `tailor tailordb migration generate` now offers to carry the values through a temporary field and writes both migrations for you; you supply the conversion expression. Non-interactive runs opt in per field with `--expand-contract "Type.field"`, and still fail without it.
|
|
12
|
+
|
|
13
|
+
Writes that land on the field while the conversion runs are dropped rather than converted, so stop writing to it first on a live workspace. Array-cardinality changes, unique fields, and fields named by an index, relationship, permission, or type-level script remain manual.
|
|
14
|
+
|
|
15
|
+
- [#2033](https://github.com/tailor-platform/sdk/pull/2033) [`d5801fc`](https://github.com/tailor-platform/sdk/commit/d5801fc94419359cfea2c3973b0d43333324510d) Thanks [@dqn](https://github.com/dqn)! - Support more TailorDB field type changes as single in-place migrations: `integer` now converts to `string` and `decimal`, `float` to `string` and `decimal`, `decimal` to `float`, and `boolean` to `string`. A `float` field that is already unique keeps to the 3-step migration when converting to `decimal`, because rounding to the target scale can merge distinct values.
|
|
16
|
+
|
|
17
|
+
- [#1991](https://github.com/tailor-platform/sdk/pull/1991) [`dcc66a6`](https://github.com/tailor-platform/sdk/commit/dcc66a61861cf4d94c6081e46d8fd9053d9f81e5) Thanks [@dqn](https://github.com/dqn)! - Renaming a TailorDB field no longer silently drops the field's data: `tailordb migration generate` now detects rename candidates and records a confirmed rename as a single breaking `field_renamed` change with a scaffolded data-copy script, instead of decomposing it into a removal plus an addition. Note: older SDK versions cannot read a `diff.json` that contains a `field_renamed` change and stop with a validation error.
|
|
18
|
+
|
|
19
|
+
- [#2026](https://github.com/tailor-platform/sdk/pull/2026) [`1346b75`](https://github.com/tailor-platform/sdk/commit/1346b75c1f3e2dd41297db18c6e7b8e676e01f77) Thanks [@dqn](https://github.com/dqn)! - Renaming a TailorDB type no longer silently drops its records: `tailordb migration generate` now detects type rename candidates and records a confirmed rename as a single breaking `type_renamed` change with a scaffolded id-preserving data-copy script, instead of decomposing it into a removal plus an addition (confirm interactively, or via `--rename "OldType:NewType"` / `--drop "Type"` in non-interactive runs). Note: older SDK versions cannot read a `diff.json` that contains a `type_renamed` change and stop with a validation error.
|
|
20
|
+
|
|
21
|
+
- [#1933](https://github.com/tailor-platform/sdk/pull/1933) [`89b5647`](https://github.com/tailor-platform/sdk/commit/89b5647c21624b3782af4e8bf3a0de39b10b1ed0) Thanks [@toiroakr](https://github.com/toiroakr)! - Support wait point keys with runtime values. Write `$paramName` in a key passed to `createWaitPoints`' `define` and the param names become the argument of `.with()`, which builds the concrete key:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
export const { lineApproval } = createWaitPoints((define) => ({
|
|
25
|
+
lineApproval: define.for("line-approval-$lineId")<{ message: string }, { approved: boolean }>(),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
await lineApproval.with({ lineId: line.id }).wait({ message: "Please approve" });
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This makes it possible for one execution to suspend on the same logical wait point more than once at a time — one approval per order line, one per approver — which previously failed because a suspension with that key was already pending. A parameterized wait point exposes only `.with()`, so the unsubstituted key can never be waited on. `mockWorkflow().waitPointWith(definition, params)` gives typed mocks for one binding.
|
|
32
|
+
|
|
33
|
+
The key has to come before the `Payload` / `Result` type arguments, because TypeScript stops inferring it as a literal type once those are given explicitly, and the param names can only be read off a literal. `createWaitPoint` takes its type arguments first, so it cannot type `$params`; `deploy` rejects such a key and points at `createWaitPoints`. Its own signature is unchanged.
|
|
34
|
+
|
|
35
|
+
Wait point keys are now checked by `deploy` instead of failing when the job creates the suspension. Keys must match `[a-z0-9-]`, be 3 to 63 characters long, and start and end with `[a-z0-9]`. A key that never worked — a camelCase `createWaitPoints` property name, say — was rejected by the platform once the job ran; `deploy` now reports it before anything is deployed. Inside `createWaitPoints`, pass a valid key to `define` to keep the property name you read at the call site:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
managerApproval: define.for("manager-approval")<{ amount: number }, { approved: boolean }>(),
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
This works for a key without `$params` too, which is the way to keep a property name that reads well at the call site while the key stays within the platform grammar.
|
|
42
|
+
|
|
43
|
+
### Patch Changes
|
|
44
|
+
|
|
45
|
+
- [#2025](https://github.com/tailor-platform/sdk/pull/2025) [`2574bdd`](https://github.com/tailor-platform/sdk/commit/2574bdd69947b0f6e050c3c0af224fc3f18c6435) Thanks [@dqn](https://github.com/dqn)! - Treat `migrate.test.ts` as a migration artifact: `tailordb migration rebaseline` now removes a test-only migration directory together with the history it belongs to, and aborts when one is added while its confirmation prompt is open.
|
|
46
|
+
|
|
47
|
+
- [#2012](https://github.com/tailor-platform/sdk/pull/2012) [`8826675`](https://github.com/tailor-platform/sdk/commit/88266754543c0975609274f0905c3a5b19cb9538) Thanks [@renovate](https://github.com/apps/renovate)! - chore(deps): lock file maintenance
|
|
48
|
+
|
|
49
|
+
- [#2014](https://github.com/tailor-platform/sdk/pull/2014) [`3852f3a`](https://github.com/tailor-platform/sdk/commit/3852f3a71dc5235c979b596cf23f1b252e3a3532) Thanks [@renovate](https://github.com/apps/renovate)! - chore(deps): update dependency tsx to v4.23.10
|
|
50
|
+
|
|
51
|
+
- [#2018](https://github.com/tailor-platform/sdk/pull/2018) [`6d13888`](https://github.com/tailor-platform/sdk/commit/6d13888b0fa07d078076ad3df9f3992f61419d6b) Thanks [@renovate](https://github.com/apps/renovate)! - fix(deps): update dependency @toiroakr/lines-db to v0.12.0
|
|
52
|
+
|
|
53
|
+
- [#2042](https://github.com/tailor-platform/sdk/pull/2042) [`6ee6584`](https://github.com/tailor-platform/sdk/commit/6ee65841670880986b392dabc69c06b1a2f3988f) Thanks [@dqn](https://github.com/dqn)! - Retry machine-user access token requests after transient connection timeouts.
|
|
54
|
+
|
|
55
|
+
- [#2032](https://github.com/tailor-platform/sdk/pull/2032) [`b173a0d`](https://github.com/tailor-platform/sdk/commit/b173a0de53c5235b8c201bc8c671ebf812953d1c) Thanks [@dqn](https://github.com/dqn)! - Workflows generated by `tailor setup preview` now include a `tailor-drift-check` step, so preview-only repositories audit their generated workflows in CI like branch, tag, and coordinator workflows already do. The check is warning-only and never fails the job. `tailor setup check` reports targets generated with an older template as outdated; re-run the matching `tailor setup` subcommand to regenerate them.
|
|
56
|
+
|
|
57
|
+
- [#2034](https://github.com/tailor-platform/sdk/pull/2034) [`413f6cb`](https://github.com/tailor-platform/sdk/commit/413f6cbf8faefefb155869f14e0ea76e939c1b41) Thanks [@dqn](https://github.com/dqn)! - Name the serial-column constraint in `db.insertInto(...).values({ ... })` and `.set({ ... })` errors, where TypeScript previously truncated the explanation away
|
|
58
|
+
|
|
59
|
+
- [#2051](https://github.com/tailor-platform/sdk/pull/2051) [`a3b980d`](https://github.com/tailor-platform/sdk/commit/a3b980da849c28b5faf985469fdde4a193ec269f) Thanks [@toiroakr](https://github.com/toiroakr)! - Fix `tailordb deploy`/`migrate` failing with `type_hook.create.expr: must be at most 10000 characters` on TailorDB types with many field hooks. The generated hook scripts are now optimized to avoid duplication.
|
|
60
|
+
|
|
61
|
+
Since generated hook/validate script text changes for any type with hooks, the first `tailordb migration generate` after upgrading will report a script update for those types even without any code changes on your side — this is expected and required for the fix to take effect.
|
|
62
|
+
|
|
63
|
+
- [#2049](https://github.com/tailor-platform/sdk/pull/2049) [`b3b2aae`](https://github.com/tailor-platform/sdk/commit/b3b2aae05a63e2514cdd796d9a8b16bf458f1fcd) Thanks [@dqn](https://github.com/dqn)! - TailorDB schema snapshots now keep their tables under a `tables` key instead of `types`, completing the `db.type()` → `db.table()` rename. Committed migration histories keep replaying: a legacy `types` key in `schema.json` is still read and moved on load, so no migration files need editing. Migration file format version is now 5 and this SDK reads versions 1 through 5.
|
|
64
|
+
|
|
65
|
+
Code that imports `SchemaSnapshot` or `NormalizedSchemaSnapshot` from `@tailor-platform/sdk/cli` and reads `snapshot.types` no longer compiles:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
Object.keys(snapshot.types); // before
|
|
69
|
+
Object.keys(snapshot.tables); // after
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This also applies to the snapshots returned by `compareSnapshots`, `createSnapshotFromLocalTypes`, `reconstructSnapshotFromMigrations`, and `compareLocalTypesWithSnapshot`.
|
|
73
|
+
|
|
74
|
+
The `types` key on parsed TailorDB service config is a different thing and is unchanged.
|
|
75
|
+
|
|
76
|
+
- [#2044](https://github.com/tailor-platform/sdk/pull/2044) [`8a5cc3f`](https://github.com/tailor-platform/sdk/commit/8a5cc3fe9a5f53f0128857f095c9b995f86c7408) Thanks [@dqn](https://github.com/dqn)! - TailorDB migration diffs now describe table-level changes as `table_*` instead of `type_*`, completing the `db.type()` → `db.table()` rename. Migration histories written by earlier versions keep working: `type_*` change kinds in committed `diff.json` files are still read and normalized on load, so no migration files need editing. Migration file format version is now 3 and this SDK reads versions 1 through 3. CLI diff output reads `[Table]` and `table(s) added` where it previously read `[Type]` and `type(s) added`.
|
|
77
|
+
|
|
78
|
+
Code that imports `MigrationDiff` / `DiffChange` from `@tailor-platform/sdk/cli` and compares `change.kind` against a renamed spelling no longer compiles, because the discriminant literal is gone from the union:
|
|
79
|
+
|
|
80
|
+
| Old spelling | New spelling |
|
|
81
|
+
| ------------------------ | ------------------------- |
|
|
82
|
+
| `type_added` | `table_added` |
|
|
83
|
+
| `type_removed` | `table_removed` |
|
|
84
|
+
| `type_renamed` | `table_renamed` |
|
|
85
|
+
| `type_modified` | `table_modified` |
|
|
86
|
+
| `type_settings_modified` | `table_settings_modified` |
|
|
87
|
+
| `type_scripts_modified` | `table_scripts_modified` |
|
|
88
|
+
|
|
89
|
+
Update those comparisons to the new spelling. Reading `diff.json` files is unaffected.
|
|
90
|
+
|
|
91
|
+
- [#2045](https://github.com/tailor-platform/sdk/pull/2045) [`c468a23`](https://github.com/tailor-platform/sdk/commit/c468a2327025dea9c3b5f8d0554010f5efba9211) Thanks [@dqn](https://github.com/dqn)! - TailorDB migration diffs now name the table they describe with `tableName` instead of `typeName`, and a rename records `previousTableName` instead of `previousTypeName`, continuing the `db.type()` → `db.table()` rename. Migration histories written by earlier versions keep replaying: the legacy field names in committed `diff.json` files are still read and normalized on load, across change entries, breaking changes, and warnings, so no migration files need editing. Migration file format version is now 4 and this SDK reads versions 1 through 4.
|
|
92
|
+
|
|
93
|
+
Code that imports `MigrationDiff` / `DiffChange` / `BreakingChangeInfo` from `@tailor-platform/sdk/cli` and reads the renamed properties no longer compiles:
|
|
94
|
+
|
|
95
|
+
| Old spelling | New spelling |
|
|
96
|
+
| ---------------------------- | ----------------------------- |
|
|
97
|
+
| `change.typeName` | `change.tableName` |
|
|
98
|
+
| `change.previousTypeName` | `change.previousTableName` |
|
|
99
|
+
| `breakingChanges[].typeName` | `breakingChanges[].tableName` |
|
|
100
|
+
| `warnings[].typeName` | `warnings[].tableName` |
|
|
101
|
+
|
|
102
|
+
Update those reads to the new spelling. `tailor tailordb migration validate --json` renames the same key wherever it appears in its output, so anything parsing that JSON needs the same update.
|
|
103
|
+
|
|
104
|
+
The `typeName` field on executor record triggers, the `.typeName()` field builder, and the file-runtime `typeName` argument are unrelated and unchanged.
|
|
105
|
+
|
|
106
|
+
- [#2052](https://github.com/tailor-platform/sdk/pull/2052) [`a31d362`](https://github.com/tailor-platform/sdk/commit/a31d362d4d7386a2f3dcce06f3c53c78537ffcec) Thanks [@toiroakr](https://github.com/toiroakr)! - Isolate the SDK test suite (every vitest project except e2e) from TAILOR_\* environment variables exported by the developer's shell, so tests pass regardless of local CLI configuration.
|
|
107
|
+
|
|
108
|
+
- [#2022](https://github.com/tailor-platform/sdk/pull/2022) [`4eb5302`](https://github.com/tailor-platform/sdk/commit/4eb530251e2480cd8179325fe43950c5cab5b954) Thanks [@dqn](https://github.com/dqn)! - Fail `deploy` and `tailordb migration validate` when a migration has both a recorded `--no-script` acknowledgment and a `migrate.ts`, instead of warning and running the script against the committed record. The error names the two ways out: rerun `tailordb migration script <n>` to clear the stale acknowledgment (the script then runs on the next deploy), or delete `migrate.ts` to keep the skip.
|
|
109
|
+
|
|
110
|
+
- [#2027](https://github.com/tailor-platform/sdk/pull/2027) [`794bab7`](https://github.com/tailor-platform/sdk/commit/794bab7ffec4c63f30a8b7a305bb34443573fbec) Thanks [@dqn](https://github.com/dqn)! - Reload user modules (config, tailordb types, workflows, resolvers, executors, HTTP adapters) on every `deploy()` run, so calling the programmatic `deploy()` repeatedly in one Node process picks up file changes and re-registers wait point keys instead of silently reusing modules cached by an earlier run.
|
|
111
|
+
|
|
112
|
+
- [#2023](https://github.com/tailor-platform/sdk/pull/2023) [`9dc826f`](https://github.com/tailor-platform/sdk/commit/9dc826fc0a83aa926de5b07245513f67c1ace877) Thanks [@dqn](https://github.com/dqn)! - Guide users through the v2 type-only import requirement. The CLI loads TypeScript by stripping types from each file in isolation, so a plain import of a type-only export fails at load time with `SyntaxError: ... does not provide an export named '<name>'` and no indication that the import form is the cause.
|
|
113
|
+
|
|
114
|
+
- The CLI now appends a suggestion to that error: import the name with `import type` and set `"verbatimModuleSyntax": true` in tsconfig.json to catch violations at typecheck.
|
|
115
|
+
- Projects scaffolded by `tailor init` now enable `verbatimModuleSyntax` in their tsconfig.json, so new projects catch violations at typecheck instead of at load time.
|
|
116
|
+
- The v2 migration guide gains a `v2/type-only-imports` entry documenting the requirement, the failure mode, and the migration steps, offered by `tailor upgrade` when crossing the v2 boundary.
|
|
117
|
+
|
|
118
|
+
## 2.2.0
|
|
119
|
+
|
|
120
|
+
### Minor Changes
|
|
121
|
+
|
|
122
|
+
- [#1992](https://github.com/tailor-platform/sdk/pull/1992) [`6e67451`](https://github.com/tailor-platform/sdk/commit/6e6745147d07d6d1a26291f3d2cc8510170ae407) Thanks [@dqn](https://github.com/dqn)! - TailorDB migration scripts can now be unit-tested before deploying:
|
|
123
|
+
|
|
124
|
+
- The generated `db.ts` exports the `Database` interface, so `createKyselyMock<Database>()` from `@tailor-platform/sdk/vitest` types queries against the migration's schema state.
|
|
125
|
+
- `tailor tailordb migration script <number> --with-test` scaffolds a ready-to-fill `migrate.test.ts` next to the migration script. When `migrate.ts` already exists (e.g. auto-generated for a breaking change), the flag adds only the test file.
|
|
126
|
+
- `createKyselyPGlite<Database>(new PGlite())` from `@tailor-platform/sdk/vitest` runs a migration script against an in-memory Postgres (`@electric-sql/pglite`, installed separately) to verify what it does to real rows.
|
|
127
|
+
- The migration guide's Testing section now documents the workflow.
|
|
128
|
+
|
|
129
|
+
- [#1975](https://github.com/tailor-platform/sdk/pull/1975) [`b5ca25b`](https://github.com/tailor-platform/sdk/commit/b5ca25b796e8a5e4262ea2e3527973d77cab766a) Thanks [@toiroakr](https://github.com/toiroakr)! - Add `tailor seed fill` to fill in the values a record gets on create for the JSONL seed data rows that are missing them. It fills `id` by default, so rows can reference each other by id, and `--fields` names any other create-time field:
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# ./seed/data/Customer.jsonl: {"name":"Acme Corporation"}
|
|
133
|
+
tailor seed fill
|
|
134
|
+
# ./seed/data/Customer.jsonl: {"id":"0b6b6f5e-...","name":"Acme Corporation"}
|
|
135
|
+
|
|
136
|
+
# also stamp a creation time on rows that have none
|
|
137
|
+
tailor seed fill --fields id,createdAt
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The values come from the type itself — its `id`, its field defaults, its create hooks — applied to each row on its own. Nothing is validated, so a row can be filled while a required field is still missing or while another file references an id that does not exist yet; that is the point, since the ids are what you need in order to write the rows that reference them. Run `tailor seed validate` when the data is ready.
|
|
141
|
+
|
|
142
|
+
Only the named fields are written, and only into a row that has no value for them, so a value already in the file is never replaced. A line that gains nothing is left byte for byte as it was; a line that takes a value is written with its keys in the order the type declares its fields, so a filled-in `id` lands at the front. A field the type gives no value to is skipped, so `--fields id` covers a whole data directory and leaves the IdP `_User` data alone, and naming a field the platform assigns — a `serial` field, for instance — fills nothing and says so.
|
|
143
|
+
|
|
144
|
+
`tailor seed apply --upsert` now points at the command when a row has no `id`, since that is the run it blocks, and newly scaffolded projects get a `seed:fill` script next to `seed:validate`.
|
|
145
|
+
|
|
146
|
+
The generated seed schema files now export the type's create hook, which is where the values come from. Run `tailor generate` after upgrading; until then `tailor seed fill` reports which file needs regenerating.
|
|
147
|
+
|
|
148
|
+
`createTailorDBHook` from `@tailor-platform/sdk/test` no longer runs the type's own `validate`. Computing the values a record gets on create and deciding whether a record is acceptable are separate jobs, and the second one now sits where the field-level validation already was: `createStandardSchema` takes the type as a third argument and reports type-level issues through its result.
|
|
149
|
+
|
|
150
|
+
`tailor seed validate` also stops printing two markers on the header of a failed run (`\u2716 \u2717 Found 2 error(s) in ...`), now that it hands the CLI a report that is already formatted.
|
|
151
|
+
|
|
152
|
+
That also fixes how `tailor seed validate` reports them. A type-level `validate` failure used to end the run at the first offending row with a bare message; it now lands in the same report as every other issue, naming the file and every row that fails.
|
|
153
|
+
|
|
154
|
+
A test calling `createTailorDBHook` directly to assert a type-level `validate` throws needs to go through `createStandardSchema` instead.
|
|
155
|
+
|
|
156
|
+
The same operation is available as `fillSeedData` from `@tailor-platform/sdk/seed`.
|
|
157
|
+
|
|
158
|
+
- [#1979](https://github.com/tailor-platform/sdk/pull/1979) [`07c50a6`](https://github.com/tailor-platform/sdk/commit/07c50a6d5728827b937160a97182c3996c00baad) Thanks [@toiroakr](https://github.com/toiroakr)! - Add `TailorDBColumns` / `TailorDBInsertable` / `TailorDBSelectable` / `TailorDBUpdateable` to `@tailor-platform/sdk/kysely`. They accept either a table (`typeof myTable`) or a bare field collection, so code that is generic over the fields can derive create/read/update inputs the same way the generated table types do: `.serial()` fields are never caller-supplied, `.default()` and `.hooks({ create })` fields may be omitted on create, optional fields stay optional, and `id` is generated. `IsReadOnlyDBField` and `IsAutoFilledDBField` are also exported from `@tailor-platform/sdk` for asking whether callers can never write a single field, or may omit it on create.
|
|
159
|
+
|
|
160
|
+
Supplying a value for a `.serial()` column now fails with the reason instead of `'<column>' does not exist in type ...`, which read as a typo:
|
|
161
|
+
|
|
162
|
+
```
|
|
163
|
+
Type 'string' is not assignable to type 'TypeLevelError<"assigned by .serial(); remove it from the input">'.
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This applies to the tables `kyselyTypePlugin` generates as well, because it comes from `Serial`. A serial column is now an omittable key on `Insertable`/`Updateable` rather than an absent one, so `keyof Insertable<Table<"MyType">>` includes it, and copying a whole record into a create input (`{ ...row }`) now reports the serial column instead of silently dropping it. Assigning the same values as before still compiles, and passing `undefined` is equivalent to omitting the column.
|
|
167
|
+
|
|
168
|
+
`Insertable`, `Selectable` and `Updateable` from the generated `Namespace` also print as a flat object rather than an intersection, so assignability errors name the shape directly.
|
|
169
|
+
|
|
170
|
+
`TailorDBField` gains an optional third type parameter carrying a nested object's own fields, so `db.object({ at: db.datetime() })` keeps that shape through the builder chain. Without it a date or datetime nested in an object resolved to `string | Date` (or `string`) while the runtime hands back a `Date`. Writing `TailorDBField<Defined, Output>` still works.
|
|
171
|
+
|
|
172
|
+
- [#1988](https://github.com/tailor-platform/sdk/pull/1988) [`f45ed5b`](https://github.com/tailor-platform/sdk/commit/f45ed5b380620d58f332fd2dd8fc5bb92ea28ecd) Thanks [@dqn](https://github.com/dqn)! - Add `tailor tailordb migration test` to rehearse pending migrations in an isolated workspace. The command can load generated seed fixtures or clone source TailorDB records, run the real migration phases, optionally execute a Kysely assertion script, and deletes workspaces it creates unless `--keep` is passed.
|
|
173
|
+
|
|
174
|
+
- [#1984](https://github.com/tailor-platform/sdk/pull/1984) [`2f8457d`](https://github.com/tailor-platform/sdk/commit/2f8457d433b583769b136ece9a0c483cfccf6cdd) Thanks [@dqn](https://github.com/dqn)! - Add `--strict` to `tailordb migration validate`: validation additionally fails when a migration not yet applied to the remote has data-loss warnings (e.g. a removed field or type) but neither a `migrate.ts` nor a recorded `--no-script` acknowledgment. The failure names the affected type and field and prints the exact command to record the acknowledgment, so CI can require destructive changes to be explicitly acknowledged before merge.
|
|
175
|
+
|
|
176
|
+
To support this, `tailordb migration script <number> --no-script --reason "..."` now accepts warning-tier migrations (previously it was rejected unless the migration required a script), and `migration generate` offers to record the reason interactively when it detects warnings. Additionally, running `migration script <number>` when `migrate.ts` already exists now clears a stale `--no-script` acknowledgment from `diff.json` instead of failing, resolving the previously unclearable state after hand-adding a script.
|
|
177
|
+
|
|
178
|
+
`diff.json` files written before data-loss warnings existed now have their warnings reconstructed from the recorded field/type removals when loaded, so `validate --strict` and `--no-script` acknowledgments treat them the same as newly generated migrations.
|
|
179
|
+
|
|
180
|
+
- [#1993](https://github.com/tailor-platform/sdk/pull/1993) [`ecff3b2`](https://github.com/tailor-platform/sdk/commit/ecff3b2267f666de0ef83aef6b7727913e724a35) Thanks [@dqn](https://github.com/dqn)! - Add generated in-place TailorDB migrations for verified field type changes. Migration scripts normalize existing values while the previous field contract remains active, and the target type is applied in the post-migration phase. Generated scripts intentionally fail TypeScript checks until their normalization logic is reviewed.
|
|
181
|
+
|
|
182
|
+
- [#1990](https://github.com/tailor-platform/sdk/pull/1990) [`36715da`](https://github.com/tailor-platform/sdk/commit/36715da7a125863c9dadd99cdcbb5fd45a51b4c9) Thanks [@dqn](https://github.com/dqn)! - Add a safe `tailordb migration rebaseline` workflow, let checked deployments adopt the new baseline, keep migration history IDs aligned across recovery commands, and reject unsupported migration file formats with upgrade guidance
|
|
183
|
+
|
|
184
|
+
### Patch Changes
|
|
185
|
+
|
|
186
|
+
- [#1960](https://github.com/tailor-platform/sdk/pull/1960) [`50743ad`](https://github.com/tailor-platform/sdk/commit/50743ad4cb38dc8f237934d3f9c905f2512ff6e4) Thanks [@toiroakr](https://github.com/toiroakr)! - Resolve the `tailor`, `tailor-seed`, and `tailor-tailordb-erd` executables through committed compile-cache launchers. The `tailor seed` command is now available as soon as the plugin is installed, and the seed and ERD plugin CLIs reuse Node's on-disk compile cache for faster warm starts.
|
|
187
|
+
|
|
188
|
+
- [#1934](https://github.com/tailor-platform/sdk/pull/1934) [`2a3ec7b`](https://github.com/tailor-platform/sdk/commit/2a3ec7b108275410bf5b35d23784b07aa147c5ea) Thanks [@toiroakr](https://github.com/toiroakr)! - Drop the `chalk` dependency in favor of Node's built-in styling, and decide color support per output stream. Diagnostics on stderr now keep their colors when you redirect stdout (`tailor executor list > out.txt`), and stop writing escape codes into the file when you redirect stderr (`tailor deploy 2> log.txt`). `NO_COLOR`, `FORCE_COLOR` and non-TTY detection keep working as before.
|
|
189
|
+
|
|
190
|
+
`@tailor-platform/sdk-codemod`, `@tailor-platform/sdk-plugin-seed` and `@tailor-platform/sdk-plugin-tailordb-erd` now declare the Node and Bun versions they need (`node >=22.15.0`, `bun >=1.2.0`), matching `@tailor-platform/sdk`. Installing them on an older runtime reports the mismatch instead of failing once the CLI runs.
|
|
191
|
+
|
|
192
|
+
- [#1985](https://github.com/tailor-platform/sdk/pull/1985) [`ab23d97`](https://github.com/tailor-platform/sdk/commit/ab23d97e79eb2be6fb3f9d7ddd21515c1bf1c244) Thanks [@dqn](https://github.com/dqn)! - Copyable migration-script hint commands — from `migration generate`, `migration validate --strict`, and deploy's missing-script error — are now rendered by one shell-aware formatter. Values are quoted for the platform shell, and on Windows a value containing `%`, `$`, or `!` (which cmd.exe/PowerShell expand even inside double quotes) switches the hint to an argv rendering instead of a command line that would resolve to a different path. The deploy hint now also pads the migration number, binds `--config` with the `=` form, and omits it for the default config path.
|
|
193
|
+
|
|
194
|
+
- [#1999](https://github.com/tailor-platform/sdk/pull/1999) [`4364357`](https://github.com/tailor-platform/sdk/commit/436435740510accbdb3aa627fe4439bd1656bb96) Thanks [@renovate](https://github.com/apps/renovate)! - fix(deps): update dependency globals to v17.9.0
|
|
195
|
+
|
|
196
|
+
- [#1994](https://github.com/tailor-platform/sdk/pull/1994) [`7e804d4`](https://github.com/tailor-platform/sdk/commit/7e804d464e40a73fb524338cf7eda42e88f5ede8) Thanks [@dqn](https://github.com/dqn)! - Make `tailor tailordb migration validate` reject generated field type normalization scaffolds until their review marker is removed.
|
|
197
|
+
|
|
198
|
+
- [#2008](https://github.com/tailor-platform/sdk/pull/2008) [`f2135ab`](https://github.com/tailor-platform/sdk/commit/f2135ab6dd3d130d88803b9829a26024de930ed3) Thanks [@toiroakr](https://github.com/toiroakr)! - Consistently call a TailorDB schema definition a "table" instead of a "type" across the docs, matching the `db.type()` → `db.table()` rename. Also fix three leftover `db.type(...)` code samples in `docs/services/tailordb.md` that should have read `db.table(...)`.
|
|
199
|
+
|
|
200
|
+
Update the `v2/idp-publish-events-rename` codemod registry description to say "tables" instead of "types", matching the same wording fix.
|
|
201
|
+
|
|
3
202
|
## 2.1.0
|
|
4
203
|
|
|
5
204
|
### Minor Changes
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { n as isSdkBranded } from "./brand-Eo4pLXPJ.mjs";
|
|
2
|
+
import { n as getScopedWaitPoints } from "./wait-point-registry-TL99zotw.mjs";
|
|
2
3
|
import { t as assertDefined } from "./assert-DBxo8jPo.mjs";
|
|
3
|
-
import { a as parseBoolean, n as logger, r as styles } from "./logger-
|
|
4
|
-
import { a as AuthConfigSchema, c as stripTailorDBTypeBuilderHelpers, d as applyRelationMetadataToFieldConfig, f as buildRelationInfo,
|
|
4
|
+
import { a as parseBoolean, n as logger, r as styles } from "./logger-DSdExfor.mjs";
|
|
5
|
+
import { a as AuthConfigSchema, b as functionSchema, c as stripTailorDBTypeBuilderHelpers, d as applyRelationMetadataToFieldConfig, f as buildRelationInfo, h as loadFilesWithIgnores, l as TailorDBServiceConfigSchema, m as validateRelationConfig, n as loadExecutor, o as AuthInvokerSchema, p as processRelationMetadata, s as TailorFieldSchema, t as createExecutorService, u as TailorDBTypeSchema, y as importUserModule } from "./service-C_WpbKHu.mjs";
|
|
5
6
|
import { t as multiline } from "./multiline-sfHpTZZK.mjs";
|
|
6
7
|
import { t as userAgent } from "./user-agent-Bgsszb5I.mjs";
|
|
7
|
-
import { t as createCLIError } from "./errors-
|
|
8
|
+
import { t as createCLIError } from "./errors-BVb6vYGy.mjs";
|
|
8
9
|
import { n as isNodeBuiltinImport, t as getNodeBuiltinMessage } from "./node-builtins-CmaL2Cbq.mjs";
|
|
9
10
|
import { t as isPluginGeneratedType } from "./type-source-DH_LH20p.mjs";
|
|
10
11
|
import { createRequire } from "node:module";
|
|
@@ -16,7 +17,6 @@ import { create } from "@bufbuild/protobuf";
|
|
|
16
17
|
import * as fs from "node:fs";
|
|
17
18
|
import { readFileSync } from "node:fs";
|
|
18
19
|
import { MethodOptions_IdempotencyLevel } from "@bufbuild/protobuf/wkt";
|
|
19
|
-
import { pathToFileURL } from "node:url";
|
|
20
20
|
import { OAuth2Client } from "@badgateway/oauth2-client";
|
|
21
21
|
import { Code, ConnectError, createClient } from "@connectrpc/connect";
|
|
22
22
|
import pLimit from "p-limit";
|
|
@@ -182,7 +182,7 @@ function initOAuth2Client(config) {
|
|
|
182
182
|
*/
|
|
183
183
|
async function initOperatorClient(accessToken, config) {
|
|
184
184
|
const platformConfig = config ?? getPlatformConfigForToken(accessToken);
|
|
185
|
-
const [{ createTracingInterceptor }, { OperatorService }] = await Promise.all([import("./interceptor-e33JtsC-.mjs"), import("./service_pb-
|
|
185
|
+
const [{ createTracingInterceptor }, { OperatorService }] = await Promise.all([import("./interceptor-e33JtsC-.mjs"), import("./service_pb-BjlhvK9E.mjs")]);
|
|
186
186
|
const interceptors = [
|
|
187
187
|
await userAgentInterceptor(),
|
|
188
188
|
await bearerTokenInterceptor(accessToken),
|
|
@@ -253,7 +253,7 @@ function retryInterceptor() {
|
|
|
253
253
|
return (next) => async (req) => {
|
|
254
254
|
if (req.stream) return await next(req);
|
|
255
255
|
let lastError;
|
|
256
|
-
for (let i = 0; i <
|
|
256
|
+
for (let i = 0; i < MAX_RETRY_ATTEMPTS; i++) {
|
|
257
257
|
if (i > 0) await waitRetryBackoff(i);
|
|
258
258
|
try {
|
|
259
259
|
return await next(req);
|
|
@@ -263,7 +263,7 @@ function retryInterceptor() {
|
|
|
263
263
|
logger.debug(`retry: ${req.method.name} returned AlreadyExists on attempt ${i + 1}; treating as success (prior attempt likely committed)`);
|
|
264
264
|
return synthesizeEmptyUnaryResponse(req);
|
|
265
265
|
}
|
|
266
|
-
const { reportCrash } = await import("./crashreport-
|
|
266
|
+
const { reportCrash } = await import("./crashreport-CINZ5dVN.mjs");
|
|
267
267
|
await reportCrash(error, "handledError");
|
|
268
268
|
}
|
|
269
269
|
if (req.method.name !== "CreateWorkspace" && isRetirable(error, req.method.idempotency)) {
|
|
@@ -397,6 +397,8 @@ function synthesizeEmptyUnaryResponse(req) {
|
|
|
397
397
|
* response was lost), which is what triggers the `already_exists` race.
|
|
398
398
|
*/
|
|
399
399
|
const RETRY_BASE_DELAY_MS = 500;
|
|
400
|
+
/** Maximum number of attempts, including the initial one, for a retried request. */
|
|
401
|
+
const MAX_RETRY_ATTEMPTS = 3;
|
|
400
402
|
/**
|
|
401
403
|
* Wait for an exponential backoff delay with jitter.
|
|
402
404
|
* @param attempt - Current retry attempt number (1-based)
|
|
@@ -631,14 +633,15 @@ async function fetchMachineUserToken(url, clientId, clientSecret) {
|
|
|
631
633
|
formData.append("grant_type", "client_credentials");
|
|
632
634
|
formData.append("client_id", clientId);
|
|
633
635
|
formData.append("client_secret", clientSecret);
|
|
634
|
-
const
|
|
636
|
+
const request = {
|
|
635
637
|
method: "POST",
|
|
636
638
|
headers: {
|
|
637
639
|
"User-Agent": await userAgent(),
|
|
638
640
|
"Content-Type": "application/x-www-form-urlencoded"
|
|
639
641
|
},
|
|
640
642
|
body: formData
|
|
641
|
-
}
|
|
643
|
+
};
|
|
644
|
+
const resp = await withConnectTimeoutRetry("machine user token request", () => fetch(tokenEndpoint, request));
|
|
642
645
|
if (!resp.ok) {
|
|
643
646
|
const body = await resp.text().catch(() => "");
|
|
644
647
|
throw new Error(`Failed to fetch machine user token: ${resp.status} ${resp.statusText} ${body.slice(0, 500)}`);
|
|
@@ -650,6 +653,29 @@ async function fetchMachineUserToken(url, clientId, clientSecret) {
|
|
|
650
653
|
expires_in: z.number()
|
|
651
654
|
}).parse(rawJson);
|
|
652
655
|
}
|
|
656
|
+
function isUndiciConnectTimeout(error) {
|
|
657
|
+
if (!(error instanceof TypeError)) return false;
|
|
658
|
+
const cause = error.cause;
|
|
659
|
+
return cause instanceof Error && "code" in cause && cause.code === "UND_ERR_CONNECT_TIMEOUT";
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Retry a request that failed before the connection was established.
|
|
663
|
+
*
|
|
664
|
+
* Only `UND_ERR_CONNECT_TIMEOUT` is retried: the request provably never reached
|
|
665
|
+
* the server, so replaying it cannot duplicate a server-side effect.
|
|
666
|
+
* @param label - Request description for the retry debug log
|
|
667
|
+
* @param send - Sends the request; called once per attempt
|
|
668
|
+
* @returns The first successful result
|
|
669
|
+
*/
|
|
670
|
+
async function withConnectTimeoutRetry(label, send) {
|
|
671
|
+
for (let attempt = 1;; attempt++) try {
|
|
672
|
+
return await send();
|
|
673
|
+
} catch (error) {
|
|
674
|
+
if (!isUndiciConnectTimeout(error) || attempt >= MAX_RETRY_ATTEMPTS) throw error;
|
|
675
|
+
logger.debug(`retry: ${label} attempt ${attempt} failed with UND_ERR_CONNECT_TIMEOUT; retrying`);
|
|
676
|
+
await waitRetryBackoff(attempt);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
653
679
|
/**
|
|
654
680
|
* Fetch an OAuth2 token for a platform machine user via client_credentials grant.
|
|
655
681
|
* @param clientId - Client ID for the platform machine user
|
|
@@ -658,12 +684,13 @@ async function fetchMachineUserToken(url, clientId, clientSecret) {
|
|
|
658
684
|
* @returns OAuth2 token
|
|
659
685
|
*/
|
|
660
686
|
async function fetchPlatformMachineUserToken(clientId, clientSecret, config) {
|
|
661
|
-
|
|
687
|
+
const server = getPlatformBaseUrl(config);
|
|
688
|
+
return await withConnectTimeoutRetry("platform machine user token request", () => new OAuth2Client({
|
|
662
689
|
clientId,
|
|
663
690
|
clientSecret,
|
|
664
|
-
server
|
|
691
|
+
server,
|
|
665
692
|
discoveryEndpoint: oauth2DiscoveryEndpoint
|
|
666
|
-
}).clientCredentials();
|
|
693
|
+
}).clientCredentials());
|
|
667
694
|
}
|
|
668
695
|
/**
|
|
669
696
|
* Close the global HTTP connection pool to prevent libuv UV_HANDLE_CLOSING
|
|
@@ -2579,6 +2606,7 @@ const tailorPrincipalMap = makePrincipalExpr({
|
|
|
2579
2606
|
attributeList: "$raw.attributes ?? []"
|
|
2580
2607
|
}
|
|
2581
2608
|
});
|
|
2609
|
+
const PRINCIPAL_VAR = "_principal";
|
|
2582
2610
|
/**
|
|
2583
2611
|
* Parse `wrapped` and return the first property of the top-level parenthesized
|
|
2584
2612
|
* object expression, or `undefined` if it does not parse as one.
|
|
@@ -2630,17 +2658,17 @@ function formatScriptContext(kind, context) {
|
|
|
2630
2658
|
const convertToScriptExpr = (fn, kind, context) => {
|
|
2631
2659
|
const precompiledExpr = getPrecompiledScriptExpr(fn);
|
|
2632
2660
|
if (precompiledExpr) return precompiledExpr;
|
|
2633
|
-
return assertParsableExpression(`(${stringifyFunction(fn)})(${kind === "validate" ? `{ value: _value }` : kind === "hooks.create" ? `{ input: _value, invoker: ${
|
|
2661
|
+
return assertParsableExpression(`(${stringifyFunction(fn)})(${kind === "validate" ? `{ value: _value }` : kind === "hooks.create" ? `{ input: _value, invoker: ${PRINCIPAL_VAR}, now: _now }` : `{ input: _value, oldValue: _oldValue, invoker: ${PRINCIPAL_VAR}, now: _now }`})`, formatScriptContext(kind, context));
|
|
2634
2662
|
};
|
|
2635
2663
|
const convertTypeHookToExpr = (fn) => {
|
|
2636
2664
|
const precompiledExpr = getPrecompiledScriptExpr(fn);
|
|
2637
2665
|
if (precompiledExpr) return precompiledExpr;
|
|
2638
|
-
return assertParsableExpression(`(${stringifyFunction(fn)})({ input: _input, oldRecord: _oldRecord, invoker: ${
|
|
2666
|
+
return assertParsableExpression(`(${stringifyFunction(fn)})({ input: _input, oldRecord: _oldRecord, invoker: ${PRINCIPAL_VAR}, now: _now })`, "type-hook");
|
|
2639
2667
|
};
|
|
2640
2668
|
const convertTypeValidateToExpr = (fn) => {
|
|
2641
2669
|
const precompiledExpr = getPrecompiledScriptExpr(fn);
|
|
2642
2670
|
if (precompiledExpr) return precompiledExpr;
|
|
2643
|
-
return assertParsableExpression(`(${stringifyFunction(fn)})({ newRecord: _newRecord, oldRecord: _oldRecord, invoker: ${
|
|
2671
|
+
return assertParsableExpression(`(${stringifyFunction(fn)})({ newRecord: _newRecord, oldRecord: _oldRecord, invoker: ${PRINCIPAL_VAR} }, __issues)`, "type-validate");
|
|
2644
2672
|
};
|
|
2645
2673
|
/**
|
|
2646
2674
|
* Parse TailorDBField into OperatorFieldConfig.
|
|
@@ -3386,7 +3414,7 @@ async function bundleScriptTarget(args) {
|
|
|
3386
3414
|
const context = `${kind} in ${sourceFilePath}`;
|
|
3387
3415
|
const fnSource = stringifyFunction(fn);
|
|
3388
3416
|
if ((kind === "typeValidate" || kind === "validate") && fn.constructor.name === "AsyncFunction") throw new Error(`${context} must be synchronous — the generated validator runs synchronously, so issues reported after an await are silently lost. Remove the async keyword.`);
|
|
3389
|
-
const argsObject = kind === "hooks.create" ? `{ input: _value, invoker: ${
|
|
3417
|
+
const argsObject = kind === "hooks.create" ? `{ input: _value, invoker: ${PRINCIPAL_VAR}, now: _now }` : kind === "hooks.update" ? `{ input: _value, oldValue: _oldValue, invoker: ${PRINCIPAL_VAR}, now: _now }` : kind === "validate" ? `{ value: _value }` : kind === "typeHook" ? `{ input: _input, oldRecord: _oldRecord, invoker: ${PRINCIPAL_VAR}, now: _now }` : `{ newRecord: _newRecord, oldRecord: _oldRecord, invoker: ${PRINCIPAL_VAR} }, __issues`;
|
|
3390
3418
|
const inlineExpr = assertParsableExpression(`(${fnSource})(${argsObject})`, context);
|
|
3391
3419
|
const freeVars = findUndefinedReferences(`const __fn = ${fnSource};`);
|
|
3392
3420
|
if (freeVars.size === 0) return inlineExpr;
|
|
@@ -3650,7 +3678,7 @@ function createTailorDBService(params) {
|
|
|
3650
3678
|
rawTypes[typeFile] = createRawTypesByName();
|
|
3651
3679
|
const loadedTypes = createRawTypesByName();
|
|
3652
3680
|
try {
|
|
3653
|
-
const module = await
|
|
3681
|
+
const module = await importUserModule(typeFile);
|
|
3654
3682
|
for (const exportName of Object.keys(module)) {
|
|
3655
3683
|
const exportedValue = module[exportName];
|
|
3656
3684
|
const result = TailorDBTypeSchema.safeParse(stripTailorDBTypeBuilderHelpers(exportedValue));
|
|
@@ -3666,10 +3694,11 @@ function createTailorDBService(params) {
|
|
|
3666
3694
|
filePath: typeFile,
|
|
3667
3695
|
exportName
|
|
3668
3696
|
});
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3697
|
+
const rawType = exportedValue;
|
|
3698
|
+
if (rawType.plugins && Array.isArray(rawType.plugins) && rawType.plugins.length > 0) {
|
|
3699
|
+
pluginAttachments.set(rawType.name, [...rawType.plugins]);
|
|
3700
|
+
logger.log(` Plugin attachments: ${styles.info(rawType.plugins.map((p) => p.pluginId).join(", "))}`);
|
|
3701
|
+
await processPluginsForType(rawType, rawType.plugins, typeFile);
|
|
3673
3702
|
}
|
|
3674
3703
|
}
|
|
3675
3704
|
} catch (error) {
|
|
@@ -4437,7 +4466,7 @@ async function loadAdapterFiles(config, baseDir) {
|
|
|
4437
4466
|
}
|
|
4438
4467
|
async function loadAdapterFromFile(filePath) {
|
|
4439
4468
|
try {
|
|
4440
|
-
const module = await
|
|
4469
|
+
const module = await importUserModule(filePath);
|
|
4441
4470
|
if (!isSdkBranded(module.default, "http-adapter")) {
|
|
4442
4471
|
const named = Object.entries(module).find(([exportName, value]) => exportName !== "default" && isSdkBranded(value, "http-adapter"));
|
|
4443
4472
|
if (named) throw new Error(`HTTP adapter must be the default export, but it is exported as \`${named[0]}\`. Re-export it: \`export default createHttpAdapter({...})\`.`);
|
|
@@ -4533,7 +4562,7 @@ const ResolverSchema = z.strictObject({
|
|
|
4533
4562
|
* @returns Parsed resolver or null if invalid
|
|
4534
4563
|
*/
|
|
4535
4564
|
async function loadResolver(resolverFilePath) {
|
|
4536
|
-
const resolver = (await
|
|
4565
|
+
const resolver = (await importUserModule(resolverFilePath)).default;
|
|
4537
4566
|
const parseResult = ResolverSchema.safeParse(resolver);
|
|
4538
4567
|
if (!parseResult.success) return null;
|
|
4539
4568
|
return parseResult.data;
|
|
@@ -4718,7 +4747,7 @@ function createResolverService(namespace, config, baseDir) {
|
|
|
4718
4747
|
});
|
|
4719
4748
|
const loadResolverForFile = async (resolverFile) => {
|
|
4720
4749
|
try {
|
|
4721
|
-
const resolverModule = await
|
|
4750
|
+
const resolverModule = await importUserModule(resolverFile);
|
|
4722
4751
|
const result = ResolverSchema.safeParse(resolverModule.default);
|
|
4723
4752
|
if (result.success) {
|
|
4724
4753
|
const relativePath = path.relative(process.cwd(), resolverFile);
|
|
@@ -5260,7 +5289,7 @@ async function loadFileContent(filePath) {
|
|
|
5260
5289
|
const jobs = [];
|
|
5261
5290
|
let workflow = null;
|
|
5262
5291
|
try {
|
|
5263
|
-
const module = await
|
|
5292
|
+
const module = await importUserModule(filePath);
|
|
5264
5293
|
for (const [exportName, exportValue] of Object.entries(module)) {
|
|
5265
5294
|
if (exportName === "default") {
|
|
5266
5295
|
const workflowResult = WorkflowSchema.safeParse(stripRuntimeStart(exportValue));
|
|
@@ -5530,6 +5559,65 @@ const StaticWebsiteSchema = z.strictObject({
|
|
|
5530
5559
|
customDomains: z.array(z.string()).optional().describe("Custom domains for the static website")
|
|
5531
5560
|
}).brand("StaticWebsiteConfig");
|
|
5532
5561
|
|
|
5562
|
+
//#endregion
|
|
5563
|
+
//#region src/parser/service/workflow/wait-point-key.ts
|
|
5564
|
+
const KEY_REGEX = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
|
|
5565
|
+
const LITERAL_SEGMENT_REGEX = /^[a-z0-9]+$/;
|
|
5566
|
+
const PARAM_NAME_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
5567
|
+
const MAX_KEY_LENGTH = 63;
|
|
5568
|
+
const KEY_GRAMMAR = "[a-z0-9-] (3-63 characters; must start and end with [a-z0-9])";
|
|
5569
|
+
/**
|
|
5570
|
+
* Check one declared wait point key against the key rules.
|
|
5571
|
+
*
|
|
5572
|
+
* The declaration matters: only `createWaitPoints`' `define` receives the key
|
|
5573
|
+
* before the type arguments, so only there can TypeScript read the `$params`
|
|
5574
|
+
* off the key literal.
|
|
5575
|
+
* @param waitPoint - A key as declared, with the declaration it came from
|
|
5576
|
+
* @returns The rule the key breaks, or undefined when the key is usable
|
|
5577
|
+
*/
|
|
5578
|
+
function checkWaitPointKey(waitPoint) {
|
|
5579
|
+
const { key, declaredBy } = waitPoint;
|
|
5580
|
+
const segments = key.split("-");
|
|
5581
|
+
const paramSegments = segments.filter((segment) => segment.startsWith("$") && segment.length > 1);
|
|
5582
|
+
if (paramSegments.length > 0 && declaredBy !== "define") return declaredBy === "property" ? `Invalid wait point key "${key}": $params cannot come from a property name. Pass the key to define instead, e.g. define.for("${key}")<Payload, Result>().` : `Invalid wait point key "${key}": createWaitPoint takes its type arguments first, which stops TypeScript inferring the key as a literal, so it cannot type the $params. Declare it through createWaitPoints instead: createWaitPoints((define) => ({ myWaitPoint: define.for("${key}")<Payload, Result>() })).`;
|
|
5583
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5584
|
+
let literals = 0;
|
|
5585
|
+
for (const segment of segments) {
|
|
5586
|
+
if (segment.startsWith("$")) {
|
|
5587
|
+
const name = segment.slice(1);
|
|
5588
|
+
if (!PARAM_NAME_REGEX.test(name)) return `Invalid wait point key "${key}": "${segment}" is not a usable parameter name. Use letters, digits and underscores, starting with a letter or underscore.`;
|
|
5589
|
+
if (seen.has(name)) return `Invalid wait point key "${key}": parameter "$${name}" appears more than once.`;
|
|
5590
|
+
seen.add(name);
|
|
5591
|
+
continue;
|
|
5592
|
+
}
|
|
5593
|
+
if (segment === "") continue;
|
|
5594
|
+
if (!LITERAL_SEGMENT_REGEX.test(segment)) return `Invalid wait point key "${key}": segment "${segment}" may only contain [a-z0-9]. Wait point keys accept ${KEY_GRAMMAR}, with $params standing in for runtime values.`;
|
|
5595
|
+
literals += 1;
|
|
5596
|
+
}
|
|
5597
|
+
if (literals === 0 && paramSegments.length > 0) return key.startsWith("-") || key.endsWith("-") ? `Invalid wait point key "${key}": must match ${KEY_GRAMMAR}.` : `Invalid wait point key "${key}": it needs at least one literal segment alongside its $params, otherwise the key carries no identity of its own and can collide with an unrelated wait point.`;
|
|
5598
|
+
if (paramSegments.length === 0) return KEY_REGEX.test(key) ? void 0 : `Invalid wait point key "${key}": must match ${KEY_GRAMMAR}.`;
|
|
5599
|
+
const shortest = segments.map((segment) => segment.startsWith("$") ? "0" : segment).join("-");
|
|
5600
|
+
if (shortest.length > MAX_KEY_LENGTH) return `Wait point key "${key}" cannot fit in ${MAX_KEY_LENGTH} characters: even single-character parameter values produce ${shortest.length}.`;
|
|
5601
|
+
return KEY_REGEX.test(shortest) ? void 0 : `Invalid wait point key "${key}": must match ${KEY_GRAMMAR}.`;
|
|
5602
|
+
}
|
|
5603
|
+
/**
|
|
5604
|
+
* Check every declared wait point key, reporting each broken rule once.
|
|
5605
|
+
* @param waitPoints - The keys declared across the project, as registered
|
|
5606
|
+
* @returns One message per distinct declaration that breaks a rule
|
|
5607
|
+
*/
|
|
5608
|
+
function collectWaitPointKeyFailures(waitPoints) {
|
|
5609
|
+
const failures = [];
|
|
5610
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5611
|
+
for (const waitPoint of waitPoints) {
|
|
5612
|
+
const identity = `${waitPoint.declaredBy} ${waitPoint.key}`;
|
|
5613
|
+
if (seen.has(identity)) continue;
|
|
5614
|
+
seen.add(identity);
|
|
5615
|
+
const failure = checkWaitPointKey(waitPoint);
|
|
5616
|
+
if (failure) failures.push(failure);
|
|
5617
|
+
}
|
|
5618
|
+
return failures;
|
|
5619
|
+
}
|
|
5620
|
+
|
|
5533
5621
|
//#endregion
|
|
5534
5622
|
//#region src/cli/services/application.ts
|
|
5535
5623
|
function defineTailorDB(config, baseDir, pluginManager) {
|
|
@@ -5803,6 +5891,11 @@ function generatePluginFilesIfNeeded(pluginManager, tailorDBServices, configPath
|
|
|
5803
5891
|
executorGenerator: generatePluginExecutorFiles
|
|
5804
5892
|
});
|
|
5805
5893
|
}
|
|
5894
|
+
function assertWaitPointKeys() {
|
|
5895
|
+
const failures = collectWaitPointKeyFailures(getScopedWaitPoints());
|
|
5896
|
+
if (failures.length === 0) return;
|
|
5897
|
+
throw new Error(failures.join("\n"));
|
|
5898
|
+
}
|
|
5806
5899
|
/**
|
|
5807
5900
|
* Load and fully initialize a Tailor application.
|
|
5808
5901
|
* This performs all I/O-heavy operations: loading types, processing plugins,
|
|
@@ -5895,6 +5988,7 @@ async function loadApplication(params) {
|
|
|
5895
5988
|
await executorService.loadExecutors();
|
|
5896
5989
|
if (pluginExecutorFiles.length > 0) await executorService.loadPluginExecutorFiles([...pluginExecutorFiles]);
|
|
5897
5990
|
}
|
|
5991
|
+
assertWaitPointKeys();
|
|
5898
5992
|
if (workflowService) workflowService.printLoadedWorkflows();
|
|
5899
5993
|
if (httpAdapterService) httpAdapterService.printLoadedAdapters();
|
|
5900
5994
|
logger.newline();
|
|
@@ -5921,5 +6015,5 @@ async function loadApplication(params) {
|
|
|
5921
6015
|
}
|
|
5922
6016
|
|
|
5923
6017
|
//#endregion
|
|
5924
|
-
export {
|
|
5925
|
-
//# sourceMappingURL=application-
|
|
6018
|
+
export { resolveStaticWebsiteUrls as $, hasGenerationHooks as A, fetchPaged as B, resolveTSConfigWithFallback as C, resolveBundleLogLevel as D, createLogLevelTreeshakeOptions as E, closeConnectionPool as F, getOrNull as G, fetchUserInfo as H, defaultPlatformBaseUrl as I, initOperatorClient as J, getPlatformBaseUrl as K, fetchAll as L, getDistDir as M, hashContent as N, createBundleLog as O, hashFile as P, rememberPlatformConfigForToken as Q, fetchAllTolerant as R, createTsconfigPathsPlugin as S, composeFunctionTreeshakeOptions as T, getConsoleBaseUrl as U, fetchPlatformMachineUserToken as V, getOAuth2ClientId as W, isNotFoundError as X, isDefaultPlatform as Y, normalizeBaseUrl as Z, assertUniqueTailorDBTypeNamesWithExternal as _, resolveInlineSourcemap as a, tailorPrincipalMap as b, WorkflowJobSchema as c, HTTP_METHODS as d, byName as et, INVOKER_EXPR as f, assertUniqueLocalTailorDBTypeNames as g, buildResolverPermissionAndInputCheckExpr as h, resolverBundleKey as i, createBundleCache as j, getPluginGenerationDependencies as k, resolveResolverDefaultPermissionForFile as l, buildResolverOperationHookExpr as m, generatePluginFilesIfNeeded as n, LOG_LEVELS as nt, getApplicationAuthNamespace as o, buildExecutorArgsExpr as p, initOAuth2Client as q, loadApplication as r, WorkflowJobFunctionExecutionPolicySchema as s, defineApplication as t, createApplyLimiter as tt, ResolverSchema as u, PRINCIPAL_VAR as v, platformBundleDefinePlugin as w, createGeneratedEntryResolverPlugin as x, stringifyFunction as y, fetchMachineUserToken as z };
|
|
6019
|
+
//# sourceMappingURL=application-F-nl107y.mjs.map
|