@tailor-platform/sdk 2.4.0 → 2.5.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 +103 -0
- package/dist/aigateway-DsWDjzk4.mjs +2 -0
- package/dist/{aigateway-DR4Kwuik.mjs.map → aigateway-DsWDjzk4.mjs.map} +1 -1
- package/dist/application-DFOUovmN.mjs +1 -0
- package/dist/application-D_4vg1KR.mjs +192 -0
- package/dist/application-D_4vg1KR.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/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/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/lib.d.mts +8 -4
- package/dist/cli/lib.mjs +1 -9
- package/dist/cli/lib.mjs.map +1 -1
- package/dist/cli/main.mjs +1170 -7754
- package/dist/cli/main.mjs.map +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 +4 -8
- package/dist/configure/services/tailordb/types.d.mts +1 -1
- 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-B-_HTKLr.mjs +42 -0
- package/dist/{crashreport-Q0pDAlrj.mjs.map → crashreport-B-_HTKLr.mjs.map} +1 -1
- package/dist/crashreport-BmsRIdpy.mjs +1 -0
- package/dist/errors-DSEXKRVD.mjs +2 -0
- package/dist/errors-DSEXKRVD.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-BcGy-u7G.mjs +9 -0
- package/dist/{logger-D0bEznPv.mjs.map → logger-BcGy-u7G.mjs.map} +1 -1
- 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-Drnaproy.mjs +640 -0
- package/dist/register-ts-hook-Drnaproy.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-Ze_dI5VX.mjs +2 -0
- package/dist/schema-Ze_dI5VX.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-BVe9u2Rt.mjs +7 -0
- package/dist/service-BVe9u2Rt.mjs.map +1 -0
- package/dist/service-CpZELSBa.mjs +1 -0
- package/dist/service-DlgaUO4V.mjs +2 -0
- package/dist/{service-LTfp03ZZ.mjs.map → service-DlgaUO4V.mjs.map} +1 -1
- 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/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-BrkwfyjS.mjs +2 -0
- package/dist/{wait-point-registry-TL99zotw.mjs.map → wait-point-registry-BrkwfyjS.mjs.map} +1 -1
- 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 +10 -9
- package/docs/migration/v2.md +13 -1
- package/docs/migration/v3.md +82 -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/workflow.md +10 -9
- package/package.json +11 -11
- 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/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/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
|
|
|
@@ -26,12 +26,15 @@ All workflow components must follow these rules:
|
|
|
26
26
|
- **Job name uniqueness**: Job names must be unique across the entire project (not just within one file)
|
|
27
27
|
- **mainJob required**: Every workflow must specify a `mainJob`
|
|
28
28
|
|
|
29
|
-
| Rule
|
|
30
|
-
|
|
|
31
|
-
| `createWorkflow` result must be default export
|
|
32
|
-
| All jobs must be named exports
|
|
33
|
-
| Job `name` values must be unique
|
|
34
|
-
| `mainJob` is required
|
|
29
|
+
| Rule | Description |
|
|
30
|
+
| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
31
|
+
| `createWorkflow` result must be default export | Workflow files must export the workflow as default |
|
|
32
|
+
| All jobs must be named exports | Includes `mainJob` and any job started via `.start()` (even if referenced only within the same file) |
|
|
33
|
+
| Job `name` values must be unique | Job names must be unique across the entire project |
|
|
34
|
+
| `mainJob` is required | Every workflow must specify a `mainJob` |
|
|
35
|
+
| `createWorkflowJob`'s `name`/`body` must be written directly in the call | Not as a reference to a variable or the result of another function — the build cannot see through that indirection and fails instead of silently leaving the job out |
|
|
36
|
+
| `.start()` must be called from within the calling job's `body` | A function defined inside `body` may call it too, but not a function defined outside `body` — the build cannot see through that indirection and fails instead of silently leaving the call out |
|
|
37
|
+
| Call `<job>.start()`, not `execJobFunction` directly | Calling `tailor.workflow.execJobFunction(...)` (or the `workflow` value imported from `@tailor-platform/sdk/runtime`) directly is not detected as a dependency and fails the build |
|
|
35
38
|
|
|
36
39
|
## Creating a Workflow Job
|
|
37
40
|
|
|
@@ -481,7 +484,7 @@ An exact-key policy applies to dispatches whose runtime key equals the policy ke
|
|
|
481
484
|
|
|
482
485
|
### Referencing a Policy from a Workflow
|
|
483
486
|
|
|
484
|
-
Pass the runtime key through the `executionPolicyKey` option on `job.start()
|
|
487
|
+
Pass the runtime key through the `executionPolicyKey` option on `job.start()`. For exact-key policies, use `<policy>.key` directly — it's typed so only a value that came from a declared policy can be passed. For wildcard policies (`matchType: "prefix"`), there is no `<policy>.key` — call `<policy>.keyFor(suffix)` to build the concrete key. `keyFor` joins the prefix and suffix with `.` by default; override it with `separator` — the second argument to `defineWorkflowExecutionPolicies` (applies to every policy in the group), or a `def` field on a single `defineWorkflowExecutionPolicy`.
|
|
485
488
|
|
|
486
489
|
```typescript
|
|
487
490
|
import { createWorkflowJob } from "@tailor-platform/sdk";
|
|
@@ -507,8 +510,6 @@ export const mainJob = createWorkflowJob({
|
|
|
507
510
|
});
|
|
508
511
|
```
|
|
509
512
|
|
|
510
|
-
The same `executionPolicyKey` option is available on `tailor.workflow.execJobFunction(name, args, options)` for jobs invoked by name.
|
|
511
|
-
|
|
512
513
|
## Starting a Workflow from a Resolver
|
|
513
514
|
|
|
514
515
|
You can start a workflow execution from a resolver using `workflow.start()`.
|