@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.
Files changed (92) hide show
  1. package/CHANGELOG.md +117 -0
  2. package/{dist/cli/index.mjs → bin/tailor.mjs} +1 -1
  3. package/dist/{application-CM6hKnSK.mjs → application-BpLeawBg.mjs} +126 -28
  4. package/dist/application-BpLeawBg.mjs.map +1 -0
  5. package/dist/application-BxLLiLsr.mjs +3 -0
  6. package/dist/cli/commands/deploy/tailordb/index.d.mts +2 -1
  7. package/dist/cli/commands/deploy/types.d.mts +2 -1
  8. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +11 -4
  9. package/dist/cli/commands/tailordb/migrate/file-state.d.mts +1 -0
  10. package/dist/cli/commands/tailordb/migrate/schema-checks.d.mts +2 -2
  11. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +8 -1
  12. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +5 -3
  13. package/dist/cli/lib.d.mts +4 -4
  14. package/dist/cli/lib.mjs +3 -482
  15. package/dist/cli/lib.mjs.map +1 -1
  16. package/dist/cli/main.mjs +997 -202
  17. package/dist/cli/main.mjs.map +1 -1
  18. package/dist/completion/zsh-worker.zsh +145 -2
  19. package/dist/configure/config/types.d.mts +12 -1
  20. package/dist/configure/index.d.mts +3 -3
  21. package/dist/configure/services/index.d.mts +3 -2
  22. package/dist/configure/services/resolver/index.d.mts +1 -1
  23. package/dist/configure/services/resolver/resolver.d.mts +1 -1
  24. package/dist/configure/services/tailordb/index.d.mts +2 -1
  25. package/dist/configure/services/tailordb/schema.d.mts +46 -46
  26. package/dist/configure/services/tailordb/types.d.mts +30 -4
  27. package/dist/{crashreport-B5LqCTfF.mjs → crashreport-CIIfLnoO.mjs} +2 -2
  28. package/dist/{crashreport-B5LqCTfF.mjs.map → crashreport-CIIfLnoO.mjs.map} +1 -1
  29. package/dist/{crashreport-eI7ty7ok.mjs → crashreport-CINZ5dVN.mjs} +1 -1
  30. package/dist/errors-CWj21238.mjs +75 -0
  31. package/dist/errors-CWj21238.mjs.map +1 -0
  32. package/dist/{globals-TfAVItuK.mjs → globals-B2nlxBrz.mjs} +2 -10
  33. package/dist/globals-B2nlxBrz.mjs.map +1 -0
  34. package/dist/kysely/index.d.mts +52 -5
  35. package/dist/kysely/index.mjs +7 -2
  36. package/dist/kysely/index.mjs.map +1 -1
  37. package/dist/{logger-CXQq9YIp.mjs → logger-DSdExfor.mjs} +83 -42
  38. package/dist/logger-DSdExfor.mjs.map +1 -0
  39. package/dist/plugin/builtin/seed/index.mjs +1 -1
  40. package/dist/{register-ts-hook-LYV7zH-e.mjs → register-ts-hook-CTth1eqj.mjs} +1587 -272
  41. package/dist/register-ts-hook-CTth1eqj.mjs.map +1 -0
  42. package/dist/runtime/globals.d.mts +0 -7
  43. package/dist/runtime/workflow.d.mts +2 -7
  44. package/dist/schema--xYWRGfe.mjs.map +1 -1
  45. package/dist/seed/index.d.mts +52 -3
  46. package/dist/seed/index.mjs +200 -44
  47. package/dist/seed/index.mjs.map +1 -1
  48. package/dist/{seed-B-yckgQY.mjs → seed-xqM9WIHP.mjs} +8 -8
  49. package/dist/seed-xqM9WIHP.mjs.map +1 -0
  50. package/dist/{service-B5WynBHQ.mjs → service-CCwl3Avt.mjs} +3 -3
  51. package/dist/{service-B5WynBHQ.mjs.map → service-CCwl3Avt.mjs.map} +1 -1
  52. package/dist/service-_XmjSEGr.mjs +3 -0
  53. package/dist/{service-k1xy_A5G.mjs → service-goqlJJgA.mjs} +2 -2
  54. package/dist/{service-k1xy_A5G.mjs.map → service-goqlJJgA.mjs.map} +1 -1
  55. package/dist/{service_pb-D5--My_M.mjs → service_pb-BEWj1pOV.mjs} +2 -2
  56. package/dist/{service_pb-D5--My_M.mjs.map → service_pb-BEWj1pOV.mjs.map} +1 -1
  57. package/dist/{service_pb-i8CmnQP4.mjs → service_pb-BjlhvK9E.mjs} +1 -1
  58. package/dist/utils/test/index.d.mts +9 -3
  59. package/dist/utils/test/index.mjs +49 -25
  60. package/dist/utils/test/index.mjs.map +1 -1
  61. package/dist/vitest/environment.mjs +1 -1
  62. package/dist/vitest/index.d.mts +2 -1
  63. package/dist/vitest/index.mjs +84 -2
  64. package/dist/vitest/index.mjs.map +1 -1
  65. package/dist/vitest/mocks/file.d.mts +1 -1
  66. package/dist/vitest/pglite-kysely.d.mts +43 -0
  67. package/dist/vitest/setup.mjs +1 -1
  68. package/dist/workflow-Bamae_Yc.mjs.map +1 -1
  69. package/dist/{workspace_resource_pb-DXnO2AT-.mjs → workspace_resource_pb-HNIL_Vfj.mjs} +10 -2
  70. package/dist/{workspace_resource_pb-DXnO2AT-.mjs.map → workspace_resource_pb-HNIL_Vfj.mjs.map} +1 -1
  71. package/docs/cli/tailordb.md +87 -22
  72. package/docs/cli-reference.md +13 -11
  73. package/docs/configuration.md +4 -1
  74. package/docs/migration/v2.md +1 -1
  75. package/docs/plugin/custom.md +48 -48
  76. package/docs/plugin/index.md +24 -24
  77. package/docs/services/auth.md +10 -10
  78. package/docs/services/executor.md +1 -1
  79. package/docs/services/resolver.md +34 -2
  80. package/docs/services/tailordb-migration.md +375 -76
  81. package/docs/services/tailordb.md +28 -28
  82. package/docs/testing.md +3 -1
  83. package/package.json +13 -8
  84. package/dist/application-CM6hKnSK.mjs.map +0 -1
  85. package/dist/application-CXNaUNhv.mjs +0 -3
  86. package/dist/errors-D7583Zz7.mjs +0 -58
  87. package/dist/errors-D7583Zz7.mjs.map +0 -1
  88. package/dist/globals-TfAVItuK.mjs.map +0 -1
  89. package/dist/logger-CXQq9YIp.mjs.map +0 -1
  90. package/dist/register-ts-hook-LYV7zH-e.mjs.map +0 -1
  91. package/dist/seed-B-yckgQY.mjs.map +0 -1
  92. 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
