@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.
- package/CHANGELOG.md +131 -0
- package/bin/tailor.mjs +3 -2
- package/dist/aigateway-DsWDjzk4.mjs +2 -0
- package/dist/{aigateway-DR4Kwuik.mjs.map → aigateway-DsWDjzk4.mjs.map} +1 -1
- package/dist/application-CNeOcaLc.mjs +1 -0
- package/dist/application-CmXOqTaK.mjs +192 -0
- package/dist/application-CmXOqTaK.mjs.map +1 -0
- package/dist/assert-WeXvmG4j.mjs +2 -0
- package/dist/{assert-DBxo8jPo.mjs.map → assert-WeXvmG4j.mjs.map} +1 -1
- package/dist/authconnection-CynFBIv8.mjs +2 -0
- package/dist/{authconnection-CZvi9ANm.mjs.map → authconnection-CynFBIv8.mjs.map} +1 -1
- package/dist/brand-C8nMKhJC.mjs +2 -0
- package/dist/{brand-Eo4pLXPJ.mjs.map → brand-C8nMKhJC.mjs.map} +1 -1
- package/dist/cli/commands/api/index.d.mts +1 -1
- package/dist/cli/commands/deploy/deploy.d.mts +2 -2
- package/dist/cli/commands/deploy/deployment-target.d.mts +2 -0
- package/dist/cli/commands/deploy/event-subscriptions.d.mts +3 -0
- package/dist/cli/commands/deploy/tailordb/apply.d.mts +3 -0
- package/dist/cli/commands/deploy/tailordb/index.d.mts +3 -10
- package/dist/cli/commands/deploy/tailordb/migration-validation.d.mts +5 -0
- package/dist/cli/commands/deploy/tailordb/plan.d.mts +8 -0
- package/dist/cli/commands/executor/jobs.d.mts +1 -1
- package/dist/cli/commands/executor/trigger.d.mts +1 -1
- package/dist/cli/commands/generate/seed/bundler.d.mts +2 -2
- package/dist/cli/commands/show.d.mts +1 -1
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +11 -11
- package/dist/cli/commands/tailordb/migrate/generate.d.mts +4 -0
- package/dist/cli/commands/tailordb/migrate/rename-detection.d.mts +1 -1
- package/dist/cli/commands/tailordb/migrate/snapshot-comparison.d.mts +43 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-files.d.mts +62 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-local.d.mts +12 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-migrations.d.mts +12 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-remote.d.mts +1 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +3 -1
- package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +5 -117
- package/dist/cli/commands/workflow/start.d.mts +1 -1
- package/dist/cli/commands/workspace/list.d.mts +1 -1
- package/dist/cli/lib.d.mts +12 -4
- package/dist/cli/lib.mjs +1 -9
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.d.mts +2 -0
- package/dist/cli/main.mjs +1170 -7754
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/shared/args.d.mts +65 -1
- package/dist/cli/shared/command.d.mts +11 -0
- package/dist/cli/shared/context.d.mts +1 -1
- package/dist/cli/shared/logger.d.mts +64 -0
- package/dist/cli/shared/script-executor.d.mts +1 -1
- package/dist/cli/shared/seed-chunker.d.mts +5 -5
- package/dist/completion/zsh-worker.zsh +82 -9
- package/dist/configure/config/index.d.mts +1 -1
- package/dist/configure/config/types.d.mts +2 -2
- package/dist/configure/index.d.mts +48 -12
- package/dist/configure/index.mjs +1 -1267
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/auth/types.d.mts +1 -1
- package/dist/configure/services/idp/types.d.mts +1 -1
- package/dist/configure/services/tailordb/schema.d.mts +22 -8
- package/dist/configure/services/tailordb/types.d.mts +2 -2
- package/dist/configure/services/workflow/execution-policy.d.mts +3 -3
- package/dist/configure/services/workflow/job.d.mts +12 -2
- package/dist/configure/types/field.types.d.mts +1 -1
- package/dist/configure/types/permission-operand.types.d.mts +1 -1
- package/dist/context-D0QjfxzD.mjs +2 -0
- package/dist/{context-DYQVYWqZ.mjs.map → context-D0QjfxzD.mjs.map} +1 -1
- package/dist/crashreport-BN28xp5B.mjs +42 -0
- package/dist/{crashreport-Q0pDAlrj.mjs.map → crashreport-BN28xp5B.mjs.map} +1 -1
- package/dist/crashreport-By23O2k-.mjs +1 -0
- package/dist/errors-DLsQ_-ol.mjs +2 -0
- package/dist/errors-DLsQ_-ol.mjs.map +1 -0
- package/dist/es-builtins-n3wBv4Sv.mjs +2 -0
- package/dist/es-builtins-n3wBv4Sv.mjs.map +1 -0
- package/dist/file-COPYfju_.mjs +2 -0
- package/dist/file-COPYfju_.mjs.map +1 -0
- package/dist/globals-CMHSnj4w.mjs +2 -0
- package/dist/{globals-B2nlxBrz.mjs.map → globals-CMHSnj4w.mjs.map} +1 -1
- package/dist/iconv-DlFMt2gW.mjs +2 -0
- package/dist/{iconv-QWaZh0TT.mjs.map → iconv-DlFMt2gW.mjs.map} +1 -1
- package/dist/idp-G_ojPBB5.mjs +2 -0
- package/dist/{idp-RA_swu-h.mjs.map → idp-G_ojPBB5.mjs.map} +1 -1
- package/dist/interceptor-DQg3cR_9.mjs +2 -0
- package/dist/{interceptor-e33JtsC-.mjs.map → interceptor-DQg3cR_9.mjs.map} +1 -1
- package/dist/kysely/index.mjs +1 -32
- package/dist/kysely/index.mjs.map +1 -1
- package/dist/kysely-type-BTi3BMtL.mjs +43 -0
- package/dist/kysely-type-BTi3BMtL.mjs.map +1 -0
- package/dist/logger-CCjs1DuH.mjs +9 -0
- package/dist/logger-CCjs1DuH.mjs.map +1 -0
- package/dist/logger-DP2BjQ93.mjs +2 -0
- package/dist/{logger-BtX0suGY.mjs.map → logger-DP2BjQ93.mjs.map} +1 -1
- package/dist/multiline-EyzjEwn9.mjs +3 -0
- package/dist/{multiline-sfHpTZZK.mjs.map → multiline-EyzjEwn9.mjs.map} +1 -1
- package/dist/node-builtins-oBl7EbyV.mjs +2 -0
- package/dist/{node-builtins-CmaL2Cbq.mjs.map → node-builtins-oBl7EbyV.mjs.map} +1 -1
- package/dist/package-json-C690ceex.mjs +2 -0
- package/dist/{package-json-8b0O9TlX.mjs.map → package-json-C690ceex.mjs.map} +1 -1
- package/dist/package-json-CmqhDJ__.mjs +1 -0
- package/dist/parser/service/tailordb/type-source.d.mts +5 -5
- package/dist/parser/service/tailordb/types.d.mts +4 -4
- package/dist/platform-serialize-DkiTdHOt.mjs +2 -0
- package/dist/{platform-serialize-RoRtBS0v.mjs.map → platform-serialize-DkiTdHOt.mjs.map} +1 -1
- package/dist/plugin/builtin/enum-constants/index.mjs +5 -114
- package/dist/plugin/builtin/enum-constants/index.mjs.map +1 -1
- package/dist/plugin/builtin/file-utils/index.mjs +22 -104
- package/dist/plugin/builtin/file-utils/index.mjs.map +1 -1
- package/dist/plugin/builtin/kysely-type/index.d.mts +8 -1
- package/dist/plugin/builtin/kysely-type/index.mjs +1 -275
- package/dist/plugin/builtin/seed/index.d.mts +5 -0
- package/dist/plugin/builtin/seed/index.mjs +1 -3
- package/dist/plugin/builtin/seed/seed-type-processor.d.mts +0 -2
- package/dist/plugin/{get-generated-type.d.mts → get-generated-table.d.mts} +5 -5
- package/dist/plugin/index.d.mts +3 -2
- package/dist/plugin/index.mjs +1 -251
- package/dist/plugin/index.mjs.map +1 -1
- package/dist/plugin/types.d.mts +30 -23
- package/dist/plugin/with-context.d.mts +3 -3
- package/dist/register-ts-hook-oDA2JLp2.mjs +640 -0
- package/dist/register-ts-hook-oDA2JLp2.mjs.map +1 -0
- package/dist/registry-HlEaGvl5.mjs +2 -0
- package/dist/{registry-BIGVUrMB.mjs.map → registry-HlEaGvl5.mjs.map} +1 -1
- package/dist/repl-editor-BG1aDOfH.mjs +2 -0
- package/dist/{repl-editor-F9LotMNx.mjs.map → repl-editor-BG1aDOfH.mjs.map} +1 -1
- package/dist/runtime/aigateway.mjs +1 -3
- package/dist/runtime/authconnection.mjs +1 -3
- package/dist/runtime/context.mjs +1 -3
- package/dist/runtime/file.d.mts +21 -21
- package/dist/runtime/file.mjs +1 -3
- package/dist/runtime/globals.mjs +1 -1
- package/dist/runtime/iconv.mjs +1 -3
- package/dist/runtime/idp.mjs +1 -3
- package/dist/runtime/index.mjs +1 -11
- package/dist/runtime/logger.mjs +1 -3
- package/dist/runtime/secretmanager.mjs +1 -3
- package/dist/runtime/types.d.mts +1 -1
- package/dist/runtime/workflow.mjs +1 -3
- package/dist/schema-AYG4OhXY.mjs +2 -0
- package/dist/schema-AYG4OhXY.mjs.map +1 -0
- package/dist/secret-file-C9wp_FCX.mjs +2 -0
- package/dist/{secret-file-C3J4Gy8r.mjs.map → secret-file-C9wp_FCX.mjs.map} +1 -1
- package/dist/secretmanager-5olfnI1b.mjs +2 -0
- package/dist/{secretmanager-IY4UvinW.mjs.map → secretmanager-5olfnI1b.mjs.map} +1 -1
- package/dist/secretmanager-vHQoXdQz.mjs +2 -0
- package/dist/{secretmanager-CYlpffsz.mjs.map → secretmanager-vHQoXdQz.mjs.map} +1 -1
- package/dist/seed/index.mjs +8 -244
- package/dist/seed/index.mjs.map +1 -1
- package/dist/seed-DwqRFdqP.mjs +207 -0
- package/dist/seed-DwqRFdqP.mjs.map +1 -0
- package/dist/service-CLPMoj9n.mjs +2 -0
- package/dist/{service-LTfp03ZZ.mjs.map → service-CLPMoj9n.mjs.map} +1 -1
- package/dist/service-D7iXk0BT.mjs +1 -0
- package/dist/service-YqDsHmlK.mjs +7 -0
- package/dist/service-YqDsHmlK.mjs.map +1 -0
- package/dist/service_pb-DGKCLuAs.mjs +2 -0
- package/dist/{service_pb-BEWj1pOV.mjs.map → service_pb-DGKCLuAs.mjs.map} +1 -1
- package/dist/service_pb-_aeFE-Nv.mjs +1 -0
- package/dist/shared/src/color.d.mts +5 -0
- package/dist/tailor-proto/src/tailor/v1/workspace_pb.d.mts +1 -1
- package/dist/telemetry-Bklv9kQY.mjs +2 -0
- package/dist/{telemetry-BRVdwh14.mjs.map → telemetry-Bklv9kQY.mjs.map} +1 -1
- package/dist/telemetry-DXHP3VVi.mjs +1 -0
- package/dist/type-source--ZNcV8RJ.mjs +2 -0
- package/dist/type-source--ZNcV8RJ.mjs.map +1 -0
- package/dist/types/executor.generated.d.mts +1 -1
- package/dist/user-agent-vdHYF3QL.mjs +2 -0
- package/dist/{user-agent-Bgsszb5I.mjs.map → user-agent-vdHYF3QL.mjs.map} +1 -1
- package/dist/utils/test/index.mjs +1 -109
- package/dist/utils/test/index.mjs.map +1 -1
- package/dist/vitest/environment.mjs +1 -41
- package/dist/vitest/environment.mjs.map +1 -1
- package/dist/vitest/index.mjs +1 -1986
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/mocks/file.d.mts +8 -8
- package/dist/vitest/setup.mjs +1 -140
- package/dist/vitest/setup.mjs.map +1 -1
- package/dist/wait-point-invoker-eiP-IIux.mjs +2 -0
- package/dist/wait-point-invoker-eiP-IIux.mjs.map +1 -0
- package/dist/wait-point-registry-B-ESkTZX.mjs +2 -0
- package/dist/wait-point-registry-B-ESkTZX.mjs.map +1 -0
- package/dist/workflow-Cs9ISw6j.mjs +2 -0
- package/dist/{workflow-Bamae_Yc.mjs.map → workflow-Cs9ISw6j.mjs.map} +1 -1
- package/dist/workspace_resource_pb--GeYQPXu.mjs +2 -0
- package/dist/{workspace_resource_pb-HNIL_Vfj.mjs.map → workspace_resource_pb--GeYQPXu.mjs.map} +1 -1
- package/docs/cli/function.md +66 -6
- package/docs/cli/setup.md +24 -14
- package/docs/cli/tailordb.md +2 -0
- package/docs/cli-reference.md +9 -8
- package/docs/github-actions.md +14 -12
- package/docs/migration/v2.md +18 -2
- package/docs/migration/v3.md +121 -0
- package/docs/plugin/custom.md +130 -85
- package/docs/plugin/index.md +3 -3
- package/docs/services/tailordb-migration.md +21 -7
- package/docs/services/tailordb.md +9 -7
- package/docs/services/workflow.md +10 -9
- package/package.json +14 -13
- package/postinstall.mjs +1 -1
- package/dist/aigateway-DR4Kwuik.mjs +0 -9
- package/dist/application-C8a0UJ-z.mjs +0 -6071
- package/dist/application-C8a0UJ-z.mjs.map +0 -1
- package/dist/application-D4zOiLLa.mjs +0 -3
- package/dist/assert-DBxo8jPo.mjs +0 -9
- package/dist/authconnection-CZvi9ANm.mjs +0 -9
- package/dist/brand-Eo4pLXPJ.mjs +0 -36
- package/dist/context-DYQVYWqZ.mjs +0 -23
- package/dist/crashreport-Cd4TqfZq.mjs +0 -3
- package/dist/crashreport-Q0pDAlrj.mjs +0 -427
- package/dist/errors-Bxut5_Sy.mjs +0 -89
- package/dist/errors-Bxut5_Sy.mjs.map +0 -1
- package/dist/file-BUcmVIH2.mjs +0 -58
- package/dist/file-BUcmVIH2.mjs.map +0 -1
- package/dist/globals-B2nlxBrz.mjs +0 -126
- package/dist/iconv-QWaZh0TT.mjs +0 -38
- package/dist/idp-RA_swu-h.mjs +0 -82
- package/dist/interceptor-e33JtsC-.mjs +0 -33
- package/dist/logger-BtX0suGY.mjs +0 -48
- package/dist/logger-D0bEznPv.mjs +0 -362
- package/dist/logger-D0bEznPv.mjs.map +0 -1
- package/dist/multiline-sfHpTZZK.mjs +0 -38
- package/dist/node-builtins-CmaL2Cbq.mjs +0 -36
- package/dist/package-json-8b0O9TlX.mjs +0 -17
- package/dist/package-json-Cv2Z-TqQ.mjs +0 -3
- package/dist/platform-serialize-RoRtBS0v.mjs +0 -46
- package/dist/plugin/builtin/kysely-type/index.mjs.map +0 -1
- package/dist/plugin/builtin/seed/types.d.mts +0 -2
- package/dist/register-ts-hook-Vqjza10T.mjs +0 -25679
- package/dist/register-ts-hook-Vqjza10T.mjs.map +0 -1
- package/dist/registry-BIGVUrMB.mjs +0 -54
- package/dist/repl-editor-F9LotMNx.mjs +0 -252
- package/dist/schema-D4TC4BC3.mjs +0 -640
- package/dist/schema-D4TC4BC3.mjs.map +0 -1
- package/dist/secret-file-C3J4Gy8r.mjs +0 -64
- package/dist/secretmanager-CYlpffsz.mjs +0 -13
- package/dist/secretmanager-IY4UvinW.mjs +0 -131
- package/dist/seed-Cibjmtry.mjs +0 -489
- package/dist/seed-Cibjmtry.mjs.map +0 -1
- package/dist/service-2grcAOCJ.mjs +0 -898
- package/dist/service-2grcAOCJ.mjs.map +0 -1
- package/dist/service-CaBPNDIZ.mjs +0 -3
- package/dist/service-LTfp03ZZ.mjs +0 -133
- package/dist/service_pb-BEWj1pOV.mjs +0 -167
- package/dist/service_pb-BjlhvK9E.mjs +0 -3
- package/dist/telemetry-BRVdwh14.mjs +0 -84
- package/dist/telemetry-CkbkeJxl.mjs +0 -3
- package/dist/type-source-DH_LH20p.mjs +0 -13
- package/dist/type-source-DH_LH20p.mjs.map +0 -1
- package/dist/user-agent-Bgsszb5I.mjs +0 -28
- package/dist/wait-point-invoker-__oE88_P.mjs +0 -148
- package/dist/wait-point-invoker-__oE88_P.mjs.map +0 -1
- package/dist/wait-point-registry-TL99zotw.mjs +0 -47
- package/dist/wait-point-registry-TL99zotw.mjs.map +0 -1
- package/dist/workflow-Bamae_Yc.mjs +0 -34
- package/dist/workspace_resource_pb-HNIL_Vfj.mjs +0 -860
package/docs/plugin/custom.md
CHANGED
|
@@ -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 `
|
|
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<
|
|
26
|
+
interface Plugin<TableConfig = unknown, PluginConfig = unknown> {
|
|
27
27
|
readonly id: string;
|
|
28
28
|
readonly description: string;
|
|
29
29
|
readonly importPath?: string;
|
|
30
|
-
readonly
|
|
30
|
+
readonly tableConfigRequired?: boolean | ((pluginConfig?: PluginConfig) => boolean);
|
|
31
31
|
readonly pluginConfig?: PluginConfig;
|
|
32
32
|
|
|
33
33
|
// Definition-time hooks
|
|
34
|
-
|
|
35
|
-
context:
|
|
36
|
-
):
|
|
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
|
|
55
|
-
|
|
|
56
|
-
| `id`
|
|
57
|
-
| `description`
|
|
58
|
-
| `importPath`
|
|
59
|
-
| `
|
|
60
|
-
| `pluginConfig`
|
|
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
|
-
###
|
|
64
|
+
### onTableLoaded
|
|
65
65
|
|
|
66
66
|
**Trigger**: Called once for each TailorDB table that has `.plugin({ pluginId: config })` attached.
|
|
67
67
|
|
|
68
|
-
**Context** (`
|
|
68
|
+
**Context** (`PluginTableProcessContext`):
|
|
69
69
|
|
|
70
70
|
| Field | Type | Description |
|
|
71
71
|
| -------------- | ----------------- | ------------------------------------------ |
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
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** (`
|
|
77
|
+
**Returns** (`TablePluginOutput`):
|
|
78
78
|
|
|
79
79
|
| Field | Type | Description |
|
|
80
80
|
| ----------- | ----------------------------------------------- | ------------------------------------------------------ |
|
|
81
|
-
| `
|
|
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
|
-
|
|
94
|
-
const {
|
|
93
|
+
onTableLoaded(context) {
|
|
94
|
+
const { table, tableConfig, namespace } = context;
|
|
95
95
|
return {
|
|
96
|
-
|
|
96
|
+
tables: { archive: db.table(`Deleted_${table.name}`, { ... }) },
|
|
97
97
|
extends: { fields: { deletedAt: db.datetime({ optional: true }) } },
|
|
98
|
-
executors: [{ name: `${
|
|
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 `
|
|
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
|
-
|
|
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
|
-
| `
|
|
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
|
|
169
|
-
Object.values(ns.
|
|
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}/
|
|
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
|
-
|
|
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
|
-
|
|
266
|
-
|
|
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
|
-
##
|
|
277
|
+
## getGeneratedTable Helper
|
|
278
278
|
|
|
279
|
-
The SDK provides an async `
|
|
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 {
|
|
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
|
|
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
|
|
297
|
-
const AuditLog = await
|
|
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
|
-
- `
|
|
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 `
|
|
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 `
|
|
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,
|
|
325
|
+
import type { Plugin, PluginTableProcessContext, TablePluginOutput } from "@tailor-platform/sdk";
|
|
326
326
|
|
|
327
|
-
interface
|
|
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
|
-
|
|
335
|
+
requireTableConfig?: boolean;
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
function processSoftDelete(
|
|
339
|
-
context:
|
|
340
|
-
):
|
|
341
|
-
const {
|
|
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
|
|
346
|
-
.table(`${prefix}${
|
|
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
|
-
...(
|
|
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 ${
|
|
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
|
-
|
|
364
|
+
tables: { archive: archiveTable },
|
|
365
365
|
extends: { fields: extendFields },
|
|
366
366
|
executors: [
|
|
367
367
|
{
|
|
368
|
-
name: `${
|
|
368
|
+
name: `${table.name.toLowerCase()}-on-delete`,
|
|
369
369
|
resolve: async () => await import("./executors/on-delete"),
|
|
370
370
|
context: {
|
|
371
|
-
|
|
372
|
-
|
|
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<
|
|
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
|
-
|
|
389
|
-
|
|
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
|
-
|
|
407
|
-
|
|
406
|
+
sourceTable: TailorAnyDBType;
|
|
407
|
+
archiveTable: TailorAnyDBType;
|
|
408
408
|
namespace: string;
|
|
409
409
|
}
|
|
410
410
|
|
|
411
411
|
export default withPluginContext((ctx: SoftDeleteContext) => {
|
|
412
|
-
const {
|
|
412
|
+
const { sourceTable, archiveTable, namespace } = ctx;
|
|
413
413
|
|
|
414
414
|
return createExecutor({
|
|
415
|
-
name: `${
|
|
416
|
-
description: `Archives deleted ${
|
|
417
|
-
trigger: recordDeletedTrigger({ type:
|
|
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(
|
|
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 (
|
|
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
|
|
472
|
-
id: "@example/
|
|
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
|
|
477
|
-
Object.
|
|
478
|
-
name:
|
|
479
|
-
fieldCount: Object.keys(
|
|
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
|
|
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}/
|
|
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
|
-
|
|
503
|
-
return {
|
|
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
|
|
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(
|
|
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 (
|
|
520
|
+
### Plugin-level type safety (TableConfig / PluginConfig)
|
|
519
521
|
|
|
520
|
-
Use TypeScript type parameters on `Plugin<
|
|
521
|
-
in `
|
|
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
|
|
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<
|
|
534
|
+
const plugin: Plugin<MyTableConfig, MyPluginConfig> = {
|
|
533
535
|
id: "@example/my-plugin",
|
|
534
536
|
// ...
|
|
535
|
-
|
|
536
|
-
// context.
|
|
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`.
|
package/docs/plugin/index.md
CHANGED
|
@@ -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
|
-
`
|
|
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
|
-
│ ├─
|
|
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
|
-
| `
|
|
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
|
|
231
|
-
| ---------------------- |
|
|
232
|
-
| `0000/schema.json` | First `migration generate`
|
|
233
|
-
| `XXXX/diff.json` | Every subsequent migration
|
|
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
|
|
236
|
-
| `XXXX/migrate.test.ts` | Added via `tailordb migration script --with-test`
|
|
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: {
|
|
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: {
|
|
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: {
|
|
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: {
|
|
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: {
|
|
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: {
|
|
271
|
+
toward: { table: user },
|
|
270
272
|
backward: "authoredPosts",
|
|
271
273
|
}),
|
|
272
274
|
reviewerID: db.uuid().relation({
|
|
273
275
|
type: "n-1",
|
|
274
|
-
toward: {
|
|
276
|
+
toward: { table: user },
|
|
275
277
|
backward: "reviewedPosts",
|
|
276
278
|
}),
|
|
277
279
|
});
|