@tailor-platform/sdk 2.0.0-next.4 → 2.0.0-next.5

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 (258) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/dist/{application-BX13RArL.mjs → application-Bf8wxOi6.mjs} +417 -589
  3. package/dist/application-Bf8wxOi6.mjs.map +1 -0
  4. package/dist/application-CUkjzfij.mjs +3 -0
  5. package/dist/cli/cache/bundle-cache.d.mts +2 -1
  6. package/dist/cli/cache/store.d.mts +1 -1
  7. package/dist/cli/commands/api/index.d.mts +1 -0
  8. package/dist/cli/commands/deploy/aigateway.d.mts +5 -1
  9. package/dist/cli/commands/deploy/application.d.mts +7 -1
  10. package/dist/cli/commands/deploy/apply-phases.d.mts +14 -1
  11. package/dist/cli/commands/deploy/auth.d.mts +5 -1
  12. package/dist/cli/commands/deploy/deploy.d.mts +5 -0
  13. package/dist/cli/commands/deploy/executor.d.mts +7 -1
  14. package/dist/cli/commands/deploy/function-registry.d.mts +5 -0
  15. package/dist/cli/commands/deploy/idp.d.mts +5 -1
  16. package/dist/cli/commands/deploy/resolver.d.mts +5 -1
  17. package/dist/cli/commands/deploy/secret-manager.d.mts +5 -1
  18. package/dist/cli/commands/deploy/staticwebsite.d.mts +5 -1
  19. package/dist/cli/commands/deploy/tailordb/index.d.mts +8 -1
  20. package/dist/cli/commands/deploy/types.d.mts +3 -1
  21. package/dist/cli/commands/deploy/workflow-execution-policy.d.mts +3 -1
  22. package/dist/cli/commands/deploy/workflow.d.mts +4 -1
  23. package/dist/cli/commands/executor/get.d.mts +0 -1
  24. package/dist/cli/commands/executor/jobs.d.mts +0 -1
  25. package/dist/cli/commands/executor/list.d.mts +0 -1
  26. package/dist/cli/commands/executor/transform.d.mts +1 -0
  27. package/dist/cli/commands/executor/trigger.d.mts +0 -1
  28. package/dist/cli/commands/executor/webhook.d.mts +0 -1
  29. package/dist/cli/commands/function/get.d.mts +0 -1
  30. package/dist/cli/commands/function/list.d.mts +0 -1
  31. package/dist/cli/commands/function/transform.d.mts +1 -0
  32. package/dist/cli/commands/generate/service.d.mts +5 -1
  33. package/dist/cli/commands/machineuser/list.d.mts +0 -1
  34. package/dist/cli/commands/machineuser/token.d.mts +0 -1
  35. package/dist/cli/commands/oauth2client/get.d.mts +0 -1
  36. package/dist/cli/commands/oauth2client/list.d.mts +0 -1
  37. package/dist/cli/commands/oauth2client/transform.d.mts +1 -0
  38. package/dist/cli/commands/organization/folder/create.d.mts +0 -1
  39. package/dist/cli/commands/organization/folder/delete.d.mts +0 -1
  40. package/dist/cli/commands/organization/folder/get.d.mts +0 -1
  41. package/dist/cli/commands/organization/folder/list.d.mts +0 -1
  42. package/dist/cli/commands/organization/folder/update.d.mts +0 -1
  43. package/dist/cli/commands/organization/get.d.mts +0 -1
  44. package/dist/cli/commands/organization/list.d.mts +0 -1
  45. package/dist/cli/commands/organization/transform.d.mts +2 -0
  46. package/dist/cli/commands/organization/tree.d.mts +0 -1
  47. package/dist/cli/commands/organization/update.d.mts +0 -1
  48. package/dist/cli/commands/remove.d.mts +0 -1
  49. package/dist/cli/commands/show.d.mts +9 -4
  50. package/dist/cli/commands/tailordb/migrate/config.d.mts +0 -1
  51. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +16 -3
  52. package/dist/cli/commands/tailordb/migrate/generate.d.mts +0 -1
  53. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +6 -0
  54. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +1 -1
  55. package/dist/cli/commands/tailordb/truncate.d.mts +0 -1
  56. package/dist/cli/commands/workflow/executions.d.mts +0 -1
  57. package/dist/cli/commands/workflow/get.d.mts +2 -1
  58. package/dist/cli/commands/workflow/list.d.mts +0 -1
  59. package/dist/cli/commands/workflow/resume.d.mts +0 -1
  60. package/dist/cli/commands/workflow/start.d.mts +0 -1
  61. package/dist/cli/commands/workflow/status.d.mts +1 -0
  62. package/dist/cli/commands/workflow/transform.d.mts +1 -0
  63. package/dist/cli/commands/workflow/wait.d.mts +0 -1
  64. package/dist/cli/commands/workflow/waiter.d.mts +1 -1
  65. package/dist/cli/commands/workspace/app/health.d.mts +0 -1
  66. package/dist/cli/commands/workspace/app/list.d.mts +0 -1
  67. package/dist/cli/commands/workspace/app/transform.d.mts +2 -0
  68. package/dist/cli/commands/workspace/create.d.mts +0 -1
  69. package/dist/cli/commands/workspace/delete.d.mts +0 -1
  70. package/dist/cli/commands/workspace/get.d.mts +0 -1
  71. package/dist/cli/commands/workspace/list.d.mts +0 -1
  72. package/dist/cli/commands/workspace/restore.d.mts +0 -1
  73. package/dist/cli/commands/workspace/transform.d.mts +2 -0
  74. package/dist/cli/commands/workspace/user/invite.d.mts +0 -1
  75. package/dist/cli/commands/workspace/user/list.d.mts +0 -1
  76. package/dist/cli/commands/workspace/user/remove.d.mts +0 -1
  77. package/dist/cli/commands/workspace/user/transform.d.mts +1 -0
  78. package/dist/cli/commands/workspace/user/update.d.mts +0 -1
  79. package/dist/cli/index.d.mts +6 -3
  80. package/dist/cli/index.mjs +142 -73
  81. package/dist/cli/index.mjs.map +1 -1
  82. package/dist/cli/lib.d.mts +4 -2
  83. package/dist/cli/lib.mjs +3 -3
  84. package/dist/cli/lib.mjs.map +1 -1
  85. package/dist/cli/query/index.d.mts +0 -1
  86. package/dist/cli/services/application.d.mts +12 -1
  87. package/dist/cli/services/auth/service.d.mts +2 -0
  88. package/dist/cli/services/executor/service.d.mts +1 -1
  89. package/dist/cli/services/http-adapter/bundler.d.mts +3 -1
  90. package/dist/cli/services/http-adapter/service.d.mts +2 -1
  91. package/dist/cli/services/resolver/service.d.mts +1 -1
  92. package/dist/cli/services/tailordb/service.d.mts +3 -1
  93. package/dist/cli/services/workflow/bundler.d.mts +2 -1
  94. package/dist/cli/services/workflow/service.d.mts +1 -1
  95. package/dist/cli/shared/args.d.mts +1 -1
  96. package/dist/cli/shared/client.d.mts +1 -1
  97. package/dist/cli/shared/config-loader.d.mts +0 -1
  98. package/dist/cli/shared/context.d.mts +2 -1
  99. package/dist/cli/shared/script-executor.d.mts +0 -1
  100. package/dist/cli/shared/seed-chunker.d.mts +7 -3
  101. package/dist/cli/shared/type-generator.d.mts +0 -1
  102. package/dist/completion/zsh-worker.zsh +1 -1
  103. package/dist/configure/config/index.d.mts +0 -1
  104. package/dist/configure/config/types.d.mts +2 -2
  105. package/dist/configure/index.d.mts +14 -4
  106. package/dist/configure/index.mjs +196 -2
  107. package/dist/configure/index.mjs.map +1 -1
  108. package/dist/configure/services/aigateway/index.d.mts +0 -1
  109. package/dist/configure/services/aigateway/types.d.mts +0 -1
  110. package/dist/configure/services/auth/index.d.mts +0 -1
  111. package/dist/configure/services/auth/types.d.mts +15 -14
  112. package/dist/configure/services/executor/executor.d.mts +1 -1
  113. package/dist/configure/services/executor/index.d.mts +1 -0
  114. package/dist/configure/services/executor/operation.d.mts +2 -2
  115. package/dist/configure/services/executor/trigger/event.d.mts +0 -1
  116. package/dist/configure/services/executor/trigger/index.d.mts +0 -1
  117. package/dist/configure/services/executor/trigger/schedule.d.mts +0 -1
  118. package/dist/configure/services/executor/trigger/webhook.d.mts +0 -1
  119. package/dist/configure/services/http-adapter/http-adapter.d.mts +1 -2
  120. package/dist/configure/services/idp/index.d.mts +1 -5
  121. package/dist/configure/services/idp/permission.d.mts +4 -5
  122. package/dist/configure/services/idp/types.d.mts +0 -1
  123. package/dist/configure/services/index.d.mts +5 -0
  124. package/dist/configure/services/resolver/resolver.d.mts +1 -0
  125. package/dist/configure/services/resolver/types.d.mts +0 -1
  126. package/dist/configure/services/secrets/index.d.mts +0 -1
  127. package/dist/configure/services/secrets/types.d.mts +0 -1
  128. package/dist/configure/services/staticwebsite/index.d.mts +0 -1
  129. package/dist/configure/services/staticwebsite/types.d.mts +0 -1
  130. package/dist/configure/services/tailordb/permission.d.mts +4 -5
  131. package/dist/configure/services/tailordb/schema.d.mts +85 -49
  132. package/dist/configure/services/tailordb/types.d.mts +66 -17
  133. package/dist/configure/services/workflow/execution-policy.d.mts +0 -1
  134. package/dist/configure/services/workflow/execution-policy.types.d.mts +0 -1
  135. package/dist/configure/services/workflow/index.d.mts +1 -0
  136. package/dist/configure/services/workflow/job.d.mts +0 -1
  137. package/dist/configure/services/workflow/wait-point.d.mts +0 -1
  138. package/dist/configure/services/workflow/workflow.d.mts +1 -1
  139. package/dist/configure/types/field-runtime.d.mts +0 -1
  140. package/dist/configure/types/field.d.mts +1 -2
  141. package/dist/configure/types/field.types.d.mts +6 -45
  142. package/dist/configure/types/index.d.mts +1 -0
  143. package/dist/configure/types/type.d.mts +1 -2
  144. package/dist/kysely/index.d.mts +3 -4
  145. package/dist/{kysely-type-D-zflMGf.mjs → kysely-type-DqIRgDYR.mjs} +4 -3
  146. package/dist/kysely-type-DqIRgDYR.mjs.map +1 -0
  147. package/dist/parser/service/auth/index.d.mts +1 -1
  148. package/dist/parser/service/auth/schema.d.mts +2 -0
  149. package/dist/parser/service/http-adapter/index.d.mts +1 -1
  150. package/dist/parser/service/idp/types.d.mts +1 -0
  151. package/dist/parser/service/tailordb/types.d.mts +6 -1
  152. package/dist/plugin/builtin/enum-constants/index.d.mts +0 -1
  153. package/dist/plugin/builtin/file-utils/index.d.mts +0 -1
  154. package/dist/plugin/builtin/kysely-type/index.d.mts +0 -1
  155. package/dist/plugin/builtin/kysely-type/index.mjs +1 -1
  156. package/dist/plugin/builtin/seed/index.d.mts +0 -1
  157. package/dist/plugin/get-generated-type.d.mts +0 -1
  158. package/dist/plugin/manager.d.mts +2 -1
  159. package/dist/plugin/types.d.mts +0 -1
  160. package/dist/plugin/with-context.d.mts +0 -1
  161. package/dist/{register-ts-hook-BM1caLT0.mjs → register-ts-hook-BhzVkej0.mjs} +553 -199
  162. package/dist/register-ts-hook-BhzVkej0.mjs.map +1 -0
  163. package/dist/runtime/aigateway.d.mts +0 -1
  164. package/dist/runtime/authconnection.d.mts +0 -1
  165. package/dist/runtime/context.d.mts +0 -1
  166. package/dist/runtime/globals.d.mts +0 -1
  167. package/dist/runtime/index.d.mts +0 -1
  168. package/dist/runtime/types.d.mts +9 -4
  169. package/dist/{schema-C4LYbXVG.mjs → schema-iCd1ugGp.mjs} +253 -50
  170. package/dist/schema-iCd1ugGp.mjs.map +1 -0
  171. package/dist/seed/index.d.mts +3 -2
  172. package/dist/service-BT0GPd01.mjs +3 -0
  173. package/dist/{service-ufH7sS8o.mjs → service-CzZEVrp9.mjs} +14 -9
  174. package/dist/service-CzZEVrp9.mjs.map +1 -0
  175. package/dist/{service_pb-B5w9rjPY.mjs → service_pb-Bk7dL-yT.mjs} +12 -2
  176. package/dist/{service_pb-B5w9rjPY.mjs.map → service_pb-Bk7dL-yT.mjs.map} +1 -1
  177. package/dist/{service_pb-B2FF59sP.mjs → service_pb-DZkfjB_6.mjs} +1 -1
  178. package/dist/tailor-proto/src/tailor/v1/aigateway_pb.d.mts +0 -1
  179. package/dist/tailor-proto/src/tailor/v1/aigateway_resource_pb.d.mts +0 -1
  180. package/dist/tailor-proto/src/tailor/v1/application_pb.d.mts +0 -1
  181. package/dist/tailor-proto/src/tailor/v1/application_resource_pb.d.mts +0 -1
  182. package/dist/tailor-proto/src/tailor/v1/auth_pb.d.mts +0 -1
  183. package/dist/tailor-proto/src/tailor/v1/auth_resource_pb.d.mts +0 -1
  184. package/dist/tailor-proto/src/tailor/v1/events_pb.d.mts +0 -1
  185. package/dist/tailor-proto/src/tailor/v1/events_resource_pb.d.mts +0 -1
  186. package/dist/tailor-proto/src/tailor/v1/executor_pb.d.mts +0 -1
  187. package/dist/tailor-proto/src/tailor/v1/executor_resource_pb.d.mts +0 -1
  188. package/dist/tailor-proto/src/tailor/v1/function_pb.d.mts +0 -1
  189. package/dist/tailor-proto/src/tailor/v1/function_registry_pb.d.mts +0 -1
  190. package/dist/tailor-proto/src/tailor/v1/function_resource_pb.d.mts +0 -1
  191. package/dist/tailor-proto/src/tailor/v1/http_adapter_resource_pb.d.mts +0 -1
  192. package/dist/tailor-proto/src/tailor/v1/idp_pb.d.mts +0 -1
  193. package/dist/tailor-proto/src/tailor/v1/idp_resource_pb.d.mts +0 -1
  194. package/dist/tailor-proto/src/tailor/v1/metadata_pb.d.mts +0 -1
  195. package/dist/tailor-proto/src/tailor/v1/metadata_resource_pb.d.mts +0 -1
  196. package/dist/tailor-proto/src/tailor/v1/meter_pb.d.mts +0 -1
  197. package/dist/tailor-proto/src/tailor/v1/pipeline_pb.d.mts +0 -1
  198. package/dist/tailor-proto/src/tailor/v1/pipeline_resource_pb.d.mts +0 -1
  199. package/dist/tailor-proto/src/tailor/v1/resource_pb.d.mts +0 -1
  200. package/dist/tailor-proto/src/tailor/v1/secret_manager_pb.d.mts +0 -1
  201. package/dist/tailor-proto/src/tailor/v1/secret_manager_resource_pb.d.mts +0 -1
  202. package/dist/tailor-proto/src/tailor/v1/service_pb.d.mts +0 -1
  203. package/dist/tailor-proto/src/tailor/v1/stateflow_pb.d.mts +0 -1
  204. package/dist/tailor-proto/src/tailor/v1/stateflow_resource_pb.d.mts +0 -1
  205. package/dist/tailor-proto/src/tailor/v1/staticwebsite_pb.d.mts +0 -1
  206. package/dist/tailor-proto/src/tailor/v1/staticwebsite_resource_pb.d.mts +0 -1
  207. package/dist/tailor-proto/src/tailor/v1/tailordb_pb.d.mts +0 -1
  208. package/dist/tailor-proto/src/tailor/v1/tailordb_resource_pb.d.mts +0 -1
  209. package/dist/tailor-proto/src/tailor/v1/telemetryrouter_pb.d.mts +0 -1
  210. package/dist/tailor-proto/src/tailor/v1/telemetryrouter_resource_pb.d.mts +0 -1
  211. package/dist/tailor-proto/src/tailor/v1/workflow_pb.d.mts +0 -1
  212. package/dist/tailor-proto/src/tailor/v1/workflow_resource_pb.d.mts +0 -1
  213. package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +0 -1
  214. package/dist/tailor-proto/src/tailor/v1/workspace_resource_pb.d.mts +0 -1
  215. package/dist/types/aigateway.generated.d.mts +5 -2
  216. package/dist/types/auth-connection.generated.d.mts +24 -11
  217. package/dist/types/auth.generated.d.mts +115 -84
  218. package/dist/types/executor.generated.d.mts +76 -84
  219. package/dist/types/helpers.d.mts +7 -6
  220. package/dist/types/http-adapter.generated.d.mts +11 -5
  221. package/dist/types/idp.generated.d.mts +536 -524
  222. package/dist/types/resolver.generated.d.mts +26 -11
  223. package/dist/types/staticwebsite.generated.d.mts +7 -3
  224. package/dist/types/tailordb.generated.d.mts +57 -29
  225. package/dist/types/workflow.generated.d.mts +9 -4
  226. package/dist/utils/test/index.d.mts +1 -2
  227. package/dist/utils/test/index.mjs +36 -10
  228. package/dist/utils/test/index.mjs.map +1 -1
  229. package/dist/utils/test/mock.d.mts +0 -1
  230. package/dist/vitest/index.d.mts +1 -1
  231. package/dist/vitest/mock-kysely.d.mts +0 -1
  232. package/dist/vitest/mocks/aigateway.d.mts +2 -2
  233. package/dist/vitest/mocks/authconnection.d.mts +2 -2
  234. package/dist/vitest/mocks/idp.d.mts +2 -2
  235. package/dist/vitest/mocks/secretmanager.d.mts +3 -1
  236. package/dist/vitest/mocks/tailordb.d.mts +6 -3
  237. package/dist/vitest/mocks/workflow.d.mts +11 -6
  238. package/dist/vitest/workflow-local.d.mts +1 -0
  239. package/docs/cli/setup.md +1 -1
  240. package/docs/cli-reference.md +7 -6
  241. package/docs/migration/v2.md +206 -0
  242. package/docs/services/aigateway.md +2 -0
  243. package/docs/services/tailordb.md +100 -68
  244. package/docs/services/workflow.md +1 -1
  245. package/package.json +22 -22
  246. package/dist/application-BO4ZF8wP.mjs +0 -3
  247. package/dist/application-BX13RArL.mjs.map +0 -1
  248. package/dist/cli/shared/trigger-context.d.mts +0 -1
  249. package/dist/field-runtime-CAnh_oow.mjs +0 -183
  250. package/dist/field-runtime-CAnh_oow.mjs.map +0 -1
  251. package/dist/kysely-type-D-zflMGf.mjs.map +0 -1
  252. package/dist/register-ts-hook-BM1caLT0.mjs.map +0 -1
  253. package/dist/schema-C4LYbXVG.mjs.map +0 -1
  254. package/dist/service-CkIwEctX.mjs +0 -3
  255. package/dist/service-ufH7sS8o.mjs.map +0 -1
  256. package/dist/types-C-lQ4se3.mjs +0 -4
  257. package/dist/types-CXF2OYdR.mjs +0 -199
  258. package/dist/types-CXF2OYdR.mjs.map +0 -1