@@ -11,4 +11,4 @@ try {
11
11
  // politty is not resolvable from here (e.g. a fully bundled CLI) —
12
12
  // start without the compile cache rather than failing the CLI.
13
13
  }
14
- await import("./main.mjs");
14
+ await import("../dist/cli/main.mjs");
@@ -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-CXQq9YIp.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-k1xy_A5G.mjs";
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-D7583Zz7.mjs";
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-i8CmnQP4.mjs")]);
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-eI7ty7ok.mjs");
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 `TailorErrorMessage` when the caller doesn't match
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
- throw new TailorErrorMessage($reasons.length > 0 ? "access denied: " + $reasons.join("; ") : "access denied");
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. References `context.caller`, `context.input`, `invoker`, and
4039
- * `_internalResolver` — the caller's wrapper must bind a `context` object
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 permission - The resolver's `permission` config
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(permission) {
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 namespace - Resolver namespace name
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(namespace, config, baseDir, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache) {
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(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel, tsconfigCache));
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(namespace, resolver, tsconfig, startContext, cache, inlineSourcemap, bundleLogLevel = "DEBUG", tsconfigCache) {
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(resolver.permission)}
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(pipeline.namespace, pipeline.config, baseDir, startContext, bundleCache, inlineSourcemap, bundleLogLevel, tsconfigCache);
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 { LOG_LEVELS as $, hashContent as A, getConsoleBaseUrl as B, createLogLevelTreeshakeOptions as C, hasGenerationHooks as D, getPluginGenerationDependencies as E, fetchAllTolerant as F, initOperatorClient as G, getOrNull as H, fetchMachineUserToken as I, normalizeBaseUrl as J, isDefaultPlatform as K, fetchPaged as L, closeConnectionPool as M, defaultPlatformBaseUrl as N, createBundleCache as O, fetchAll as P, createApplyLimiter as Q, fetchPlatformMachineUserToken as R, composeFunctionTreeshakeOptions as S, createBundleLog as T, getPlatformBaseUrl as U, getOAuth2ClientId as V, initOAuth2Client as W, resolveStaticWebsiteUrls as X, rememberPlatformConfigForToken as Y, byName as Z, stringifyFunction as _, resolveInlineSourcemap as a, resolveTSConfigWithFallback as b, WorkflowJobSchema as c, INVOKER_EXPR as d, buildExecutorArgsExpr as f, assertUniqueTailorDBTypeNamesWithExternal as g, assertUniqueLocalTailorDBTypeNames as h, resolverBundleKey as i, hashFile as j, getDistDir as k, ResolverSchema as l, buildResolverPermissionAndInputCheckExpr as m, generatePluginFilesIfNeeded as n, getApplicationAuthNamespace as o, buildResolverOperationHookExpr as p, isNotFoundError as q, loadApplication as r, WorkflowJobFunctionExecutionPolicySchema as s, defineApplication as t, HTTP_METHODS as u, createGeneratedEntryResolverPlugin as v, resolveBundleLogLevel as w, platformBundleDefinePlugin as x, createTsconfigPathsPlugin as y, fetchUserInfo as z };
5827
- //# sourceMappingURL=application-CM6hKnSK.mjs.map
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