@tailor-platform/sdk 2.4.0 → 2.6.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 (252) hide show
  1. package/CHANGELOG.md +131 -0
  2. package/bin/tailor.mjs +3 -2
  3. package/dist/aigateway-DsWDjzk4.mjs +2 -0
  4. package/dist/{aigateway-DR4Kwuik.mjs.map → aigateway-DsWDjzk4.mjs.map} +1 -1
  5. package/dist/application-CNeOcaLc.mjs +1 -0
  6. package/dist/application-CmXOqTaK.mjs +192 -0
  7. package/dist/application-CmXOqTaK.mjs.map +1 -0
  8. package/dist/assert-WeXvmG4j.mjs +2 -0
  9. package/dist/{assert-DBxo8jPo.mjs.map → assert-WeXvmG4j.mjs.map} +1 -1
  10. package/dist/authconnection-CynFBIv8.mjs +2 -0
  11. package/dist/{authconnection-CZvi9ANm.mjs.map → authconnection-CynFBIv8.mjs.map} +1 -1
  12. package/dist/brand-C8nMKhJC.mjs +2 -0
  13. package/dist/{brand-Eo4pLXPJ.mjs.map → brand-C8nMKhJC.mjs.map} +1 -1
  14. package/dist/cli/commands/api/index.d.mts +1 -1
  15. package/dist/cli/commands/deploy/deploy.d.mts +2 -2
  16. package/dist/cli/commands/deploy/deployment-target.d.mts +2 -0
  17. package/dist/cli/commands/deploy/event-subscriptions.d.mts +3 -0
  18. package/dist/cli/commands/deploy/tailordb/apply.d.mts +3 -0
  19. package/dist/cli/commands/deploy/tailordb/index.d.mts +3 -10
  20. package/dist/cli/commands/deploy/tailordb/migration-validation.d.mts +5 -0
  21. package/dist/cli/commands/deploy/tailordb/plan.d.mts +8 -0
  22. package/dist/cli/commands/executor/jobs.d.mts +1 -1
  23. package/dist/cli/commands/executor/trigger.d.mts +1 -1
  24. package/dist/cli/commands/generate/seed/bundler.d.mts +2 -2
  25. package/dist/cli/commands/show.d.mts +1 -1
  26. package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +11 -11
  27. package/dist/cli/commands/tailordb/migrate/generate.d.mts +4 -0
  28. package/dist/cli/commands/tailordb/migrate/rename-detection.d.mts +1 -1
  29. package/dist/cli/commands/tailordb/migrate/snapshot-comparison.d.mts +43 -0
  30. package/dist/cli/commands/tailordb/migrate/snapshot-files.d.mts +62 -0
  31. package/dist/cli/commands/tailordb/migrate/snapshot-local.d.mts +12 -0
  32. package/dist/cli/commands/tailordb/migrate/snapshot-migrations.d.mts +12 -0
  33. package/dist/cli/commands/tailordb/migrate/snapshot-remote.d.mts +1 -0
  34. package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +3 -1
  35. package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +5 -117
  36. package/dist/cli/commands/workflow/start.d.mts +1 -1
  37. package/dist/cli/commands/workspace/list.d.mts +1 -1
  38. package/dist/cli/lib.d.mts +12 -4
  39. package/dist/cli/lib.mjs +1 -9
  40. package/dist/cli/lib.mjs.map +1 -1
  41. package/dist/cli/main.d.mts +2 -0
  42. package/dist/cli/main.mjs +1170 -7754
  43. package/dist/cli/main.mjs.map +1 -1
  44. package/dist/cli/shared/args.d.mts +65 -1
  45. package/dist/cli/shared/command.d.mts +11 -0
  46. package/dist/cli/shared/context.d.mts +1 -1
  47. package/dist/cli/shared/logger.d.mts +64 -0
  48. package/dist/cli/shared/script-executor.d.mts +1 -1
  49. package/dist/cli/shared/seed-chunker.d.mts +5 -5
  50. package/dist/completion/zsh-worker.zsh +82 -9
  51. package/dist/configure/config/index.d.mts +1 -1
  52. package/dist/configure/config/types.d.mts +2 -2
  53. package/dist/configure/index.d.mts +48 -12
  54. package/dist/configure/index.mjs +1 -1267
  55. package/dist/configure/index.mjs.map +1 -1
  56. package/dist/configure/services/auth/types.d.mts +1 -1
  57. package/dist/configure/services/idp/types.d.mts +1 -1
  58. package/dist/configure/services/tailordb/schema.d.mts +22 -8
  59. package/dist/configure/services/tailordb/types.d.mts +2 -2
  60. package/dist/configure/services/workflow/execution-policy.d.mts +3 -3
  61. package/dist/configure/services/workflow/job.d.mts +12 -2
  62. package/dist/configure/types/field.types.d.mts +1 -1
  63. package/dist/configure/types/permission-operand.types.d.mts +1 -1
  64. package/dist/context-D0QjfxzD.mjs +2 -0
  65. package/dist/{context-DYQVYWqZ.mjs.map → context-D0QjfxzD.mjs.map} +1 -1
  66. package/dist/crashreport-BN28xp5B.mjs +42 -0
  67. package/dist/{crashreport-Q0pDAlrj.mjs.map → crashreport-BN28xp5B.mjs.map} +1 -1
  68. package/dist/crashreport-By23O2k-.mjs +1 -0
  69. package/dist/errors-DLsQ_-ol.mjs +2 -0
  70. package/dist/errors-DLsQ_-ol.mjs.map +1 -0
  71. package/dist/es-builtins-n3wBv4Sv.mjs +2 -0
  72. package/dist/es-builtins-n3wBv4Sv.mjs.map +1 -0
  73. package/dist/file-COPYfju_.mjs +2 -0
  74. package/dist/file-COPYfju_.mjs.map +1 -0
  75. package/dist/globals-CMHSnj4w.mjs +2 -0
  76. package/dist/{globals-B2nlxBrz.mjs.map → globals-CMHSnj4w.mjs.map} +1 -1
  77. package/dist/iconv-DlFMt2gW.mjs +2 -0
  78. package/dist/{iconv-QWaZh0TT.mjs.map → iconv-DlFMt2gW.mjs.map} +1 -1
  79. package/dist/idp-G_ojPBB5.mjs +2 -0
  80. package/dist/{idp-RA_swu-h.mjs.map → idp-G_ojPBB5.mjs.map} +1 -1
  81. package/dist/interceptor-DQg3cR_9.mjs +2 -0
  82. package/dist/{interceptor-e33JtsC-.mjs.map → interceptor-DQg3cR_9.mjs.map} +1 -1
  83. package/dist/kysely/index.mjs +1 -32
  84. package/dist/kysely/index.mjs.map +1 -1
  85. package/dist/kysely-type-BTi3BMtL.mjs +43 -0
  86. package/dist/kysely-type-BTi3BMtL.mjs.map +1 -0
  87. package/dist/logger-CCjs1DuH.mjs +9 -0
  88. package/dist/logger-CCjs1DuH.mjs.map +1 -0
  89. package/dist/logger-DP2BjQ93.mjs +2 -0
  90. package/dist/{logger-BtX0suGY.mjs.map → logger-DP2BjQ93.mjs.map} +1 -1
  91. package/dist/multiline-EyzjEwn9.mjs +3 -0
  92. package/dist/{multiline-sfHpTZZK.mjs.map → multiline-EyzjEwn9.mjs.map} +1 -1
  93. package/dist/node-builtins-oBl7EbyV.mjs +2 -0
  94. package/dist/{node-builtins-CmaL2Cbq.mjs.map → node-builtins-oBl7EbyV.mjs.map} +1 -1
  95. package/dist/package-json-C690ceex.mjs +2 -0
  96. package/dist/{package-json-8b0O9TlX.mjs.map → package-json-C690ceex.mjs.map} +1 -1
  97. package/dist/package-json-CmqhDJ__.mjs +1 -0
  98. package/dist/parser/service/tailordb/type-source.d.mts +5 -5
  99. package/dist/parser/service/tailordb/types.d.mts +4 -4
  100. package/dist/platform-serialize-DkiTdHOt.mjs +2 -0
  101. package/dist/{platform-serialize-RoRtBS0v.mjs.map → platform-serialize-DkiTdHOt.mjs.map} +1 -1
  102. package/dist/plugin/builtin/enum-constants/index.mjs +5 -114
  103. package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
  104. package/dist/plugin/builtin/file-utils/index.mjs +22 -104
  105. package/dist/plugin/builtin/file-utils/index.mjs.map +1 -1
  106. package/dist/plugin/builtin/kysely-type/index.d.mts +8 -1
  107. package/dist/plugin/builtin/kysely-type/index.mjs +1 -275
  108. package/dist/plugin/builtin/seed/index.d.mts +5 -0
  109. package/dist/plugin/builtin/seed/index.mjs +1 -3
  110. package/dist/plugin/builtin/seed/seed-type-processor.d.mts +0 -2
  111. package/dist/plugin/{get-generated-type.d.mts → get-generated-table.d.mts} +5 -5
  112. package/dist/plugin/index.d.mts +3 -2
  113. package/dist/plugin/index.mjs +1 -251
  114. package/dist/plugin/index.mjs.map +1 -1
  115. package/dist/plugin/types.d.mts +30 -23
  116. package/dist/plugin/with-context.d.mts +3 -3
  117. package/dist/register-ts-hook-oDA2JLp2.mjs +640 -0
  118. package/dist/register-ts-hook-oDA2JLp2.mjs.map +1 -0
  119. package/dist/registry-HlEaGvl5.mjs +2 -0
  120. package/dist/{registry-BIGVUrMB.mjs.map → registry-HlEaGvl5.mjs.map} +1 -1
  121. package/dist/repl-editor-BG1aDOfH.mjs +2 -0
  122. package/dist/{repl-editor-F9LotMNx.mjs.map → repl-editor-BG1aDOfH.mjs.map} +1 -1
  123. package/dist/runtime/aigateway.mjs +1 -3
  124. package/dist/runtime/authconnection.mjs +1 -3
  125. package/dist/runtime/context.mjs +1 -3
  126. package/dist/runtime/file.d.mts +21 -21
  127. package/dist/runtime/file.mjs +1 -3
  128. package/dist/runtime/globals.mjs +1 -1
  129. package/dist/runtime/iconv.mjs +1 -3
  130. package/dist/runtime/idp.mjs +1 -3
  131. package/dist/runtime/index.mjs +1 -11
  132. package/dist/runtime/logger.mjs +1 -3
  133. package/dist/runtime/secretmanager.mjs +1 -3
  134. package/dist/runtime/types.d.mts +1 -1
  135. package/dist/runtime/workflow.mjs +1 -3
  136. package/dist/schema-AYG4OhXY.mjs +2 -0
  137. package/dist/schema-AYG4OhXY.mjs.map +1 -0
  138. package/dist/secret-file-C9wp_FCX.mjs +2 -0
  139. package/dist/{secret-file-C3J4Gy8r.mjs.map → secret-file-C9wp_FCX.mjs.map} +1 -1
  140. package/dist/secretmanager-5olfnI1b.mjs +2 -0
  141. package/dist/{secretmanager-IY4UvinW.mjs.map → secretmanager-5olfnI1b.mjs.map} +1 -1
  142. package/dist/secretmanager-vHQoXdQz.mjs +2 -0
  143. package/dist/{secretmanager-CYlpffsz.mjs.map → secretmanager-vHQoXdQz.mjs.map} +1 -1
  144. package/dist/seed/index.mjs +8 -244
  145. package/dist/seed/index.mjs.map +1 -1
  146. package/dist/seed-DwqRFdqP.mjs +207 -0
  147. package/dist/seed-DwqRFdqP.mjs.map +1 -0
  148. package/dist/service-CLPMoj9n.mjs +2 -0
  149. package/dist/{service-LTfp03ZZ.mjs.map → service-CLPMoj9n.mjs.map} +1 -1
  150. package/dist/service-D7iXk0BT.mjs +1 -0
  151. package/dist/service-YqDsHmlK.mjs +7 -0
  152. package/dist/service-YqDsHmlK.mjs.map +1 -0
  153. package/dist/service_pb-DGKCLuAs.mjs +2 -0
  154. package/dist/{service_pb-BEWj1pOV.mjs.map → service_pb-DGKCLuAs.mjs.map} +1 -1
  155. package/dist/service_pb-_aeFE-Nv.mjs +1 -0
  156. package/dist/shared/src/color.d.mts +5 -0
  157. package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +1 -1
  158. package/dist/telemetry-Bklv9kQY.mjs +2 -0
  159. package/dist/{telemetry-BRVdwh14.mjs.map → telemetry-Bklv9kQY.mjs.map} +1 -1
  160. package/dist/telemetry-DXHP3VVi.mjs +1 -0
  161. package/dist/type-source--ZNcV8RJ.mjs +2 -0
  162. package/dist/type-source--ZNcV8RJ.mjs.map +1 -0
  163. package/dist/types/executor.generated.d.mts +1 -1
  164. package/dist/user-agent-vdHYF3QL.mjs +2 -0
  165. package/dist/{user-agent-Bgsszb5I.mjs.map → user-agent-vdHYF3QL.mjs.map} +1 -1
  166. package/dist/utils/test/index.mjs +1 -109
  167. package/dist/utils/test/index.mjs.map +1 -1
  168. package/dist/vitest/environment.mjs +1 -41
  169. package/dist/vitest/environment.mjs.map +1 -1
  170. package/dist/vitest/index.mjs +1 -1986
  171. package/dist/vitest/index.mjs.map +1 -1
  172. package/dist/vitest/mocks/file.d.mts +8 -8
  173. package/dist/vitest/setup.mjs +1 -140
  174. package/dist/vitest/setup.mjs.map +1 -1
  175. package/dist/wait-point-invoker-eiP-IIux.mjs +2 -0
  176. package/dist/wait-point-invoker-eiP-IIux.mjs.map +1 -0
  177. package/dist/wait-point-registry-B-ESkTZX.mjs +2 -0
  178. package/dist/wait-point-registry-B-ESkTZX.mjs.map +1 -0
  179. package/dist/workflow-Cs9ISw6j.mjs +2 -0
  180. package/dist/{workflow-Bamae_Yc.mjs.map → workflow-Cs9ISw6j.mjs.map} +1 -1
  181. package/dist/workspace_resource_pb--GeYQPXu.mjs +2 -0
  182. package/dist/{workspace_resource_pb-HNIL_Vfj.mjs.map → workspace_resource_pb--GeYQPXu.mjs.map} +1 -1
  183. package/docs/cli/function.md +66 -6
  184. package/docs/cli/setup.md +24 -14
  185. package/docs/cli/tailordb.md +2 -0
  186. package/docs/cli-reference.md +9 -8
  187. package/docs/github-actions.md +14 -12
  188. package/docs/migration/v2.md +18 -2
  189. package/docs/migration/v3.md +121 -0
  190. package/docs/plugin/custom.md +130 -85
  191. package/docs/plugin/index.md +3 -3
  192. package/docs/services/tailordb-migration.md +21 -7
  193. package/docs/services/tailordb.md +9 -7
  194. package/docs/services/workflow.md +10 -9
  195. package/package.json +14 -13
  196. package/postinstall.mjs +1 -1
  197. package/dist/aigateway-DR4Kwuik.mjs +0 -9
  198. package/dist/application-C8a0UJ-z.mjs +0 -6071
  199. package/dist/application-C8a0UJ-z.mjs.map +0 -1
  200. package/dist/application-D4zOiLLa.mjs +0 -3
  201. package/dist/assert-DBxo8jPo.mjs +0 -9
  202. package/dist/authconnection-CZvi9ANm.mjs +0 -9
  203. package/dist/brand-Eo4pLXPJ.mjs +0 -36
  204. package/dist/context-DYQVYWqZ.mjs +0 -23
  205. package/dist/crashreport-Cd4TqfZq.mjs +0 -3
  206. package/dist/crashreport-Q0pDAlrj.mjs +0 -427
  207. package/dist/errors-Bxut5_Sy.mjs +0 -89
  208. package/dist/errors-Bxut5_Sy.mjs.map +0 -1
  209. package/dist/file-BUcmVIH2.mjs +0 -58
  210. package/dist/file-BUcmVIH2.mjs.map +0 -1
  211. package/dist/globals-B2nlxBrz.mjs +0 -126
  212. package/dist/iconv-QWaZh0TT.mjs +0 -38
  213. package/dist/idp-RA_swu-h.mjs +0 -82
  214. package/dist/interceptor-e33JtsC-.mjs +0 -33
  215. package/dist/logger-BtX0suGY.mjs +0 -48
  216. package/dist/logger-D0bEznPv.mjs +0 -362
  217. package/dist/logger-D0bEznPv.mjs.map +0 -1
  218. package/dist/multiline-sfHpTZZK.mjs +0 -38
  219. package/dist/node-builtins-CmaL2Cbq.mjs +0 -36
  220. package/dist/package-json-8b0O9TlX.mjs +0 -17
  221. package/dist/package-json-Cv2Z-TqQ.mjs +0 -3
  222. package/dist/platform-serialize-RoRtBS0v.mjs +0 -46
  223. package/dist/plugin/builtin/kysely-type/index.mjs.map +0 -1
  224. package/dist/plugin/builtin/seed/types.d.mts +0 -2
  225. package/dist/register-ts-hook-Vqjza10T.mjs +0 -25679
  226. package/dist/register-ts-hook-Vqjza10T.mjs.map +0 -1
  227. package/dist/registry-BIGVUrMB.mjs +0 -54
  228. package/dist/repl-editor-F9LotMNx.mjs +0 -252
  229. package/dist/schema-D4TC4BC3.mjs +0 -640
  230. package/dist/schema-D4TC4BC3.mjs.map +0 -1
  231. package/dist/secret-file-C3J4Gy8r.mjs +0 -64
  232. package/dist/secretmanager-CYlpffsz.mjs +0 -13
  233. package/dist/secretmanager-IY4UvinW.mjs +0 -131
  234. package/dist/seed-Cibjmtry.mjs +0 -489
  235. package/dist/seed-Cibjmtry.mjs.map +0 -1
  236. package/dist/service-2grcAOCJ.mjs +0 -898
  237. package/dist/service-2grcAOCJ.mjs.map +0 -1
  238. package/dist/service-CaBPNDIZ.mjs +0 -3
  239. package/dist/service-LTfp03ZZ.mjs +0 -133
  240. package/dist/service_pb-BEWj1pOV.mjs +0 -167
  241. package/dist/service_pb-BjlhvK9E.mjs +0 -3
  242. package/dist/telemetry-BRVdwh14.mjs +0 -84
  243. package/dist/telemetry-CkbkeJxl.mjs +0 -3
  244. package/dist/type-source-DH_LH20p.mjs +0 -13
  245. package/dist/type-source-DH_LH20p.mjs.map +0 -1
  246. package/dist/user-agent-Bgsszb5I.mjs +0 -28
  247. package/dist/wait-point-invoker-__oE88_P.mjs +0 -148
  248. package/dist/wait-point-invoker-__oE88_P.mjs.map +0 -1
  249. package/dist/wait-point-registry-TL99zotw.mjs +0 -47
  250. package/dist/wait-point-registry-TL99zotw.mjs.map +0 -1
  251. package/dist/workflow-Bamae_Yc.mjs +0 -34
  252. package/dist/workspace_resource_pb-HNIL_Vfj.mjs +0 -860