@@ -582,6 +582,54 @@ calls to db.table. Leave unrelated local objects with a .type() method unchanged
582
582
 
583
583
  </details>
584
584
 
585
+ ## TailorDB forward relation names derive from field names
586
+
587
+ **Migration:** Partially automatic
588
+
589
+ Review TailorDB relations that omit `toward.as`. Their forward GraphQL field names now derive from the relation field name with a trailing `ID`, `Id`, or `id` removed, instead of from the target table name.
590
+
591
+ Preserve the v1 GraphQL field name by making it explicit:
592
+
593
+ Before:
594
+
595
+ ```ts
596
+ ownerId: db.uuid().relation({
597
+ type: "n-1",
598
+ toward: { type: user },
599
+ }),
600
+ ```
601
+
602
+ After:
603
+
604
+ ```ts
605
+ ownerId: db.uuid().relation({
606
+ type: "n-1",
607
+ toward: { type: user, as: "user" },
608
+ }),
609
+ ```
610
+
611
+ <details>
612
+ <summary>Prompt for an AI agent (to finish the cases the codemod could not migrate)</summary>
613
+
614
+ ```text
615
+ Tailor SDK v2 derives a default forward GraphQL relation name from the source
616
+ field name by removing a trailing ID, Id, or id. V1 derived it from the target
617
+ table name. Review each reported non-self relation that omits toward.as.
618
+
619
+ If consumers must keep using the v1 GraphQL field name, inspect the v1 schema and
620
+ copy that exact field name into toward.as. Otherwise, update GraphQL operations
621
+ and consumer code to use the new field-based name. No change is needed when the old
622
+ and new names are identical. Relations with a guaranteed non-empty toward.as,
623
+ self-relations, and keyOnly relations are unchanged. For an empty or dynamic
624
+ toward.as, determine whether its runtime value can be falsy; if so, treat the
625
+ relation as using the default name.
626
+
627
+ A relation field without a trailing ID, Id, or id would default to its own scalar
628
+ field name and therefore conflict. Give that relation an explicit toward.as.
629
+ ```
630
+
631
+ </details>
632
+
585
633
  ## executeScript arg JSON.stringify → value
