@tailor-platform/sdk 2.0.1 → 2.2.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 +117 -0
- package/{dist/cli/index.mjs → bin/tailor.mjs} +1 -1
- package/dist/{application-CM6hKnSK.mjs → application-BpLeawBg.mjs} +126 -28
- package/dist/application-BpLeawBg.mjs.map +1 -0
- package/dist/application-BxLLiLsr.mjs +3 -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 +11 -4
- package/dist/cli/commands/tailordb/migrate/file-state.d.mts +1 -0
- package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +2 -2
- package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +8 -1
- package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +5 -3
- 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 +997 -202
- package/dist/cli/main.mjs.map +1 -1
- package/dist/completion/zsh-worker.zsh +145 -2
- package/dist/configure/config/types.d.mts +12 -1
- package/dist/configure/index.d.mts +3 -3
- package/dist/configure/services/index.d.mts +3 -2
- package/dist/configure/services/resolver/index.d.mts +1 -1
- package/dist/configure/services/resolver/resolver.d.mts +1 -1
- 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/{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-CWj21238.mjs +75 -0
- package/dist/errors-CWj21238.mjs.map +1 -0
- package/dist/{globals-TfAVItuK.mjs → globals-B2nlxBrz.mjs} +2 -10
- package/dist/globals-B2nlxBrz.mjs.map +1 -0
- package/dist/kysely/index.d.mts +52 -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-LYV7zH-e.mjs → register-ts-hook-CTth1eqj.mjs} +1587 -272
- package/dist/register-ts-hook-CTth1eqj.mjs.map +1 -0
- package/dist/runtime/globals.d.mts +0 -7
- package/dist/runtime/workflow.d.mts +2 -7
- 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-B5WynBHQ.mjs → service-CCwl3Avt.mjs} +3 -3
- package/dist/{service-B5WynBHQ.mjs.map → service-CCwl3Avt.mjs.map} +1 -1
- package/dist/service-_XmjSEGr.mjs +3 -0
- package/dist/{service-k1xy_A5G.mjs → service-goqlJJgA.mjs} +2 -2
- package/dist/{service-k1xy_A5G.mjs.map → service-goqlJJgA.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 +9 -3
- package/dist/utils/test/index.mjs +49 -25
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/environment.mjs +1 -1
- package/dist/vitest/index.d.mts +2 -1
- package/dist/vitest/index.mjs +84 -2
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/mocks/file.d.mts +1 -1
- package/dist/vitest/pglite-kysely.d.mts +43 -0
- package/dist/vitest/setup.mjs +1 -1
- package/dist/workflow-Bamae_Yc.mjs.map +1 -1
- 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/tailordb.md +87 -22
- package/docs/cli-reference.md +13 -11
- package/docs/configuration.md +4 -1
- package/docs/migration/v2.md +1 -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 +34 -2
- package/docs/services/tailordb-migration.md +375 -76
- package/docs/services/tailordb.md +28 -28
- package/docs/testing.md +3 -1
- package/package.json +13 -8
- package/dist/application-CM6hKnSK.mjs.map +0 -1
- package/dist/application-CXNaUNhv.mjs +0 -3
- package/dist/errors-D7583Zz7.mjs +0 -58
- package/dist/errors-D7583Zz7.mjs.map +0 -1
- package/dist/globals-TfAVItuK.mjs.map +0 -1
- package/dist/logger-CXQq9YIp.mjs.map +0 -1
- package/dist/register-ts-hook-LYV7zH-e.mjs.map +0 -1
- package/dist/seed-B-yckgQY.mjs.map +0 -1
- package/dist/service-M7OYziQP.mjs +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,122 @@
|
|
|
1
1
|
# @tailor-platform/sdk
|
|
2
2
|
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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:
|
|
8
|
+
|
|
9
|
+
- The generated `db.ts` exports the `Database` interface, so `createKyselyMock<Database>()` from `@tailor-platform/sdk/vitest` types queries against the migration's schema state.
|
|
10
|
+
- `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.
|
|
11
|
+
- `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.
|
|
12
|
+
- The migration guide's Testing section now documents the workflow.
|
|
13
|
+
|
|
14
|
+
- [#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:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# ./seed/data/Customer.jsonl: {"name":"Acme Corporation"}
|
|
18
|
+
tailor seed fill
|
|
19
|
+
# ./seed/data/Customer.jsonl: {"id":"0b6b6f5e-...","name":"Acme Corporation"}
|
|
20
|
+
|
|
21
|
+
# also stamp a creation time on rows that have none
|
|
22
|
+
tailor seed fill --fields id,createdAt
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
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.
|
|
26
|
+
|
|
27
|
+
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.
|
|
28
|
+
|
|
29
|
+
`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`.
|
|
30
|
+
|
|
31
|
+
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.
|
|
32
|
+
|
|
33
|
+
`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.
|
|
34
|
+
|
|
35
|
+
`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.
|
|
36
|
+
|
|
37
|
+
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.
|
|
38
|
+
|
|
39
|
+
A test calling `createTailorDBHook` directly to assert a type-level `validate` throws needs to go through `createStandardSchema` instead.
|
|
40
|
+
|
|
41
|
+
The same operation is available as `fillSeedData` from `@tailor-platform/sdk/seed`.
|
|
42
|
+
|
|
43
|
+
- [#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.
|
|
44
|
+
|
|
45
|
+
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:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Type 'string' is not assignable to type 'TypeLevelError<"assigned by .serial(); remove it from the input">'.
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
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.
|
|
52
|
+
|
|
53
|
+
`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.
|
|
54
|
+
|
|
55
|
+
`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.
|
|
56
|
+
|
|
57
|
+
- [#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.
|
|
58
|
+
|
|
59
|
+
- [#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.
|
|
60
|
+
|
|
61
|
+
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.
|
|
62
|
+
|
|
63
|
+
`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.
|
|
64
|
+
|
|
65
|
+
- [#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.
|
|
66
|
+
|
|
67
|
+
- [#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
|
|
68
|
+
|
|
69
|
+
### Patch Changes
|
|
70
|
+
|
|
71
|
+
- [#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.
|
|
72
|
+
|
|
73
|
+
- [#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.
|
|
74
|
+
|
|
75
|
+
`@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.
|
|
76
|
+
|
|
77
|
+
- [#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.
|
|
78
|
+
|
|
79
|
+
- [#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
|
|
80
|
+
|
|
81
|
+
- [#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.
|
|
82
|
+
|
|
83
|
+
- [#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(...)`.
|
|
84
|
+
|
|
85
|
+
Update the `v2/idp-publish-events-rename` codemod registry description to say "tables" instead of "types", matching the same wording fix.
|
|
86
|
+
|
|
87
|
+
## 2.1.0
|
|
88
|
+
|
|
89
|
+
### Minor Changes
|
|
90
|
+
|
|
91
|
+
- [#1976](https://github.com/tailor-platform/sdk/pull/1976) [`aef43a7`](https://github.com/tailor-platform/sdk/commit/aef43a765d2ab26c2eee9bbbe5463e28c845f8dc) Thanks [@toiroakr](https://github.com/toiroakr)! - Add `defaultPermission` to resolver namespaces in `defineConfig`, applying an access requirement to every resolver in the namespace that declares no `permission` of its own — securing a namespace no longer means editing every resolver. It takes the same values as a resolver's `permission`, including `"allowAnonymous"` for a namespace that is public by design, and a resolver's own `permission` replaces it rather than merging with it. `generate` and `deploy` now warn when a namespace declares neither a `defaultPermission` nor a `permission` on each of its resolvers.
|
|
92
|
+
|
|
93
|
+
### Patch Changes
|
|
94
|
+
|
|
95
|
+
- [#1982](https://github.com/tailor-platform/sdk/pull/1982) [`287c551`](https://github.com/tailor-platform/sdk/commit/287c55173c75ae6533732fb1128a16e4366961e0) Thanks [@renovate](https://github.com/apps/renovate)! - fix(deps): update dependency get-tsconfig to v4.14.1
|
|
96
|
+
|
|
97
|
+
- [#1995](https://github.com/tailor-platform/sdk/pull/1995) [`b6ed05d`](https://github.com/tailor-platform/sdk/commit/b6ed05db825886dba844664210f32855572e3f88) Thanks [@renovate](https://github.com/apps/renovate)! - chore(deps): update dependency tsx to v4.23.5
|
|
98
|
+
|
|
99
|
+
- [#1976](https://github.com/tailor-platform/sdk/pull/1976) [`5d0f513`](https://github.com/tailor-platform/sdk/commit/5d0f5135fb1dc6dc9a467f48a7b5aa3d8ac57e5e) Thanks [@toiroakr](https://github.com/toiroakr)! - Fix a resolver `permission` denial returning `ReferenceError: TailorErrorMessage is not defined` to the caller instead of `access denied`. The generated guard now raises `TailorErrors`, which is the only error class the platform turns back into a message the caller can read.
|
|
100
|
+
|
|
101
|
+
`TailorErrorMessage` no longer exists in the platform runtime, so its ambient global declaration and its Vitest mock are removed as well — together they let code that always failed in production pass both type checking and tests. Code that throws `TailorErrorMessage` now fails to compile; replace it with `TailorErrors`:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
throw new TailorErrors([{ message: "not found", path: [] }]);
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
- [#1978](https://github.com/tailor-platform/sdk/pull/1978) [`49aa0d3`](https://github.com/tailor-platform/sdk/commit/49aa0d38fc60224d701d7663483f2137b280841f) Thanks [@toiroakr](https://github.com/toiroakr)! - `createTailorDBHook` now takes each field from the data's own properties. A type declaring a field named after a member of `Object` — `toString`, say — used to get that member as the field's value on every record that omitted the field, so validation rejected otherwise valid rows:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
✗ Found 1 error(s) in ./seed/data/Customer.jsonl
|
|
111
|
+
Expected a string: received function toString() { [native code] }
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
A field named `__proto__` is recorded as a data property rather than assigned, so its value is kept instead of being swallowed by the inherited setter.
|
|
115
|
+
|
|
116
|
+
A field the data does not carry still lands as an `undefined` key, which is what keeps a column inferred from these records nullable.
|
|
117
|
+
|
|
118
|
+
- [#1967](https://github.com/tailor-platform/sdk/pull/1967) [`47e4f2b`](https://github.com/tailor-platform/sdk/commit/47e4f2bc37a735de091f83f3c4d453a004daec62) Thanks [@toiroakr](https://github.com/toiroakr)! - Drop internal RPC vocabulary from the JSDoc on the `tailor.workflow` runtime API. The module doc and `execJobFunction`'s own doc described the wire-format history behind the current names, which reached editor tooltips without telling users anything they could act on. The behaviour the text was explaining is kept: `execJobFunction` blocks until the job finishes and returns its result, while `startWorkflow` returns only an execution ID.
|
|
119
|
+
|
|
3
120
|
## 2.0.1
|
|
4
121
|
|
|
5
122
|
### Patch Changes
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { n as isSdkBranded } from "./brand-Eo4pLXPJ.mjs";
|
|
2
2
|
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, g as functionSchema, 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 } from "./service-
|
|
3
|
+
import { a as parseBoolean, n as logger, r as styles } from "./logger-DSdExfor.mjs";
|
|
4
|
+
import { a as AuthConfigSchema, c as stripTailorDBTypeBuilderHelpers, d as applyRelationMetadataToFieldConfig, f as buildRelationInfo, g as functionSchema, 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 } from "./service-goqlJJgA.mjs";
|
|
5
5
|
import { t as multiline } from "./multiline-sfHpTZZK.mjs";
|
|
6
6
|
import { t as userAgent } from "./user-agent-Bgsszb5I.mjs";
|
|
7
|
-
import { t as createCLIError } from "./errors-
|
|
7
|
+
import { t as createCLIError } from "./errors-CWj21238.mjs";
|
|
8
8
|
import { n as isNodeBuiltinImport, t as getNodeBuiltinMessage } from "./node-builtins-CmaL2Cbq.mjs";
|
|
9
9
|
import { t as isPluginGeneratedType } from "./type-source-DH_LH20p.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
@@ -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),
|
|
@@ -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)) {
|
|
@@ -3996,7 +3996,8 @@ function policyEntryExpr(policy) {
|
|
|
3996
3996
|
/**
|
|
3997
3997
|
* Build the permission guard statement injected at resolver entry.
|
|
3998
3998
|
*
|
|
3999
|
-
* Rejects the call with `
|
|
3999
|
+
* Rejects the call with `TailorErrors` — the only error class the platform
|
|
4000
|
+
* turns back into a message the caller can read — when the caller doesn't match
|
|
4000
4001
|
* `permission`, evaluated against `context.caller` — the original caller,
|
|
4001
4002
|
* unaffected by `authInvoker`. `permission` is deny-by-default: a caller is
|
|
4002
4003
|
* granted only by a matching `permit: true` policy, and a matching
|
|
@@ -4025,7 +4026,8 @@ function buildResolverPermissionGuardExpr(permission) {
|
|
|
4025
4026
|
const $reasons = ($matchedDeny.length > 0 ? $matchedDeny : $allowPolicies)
|
|
4026
4027
|
.map((p) => p.description)
|
|
4027
4028
|
.filter(Boolean);
|
|
4028
|
-
|
|
4029
|
+
const $message = $reasons.length > 0 ? "access denied: " + $reasons.join("; ") : "access denied";
|
|
4030
|
+
throw new TailorErrors([{ message: $message, path: [] }]);
|
|
4029
4031
|
}
|
|
4030
4032
|
}`;
|
|
4031
4033
|
}
|
|
@@ -4035,16 +4037,18 @@ function buildResolverPermissionGuardExpr(permission) {
|
|
|
4035
4037
|
*
|
|
4036
4038
|
* Kept as a single generator so a resolver-wrapping behavior (like the
|
|
4037
4039
|
* permission guard) can't be added to one entry-point template and forgotten
|
|
4038
|
-
* in the other
|
|
4039
|
-
*
|
|
4040
|
+
* in the other — the namespace-default precedence below is resolved here for
|
|
4041
|
+
* the same reason. References `context.caller`, `context.input`, `invoker`,
|
|
4042
|
+
* and `_internalResolver` — the caller's wrapper must bind a `context` object
|
|
4040
4043
|
* with `user`/`input` properties and an `invoker` binding (from
|
|
4041
4044
|
* `INVOKER_EXPR`) before inlining this expression.
|
|
4042
|
-
* @param
|
|
4045
|
+
* @param params - The resolver's and its namespace's permission config
|
|
4043
4046
|
* @returns A JS statement block to inline before calling `_internalResolver.body(...)`
|
|
4044
4047
|
*/
|
|
4045
|
-
function buildResolverPermissionAndInputCheckExpr(
|
|
4048
|
+
function buildResolverPermissionAndInputCheckExpr(params) {
|
|
4049
|
+
const { permission, defaultPermission } = params;
|
|
4046
4050
|
return `
|
|
4047
|
-
${buildResolverPermissionGuardExpr(permission) ?? ""}
|
|
4051
|
+
${buildResolverPermissionGuardExpr(permission ?? defaultPermission) ?? ""}
|
|
4048
4052
|
if (_internalResolver.input) {
|
|
4049
4053
|
const result = t.object(_internalResolver.input).parse({
|
|
4050
4054
|
value: context.input,
|
|
@@ -4544,17 +4548,11 @@ async function loadResolver(resolverFilePath) {
|
|
|
4544
4548
|
* 1. Uses a transform plugin to add validation wrapper during bundling
|
|
4545
4549
|
* 2. Creates an in-memory entry module
|
|
4546
4550
|
* 3. Bundles in a single step with tree-shaking
|
|
4547
|
-
* @param
|
|
4548
|
-
* @param config - Resolver file loading configuration
|
|
4549
|
-
* @param baseDir - Directory the config's file patterns are resolved against
|
|
4550
|
-
* @param startContext - Start context for workflow/job transformations
|
|
4551
|
-
* @param cache - Optional bundle cache for skipping unchanged builds
|
|
4552
|
-
* @param inlineSourcemap - Whether to enable inline sourcemaps
|
|
4553
|
-
* @param bundleLogLevel - Controls which console calls are kept in bundled code
|
|
4554
|
-
* @param tsconfigCache - Optional tsconfig lookup cache shared across bundles in this CLI run
|
|
4551
|
+
* @param options - Bundle options
|
|
4555
4552
|
* @returns Map of resolver name to bundled code
|
|
4556
4553
|
*/
|
|
4557
|
-
async function bundleResolvers(
|
|
4554
|
+
async function bundleResolvers(options) {
|
|
4555
|
+
const { namespace, config, baseDir, defaultPermission, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache } = options;
|
|
4558
4556
|
const bundledCode = /* @__PURE__ */ new Map();
|
|
4559
4557
|
const files = loadFilesWithIgnores(config, baseDir);
|
|
4560
4558
|
if (files.length === 0) {
|
|
@@ -4577,16 +4575,27 @@ async function bundleResolvers(namespace, config, baseDir, startContext, cache,
|
|
|
4577
4575
|
});
|
|
4578
4576
|
}
|
|
4579
4577
|
const tsconfig = await resolveTSConfigWithFallback(baseDir);
|
|
4580
|
-
const results = await withBundleConcurrency(resolvers, (resolver) => bundleSingleResolver(
|
|
4578
|
+
const results = await withBundleConcurrency(resolvers, (resolver) => bundleSingleResolver({
|
|
4579
|
+
namespace,
|
|
4580
|
+
resolver,
|
|
4581
|
+
tsconfig,
|
|
4582
|
+
defaultPermission,
|
|
4583
|
+
startContext,
|
|
4584
|
+
cache,
|
|
4585
|
+
inlineSourcemap,
|
|
4586
|
+
bundleLogLevel,
|
|
4587
|
+
tsconfigCache
|
|
4588
|
+
}));
|
|
4581
4589
|
for (const [name, code] of results) bundledCode.set(name, code);
|
|
4582
4590
|
logger.log(`${styles.success("Bundled")} ${styles.info(`"${namespace}"`)}`);
|
|
4583
4591
|
return bundledCode;
|
|
4584
4592
|
}
|
|
4585
|
-
async function bundleSingleResolver(
|
|
4593
|
+
async function bundleSingleResolver(options) {
|
|
4594
|
+
const { namespace, resolver, tsconfig, defaultPermission, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache } = options;
|
|
4586
4595
|
const serializedStartContext = serializeStartContext(startContext);
|
|
4587
4596
|
const contextHash = computeBundlerContextHash({
|
|
4588
4597
|
sourceFile: resolver.sourceFile,
|
|
4589
|
-
extraContext: serializedStartContext,
|
|
4598
|
+
extraContext: JSON.stringify([serializedStartContext, defaultPermission ?? null]),
|
|
4590
4599
|
tsconfig,
|
|
4591
4600
|
inlineSourcemap,
|
|
4592
4601
|
bundleLogLevel
|
|
@@ -4606,7 +4615,10 @@ async function bundleSingleResolver(namespace, resolver, tsconfig, startContext,
|
|
|
4606
4615
|
|
|
4607
4616
|
const $tailor_resolver_body = async (context) => {
|
|
4608
4617
|
const invoker = ${INVOKER_EXPR};
|
|
4609
|
-
${buildResolverPermissionAndInputCheckExpr(
|
|
4618
|
+
${buildResolverPermissionAndInputCheckExpr({
|
|
4619
|
+
permission: resolver.permission,
|
|
4620
|
+
defaultPermission
|
|
4621
|
+
})}
|
|
4610
4622
|
return _internalResolver.body({ ...context, invoker });
|
|
4611
4623
|
};
|
|
4612
4624
|
|
|
@@ -4642,6 +4654,53 @@ async function bundleSingleResolver(namespace, resolver, tsconfig, startContext,
|
|
|
4642
4654
|
return [resolver.name, code];
|
|
4643
4655
|
}
|
|
4644
4656
|
|
|
4657
|
+
//#endregion
|
|
4658
|
+
//#region src/cli/services/resolver/default-permission.ts
|
|
4659
|
+
/**
|
|
4660
|
+
* Validate a resolver namespace's `defaultPermission` with the same schema as
|
|
4661
|
+
* a resolver's own `permission`, so an invalid policy fails the build instead
|
|
4662
|
+
* of compiling into a guard that lets everyone through.
|
|
4663
|
+
* @param params - The namespace name and its resolver service config
|
|
4664
|
+
* @returns The validated default, or `undefined` when the namespace declares none
|
|
4665
|
+
*/
|
|
4666
|
+
function parseResolverDefaultPermission(params) {
|
|
4667
|
+
const { namespace, config } = params;
|
|
4668
|
+
if (config.defaultPermission === void 0) return;
|
|
4669
|
+
const result = ResolverPermissionSchema.safeParse(config.defaultPermission);
|
|
4670
|
+
if (!result.success) throw new Error(`Invalid \`defaultPermission\` for resolver namespace "${namespace}": ` + result.error.issues.map((issue) => issue.message).join("; "));
|
|
4671
|
+
return result.data;
|
|
4672
|
+
}
|
|
4673
|
+
/**
|
|
4674
|
+
* Find the `defaultPermission` of the resolver namespace a file belongs to.
|
|
4675
|
+
*
|
|
4676
|
+
* `function test-run` receives a single file rather than a namespace, so the
|
|
4677
|
+
* namespace is recovered by matching the file against each namespace's own
|
|
4678
|
+
* patterns — otherwise a test run would skip a guard the deployed resolver has.
|
|
4679
|
+
*
|
|
4680
|
+
* Nothing stops two namespaces' patterns from claiming the same file, and
|
|
4681
|
+
* `deploy` then bundles that resolver once per namespace, each with its own
|
|
4682
|
+
* default. Picking one here would make the test run agree with only one of
|
|
4683
|
+
* the deployed copies, so an ambiguous file is rejected instead.
|
|
4684
|
+
* @param params - The config's resolver section, the resolver file, and the config's own directory
|
|
4685
|
+
* @returns The owning namespace's validated default, or `undefined` when no namespace claims the file
|
|
4686
|
+
*/
|
|
4687
|
+
function resolveResolverDefaultPermissionForFile(params) {
|
|
4688
|
+
const { config, filePath, baseDir } = params;
|
|
4689
|
+
if (!config) return;
|
|
4690
|
+
const targetFile = path.resolve(filePath);
|
|
4691
|
+
const owners = [];
|
|
4692
|
+
for (const [namespace, serviceConfig] of Object.entries(config)) {
|
|
4693
|
+
if ("external" in serviceConfig) continue;
|
|
4694
|
+
if (loadFilesWithIgnores(serviceConfig, baseDir).some((file) => path.resolve(file) === targetFile)) owners.push({
|
|
4695
|
+
namespace,
|
|
4696
|
+
config: serviceConfig
|
|
4697
|
+
});
|
|
4698
|
+
}
|
|
4699
|
+
if (owners.length > 1) throw new Error(`Resolver ${path.relative(process.cwd(), targetFile)} matches more than one resolver namespace: ${owners.map((owner) => `"${owner.namespace}"`).join(", ")}. Each namespace applies its own \`defaultPermission\`, so narrow the \`files\`/\`ignores\` patterns until exactly one namespace claims this file.`);
|
|
4700
|
+
const [owner] = owners;
|
|
4701
|
+
return owner ? parseResolverDefaultPermission(owner) : void 0;
|
|
4702
|
+
}
|
|
4703
|
+
|
|
4645
4704
|
//#endregion
|
|
4646
4705
|
//#region src/cli/services/resolver/service.ts
|
|
4647
4706
|
/**
|
|
@@ -4653,6 +4712,10 @@ async function bundleSingleResolver(namespace, resolver, tsconfig, startContext,
|
|
|
4653
4712
|
*/
|
|
4654
4713
|
function createResolverService(namespace, config, baseDir) {
|
|
4655
4714
|
const resolvers = {};
|
|
4715
|
+
const defaultPermission = parseResolverDefaultPermission({
|
|
4716
|
+
namespace,
|
|
4717
|
+
config
|
|
4718
|
+
});
|
|
4656
4719
|
const loadResolverForFile = async (resolverFile) => {
|
|
4657
4720
|
try {
|
|
4658
4721
|
const resolverModule = await import(pathToFileURL(resolverFile).href);
|
|
@@ -4674,6 +4737,7 @@ function createResolverService(namespace, config, baseDir) {
|
|
|
4674
4737
|
return {
|
|
4675
4738
|
namespace,
|
|
4676
4739
|
config,
|
|
4740
|
+
defaultPermission,
|
|
4677
4741
|
get resolvers() {
|
|
4678
4742
|
return resolvers;
|
|
4679
4743
|
},
|
|
@@ -4684,10 +4748,34 @@ function createResolverService(namespace, config, baseDir) {
|
|
|
4684
4748
|
logger.log(`Found ${styles.highlight(resolverFiles.length.toString())} resolver files for service ${styles.highlight(`"${namespace}"`)}`);
|
|
4685
4749
|
await Promise.all(resolverFiles.map((resolverFile) => loadResolverForFile(resolverFile)));
|
|
4686
4750
|
assertUniqueResolverNames(resolvers, namespace);
|
|
4751
|
+
warnUndeclaredPermissions({
|
|
4752
|
+
namespace,
|
|
4753
|
+
defaultPermission,
|
|
4754
|
+
resolvers
|
|
4755
|
+
});
|
|
4687
4756
|
}
|
|
4688
4757
|
};
|
|
4689
4758
|
}
|
|
4690
4759
|
/**
|
|
4760
|
+
* Warn about resolvers that declare no access requirement at all.
|
|
4761
|
+
*
|
|
4762
|
+
* A namespace-level `defaultPermission` covers every resolver in the
|
|
4763
|
+
* namespace, so the warning only fires when the namespace declares none and
|
|
4764
|
+
* at least one of its resolvers declares none either — those resolvers are
|
|
4765
|
+
* reachable by anonymous callers.
|
|
4766
|
+
* @param params - The namespace, its default permission, and its loaded resolvers
|
|
4767
|
+
*/
|
|
4768
|
+
function warnUndeclaredPermissions(params) {
|
|
4769
|
+
const { namespace, defaultPermission, resolvers } = params;
|
|
4770
|
+
if (defaultPermission !== void 0) return;
|
|
4771
|
+
const loaded = Object.values(resolvers);
|
|
4772
|
+
const undeclared = loaded.filter((resolver) => resolver.permission === void 0);
|
|
4773
|
+
if (undeclared.length === 0) return;
|
|
4774
|
+
logger.warn(`Resolver namespace ${styles.highlight(`"${namespace}"`)}: ${undeclared.length} of ${loaded.length} resolvers declare no \`permission\`, so anonymous callers can reach them. Set \`defaultPermission\` on the namespace, or declare \`permission\` on each resolver ("allowAnonymous" if public access is intended).`);
|
|
4775
|
+
const names = undeclared.map((resolver) => resolver.name).toSorted();
|
|
4776
|
+
logger.debug(` Resolvers without \`permission\`: ${names.join(", ")}`);
|
|
4777
|
+
}
|
|
4778
|
+
/**
|
|
4691
4779
|
* Assert that every loaded resolver in a namespace has a unique name.
|
|
4692
4780
|
* Resolvers are stored by source file, so two files declaring the same
|
|
4693
4781
|
* `name` would otherwise silently share a single bundle cache entry.
|
|
@@ -5751,7 +5839,17 @@ async function loadApplication(params) {
|
|
|
5751
5839
|
authHooks: /* @__PURE__ */ new Map()
|
|
5752
5840
|
};
|
|
5753
5841
|
for (const pipeline of resolverResult.resolverServices) {
|
|
5754
|
-
const resolverBundles = await bundleResolvers(
|
|
5842
|
+
const resolverBundles = await bundleResolvers({
|
|
5843
|
+
namespace: pipeline.namespace,
|
|
5844
|
+
config: pipeline.config,
|
|
5845
|
+
baseDir,
|
|
5846
|
+
defaultPermission: pipeline.defaultPermission,
|
|
5847
|
+
startContext,
|
|
5848
|
+
cache: bundleCache,
|
|
5849
|
+
inlineSourcemap,
|
|
5850
|
+
bundleLogLevel,
|
|
5851
|
+
tsconfigCache
|
|
5852
|
+
});
|
|
5755
5853
|
for (const [name, code] of resolverBundles) bundledScripts.resolvers.set(resolverBundleKey(pipeline.namespace, name), code);
|
|
5756
5854
|
}
|
|
5757
5855
|
if (executorService) bundledScripts.executors = await bundleExecutors({
|
|
@@ -5823,5 +5921,5 @@ async function loadApplication(params) {
|
|
|
5823
5921
|
}
|
|
5824
5922
|
|
|
5825
5923
|
//#endregion
|
|
5826
|
-
export {
|
|
5827
|
-
//# sourceMappingURL=application-
|
|
5924
|
+
export { createApplyLimiter as $, getDistDir as A, fetchUserInfo as B, composeFunctionTreeshakeOptions as C, getPluginGenerationDependencies as D, createBundleLog as E, fetchAll as F, initOAuth2Client as G, getOAuth2ClientId as H, fetchAllTolerant as I, isNotFoundError as J, initOperatorClient as K, fetchMachineUserToken as L, hashFile as M, closeConnectionPool as N, hasGenerationHooks as O, defaultPlatformBaseUrl as P, byName as Q, fetchPaged as R, platformBundleDefinePlugin as S, resolveBundleLogLevel as T, getOrNull as U, getConsoleBaseUrl as V, getPlatformBaseUrl as W, rememberPlatformConfigForToken as X, normalizeBaseUrl as Y, resolveStaticWebsiteUrls as Z, assertUniqueTailorDBTypeNamesWithExternal as _, resolveInlineSourcemap as a, createTsconfigPathsPlugin as b, WorkflowJobSchema as c, HTTP_METHODS as d, LOG_LEVELS as et, INVOKER_EXPR as f, assertUniqueLocalTailorDBTypeNames as g, buildResolverPermissionAndInputCheckExpr as h, resolverBundleKey as i, hashContent as j, createBundleCache as k, resolveResolverDefaultPermissionForFile as l, buildResolverOperationHookExpr as m, generatePluginFilesIfNeeded as n, getApplicationAuthNamespace as o, buildExecutorArgsExpr as p, isDefaultPlatform as q, loadApplication as r, WorkflowJobFunctionExecutionPolicySchema as s, defineApplication as t, ResolverSchema as u, stringifyFunction as v, createLogLevelTreeshakeOptions as w, resolveTSConfigWithFallback as x, createGeneratedEntryResolverPlugin as y, fetchPlatformMachineUserToken as z };
|
|
5925
|
+
//# sourceMappingURL=application-BpLeawBg.mjs.map
|