@@ -18,22 +18,22 @@ const myPlugin: Plugin = {
18
18
  export default myPlugin; // Required: must be default export
19
19
  ```
20
20
 
21
- This is required so that other plugins and generation-time hooks can use plugin-generated TailorDB tables via `getGeneratedType()`.
21
+ This is required so that other plugins and generation-time hooks can use plugin-generated TailorDB tables via `getGeneratedTable()`.
22
22
 
23
23
  ## Plugin Interface
24
24
 
25
25
  ```typescript
26
- interface Plugin<TypeConfig = unknown, PluginConfig = unknown> {
26
+ interface Plugin<TableConfig = unknown, PluginConfig = unknown> {
27
27
  readonly id: string;
28
28
  readonly description: string;
29
29
  readonly importPath?: string;
30
- readonly typeConfigRequired?: boolean | ((pluginConfig?: PluginConfig) => boolean);
30
+ readonly tableConfigRequired?: boolean | ((pluginConfig?: PluginConfig) => boolean);
31
31
  readonly pluginConfig?: PluginConfig;
32
32
 
33
33
  // Definition-time hooks
34
- onTypeLoaded?(
35
- context: PluginProcessContext<TypeConfig, PluginConfig>,
36
- ): TypePluginOutput | Promise<TypePluginOutput>;
34
+ onTableLoaded?(
35
+ context: PluginTableProcessContext<TableConfig, PluginConfig>,
36
+ ): TablePluginOutput | Promise<TablePluginOutput>;
37
37
  onNamespaceLoaded?(
38
38
  context: PluginNamespaceProcessContext<PluginConfig>,
39
39
  ): PluginOutput | Promise<PluginOutput>;
@@ -51,34 +51,34 @@ interface Plugin<TypeConfig = unknown, PluginConfig = unknown> {
51
51
  }
52
52
  ```
53
53
 
54
- | Property | Required | Description |
55
- | -------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------ |
56
- | `id` | Yes | Unique plugin identifier (e.g., `"@my-company/soft-delete"`) |
57
- | `description` | Yes | Human-readable description |
58
- | `importPath` | When using definition-time hooks | Path resolvable from `tailor.config.ts` directory. Used for import statements in generated code. |
59
- | `typeConfigRequired` | No | Whether per-table config is required when attaching via `.plugin()`. Default: optional. |
60
- | `pluginConfig` | No | Plugin-level config passed via `definePlugins()`. Set via factory function. |
54
+ | Property | Required | Description |
55
+ | --------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------ |
56
+ | `id` | Yes | Unique plugin identifier (e.g., `"@my-company/soft-delete"`) |
57
+ | `description` | Yes | Human-readable description |
58
+ | `importPath` | When using definition-time hooks | Path resolvable from `tailor.config.ts` directory. Used for import statements in generated code. |
59
+ | `tableConfigRequired` | No | Whether per-table config is required when attaching via `.plugin()`. Default: optional. |
60
+ | `pluginConfig` | No | Plugin-level config passed via `definePlugins()`. Set via factory function. |
61
61
 
62
62
  ## Hook Reference
63
63
 
64
- ### onTypeLoaded
64
+ ### onTableLoaded
65
65
 
66
66
  **Trigger**: Called once for each TailorDB table that has `.plugin({ pluginId: config })` attached.
67
67
 
68
- **Context** (`PluginProcessContext`):
68
+ **Context** (`PluginTableProcessContext`):
69
69
 
70
70
  | Field | Type | Description |
71
71
  | -------------- | ----------------- | ------------------------------------------ |
72
- | `type` | `TailorAnyDBType` | The TailorDB table being processed |
73
- | `typeConfig` | `TypeConfig` | Per-table config from `.plugin()` |
72
+ | `table` | `TailorAnyDBType` | The TailorDB table being processed |
73
+ | `tableConfig` | `TableConfig` | Per-table config from `.plugin()` |
74
74
  | `pluginConfig` | `PluginConfig` | Plugin-level config from `definePlugins()` |
75
75
  | `namespace` | `string` | Namespace of the TailorDB table |
76
76
 
77
- **Returns** (`TypePluginOutput`):
77
+ **Returns** (`TablePluginOutput`):
78
78
 
79
79
  | Field | Type | Description |
80
80
  | ----------- | ----------------------------------------------- | ------------------------------------------------------ |
81
- | `types` | `Record<string, TailorAnyDBType>` | Additional TailorDB tables to generate (keyed by kind) |
81
+ | `tables` | `Record<string, TailorAnyDBType>` | Additional TailorDB tables to generate (keyed by kind) |
82
82
  | `resolvers` | `PluginGeneratedResolver[]` | Additional resolvers to generate |
83
83
  | `executors` | `PluginGeneratedExecutor[]` | Additional executors to generate |
84
84
  | `extends` | `{ fields?: Record<string, TailorAnyDBField> }` | Fields to add to the source table |
@@ -90,12 +90,12 @@ interface Plugin<TypeConfig = unknown, PluginConfig = unknown> {
90
90
  - Generate executors triggered by record events on the source table
91
91
 
92
92
  ```typescript
93
- onTypeLoaded(context) {
94
- const { type, typeConfig, namespace } = context;
93
+ onTableLoaded(context) {
94
+ const { table, tableConfig, namespace } = context;
95
95
  return {
96
- types: { archive: db.table(`Deleted_${type.name}`, { ... }) },
96
+ tables: { archive: db.table(`Deleted_${table.name}`, { ... }) },
97
97
  extends: { fields: { deletedAt: db.datetime({ optional: true }) } },
98
- executors: [{ name: `${type.name}-on-delete`, resolve: async () => await import("./on-delete"), context: { sourceType: type, namespace } }],
98
+ executors: [{ name: `${table.name}-on-delete`, resolve: async () => await import("./on-delete"), context: { sourceTable: table, namespace } }],
99
99
  };
100
100
  },
101
101
  ```
@@ -113,7 +113,7 @@ onTypeLoaded(context) {
113
113
 
114
114
  **Returns** (`PluginOutput`):
115
115
 
116
- Same as `TypePluginOutput` but without `extends` (namespace plugins cannot extend a source table).
116
+ Same as `TablePluginOutput` but without `extends` (namespace plugins cannot extend a source table).
117
117
 
118
118
  **Use cases**:
119
119
 
@@ -122,7 +122,7 @@ Same as `TypePluginOutput` but without `extends` (namespace plugins cannot exten
122
122
  ```typescript
123
123
  onNamespaceLoaded(context) {
124
124
  return {
125
- types: { auditLog: db.table("AuditLog", { action: db.string(), ... }) },
125
+ tables: { auditLog: db.table("AuditLog", { action: db.string(), ... }) },
126
126
  };
127
127
  },
128
128
  ```
@@ -146,7 +146,7 @@ onNamespaceLoaded(context) {
146
146
  | Field | Type | Description |
147
147
  | ------------------- | ------------------------------------------ | ------------------------------------- |
148
148
  | `namespace` | `string` | Namespace name |
149
- | `types` | `Record<string, TailorDBType>` | All finalized tables in the namespace |
149
+ | `tables` | `Record<string, TailorDBType>` | All finalized tables in the namespace |
150
150
  | `sourceInfo` | `ReadonlyMap<string, TypeSourceInfoEntry>` | Source file info for each table |
151
151
  | `pluginAttachments` | `ReadonlyMap<string, PluginAttachment[]>` | Plugin configs attached to each table |
152
152
 
@@ -165,11 +165,11 @@ onNamespaceLoaded(context) {
165
165
 
166
166
  ```typescript
167
167
  onTailorDBReady(ctx) {
168
- const allTypes = ctx.tailordb.flatMap((ns) =>
169
- Object.values(ns.types).map((t) => t.name),
168
+ const allTables = ctx.tailordb.flatMap((ns) =>
169
+ Object.values(ns.tables).map((table) => table.name),
170
170
  );
171
171
  return {
172
- files: [{ path: `${ctx.baseDir}/types.ts`, content: `export const types = ${JSON.stringify(allTypes)};\n` }],
172
+ files: [{ path: `${ctx.baseDir}/tables.ts`, content: `export const tables = ${JSON.stringify(allTables)};\n` }],
173
173
  };
174
174
  },
175
175
  ```
@@ -233,7 +233,7 @@ All fields from `ResolverReadyContext`, plus:
233
233
  ```typescript
234
234
  onExecutorReady(ctx) {
235
235
  const summary = {
236
- types: ctx.tailordb.flatMap((ns) => Object.keys(ns.types)),
236
+ tables: ctx.tailordb.flatMap((ns) => Object.keys(ns.tables)),
237
237
  resolvers: ctx.resolvers.flatMap((ns) => Object.keys(ns.resolvers)),
238
238
  executors: Object.keys(ctx.executors),
239
239
  };
@@ -262,8 +262,8 @@ All context and result types are exported from `@tailor-platform/sdk`:
262
262
  ```typescript
263
263
  import type {
264
264
  Plugin,
265
- PluginProcessContext,
266
- TypePluginOutput,
265
+ PluginTableProcessContext,
266
+ TablePluginOutput,
267
267
  PluginOutput,
268
268
  TailorDBReadyContext,
269
269
  ResolverReadyContext,
@@ -274,34 +274,34 @@ import type {
274
274
  } from "@tailor-platform/sdk";
275
275
  ```
276
276
 
277
- ## getGeneratedType Helper
277
+ ## getGeneratedTable Helper
278
278
 
279
- The SDK provides an async `getGeneratedType()` helper function to retrieve plugin-generated TailorDB tables. This enables plugins and other tools to work with tables generated by plugins.
279
+ The SDK provides an async `getGeneratedTable()` helper function to retrieve plugin-generated TailorDB tables. This enables plugins and other tools to work with tables generated by plugins.
280
280
 
281
281
  ```typescript
282
282
  import { join } from "node:path";
283
- import { getGeneratedType } from "@tailor-platform/sdk/plugin";
283
+ import { getGeneratedTable } from "@tailor-platform/sdk/plugin";
284
284
  import { customer } from "./tailordb/customer";
285
285
 
286
286
  const configPath = join(import.meta.dirname, "./tailor.config.ts");
287
287
 
288
288
  // Table-attached plugin
289
- const DeletedCustomer = await getGeneratedType(
289
+ const DeletedCustomer = await getGeneratedTable(
290
290
  configPath,
291
291
  "@example/soft-delete",
292
292
  customer,
293
293
  "archive",
294
294
  );
295
295
 
296
- // Namespace plugin (pass null as sourceType)
297
- const AuditLog = await getGeneratedType(configPath, "@example/audit-log", null, "auditLog");
296
+ // Namespace plugin (pass null as sourceTable)
297
+ const AuditLog = await getGeneratedTable(configPath, "@example/audit-log", null, "auditLog");
298
298
  ```
299
299
 
300
300
  **Parameters:**
301
301
 
302
302
  - `configPath`: Path to `tailor.config.ts` (absolute or relative to cwd)
303
303
  - `pluginId`: The plugin's unique identifier (e.g., `"@example/soft-delete"`)
304
- - `sourceType`: The TailorDB table that the plugin is attached to (`null` for namespace plugins)
304
+ - `sourceTable`: The TailorDB table that the plugin is attached to (`null` for namespace plugins)
305
305
  - `kind`: The generated table kind (e.g., `"archive"`, `"auditLog"`)
306
306
 
307
307
  **How it works:**
@@ -309,7 +309,7 @@ const AuditLog = await getGeneratedType(configPath, "@example/audit-log", null,
309
309
  1. Loads and caches the config from the given path
310
310
  2. Finds the plugin by ID from `definePlugins()` exports
311
311
  3. Auto-resolves the namespace from config
312
- 4. Calls the plugin's `onTypeLoaded()` or `onNamespaceLoaded()` method
312
+ 4. Calls the plugin's `onTableLoaded()` or `onNamespaceLoaded()` method
313
313
  5. Caches the result to avoid redundant processing
314
314
  6. Returns the generated table matching the specified kind
315
315
 
@@ -317,14 +317,14 @@ const AuditLog = await getGeneratedType(configPath, "@example/audit-log", null,
317
317
 
318
318
  ### Definition-time Plugin (Soft Delete)
319
319
 
320
- A plugin that adds soft delete functionality via `onTypeLoaded`:
320
+ A plugin that adds soft delete functionality via `onTableLoaded`:
321
321
 
322
322
  ```typescript
323
323
  // plugins/soft-delete/plugin.ts
324
324
  import { db } from "@tailor-platform/sdk";
325
- import type { Plugin, PluginProcessContext, TypePluginOutput } from "@tailor-platform/sdk";
325
+ import type { Plugin, PluginTableProcessContext, TablePluginOutput } from "@tailor-platform/sdk";
326
326
 
327
- interface SoftDeleteConfig {
327
+ interface SoftDeleteTableConfig {
328
328
  archiveReason?: boolean;
329
329
  retentionDays?: number;
330
330
  }
@@ -332,28 +332,28 @@ interface SoftDeleteConfig {
332
332
  interface SoftDeletePluginConfig {
333
333
  archiveTablePrefix?: string;
334
334
  defaultRetentionDays?: number;
335
- requireTypeConfig?: boolean;
335
+ requireTableConfig?: boolean;
336
336
  }
337
337
 
338
338
  function processSoftDelete(
339
- context: PluginProcessContext<SoftDeleteConfig, SoftDeletePluginConfig>,
340
- ): TypePluginOutput {
341
- const { type, typeConfig, pluginConfig, namespace } = context;
339
+ context: PluginTableProcessContext<SoftDeleteTableConfig, SoftDeletePluginConfig>,
340
+ ): TablePluginOutput {
341
+ const { table, tableConfig, pluginConfig, namespace } = context;
342
342
  const prefix = pluginConfig?.archiveTablePrefix ?? "Deleted_";
343
343
 
344
344
  // Generate archive table
345
- const archiveType = db
346
- .table(`${prefix}${type.name}`, {
345
+ const archiveTable = db
346
+ .table(`${prefix}${table.name}`, {
347
347
  originalId: db.uuid().description("ID of the deleted record"),
348
348
  originalData: db.string().description("JSON snapshot of deleted record"),
349
349
  deletedAt: db.datetime().description("When the record was deleted"),
350
350
  deletedBy: db.uuid().description("User who deleted the record"),
351
- ...(typeConfig.archiveReason && {
351
+ ...(tableConfig.archiveReason && {
352
352
  reason: db.string({ optional: true }).description("Reason for deletion"),
353
353
  }),
354
354
  ...db.fields.timestamps(),
355
355
  })
356
- .description(`Archive for deleted ${type.name} records`);
356
+ .description(`Archive for deleted ${table.name} records`);
357
357
 
358
358
  // Extend source table with deletedAt field
359
359
  const extendFields = {
@@ -361,15 +361,15 @@ function processSoftDelete(
361
361
  };
362
362
 
363
363
  return {
364
- types: { archive: archiveType },
364
+ tables: { archive: archiveTable },
365
365
  extends: { fields: extendFields },
366
366
  executors: [
367
367
  {
368
- name: `${type.name.toLowerCase()}-on-delete`,
368
+ name: `${table.name.toLowerCase()}-on-delete`,
369
369
  resolve: async () => await import("./executors/on-delete"),
370
370
  context: {
371
- sourceType: type,
372
- archiveType,
371
+ sourceTable: table,
372
+ archiveTable,
373
373
  namespace,
374
374
  },
375
375
  },
@@ -379,14 +379,14 @@ function processSoftDelete(
379
379
 
380
380
  function createSoftDeletePlugin(
381
381
  pluginConfig?: SoftDeletePluginConfig,
382
- ): Plugin<SoftDeleteConfig, SoftDeletePluginConfig> {
382
+ ): Plugin<SoftDeleteTableConfig, SoftDeletePluginConfig> {
383
383
  return {
384
384
  id: "@example/soft-delete",
385
385
  description: "Adds soft delete with archive functionality",
386
386
  importPath: "./plugins/soft-delete",
387
387
  pluginConfig,
388
- typeConfigRequired: (config) => config?.requireTypeConfig === true,
389
- onTypeLoaded: processSoftDelete,
388
+ tableConfigRequired: (config) => config?.requireTableConfig === true,
389
+ onTableLoaded: processSoftDelete,
390
390
  };
391
391
  }
392
392
 
@@ -403,24 +403,24 @@ import { withPluginContext } from "@tailor-platform/sdk/plugin";
403
403
  import { getDB } from "generated/tailordb";
404
404
 
405
405
  interface SoftDeleteContext {
406
- sourceType: TailorAnyDBType;
407
- archiveType: TailorAnyDBType;
406
+ sourceTable: TailorAnyDBType;
407
+ archiveTable: TailorAnyDBType;
408
408
  namespace: string;
409
409
  }
410
410
 
411
411
  export default withPluginContext((ctx: SoftDeleteContext) => {
412
- const { sourceType, archiveType, namespace } = ctx;
412
+ const { sourceTable, archiveTable, namespace } = ctx;
413
413
 
414
414
  return createExecutor({
415
- name: `${sourceType.name.toLowerCase()}-on-delete`,
416
- description: `Archives deleted ${sourceType.name} records`,
417
- trigger: recordDeletedTrigger({ type: sourceType }),
415
+ name: `${sourceTable.name.toLowerCase()}-on-delete`,
416
+ description: `Archives deleted ${sourceTable.name} records`,
417
+ trigger: recordDeletedTrigger({ type: sourceTable }),
418
418
  operation: {
419
419
  kind: "function",
420
420
  body: async ({ oldRecord, user }) => {
421
421
  const db = getDB(namespace as "tailordb");
422
422
  await db
423
- .insertInto(archiveType.name)
423
+ .insertInto(archiveTable.name)
424
424
  .values({
425
425
  originalId: oldRecord.id,
426
426
  originalData: JSON.stringify(oldRecord),
@@ -461,28 +461,28 @@ export const customer = db
461
461
  });
462
462
  ```
463
463
 
464
- ### Generation-only Plugin (Type List)
464
+ ### Generation-only Plugin (Table List)
465
465
 
466
466
  A plugin that only uses `onTailorDBReady` to generate output files:
467
467
 
468
468
  ```typescript
469
469
  import type { Plugin, GeneratorResult } from "@tailor-platform/sdk";
470
470
 
471
- const typeListPlugin: Plugin = {
472
- id: "@example/type-list",
471
+ const tableListPlugin: Plugin = {
472
+ id: "@example/table-list",
473
473
  description: "Generates a list of all TailorDB table names",
474
474
 
475
475
  onTailorDBReady(ctx): GeneratorResult {
476
- const allTypes = ctx.tailordb.flatMap((ns) =>
477
- Object.entries(ns.types).map(([_, type]) => ({
478
- name: type.name,
479
- fieldCount: Object.keys(type.fields).length,
476
+ const allTables = ctx.tailordb.flatMap((ns) =>
477
+ Object.values(ns.tables).map((table) => ({
478
+ name: table.name,
479
+ fieldCount: Object.keys(table.fields).length,
480
480
  namespace: ns.namespace,
481
481
  })),
482
482
  );
483
- const content = `// Generated type list\nexport const types = ${JSON.stringify(allTypes, null, 2)} as const;\n`;
483
+ const content = `// Generated table list\nexport const tables = ${JSON.stringify(allTables, null, 2)} as const;\n`;
484
484
  return {
485
- files: [{ path: `${ctx.baseDir}/types.ts`, content }],
485
+ files: [{ path: `${ctx.baseDir}/tables.ts`, content }],
486
486
  };
487
487
  },
488
488
  };
@@ -499,15 +499,17 @@ const plugin: Plugin = {
499
499
  importPath: "./plugins/hybrid",
500
500
 
501
501
  // Definition-time: Generate additional tables from attached source tables
502
- onTypeLoaded(context) {
503
- return { types: { derived: createDerivedType(context.type) } };
502
+ onTableLoaded(context) {
503
+ return { tables: { derived: createDerivedTable(context.table) } };
504
504
  },
505
505
 
506
506
  // Generation-time: Generate output files from all finalized tables
507
507
  onTailorDBReady(ctx) {
508
- const allTypes = ctx.tailordb.flatMap((ns) => Object.values(ns.types).map((t) => t.name));
508
+ const allTables = ctx.tailordb.flatMap((ns) =>
509
+ Object.values(ns.tables).map((table) => table.name),
510
+ );
509
511
  return {
510
- files: [{ path: `${ctx.baseDir}/output.ts`, content: generateCode(allTypes) }],
512
+ files: [{ path: `${ctx.baseDir}/output.ts`, content: generateCode(allTables) }],
511
513
  };
512
514
  },
513
515
  };
@@ -515,13 +517,13 @@ const plugin: Plugin = {
515
517
 
516
518
  ## Adding Type Safety
517
519
 
518
- ### Plugin-level type safety (TypeConfig / PluginConfig)
520
+ ### Plugin-level type safety (TableConfig / PluginConfig)
519
521
 
520
- Use TypeScript type parameters on `Plugin<TypeConfig, PluginConfig>` to get type-safe config
521
- in `onTypeLoaded` and `onNamespaceLoaded` methods:
522
+ Use TypeScript type parameters on `Plugin<TableConfig, PluginConfig>` to get type-safe config
523
+ in `onTableLoaded` and `onNamespaceLoaded` methods:
522
524
 
523
525
  ```typescript
524
- interface MyTypeConfig {
526
+ interface MyTableConfig {
525
527
  archiveReason?: boolean;
526
528
  }
527
529
 
@@ -529,11 +531,11 @@ interface MyPluginConfig {
529
531
  prefix?: string;
530
532
  }
531
533
 
532
- const plugin: Plugin<MyTypeConfig, MyPluginConfig> = {
534
+ const plugin: Plugin<MyTableConfig, MyPluginConfig> = {
533
535
  id: "@example/my-plugin",
534
536
  // ...
535
- onTypeLoaded(context) {
536
- // context.typeConfig is MyTypeConfig
537
+ onTableLoaded(context) {
538
+ // context.tableConfig is MyTableConfig
537
539
  // context.pluginConfig is MyPluginConfig
538
540
  },
539
541
  };
@@ -546,6 +548,9 @@ for the `PluginConfigs` interface. Plugin authors should ship this in their pack
546
548
 
547
549
  ```typescript
548
550
  // your-plugin/types.d.ts (shipped with your plugin package)
551
+ export {}; // required: a top-level import/export makes this file augment
552
+ // the module below instead of replacing its other exports
553
+
549
554
  declare module "@tailor-platform/sdk" {
550
555
  interface PluginConfigs<Fields extends string> {
551
556
  "@example/soft-delete": {
@@ -559,6 +564,8 @@ declare module "@tailor-platform/sdk" {
559
564
  The `Fields` type parameter provides field names from the table being configured, enabling field-aware configurations:
560
565
 
561
566
  ```typescript
567
+ export {};
568
+
562
569
  declare module "@tailor-platform/sdk" {
563
570
  interface PluginConfigs<Fields extends string> {
564
571
  "@example/i18n": {
@@ -567,3 +574,41 @@ declare module "@tailor-platform/sdk" {
567
574
  }
568
575
  }
569
576
  ```
577
+
578
+ ### Resolving plugin-level config from a `Plugin[]` array (declaration merging)
579
+
580
+ `PluginConfig` is already available inside your own plugin's hooks via `context.pluginConfig`.
581
+ If other code instead needs to look up your plugin's config from a `Plugin[]` array by `id` —
582
+ without importing your plugin's config type — register it on the `PluginConfigRegistry`
583
+ interface. Plugin authors should ship this in their package's type definitions:
584
+
585
+ ```typescript
586
+ // your-plugin/types.d.ts (shipped with your plugin package)
587
+ export {}; // required: a top-level import/export makes this file augment
588
+ // the module below instead of replacing its other exports
589
+
590
+ declare module "@tailor-platform/sdk/plugin" {
591
+ interface PluginConfigRegistry {
592
+ "@example/soft-delete": {
593
+ archiveTablePrefix?: string;
594
+ };
595
+ }
596
+ }
597
+ ```
598
+
599
+ This only registers the type; it does not provide a function to read it. Callers resolve a
600
+ registered config from `Plugin[]` using the public `Plugin` and `PluginConfigRegistry` types:
601
+
602
+ ```typescript
603
+ import type { Plugin } from "@tailor-platform/sdk";
604
+ import type { PluginConfigRegistry } from "@tailor-platform/sdk/plugin";
605
+
606
+ function resolvePluginConfig<Id extends keyof PluginConfigRegistry>(
607
+ plugins: readonly Plugin[],
608
+ id: Id,
609
+ ): PluginConfigRegistry[Id] | undefined {
610
+ return plugins.find((p) => p.id === id)?.pluginConfig as PluginConfigRegistry[Id] | undefined;
611
+ }
612
+ ```
613
+
614
+ An `id` that isn't registered fails to compile, instead of silently resolving to `unknown`.
@@ -73,7 +73,7 @@ export const customer = db
73
73
  ### Per-table Config Requirement
74
74
 
75
75
  Per-table config is optional by default. Plugin authors can change this with
76
- `typeConfigRequired` (boolean or function). When a function is used, it receives
76
+ `tableConfigRequired` (boolean or function). When a function is used, it receives
77
77
  the plugin-level config from `definePlugins()`.
78
78
 
79
79
  ### Global Plugin Configuration
@@ -116,7 +116,7 @@ Plugins have 5 hooks across two lifecycle phases. Each hook fires at a specific
116
116
  tailor generate
117
117
 
118
118
  ├─ Load TailorDB tables
119
- │ ├─ onTypeLoaded ← per table with .plugin() attached
119
+ │ ├─ onTableLoaded ← per table with .plugin() attached
120
120
  │ └─ onNamespaceLoaded ← once per namespace (namespace plugins)
121
121
 
122
122
  ├─ Resolve Auth
@@ -136,7 +136,7 @@ tailor generate
136
136
 
137
137
  | Hook | Trigger | Can do |
138
138
  | ------------------- | ------------------------------------ | ----------------------------------------------------------------- |
139
- | `onTypeLoaded` | Each table with `.plugin()` attached | Generate tables, resolvers, executors; extend source table fields |
139
+ | `onTableLoaded` | Each table with `.plugin()` attached | Generate tables, resolvers, executors; extend source table fields |
140
140
  | `onNamespaceLoaded` | Once per namespace | Generate tables, resolvers, executors |
141
141
 
142
142
  These hooks produce TailorDB tables, resolvers, and executors that become part of the application. Requires `importPath` on the plugin.
@@ -201,6 +201,20 @@ tailor tailordb migration script 0002 --no-script --reason "no data yet, safe to
201
201
 
202
202
  This stores the reason in `migrations/0002/diff.json` (commit the change). The next `tailor deploy` applies the schema change as usual, skips only the script step, and logs the recorded reason. The command refuses to record a skip while `migrate.ts` exists — delete the script first. If `migrate.ts` is added back later, `tailor deploy` fails rather than choosing between the script and the acknowledgment; run `tailor tailordb migration script 0002` again to clear the now-stale acknowledgment from `diff.json` (the script then runs on the next deploy), or delete `migrate.ts` to keep the skip.
203
203
 
204
+ ### Data-only migrations
205
+
206
+ Sometimes existing data must be transformed without any schema change — fixing values written by an application bug, or a one-off normalization. Create a migration that carries no schema diff and exists only to run its script:
207
+
208
+ ```bash
209
+ tailor tailordb migration generate --data-only --name "normalize legacy phone numbers"
210
+ ```
211
+
212
+ This writes a numbered migration with an empty `diff.json`, a `migrate.ts` skeleton, and `db.ts` typed against the current schema. Edit `migrate.ts` to implement the transformation; the next `tailor deploy` runs it like any other migration script — in a single transaction, advancing the migration checkpoint (see [Performance and Large Tables](#performance-and-large-tables) for batching patterns). Because the entry is part of the migration history, the fix is versioned, ordered relative to schema changes, and applied once per workspace.
213
+
214
+ The command requires a clean state: if the namespace has schema changes that are not yet in migration files, generate the schema migration first. With multiple namespaces, pass `--namespace` to name the target. `--data-only` cannot be combined with `--init`, `--rename`, `--drop`, or `--expand-contract`.
215
+
216
+ A data-only migration runs in **every** workspace the history is applied to, including freshly created ones. Write the script so it is safe against tables with no matching rows (a set-based `UPDATE` with a `WHERE` clause is naturally a no-op on an empty table). For a fix that should run in a single environment only, or that is too large for one transaction, run it outside the migration history instead.
217
+
204
218
  ## Configuration
205
219
 
206
220
  ```typescript
@@ -227,13 +241,13 @@ export default defineConfig({
227
241
 
228
242
  ## Generated Files
229
243
 
230
- | File | When generated | Description |
231
- | ---------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
232
- | `0000/schema.json` | First `migration generate` | Full snapshot of all tables in the namespace. |
233
- | `XXXX/diff.json` | Every subsequent migration | Field-level diff against the previous snapshot. |
234
- | `XXXX/migrate.ts` | Auto-generated for breaking changes; added manually via `tailordb migration script` for warning-tier changes | Data transformation script. The `main` export receives a Kysely `Transaction`. |
235
- | `XXXX/db.ts` | Generated once when `migrate.ts` is created | Kysely types reflecting the schema **before** this migration. Exports `Database`, `Transaction`, and `MigrationContext`. |
236
- | `XXXX/migrate.test.ts` | Added via `tailordb migration script --with-test` | Unit-test scaffold for `migrate.ts` (see [Testing Migrations Locally](#testing-migrations-locally)). Never deployed. |
244
+ | File | When generated | Description |
245
+ | ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
246
+ | `0000/schema.json` | First `migration generate` | Full snapshot of all tables in the namespace. |
247
+ | `XXXX/diff.json` | Every subsequent migration | Field-level diff against the previous snapshot. |
248
+ | `XXXX/migrate.ts` | Auto-generated for breaking changes and `--data-only` migrations; added manually via `tailordb migration script` for warning-tier changes | Data transformation script. The `main` export receives a Kysely `Transaction`. |
249
+ | `XXXX/db.ts` | Generated once when `migrate.ts` is created | Kysely types reflecting the schema **before** this migration. Exports `Database`, `Transaction`, and `MigrationContext`. |
250
+ | `XXXX/migrate.test.ts` | Added via `tailordb migration script --with-test` | Unit-test scaffold for `migrate.ts` (see [Testing Migrations Locally](#testing-migrations-locally)). Never deployed. |
237
251
 
238
252
  `db.ts` reflects the pre-migration schema because the script runs after the pre-migration phase has temporarily relaxed breaking constraints (e.g., a new `required` field is added as `optional` first), so the data being read still matches the previous shape.
239
253
 
@@ -182,18 +182,20 @@ const user = db.table("User", {
182
182
  name: db.string(),
183
183
  roleId: db.uuid().relation({
184
184
  type: "n-1",
185
- toward: { type: role },
185
+ toward: { table: role },
186
186
  }),
187
187
  });
188
188
  ```
189
189
 
190
+ `toward.type` is a deprecated alias for `toward.table` and will be removed in v3; `tailor upgrade` offers a codemod to rewrite it.
191
+
190
192
  For one-to-one relations, use `type: "1-1"`:
191
193
 
192
194
  ```typescript
193
195
  const userProfile = db.table("UserProfile", {
194
196
  userId: db.uuid().relation({
195
197
  type: "1-1",
196
- toward: { type: user },
198
+ toward: { table: user },
197
199
  }),
198
200
  bio: db.string(),
199
201
  });
@@ -205,7 +207,7 @@ For foreign key constraint without creating a relation, use `type: "keyOnly"`:
205
207
  const user = db.table("User", {
206
208
  roleId: db.uuid().relation({
207
209
  type: "keyOnly",
208
- toward: { type: role },
210
+ toward: { table: role },
209
211
  }),
210
212
  });
211
213
  ```
@@ -220,7 +222,7 @@ const user = db.table("User", {
220
222
  const userProfile = db.table("UserProfile", {
221
223
  userEmail: db.string().relation({
222
224
  type: "1-1",
223
- toward: { type: user, key: "email", as: "user" },
225
+ toward: { table: user, key: "email", as: "user" },
224
226
  }),
225
227
  });
226
228
  ```
@@ -234,7 +236,7 @@ Customize relation names using `toward.as` / `backward` options:
234
236
  const userProfile = db.table("UserProfile", {
235
237
  userId: db.uuid().relation({
236
238
  type: "1-1",
237
- toward: { type: user, as: "base" },
239
+ toward: { table: user, as: "base" },
238
240
  backward: "profile",
239
241
  }),
240
242
  });
@@ -266,12 +268,12 @@ removed. This lets multiple fields point to the same target table with distinct
266
268
  const post = db.table("Post", {
267
269
  authorID: db.uuid().relation({
268
270
  type: "n-1",
269
- toward: { type: user },
271
+ toward: { table: user },
270
272
  backward: "authoredPosts",
271
273
  }),
272
274
  reviewerID: db.uuid().relation({
273
275
  type: "n-1",
274
- toward: { type: user },
276
+ toward: { table: user },
275
277
  backward: "reviewedPosts",
276
278
  }),
277
279
  });