586
634
 
587
635
  **Migration:** Partially automatic
@@ -825,6 +873,164 @@ After:
825
873
  .tailor/
826
874
  ```
827
875
 
876
+ ## ValidateFn simplification and type-level validate
877
+
878
+ **Migration:** Manual
879
+
880
+ Field-level `ValidateFn` is simplified from `(args: { value, data, invoker }) => boolean` to `(args: { value }) => string | void` — the function now returns the error message directly instead of a separate `[fn, message]` tuple. The `ValidateConfig` tuple form and `Validators<F>` record syntax on `db.type().validate()` are removed. Type-level validation uses `db.type().validate((args, issues) => void)` with `{ newRecord, oldRecord, invoker }` args and an `issues(field, message)` callback for cross-field rules.
881
+
882
+ Field-level validate: return an error message string instead of a boolean (tuple form removed):
883
+
884
+ Before:
885
+
886
+ ```ts
887
+ .validate(
888
+ [({ value }) => value.length > 5, "Name must be longer than 5 characters"],
889
+ )
890
+ ```
891
+
892
+ After:
893
+
894
+ ```ts
895
+ .validate(({ value }) =>
896
+ value.length <= 5 ? "Name must be longer than 5 characters" : undefined,
897
+ )
898
+ ```
899
+
900
+ Type-level validate: per-field record syntax replaced by a single function with `issues()` callback:
901
+
902
+ Before:
903
+
904
+ ```ts
905
+ .validate({
906
+ name: [({ value }) => value.length > 5, "Name must be longer than 5"],
907
+ })
908
+ ```
909
+
910
+ After:
911
+
912
+ ```ts
913
+ .validate(({ newRecord }, issues) => {
914
+ if (newRecord.name && newRecord.name.length <= 5) {
915
+ issues("name", "Name must be longer than 5");
916
+ }
917
+ })
918
+ ```
919
+
920
+ <details>
921
+ <summary>Prompt for an AI agent (to perform this migration)</summary>
922
+
923
+ ```text
924
+ The v2 SDK simplifies field validation and introduces type-level validation.
925
+
926
+ Field-level `.validate()` changes:
927
+ - Signature: `(args: { value, data, invoker }) => boolean` → `(args: { value }) => string | void`
928
+ - The function now returns the error message string directly (or undefined/void to pass)
929
+ instead of returning a boolean with the message in a separate tuple.
930
+ - The `[fn, errorMessage]` tuple form (`ValidateConfig`) is removed.
931
+ - `data` and `invoker` are no longer available in field-level validators.
932
+ Use type-level `.validate()` for cross-field or invoker-dependent rules.
933
+
934
+ Type-level `.validate()` on `db.type()` changes:
935
+ - Old: `.validate({ fieldName: fn | [fn, msg] | fn[] })` (per-field record, `Validators<F>` type)
936
+ - New: `.validate((args, issues) => void)` (single function, `TypeValidateFn<F>` type)
937
+ - Args: `{ newRecord, oldRecord, invoker }` — `newRecord` is the record after hooks run
938
+ - Call `issues(field, message)` to report validation errors; `field` supports dotted paths
939
+ - Move per-field validators that need `data`/`invoker` to the type-level function
940
+
941
+ For each remaining `ValidateConfig`, `Validators<`, or old-signature `.validate()` usage:
942
+ 1. Rewrite field-level validators to return the error string directly
943
+ 2. Move cross-field / invoker-dependent validators to the type-level function
944
+ 3. Remove unused `ValidateConfig` / `Validators` type imports
945
+ ```
946
+
947
+ </details>
948
+
949
+ ## TailorDB hook redesign: field-level args and type-level hooks
950
+
951
+ **Migration:** Manual
952
+
953
+ Field-level `HookFn` args change from `{ value, data, invoker }` to create `{ input, invoker, now }` / update `{ input, oldValue, invoker, now }` — `value` is renamed to `input`, matching the `input` arg on type-level hooks (same pre-hook data, narrowed to one field); `data` (the full record) is removed; `oldValue` (previous field value) is added for update hooks only; `now` (operation timestamp) is shared across all hooks. Type-level hooks on `db.type().hooks()` change from per-field mapping `{ fieldName: { create, update } }` (`Hooks<F>`) to a single `{ create, update }` object (`TypeHook<F>`) — create hooks take `{ input, invoker, now }`, update hooks take `{ input, oldRecord, invoker, now }` (oldRecord is always non-null). Both return partial field overrides.
954
+
955
+ Field-level hooks: `value` renamed to `input`, `data` replaced by `oldValue` and `now`; use `now` instead of `new Date()`:
956
+
957
+ Before:
958
+
959
+ ```ts
960
+ db.datetime().hooks({
961
+ create: ({ value }) => value ?? new Date(),
962
+ update: () => new Date(),
963
+ })
964
+ ```
965
+
966
+ After:
967
+
968
+ ```ts
969
+ db.datetime().hooks({
970
+ create: ({ input, now }) => input ?? now,
971
+ update: ({ now }) => now,
972
+ })
973
+ ```
974
+
975
+ Type-level hooks: per-field mapping replaced by single create/update functions:
976
+
977
+ Before:
978
+
979
+ ```ts
980
+ .hooks({
981
+ fullAddress: {
982
+ create: ({ data }) => `${data.postalCode} ${data.address}`,
983
+ update: ({ data }) => `${data.postalCode} ${data.address}`,
984
+ },
985
+ })
986
+ ```
987
+
988
+ After:
989
+
990
+ ```ts
991
+ .hooks({
992
+ create: ({ input }) => ({
993
+ fullAddress: `${input.postalCode} ${input.address}`,
994
+ }),
995
+ update: ({ input }) => ({
996
+ fullAddress: `${input.postalCode} ${input.address}`,
997
+ }),
998
+ })
999
+ ```
1000
+
1001
+ <details>
1002
+ <summary>Prompt for an AI agent (to perform this migration)</summary>
1003
+
1004
+ ```text
1005
+ The v2 SDK redesigns TailorDB hooks at both field and type levels.
1006
+
1007
+ Field-level `.hooks()` on individual fields:
1008
+ - Create args: `{ value, data, invoker }` → `{ input, invoker, now }` (no `oldValue`)
1009
+ - Update args: `{ value, data, invoker }` → `{ input, oldValue, invoker, now }`
1010
+ - `value` is renamed to `input`, matching the type-level hook's `input` arg — both are
1011
+ the same pre-hook data, at different granularity
1012
+ - `data` (full record) is removed; update hooks get `oldValue` (previous field value) instead
1013
+ - `now` provides the operation timestamp — use `now` instead of `new Date()`
1014
+ - If a field-level hook needs the full record (other fields), move it to a type-level hook
1015
+
1016
+ Type-level `.hooks()` on `db.type()`:
1017
+ - Old: `.hooks({ fieldName: { create: fn, update: fn } })` (per-field mapping, `Hooks<F>` type)
1018
+ - New: `.hooks({ create: fn, update: fn })` (single object, `TypeHook<F>` type)
1019
+ - Each function: `({ input, oldRecord, invoker, now }) => ({ fieldName: value, ... })`
1020
+ - `input` is the pre-hook input (may have nullish values for optional/defaulted fields)
1021
+ - Create hooks do not receive `oldRecord`; update hooks receive `oldRecord` (always non-null)
1022
+ - Return an object with only the fields to override; unmentioned fields are unchanged
1023
+
1024
+ Migration steps for each `.hooks()` call on a `db.type()`:
1025
+ 1. If the old per-field hooks only use `value`/`invoker` and don't reference `data`,
1026
+ convert them to field-level hooks with the new args (`value` → `input`, plus `oldValue`, `now`)
1027
+ 2. If the old hooks reference `data` (cross-field access), convert to a type-level hook
1028
+ using `input`/`oldRecord`
1029
+ 3. Remove unused `Hooks<F>` / `HookFn<>` type imports
1030
+ ```
1031
+
1032
+ </details>
1033
+
828
1034
  ## Behavioral changes (no migration required)
829
1035
 
830
1036
  These v2 changes alter runtime or CLI behavior; no source change is needed.
@@ -111,3 +111,5 @@ const { url } = await aigateway.get("my-aigateway");
111
111
  ```
112
112
 
113
113
  Type narrowing is provided by the generated `tailor.d.ts` (the `AIGatewayNameRegistry` interface). Run `tailor generate` (or `deploy`) after defining new AI Gateways to refresh it. Before the first generate run, `get()` accepts any string.
114
+
115
+ The same URL is also shown by `tailor show`, which lists the URL of each AI Gateway defined in `aiGateways` once it has been deployed.
@@ -220,11 +220,14 @@ const user = db.table("User", {
220
220
  const userProfile = db.table("UserProfile", {
221
221
  userEmail: db.string().relation({
222
222
  type: "1-1",
223
- toward: { type: user, key: "email" },
223
+ toward: { type: user, key: "email", as: "user" },
224
224
  }),
225
225
  });
226
226
  ```
227
227
 
228
+ `userEmail` does not end in `ID`, `Id`, or `id`, so this example specifies the forward relation
229
+ name with `toward.as`.
230
+
228
231
  Customize relation names using `toward.as` / `backward` options:
229
232
 
230
233
  ```typescript
@@ -255,52 +258,72 @@ type User {
255
258
  - `backward` - Customizes the field name for accessing this type from the related type
256
259
 
257
260
  Relation names share the same GraphQL field namespace as fields, files, and other relations on
258
- the type. The SDK rejects duplicate or empty relation names. Use `toward.as` when multiple fields
259
- on the same type point to the same target type, because their default forward names are derived
260
- from the target type name:
261
+ the table. The SDK rejects duplicate or empty relation names. When `toward.as` is omitted, the
262
+ default forward name comes from the relation field name with a trailing `ID`, `Id`, or `id`
263
+ removed. This lets multiple fields point to the same target table with distinct forward names:
261
264
 
262
265
  ```typescript
263
266
  const post = db.table("Post", {
264
267
  authorID: db.uuid().relation({
265
268
  type: "n-1",
266
- toward: { type: user, as: "author" },
269
+ toward: { type: user },
267
270
  backward: "authoredPosts",
268
271
  }),
269
272
  reviewerID: db.uuid().relation({
270
273
  type: "n-1",
271
- toward: { type: user, as: "reviewer" },
274
+ toward: { type: user },
272
275
  backward: "reviewedPosts",
273
276
  }),
274
277
  });
275
278
  ```
276
279
 
280
+ These fields generate the forward names `author` and `reviewer`. A relation field without one of
281
+ the recognized ID suffixes needs an explicit `toward.as`, because its generated forward name
282
+ would conflict with the field itself.
283
+
277
284
  Use `toward.as` or `backward` when a generated relation name would conflict with an existing
278
- field, files entry, or relation on the same type.
285
+ field, files entry, or relation on the same table.
279
286
 
280
287
  ### Hooks
281
288
 
282
- Add hooks to execute functions during data creation or update. Hooks receive three arguments:
289
+ Add hooks to execute functions during data creation or update.
290
+
291
+ #### Field-level Hooks
292
+
293
+ Set hooks directly on individual fields.
283
294
 
284
- - `value`: User input if provided, otherwise existing value on update or null on create
285
- - `data`: Entire record data (for accessing other field values)
295
+ Create hooks receive:
296
+
297
+ - `input`: The field value from the input (null when not provided)
286
298
  - `invoker`: Principal performing the operation
299
+ - `now`: Operation timestamp (`Date`), shared across all hooks in the same operation
287
300
 
288
- #### Field-level Hooks
301
+ Update hooks receive the same arguments plus:
289
302
 
290
- Set hooks directly on individual fields:
303
+ - `oldValue`: The previous field value (null only for optional fields)
291
304
 
292
305
  ```typescript
293
306
  db.string().hooks({
294
307
  create: ({ invoker }) => invoker?.id ?? "",
295
- update: ({ value }) => value,
308
+ update: ({ input, oldValue }) => input ?? oldValue,
296
309
  });
297
310
  ```
298
311
 
299
- **Note:** When setting hooks at the field level, the `data` argument type is `unknown` since the field doesn't know about other fields in the type. Use type-level hooks if you need to access other fields with type safety.
312
+ Field-level hooks operate on a single field and cannot access other fields. Use type-level hooks for cross-field logic.
300
313
 
301
314
  #### Type-level Hooks
302
315
 
303
- Set hooks for multiple fields at once using `db.table().hooks()`:
316
+ Set hooks across multiple fields using `db.table().hooks()`. The hook returns an object with the fields to override. When both field-level and type-level hooks exist for the same field, type-level hooks take priority.
317
+
318
+ Create hooks receive:
319
+
320
+ - `input`: The submitted record data. When field-level hooks or defaults exist, `input` reflects their applied results
321
+ - `invoker`: Principal performing the operation
322
+ - `now`: Operation timestamp (`Date`), shared across all hooks in the same operation
323
+
324
+ Update hooks receive the same arguments plus:
325
+
326
+ - `oldRecord`: The existing record (non-null)
304
327
 
305
328
  ```typescript
306
329
  export const customer = db
@@ -310,60 +333,56 @@ export const customer = db
310
333
  fullName: db.string(),
311
334
  })
312
335
  .hooks({
313
- fullName: {
314
- create: ({ data }) => `${data.firstName} ${data.lastName}`,
315
- update: ({ data }) => `${data.firstName} ${data.lastName}`,
316
- },
336
+ create: ({ input }) => ({
337
+ fullName: `${input.firstName} ${input.lastName}`,
338
+ }),
339
+ update: ({ input, oldRecord }) => ({
340
+ fullName: `${input.firstName ?? oldRecord.firstName} ${input.lastName ?? oldRecord.lastName}`,
341
+ }),
317
342
  });
318
343
  ```
319
344
 
320
- **Important:** Field-level and type-level hooks cannot coexist on the same field. TypeScript will prevent this at compile time:
345
+ Use `now` to stamp several fields with the exact same instant:
321
346
 
322
347
  ```typescript
323
- // Compile error - cannot set hooks on the same field twice
324
- export const user = db
325
- .table("User", {
326
- name: db.string().hooks({ create: ({ data }) => data.firstName }), // Field-level
348
+ export const order = db
349
+ .table("Order", {
350
+ createdAt: db.datetime(),
351
+ updatedAt: db.datetime(),
327
352
  })
328
353
  .hooks({
329
- name: { create: ({ data }) => data.lastName }, // Type-level - ERROR
330
- });
331
-
332
- // OK - set hooks on different fields
333
- export const user = db
334
- .table("User", {
335
- firstName: db.string().hooks({ create: () => "John" }), // Field-level on firstName
336
- lastName: db.string(),
337
- })
338
- .hooks({
339
- lastName: { create: () => "Doe" }, // Type-level on lastName
354
+ create: ({ now }) => ({ createdAt: now, updatedAt: now }),
355
+ update: ({ now }) => ({ updatedAt: now }),
340
356
  });
341
357
  ```
342
358
 
359
+ **Note:** `.hooks()` can only be called once on a type. Duplicate type-level calls fail at compile time and throw at runtime.
360
+
343
361
  ### Validation
344
362
 
345
- Add validation rules to fields. Validators receive three arguments (executed after hooks):
363
+ Add validation rules to fields. Validators run after hooks.
346
364
 
347
- - `value`: Field value after hook transformation
348
- - `data`: Entire record data after hook transformations (for accessing other field values)
349
- - `invoker`: Principal performing the operation
365
+ **Note:** Custom validators run only when built-in type validation succeeds, so `value` always has the field's declared type. For array fields, the validator is called once with the complete array, not per element:
350
366
 
351
- Validators return `true` for success, `false` for failure. Use array form `[validator, errorMessage]` for custom error messages.
367
+ ```typescript
368
+ // value is string[], not string
369
+ db.string({ array: true }).validate(({ value }) => value.length >= 2);
370
+ ```
352
371
 
353
372
  #### Field-level Validation
354
373
 
355
- Set validators directly on individual fields:
374
+ Set validators directly on individual fields. Each validator receives `{ value }` (the field value after hooks) and returns an error message string to fail, or void to pass:
356
375
 
357
376
  ```typescript
358
377
  db.string().validate(
359
- ({ value }) => value.includes("@"),
360
- [({ value }) => value.length >= 5, "Email must be at least 5 characters"],
378
+ ({ value }) => (value.includes("@") ? undefined : "Must contain @"),
379
+ ({ value }) => (value.length >= 5 ? undefined : "Must be at least 5 characters"),
361
380
  );
362
381
  ```
363
382
 
364
383
  #### Type-level Validation
365
384
 
366
- Set validators for multiple fields at once using `db.table().validate()`:
385
+ Set a validator across all fields using `db.table().validate()`. The validator receives `{ newRecord, oldRecord, invoker }` and an `issues()` callback to report errors per field:
367
386
 
368
387
  ```typescript
369
388
  export const user = db
@@ -371,38 +390,33 @@ export const user = db
371
390
  name: db.string(),
372
391
  email: db.string(),
373
392
  })
374
- .validate({
375
- name: [({ value }) => value.length > 5, "Name must be longer than 5 characters"],
376
- email: [
377
- ({ value }) => value.includes("@"),
378
- [({ value }) => value.length >= 5, "Email must be at least 5 characters"],
379
- ],
393
+ .validate(({ newRecord }, issues) => {
394
+ if (newRecord.name.length <= 5) {
395
+ issues("name", "Name must be longer than 5 characters");
396
+ }
397
+ if (!newRecord.email.includes("@")) {
398
+ issues("email", "Must contain @");
399
+ }
380
400
  });
381
401
  ```
382
402
 
383
- **Important:** Field-level and type-level validation cannot coexist on the same field. TypeScript will prevent this at compile time:
403
+ ### Defaults
404
+
405
+ Set a default value for a required field on create. The field becomes optional in the create input — the default fills in when no value is provided:
384
406
 
385
407
  ```typescript
386
- // Compile error - cannot set validation on the same field twice
387
- export const user = db
388
- .table("User", {
389
- name: db.string().validate(({ value }) => value.length > 0), // Field-level
390
- })
391
- .validate({
392
- name: [({ value }) => value.length < 100, "Too long"], // Type-level - ERROR
393
- });
408
+ db.int().default(0);
409
+ db.string().default("pending");
410
+ ```
394
411
 
395
- // OK - set validation on different fields
396
- export const user = db
397
- .table("User", {
398
- name: db.string().validate(({ value }) => value.length > 0), // Field-level on name
399
- email: db.string(),
400
- })
401
- .validate({
402
- email: [({ value }) => value.includes("@"), "Invalid email"], // Type-level on email
403
- });
412
+ For datetime/date/time fields, pass `"now"` to use the operation timestamp:
413
+
414
+ ```typescript
415
+ db.datetime().default("now");
404
416
  ```
405
417
 
418
+ **Note:** `.validate()` can only be called once on a type. Duplicate type-level calls fail at compile time and throw at runtime.
419
+
406
420
  ### Vector Search
407
421
 
408
422
  ```typescript
@@ -436,6 +450,22 @@ export const user = db.table("User", {
436
450
 
437
451
  ## Type Modifiers
438
452
 
453
+ Type builder methods that set one type-level configuration can be called only once on the same type. Duplicate calls fail at compile time and throw at runtime. This applies to `.description()`, `.hooks()`, `.validate()`, `.features()`, `.indexes()`, `.files()`, `.permission()`, and `.gqlPermission()`.
454
+
455
+ Conditional assignment is still supported when only one branch calls the method:
456
+
457
+ ```typescript
458
+ let user = db.type("User", {
459
+ name: db.string(),
460
+ });
461
+
462
+ if (enableFiles) {
463
+ user = user.files({
464
+ avatar: "profile image",
465
+ });
466
+ }
467
+ ```
468
+
439
469
  ### Composite Indexes
440
470
 
441
471
  ```typescript
@@ -552,6 +582,8 @@ Available options:
552
582
  | `optional` | Makes the selected fields optional |
553
583
  | `array` | Makes the selected fields array types |
554
584
 
585
+ **Note:** The `array` option cannot change fields with custom validation — their validators expect the original value shape. Define a new field with a matching validator instead.
586
+
555
587
  #### `omitFields(keys)`
556
588
 
557
589
  Return all fields except the specified ones:
@@ -397,7 +397,7 @@ export default defineConfig({
397
397
 
398
398
  `key` accepts `[a-z0-9_:.-]` and must start with `[a-z0-9]`. An exact key must also end with `[a-z0-9]`; a wildcard prefix (`matchType: "prefix"`) may end with any of those characters, since the platform appends a trailing `*` after it. The platform-registered key — including that trailing `*` when wildcarded — is 2 to 64 characters long, so a wildcard prefix must be at most 63 characters. `foo:bar` is a valid exact key; `tenant-api` with `matchType: "prefix"` registers `tenant-api*` as a wildcard prefix.
399
399
 
400
- An exact-key policy applies to dispatches whose runtime key equals the policy key. A wildcard policy applies to every dispatch whose runtime key begins with the prefix; each concrete resolved key gets its own independent pool of the declared size (a `cap = 3` wildcard yields three concurrent dispatches per resolved key, not three across every match). The longest matching prefix wins when a dispatch could match more than one wildcard.
400
+ An exact-key policy applies to dispatches whose runtime key equals the policy key. A wildcard policy applies to every dispatch whose runtime key begins with the prefix; each concrete resolved key gets its own independent pool of the declared size (a `cap = 3` wildcard yields three concurrent dispatches per resolved key, not three across every match). When a dispatch matches more than one policy (for example, an exact key that also falls under a wildcard prefix, or two wildcard prefixes where one starts with the other), every matching policy's cap is enforced independently, and the tightest one blocks.
401
401
 
402
402
  ### Referencing a Policy from a Workflow
403
403
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tailor-platform/sdk",
3
- "version": "2.0.0-next.4",
3
+ "version": "2.0.0-next.5",
4
4
  "description": "Tailor Platform SDK - The SDK to work with Tailor Platform",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -157,11 +157,11 @@
157
157
  "@opentelemetry/exporter-trace-otlp-proto": "0.220.0",
158
158
  "@opentelemetry/resources": "2.9.0",
159
159
  "@opentelemetry/sdk-trace-node": "2.9.0",
160
- "@opentelemetry/semantic-conventions": "1.41.1",
161
- "@oxc-project/types": "0.138.0",
160
+ "@opentelemetry/semantic-conventions": "1.43.0",
161
+ "@oxc-project/types": "0.139.0",
162
162
  "@standard-schema/spec": "1.1.0",
163
163
  "@tailor-platform/function-kysely-tailordb": "0.1.3",
164
- "@toiroakr/lines-db": "0.10.0",
164
+ "@toiroakr/lines-db": "0.10.1",
165
165
  "@toiroakr/read-multiline": "0.4.1",
166
166
  "@urql/core": "6.0.3",
167
167
  "amaro": "1.1.10",
@@ -172,26 +172,26 @@
172
172
  "es-toolkit": "1.49.0",
173
173
  "find-up-simple": "1.0.1",
174
174
  "globals": "17.7.0",
175
- "graphql": "17.0.1",
175
+ "graphql": "17.0.2",
176
176
  "inflection": "3.0.2",
177
- "kysely": "0.29.2",
177
+ "kysely": "0.29.3",
178
178
  "madge": "8.0.0",
179
179
  "mime-types": "3.0.2",
180
180
  "open": "11.0.0",
181
- "oxc-parser": "0.138.0",
181
+ "oxc-parser": "0.139.0",
182
182
  "p-limit": "7.3.0",
183
183
  "pathe": "2.0.3",
184
184
  "pgsql-ast-parser": "12.0.2",
185
185
  "pkg-types": "2.3.1",
186
- "politty": "0.11.0",
187
- "rolldown": "1.1.4",
186
+ "politty": "0.11.2",
187
+ "rolldown": "1.1.5",
188
188
  "semver": "7.8.5",
189
189
  "sql-highlight": "6.1.0",
190
- "std-env": "4.1.0",
190
+ "std-env": "4.2.0",
191
191
  "table": "6.9.0",
192
192
  "ts-cron-validator": "1.1.5",
193
- "type-fest": "5.7.0",
194
- "undici": "8.6.0",
193
+ "type-fest": "5.8.0",
194
+ "undici": "8.7.0",
195
195
  "xdg-basedir": "5.1.0",
196
196
  "zod": "4.4.3"
197
197
  },
@@ -199,19 +199,19 @@
199
199
  "@opentelemetry/sdk-trace-base": "2.9.0",
200
200
  "@types/madge": "5.0.3",
201
201
  "@types/mime-types": "3.0.1",
202
- "@types/node": "24.13.2",
202
+ "@types/node": "24.13.3",
203
203
  "@types/semver": "7.7.1",
204
- "@typescript/native-preview": "7.0.0-dev.20260703.1",
205
- "@vitest/coverage-v8": "4.1.9",
204
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
205
+ "@vitest/coverage-v8": "4.1.10",
206
206
  "eslint-plugin-zod": "4.7.0",
207
- "oxfmt": "0.57.0",
208
- "oxlint": "1.72.0",
207
+ "oxfmt": "0.58.0",
208
+ "oxlint": "1.73.0",
209
209
  "oxlint-tsgolint": "0.24.0",
210
- "sonda": "0.13.1",
211
- "tsdown": "0.22.3",
210
+ "sonda": "0.14.0",
211
+ "tsdown": "0.22.4",
212
212
  "typescript": "6.0.3",
213
- "vitest": "4.1.9",
214
- "zinfer": "0.2.3",
213
+ "vitest": "4.1.10",
214
+ "zinfer": "0.2.5",
215
215
  "@tailor-platform/tailor-proto": "^0.0.0"
216
216
  },
217
217
  "peerDependencies": {
@@ -244,7 +244,7 @@
244
244
  "check:import-cycles": "node --experimental-strip-types scripts/check-import-cycles.ts",
245
245
  "lint:fix": "oxlint --type-aware . --fix",
246
246
  "typecheck": "tsc --noEmit",
247
- "typecheck:go": "tsgo",
247
+ "typecheck:go": "tsgo --tsBuildInfoFile ./.tsgo.tsbuildinfo",
248
248
  "perf:typecheck": "bash scripts/perf/exec.sh",
249
249
  "perf:runtime": "bash scripts/perf/runtime-perf.sh",
250
250
  "prepublish": "pnpm run build",
@@ -1,3 +0,0 @@
1
- import { n as generatePluginFilesIfNeeded, r as loadApplication, t as defineApplication } from "./application-BX13RArL.mjs";
2
-
3
- export { defineApplication, generatePluginFilesIfNeeded };