@tailor-platform/sdk 2.2.0 → 2.3.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 +115 -0
- package/dist/application-BZfk4HKm.mjs +3 -0
- package/dist/{application-BpLeawBg.mjs → application-F-nl107y.mjs} +118 -24
- package/dist/application-F-nl107y.mjs.map +1 -0
- package/dist/cli/commands/tailordb/migrate/diff-calculator.d.mts +43 -20
- package/dist/cli/commands/tailordb/migrate/generate.d.mts +6 -0
- package/dist/cli/commands/tailordb/migrate/rename-detection.d.mts +22 -0
- package/dist/cli/commands/tailordb/migrate/snapshot-types.d.mts +1 -1
- package/dist/cli/commands/tailordb/migrate/snapshot.d.mts +26 -7
- package/dist/cli/lib.mjs +2 -2
- package/dist/cli/main.mjs +203 -42
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/ts-hook.mjs +52 -7
- package/dist/completion/zsh-worker.zsh +23 -3
- package/dist/configure/index.d.mts +2 -2
- package/dist/configure/index.mjs +90 -23
- package/dist/configure/index.mjs.map +1 -1
- package/dist/configure/services/index.d.mts +2 -2
- package/dist/configure/services/workflow/index.d.mts +2 -2
- package/dist/configure/services/workflow/wait-point.d.mts +72 -13
- package/dist/{errors-CWj21238.mjs → errors-BVb6vYGy.mjs} +16 -2
- package/dist/{errors-CWj21238.mjs.map → errors-BVb6vYGy.mjs.map} +1 -1
- package/dist/kysely/index.d.mts +2 -1
- package/dist/kysely/index.mjs.map +1 -1
- package/dist/{register-ts-hook-CTth1eqj.mjs → register-ts-hook-ClI226n2.mjs} +2034 -511
- package/dist/register-ts-hook-ClI226n2.mjs.map +1 -0
- package/dist/{service-goqlJJgA.mjs → service-C_WpbKHu.mjs} +38 -4
- package/dist/service-C_WpbKHu.mjs.map +1 -0
- package/dist/service-D1RCdzIL.mjs +3 -0
- package/dist/{service-CCwl3Avt.mjs → service-hZskxZmg.mjs} +2 -2
- package/dist/{service-CCwl3Avt.mjs.map → service-hZskxZmg.mjs.map} +1 -1
- package/dist/vitest/index.mjs +83 -1
- package/dist/vitest/index.mjs.map +1 -1
- package/dist/vitest/mocks/file.d.mts +1 -1
- package/dist/vitest/mocks/workflow.d.mts +13 -1
- package/dist/wait-point-invoker-__oE88_P.mjs +148 -0
- package/dist/wait-point-invoker-__oE88_P.mjs.map +1 -0
- package/dist/wait-point-registry-TL99zotw.mjs +47 -0
- package/dist/wait-point-registry-TL99zotw.mjs.map +1 -0
- package/docs/cli/setup.md +14 -1
- package/docs/cli/tailordb.md +9 -6
- package/docs/cli-reference.md +2 -1
- package/docs/github-actions.md +73 -28
- package/docs/migration/v2.md +54 -0
- package/docs/services/tailordb-migration.md +137 -35
- package/docs/services/workflow.md +52 -2
- package/docs/testing.md +12 -0
- package/package.json +4 -4
- package/dist/application-BpLeawBg.mjs.map +0 -1
- package/dist/application-BxLLiLsr.mjs +0 -3
- package/dist/register-ts-hook-CTth1eqj.mjs.map +0 -1
- package/dist/service-_XmjSEGr.mjs +0 -3
- package/dist/service-goqlJJgA.mjs.map +0 -1
- package/dist/test-env-key-D7UkZp99.mjs +0 -75
- package/dist/test-env-key-D7UkZp99.mjs.map +0 -1
|
@@ -46,10 +46,10 @@ declare function mockFile(options?: MockFileOptions): {
|
|
|
46
46
|
calls: FileCall[];
|
|
47
47
|
clear(): void;
|
|
48
48
|
reset(): void;
|
|
49
|
-
delete: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<void>>;
|
|
50
49
|
upload: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string, data: string | ArrayBuffer | Uint8Array | number[], options?: FileUploadOptions) => Promise<FileUploadResponse>>;
|
|
51
50
|
download: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileDownloadResponse>>;
|
|
52
51
|
downloadAsBase64: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileDownloadAsBase64Response>>;
|
|
52
|
+
delete: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<void>>;
|
|
53
53
|
getMetadata: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileMetadata>>;
|
|
54
54
|
downloadStream: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string) => Promise<FileDownloadStreamResponse>>;
|
|
55
55
|
uploadStream: Mock<(namespace: string, typeName: string, fieldName: string, recordId: string, readableStream: ReadableStream<Uint8Array | ArrayBuffer>, options?: FileUploadStreamOptions) => Promise<FileUploadResponse>>;
|
|
@@ -2,7 +2,7 @@ import { TailorEnv } from "../../runtime/types.mjs";
|
|
|
2
2
|
import { ExecJobFunctionOptions, StartWorkflowOptions } from "../../runtime/workflow.mjs";
|
|
3
3
|
import { WorkflowJob } from "../../configure/services/workflow/job.mjs";
|
|
4
4
|
import { Workflow } from "../../configure/services/workflow/workflow.mjs";
|
|
5
|
-
import { WaitPointInstance } from "../../configure/services/workflow/wait-point.mjs";
|
|
5
|
+
import { ParameterizedWaitPointInstance, WaitPointInstance } from "../../configure/services/workflow/wait-point.mjs";
|
|
6
6
|
import { Mock } from "vitest";
|
|
7
7
|
//#region src/vitest/mocks/workflow.d.ts
|
|
8
8
|
type JobHandler = (jobName: string, args: unknown, options?: ExecJobFunctionOptions) => unknown;
|
|
@@ -72,6 +72,18 @@ declare function mockWorkflow(): {
|
|
|
72
72
|
resolve: Mock<WaitPointInstance<Payload, Result>["resolve"]>;
|
|
73
73
|
setResolvePayload(payload: WaitPayload<Payload>): void;
|
|
74
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Get stable, typed mocks for one param binding of a parameterized wait point.
|
|
77
|
+
* Calls made with other bindings fall through to the platform mock.
|
|
78
|
+
* @param definition - Parameterized wait point definition to mock
|
|
79
|
+
* @param params - Param binding to intercept, as passed to `.with()`
|
|
80
|
+
* @returns Typed wait point mock control object
|
|
81
|
+
*/
|
|
82
|
+
waitPointWith<Params extends object, Payload, Result>(definition: ParameterizedWaitPointInstance<Params, Payload, Result>, params: Params): {
|
|
83
|
+
wait: Mock<WaitPointInstance<Payload, Result>["wait"]>;
|
|
84
|
+
resolve: Mock<WaitPointInstance<Payload, Result>["resolve"]>;
|
|
85
|
+
setResolvePayload(payload: WaitPayload<Payload>): void;
|
|
86
|
+
};
|
|
75
87
|
/**
|
|
76
88
|
* Set a fallback job handler. Called when the enqueue queue is empty.
|
|
77
89
|
* @param handler - Function returning a result for a job name, args, and options
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
|
|
3
|
+
//#region src/configure/services/workflow/test-env-key.ts
|
|
4
|
+
/**
|
|
5
|
+
* Typed accessors for the test-time globalThis slot used to pass `env` from
|
|
6
|
+
* `mockWorkflow().setEnv()` (in `@tailor-platform/sdk/vitest`) to
|
|
7
|
+
* `runWorkflowLocally()` job bodies. The slot key is private to this
|
|
8
|
+
* module; callers go through the get/set/clear functions below so both sides
|
|
9
|
+
* share the same access path.
|
|
10
|
+
*
|
|
11
|
+
* Lives in its own file (with no `@/` imports) so `vitest/mock.ts` can load
|
|
12
|
+
* it from nested Vitest configs that do not resolve `@/` aliases.
|
|
13
|
+
* @internal
|
|
14
|
+
*/
|
|
15
|
+
const SLOT_KEY = "__tailorWorkflowTestEnv";
|
|
16
|
+
let invokerStorage;
|
|
17
|
+
function workflowInvokerStorage() {
|
|
18
|
+
if (!invokerStorage) invokerStorage = new AsyncLocalStorage();
|
|
19
|
+
return invokerStorage;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read the test-time env slot.
|
|
23
|
+
* @returns Current env, or `undefined` when unset.
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
function readWorkflowTestEnv() {
|
|
27
|
+
return globalThis[SLOT_KEY];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Write the test-time env slot.
|
|
31
|
+
* @param env - Env value to expose to `runWorkflowLocally()` job bodies.
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
function writeWorkflowTestEnv(env) {
|
|
35
|
+
globalThis[SLOT_KEY] = env;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Clear the test-time env slot.
|
|
39
|
+
* @internal
|
|
40
|
+
*/
|
|
41
|
+
function clearWorkflowTestEnv() {
|
|
42
|
+
delete globalThis[SLOT_KEY];
|
|
43
|
+
}
|
|
44
|
+
function withWorkflowTestInvoker(invoker, run) {
|
|
45
|
+
return workflowInvokerStorage().run(invoker, run);
|
|
46
|
+
}
|
|
47
|
+
function readRuntimeInvoker() {
|
|
48
|
+
const runtime = globalThis.tailor?.context?.getInvoker;
|
|
49
|
+
const raw = runtime?.();
|
|
50
|
+
if (!raw) return null;
|
|
51
|
+
return {
|
|
52
|
+
id: raw.id,
|
|
53
|
+
type: raw.type,
|
|
54
|
+
workspaceId: raw.workspaceId,
|
|
55
|
+
attributes: raw.attributeMap ?? (Array.isArray(raw.attributes) ? {} : raw.attributes ?? {}),
|
|
56
|
+
attributeList: raw.attributeList ?? (Array.isArray(raw.attributes) ? raw.attributes : [])
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function buildJobContext() {
|
|
60
|
+
const storedInvoker = invokerStorage?.getStore();
|
|
61
|
+
const invoker = storedInvoker === void 0 ? readRuntimeInvoker() : storedInvoker;
|
|
62
|
+
const fromGlobal = readWorkflowTestEnv();
|
|
63
|
+
if (fromGlobal !== void 0) return {
|
|
64
|
+
env: { ...fromGlobal },
|
|
65
|
+
invoker
|
|
66
|
+
};
|
|
67
|
+
return {
|
|
68
|
+
env: {},
|
|
69
|
+
invoker
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
//#endregion
|
|
74
|
+
//#region src/configure/services/workflow/wait-point-invoker.ts
|
|
75
|
+
const WAIT_POINT_INVOKER = Symbol.for("tailor-platform/sdk:wait-point-invoker");
|
|
76
|
+
const WAIT_POINT_KEY = Symbol.for("tailor-platform/sdk:wait-point-key");
|
|
77
|
+
function getPlatformWorkflow() {
|
|
78
|
+
const workflow = globalThis.tailor?.workflow;
|
|
79
|
+
if (!workflow) throw new Error("tailor.workflow is not available. Run tests in the `tailor-runtime` Vitest environment, or acquire mockWorkflow() from @tailor-platform/sdk/vitest and set a wait/resolve handler.");
|
|
80
|
+
return workflow;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Create the invoker a single wait point definition delegates to.
|
|
84
|
+
* @returns An invoker bound to the platform runtime
|
|
85
|
+
*/
|
|
86
|
+
function createWaitPointInvoker() {
|
|
87
|
+
return {
|
|
88
|
+
wait(key, payload) {
|
|
89
|
+
return getPlatformWorkflow().wait(key, payload);
|
|
90
|
+
},
|
|
91
|
+
async resolve(key, executionId, callback) {
|
|
92
|
+
await getPlatformWorkflow().resolve(executionId, key, callback);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Attach an invoker to a wait point definition so test doubles can intercept it.
|
|
98
|
+
*
|
|
99
|
+
* The slot itself is fixed once attached; a double swaps the invoker's `wait` /
|
|
100
|
+
* `resolve` methods rather than the invoker object.
|
|
101
|
+
* @param target - Wait point definition to attach to
|
|
102
|
+
* @param invoker - Invoker the definition delegates to
|
|
103
|
+
* @returns The same definition
|
|
104
|
+
*/
|
|
105
|
+
function attachWaitPointInvoker(target, invoker) {
|
|
106
|
+
Object.defineProperty(target, WAIT_POINT_INVOKER, {
|
|
107
|
+
value: invoker,
|
|
108
|
+
enumerable: false,
|
|
109
|
+
configurable: false,
|
|
110
|
+
writable: false
|
|
111
|
+
});
|
|
112
|
+
return target;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Read the invoker attached to a wait point definition.
|
|
116
|
+
* @param target - Wait point definition to read from
|
|
117
|
+
* @returns The attached invoker, or undefined when the value is not a wait point
|
|
118
|
+
*/
|
|
119
|
+
function getWaitPointInvoker(target) {
|
|
120
|
+
return target[WAIT_POINT_INVOKER];
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Record the resolved key on a wait point bound by `.with()`.
|
|
124
|
+
* @param target - Bound wait point to attach to
|
|
125
|
+
* @param key - Resolved runtime key
|
|
126
|
+
* @returns The same bound wait point
|
|
127
|
+
*/
|
|
128
|
+
function attachWaitPointKey(target, key) {
|
|
129
|
+
Object.defineProperty(target, WAIT_POINT_KEY, {
|
|
130
|
+
value: key,
|
|
131
|
+
enumerable: false,
|
|
132
|
+
configurable: false,
|
|
133
|
+
writable: false
|
|
134
|
+
});
|
|
135
|
+
return target;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Read the resolved key recorded on a bound wait point.
|
|
139
|
+
* @param target - Bound wait point to read from
|
|
140
|
+
* @returns The resolved key, or undefined when the value is not a bound wait point
|
|
141
|
+
*/
|
|
142
|
+
function getWaitPointKey(target) {
|
|
143
|
+
return target[WAIT_POINT_KEY];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
export { getWaitPointKey as a, readWorkflowTestEnv as c, getWaitPointInvoker as i, withWorkflowTestInvoker as l, attachWaitPointKey as n, buildJobContext as o, createWaitPointInvoker as r, clearWorkflowTestEnv as s, attachWaitPointInvoker as t, writeWorkflowTestEnv as u };
|
|
148
|
+
//# sourceMappingURL=wait-point-invoker-__oE88_P.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-point-invoker-__oE88_P.mjs","names":["platform"],"sources":["../src/configure/services/workflow/test-env-key.ts","../src/configure/services/workflow/wait-point-invoker.ts"],"sourcesContent":["/**\n * Typed accessors for the test-time globalThis slot used to pass `env` from\n * `mockWorkflow().setEnv()` (in `@tailor-platform/sdk/vitest`) to\n * `runWorkflowLocally()` job bodies. The slot key is private to this\n * module; callers go through the get/set/clear functions below so both sides\n * share the same access path.\n *\n * Lives in its own file (with no `@/` imports) so `vitest/mock.ts` can load\n * it from nested Vitest configs that do not resolve `@/` aliases.\n * @internal\n */\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport type { TailorEnv, TailorPrincipal } from \"../../../runtime/types\";\n\nconst SLOT_KEY = \"__tailorWorkflowTestEnv\";\n\ntype AsyncLocalStorageLike<T> = {\n getStore(): T | undefined;\n run<R>(store: T, callback: () => R): R;\n};\n\nlet invokerStorage: AsyncLocalStorageLike<TailorPrincipal | null> | undefined;\n\nfunction workflowInvokerStorage(): AsyncLocalStorageLike<TailorPrincipal | null> {\n if (!invokerStorage) {\n invokerStorage = new AsyncLocalStorage<TailorPrincipal | null>();\n }\n return invokerStorage;\n}\n\n/**\n * Read the test-time env slot.\n * @returns Current env, or `undefined` when unset.\n * @internal\n */\nexport function readWorkflowTestEnv(): TailorEnv | undefined {\n return (globalThis as unknown as Record<string, TailorEnv | undefined>)[SLOT_KEY];\n}\n\n/**\n * Write the test-time env slot.\n * @param env - Env value to expose to `runWorkflowLocally()` job bodies.\n * @internal\n */\nexport function writeWorkflowTestEnv(env: TailorEnv): void {\n (globalThis as unknown as Record<string, TailorEnv>)[SLOT_KEY] = env;\n}\n\n/**\n * Clear the test-time env slot.\n * @internal\n */\nexport function clearWorkflowTestEnv(): void {\n delete (globalThis as unknown as Record<string, unknown>)[SLOT_KEY];\n}\n\nexport function withWorkflowTestInvoker<T>(invoker: TailorPrincipal | null, run: () => T): T {\n return workflowInvokerStorage().run(invoker, run);\n}\n\ntype RuntimeInvoker = {\n id: string;\n type: \"user\" | \"machine_user\";\n workspaceId: string;\n attributes?: string[] | TailorPrincipal[\"attributes\"];\n attributeMap?: TailorPrincipal[\"attributes\"];\n attributeList?: TailorPrincipal[\"attributeList\"];\n};\n\nfunction readRuntimeInvoker(): TailorPrincipal | null {\n const runtime = (\n globalThis as unknown as {\n tailor?: { context?: { getInvoker?: () => RuntimeInvoker | null } };\n }\n ).tailor?.context?.getInvoker;\n const raw = runtime?.();\n if (!raw) return null;\n return {\n id: raw.id,\n type: raw.type,\n workspaceId: raw.workspaceId,\n attributes: raw.attributeMap ?? (Array.isArray(raw.attributes) ? {} : (raw.attributes ?? {})),\n attributeList: (raw.attributeList ??\n (Array.isArray(raw.attributes) ? raw.attributes : [])) as TailorPrincipal[\"attributeList\"],\n };\n}\n\n// Shallow-copied to isolate against cross-trigger mutation.\nexport function buildJobContext(): { env: TailorEnv; invoker: TailorPrincipal | null } {\n const storedInvoker = invokerStorage?.getStore();\n const invoker = storedInvoker === undefined ? readRuntimeInvoker() : storedInvoker;\n const fromGlobal = readWorkflowTestEnv();\n if (fromGlobal !== undefined) return { env: { ...fromGlobal }, invoker };\n return { env: {} as TailorEnv, invoker };\n}\n","import type { PlatformWorkflowAPI } from \"#/runtime/workflow\";\n\n// Not re-exported from the workflow barrel: the slot exists so the Vitest mock\n// can intercept parameterized wait points, whose `wait`/`resolve` live on\n// short-lived objects returned by `.with()` rather than on the definition.\nconst WAIT_POINT_INVOKER: unique symbol = Symbol.for(\"tailor-platform/sdk:wait-point-invoker\");\nconst WAIT_POINT_KEY: unique symbol = Symbol.for(\"tailor-platform/sdk:wait-point-key\");\n\n/** Indirection every wait point call routes through, keyed by resolved key. */\nexport interface WaitPointInvoker {\n wait(key: string, payload: unknown): unknown;\n resolve(\n key: string,\n executionId: string,\n callback: (payload: unknown) => unknown | Promise<unknown>,\n ): Promise<void>;\n}\n\nfunction getPlatformWorkflow(): PlatformWorkflowAPI {\n const platform = globalThis as { tailor?: { workflow?: PlatformWorkflowAPI } };\n const workflow = platform.tailor?.workflow;\n if (!workflow) {\n throw new Error(\n \"tailor.workflow is not available. Run tests in the `tailor-runtime` Vitest environment, \" +\n \"or acquire mockWorkflow() from @tailor-platform/sdk/vitest and set a wait/resolve handler.\",\n );\n }\n return workflow;\n}\n\n/**\n * Create the invoker a single wait point definition delegates to.\n * @returns An invoker bound to the platform runtime\n */\nexport function createWaitPointInvoker(): WaitPointInvoker {\n return {\n wait(key, payload) {\n return getPlatformWorkflow().wait(key, payload);\n },\n async resolve(key, executionId, callback) {\n await getPlatformWorkflow().resolve(executionId, key, callback);\n },\n };\n}\n\n/**\n * Attach an invoker to a wait point definition so test doubles can intercept it.\n *\n * The slot itself is fixed once attached; a double swaps the invoker's `wait` /\n * `resolve` methods rather than the invoker object.\n * @param target - Wait point definition to attach to\n * @param invoker - Invoker the definition delegates to\n * @returns The same definition\n */\nexport function attachWaitPointInvoker<T extends object>(target: T, invoker: WaitPointInvoker): T {\n Object.defineProperty(target, WAIT_POINT_INVOKER, {\n value: invoker,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n return target;\n}\n\n/**\n * Read the invoker attached to a wait point definition.\n * @param target - Wait point definition to read from\n * @returns The attached invoker, or undefined when the value is not a wait point\n */\nexport function getWaitPointInvoker(target: object): WaitPointInvoker | undefined {\n return (target as Record<symbol, WaitPointInvoker | undefined>)[WAIT_POINT_INVOKER];\n}\n\n/**\n * Record the resolved key on a wait point bound by `.with()`.\n * @param target - Bound wait point to attach to\n * @param key - Resolved runtime key\n * @returns The same bound wait point\n */\nexport function attachWaitPointKey<T extends object>(target: T, key: string): T {\n Object.defineProperty(target, WAIT_POINT_KEY, {\n value: key,\n enumerable: false,\n configurable: false,\n writable: false,\n });\n return target;\n}\n\n/**\n * Read the resolved key recorded on a bound wait point.\n * @param target - Bound wait point to read from\n * @returns The resolved key, or undefined when the value is not a bound wait point\n */\nexport function getWaitPointKey(target: object): string | undefined {\n return (target as Record<symbol, string | undefined>)[WAIT_POINT_KEY];\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,MAAM,WAAW;AAOjB,IAAI;AAEJ,SAAS,yBAAwE;CAC/E,IAAI,CAAC,gBACH,iBAAiB,IAAI,kBAA0C;CAEjE,OAAO;AACT;;;;;;AAOA,SAAgB,sBAA6C;CAC3D,OAAQ,WAAgE;AAC1E;;;;;;AAOA,SAAgB,qBAAqB,KAAsB;CACzD,AAAC,WAAoD,YAAY;AACnE;;;;;AAMA,SAAgB,uBAA6B;CAC3C,OAAQ,WAAkD;AAC5D;AAEA,SAAgB,wBAA2B,SAAiC,KAAiB;CAC3F,OAAO,uBAAuB,CAAC,CAAC,IAAI,SAAS,GAAG;AAClD;AAWA,SAAS,qBAA6C;CACpD,MAAM,UACJ,WAGA,QAAQ,SAAS;CACnB,MAAM,MAAM,UAAU;CACtB,IAAI,CAAC,KAAK,OAAO;CACjB,OAAO;EACL,IAAI,IAAI;EACR,MAAM,IAAI;EACV,aAAa,IAAI;EACjB,YAAY,IAAI,iBAAiB,MAAM,QAAQ,IAAI,UAAU,IAAI,CAAC,IAAK,IAAI,cAAc,CAAC;EAC1F,eAAgB,IAAI,kBACjB,MAAM,QAAQ,IAAI,UAAU,IAAI,IAAI,aAAa,CAAC;CACvD;AACF;AAGA,SAAgB,kBAAuE;CACrF,MAAM,gBAAgB,gBAAgB,SAAS;CAC/C,MAAM,UAAU,kBAAkB,SAAY,mBAAmB,IAAI;CACrE,MAAM,aAAa,oBAAoB;CACvC,IAAI,eAAe,QAAW,OAAO;EAAE,KAAK,EAAE,GAAG,WAAW;EAAG;CAAQ;CACvE,OAAO;EAAE,KAAK,CAAC;EAAgB;CAAQ;AACzC;;;;ACzFA,MAAM,qBAAoC,OAAO,IAAI,wCAAwC;AAC7F,MAAM,iBAAgC,OAAO,IAAI,oCAAoC;AAYrF,SAAS,sBAA2C;CAElD,MAAM,WAAWA,WAAS,QAAQ;CAClC,IAAI,CAAC,UACH,MAAM,IAAI,MACR,oLAEF;CAEF,OAAO;AACT;;;;;AAMA,SAAgB,yBAA2C;CACzD,OAAO;EACL,KAAK,KAAK,SAAS;GACjB,OAAO,oBAAoB,CAAC,CAAC,KAAK,KAAK,OAAO;EAChD;EACA,MAAM,QAAQ,KAAK,aAAa,UAAU;GACxC,MAAM,oBAAoB,CAAC,CAAC,QAAQ,aAAa,KAAK,QAAQ;EAChE;CACF;AACF;;;;;;;;;;AAWA,SAAgB,uBAAyC,QAAW,SAA8B;CAChG,OAAO,eAAe,QAAQ,oBAAoB;EAChD,OAAO;EACP,YAAY;EACZ,cAAc;EACd,UAAU;CACZ,CAAC;CACD,OAAO;AACT;;;;;;AAOA,SAAgB,oBAAoB,QAA8C;CAChF,OAAQ,OAAwD;AAClE;;;;;;;AAQA,SAAgB,mBAAqC,QAAW,KAAgB;CAC9E,OAAO,eAAe,QAAQ,gBAAgB;EAC5C,OAAO;EACP,YAAY;EACZ,cAAc;EACd,UAAU;CACZ,CAAC;CACD,OAAO;AACT;;;;;;AAOA,SAAgB,gBAAgB,QAAoC;CAClE,OAAQ,OAA8C;AACxD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/utils/wait-point-registry.ts
|
|
2
|
+
const WAIT_POINT_REGISTRY_KEY = Symbol.for("tailor-platform/sdk:wait-point-registry");
|
|
3
|
+
function registry() {
|
|
4
|
+
const g = globalThis;
|
|
5
|
+
let state = g[WAIT_POINT_REGISTRY_KEY];
|
|
6
|
+
if (!state) {
|
|
7
|
+
state = {
|
|
8
|
+
entries: [],
|
|
9
|
+
scopeStart: 0
|
|
10
|
+
};
|
|
11
|
+
g[WAIT_POINT_REGISTRY_KEY] = state;
|
|
12
|
+
}
|
|
13
|
+
return state;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Record a declared wait point key so the CLI can check it against the key
|
|
17
|
+
* rules once the declaring module has loaded.
|
|
18
|
+
* @param entry - The key and the declaration it came from
|
|
19
|
+
*/
|
|
20
|
+
function registerWaitPoint(entry) {
|
|
21
|
+
registry().entries.push(entry);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Start a scope here, so what a run declares can be told apart from what an
|
|
25
|
+
* earlier one left behind.
|
|
26
|
+
*
|
|
27
|
+
* The registry is process-wide, and a run that fails partway still leaves its
|
|
28
|
+
* keys in it. Without a scope, a second run in the same process would be judged
|
|
29
|
+
* on the first run's keys as well as its own.
|
|
30
|
+
*/
|
|
31
|
+
function beginWaitPointScope() {
|
|
32
|
+
const state = registry();
|
|
33
|
+
state.scopeStart = state.entries.length;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read the wait points declared since {@link beginWaitPointScope}, or every one
|
|
37
|
+
* of them when no scope was started.
|
|
38
|
+
* @returns The wait points registered in the current scope, in declaration order
|
|
39
|
+
*/
|
|
40
|
+
function getScopedWaitPoints() {
|
|
41
|
+
const state = registry();
|
|
42
|
+
return state.entries.slice(state.scopeStart);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { getScopedWaitPoints as n, registerWaitPoint as r, beginWaitPointScope as t };
|
|
47
|
+
//# sourceMappingURL=wait-point-registry-TL99zotw.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wait-point-registry-TL99zotw.mjs","names":[],"sources":["../src/utils/wait-point-registry.ts"],"sourcesContent":["/**\n * How a wait point key reached the SDK. The declaration decides what the key\n * may contain: only `define` sees the key as a literal type, so only it can\n * type the `$params` a key carries.\n */\nexport type WaitPointDeclaration = \"createWaitPoint\" | \"define\" | \"property\";\n\n/** A wait point key as declared, before the deploy-time key rules run. */\nexport interface RegisteredWaitPoint {\n key: string;\n declaredBy: WaitPointDeclaration;\n}\n\nconst WAIT_POINT_REGISTRY_KEY: unique symbol = Symbol.for(\n \"tailor-platform/sdk:wait-point-registry\",\n);\n\ninterface Registry {\n entries: RegisteredWaitPoint[];\n scopeStart: number;\n}\n\ntype GlobalWithRegistry = typeof globalThis & {\n [WAIT_POINT_REGISTRY_KEY]?: Registry;\n};\n\nfunction registry(): Registry {\n const g = globalThis as GlobalWithRegistry;\n let state = g[WAIT_POINT_REGISTRY_KEY];\n if (!state) {\n state = { entries: [], scopeStart: 0 };\n g[WAIT_POINT_REGISTRY_KEY] = state;\n }\n return state;\n}\n\n/**\n * Record a declared wait point key so the CLI can check it against the key\n * rules once the declaring module has loaded.\n * @param entry - The key and the declaration it came from\n */\nexport function registerWaitPoint(entry: RegisteredWaitPoint): void {\n registry().entries.push(entry);\n}\n\n/**\n * Read every wait point declared by the modules loaded so far.\n * @returns The registered wait points, in declaration order\n */\nexport function getRegisteredWaitPoints(): readonly RegisteredWaitPoint[] {\n return registry().entries;\n}\n\n/**\n * Start a scope here, so what a run declares can be told apart from what an\n * earlier one left behind.\n *\n * The registry is process-wide, and a run that fails partway still leaves its\n * keys in it. Without a scope, a second run in the same process would be judged\n * on the first run's keys as well as its own.\n */\nexport function beginWaitPointScope(): void {\n const state = registry();\n state.scopeStart = state.entries.length;\n}\n\n/**\n * Read the wait points declared since {@link beginWaitPointScope}, or every one\n * of them when no scope was started.\n * @returns The wait points registered in the current scope, in declaration order\n */\nexport function getScopedWaitPoints(): readonly RegisteredWaitPoint[] {\n const state = registry();\n return state.entries.slice(state.scopeStart);\n}\n\n/**\n * Drop everything registered after a mark, where the mark is the length\n * {@link getRegisteredWaitPoints} returned earlier.\n *\n * The registry is process-wide, so a test that declares a key `deploy` rejects\n * would otherwise leave it for the deploy-time check another test file runs.\n * Nothing outside a test needs this: a CLI run declares one project's keys and\n * checks all of them.\n * @param mark - The registry length to return to\n */\nexport function restoreWaitPointRegistry(mark: number): void {\n const state = registry();\n state.entries.length = mark;\n if (state.scopeStart > mark) state.scopeStart = mark;\n}\n"],"mappings":";AAaA,MAAM,0BAAyC,OAAO,IACpD,yCACF;AAWA,SAAS,WAAqB;CAC5B,MAAM,IAAI;CACV,IAAI,QAAQ,EAAE;CACd,IAAI,CAAC,OAAO;EACV,QAAQ;GAAE,SAAS,CAAC;GAAG,YAAY;EAAE;EACrC,EAAE,2BAA2B;CAC/B;CACA,OAAO;AACT;;;;;;AAOA,SAAgB,kBAAkB,OAAkC;CAClE,SAAS,CAAC,CAAC,QAAQ,KAAK,KAAK;AAC/B;;;;;;;;;AAkBA,SAAgB,sBAA4B;CAC1C,MAAM,QAAQ,SAAS;CACvB,MAAM,aAAa,MAAM,QAAQ;AACnC;;;;;;AAOA,SAAgB,sBAAsD;CACpE,MAAM,QAAQ,SAAS;CACvB,OAAO,MAAM,QAAQ,MAAM,MAAM,UAAU;AAC7C"}
|
package/docs/cli/setup.md
CHANGED
|
@@ -4,7 +4,7 @@ Commands for setting up project infrastructure.
|
|
|
4
4
|
|
|
5
5
|
## setup
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Set up repository automation for your project. (beta)
|
|
8
8
|
|
|
9
9
|
**Usage**
|
|
10
10
|
|
|
@@ -23,6 +23,7 @@ See [Global Options](../cli-reference.md#global-options) for options available t
|
|
|
23
23
|
| [`setup preview`](#setup-preview) | Generate a preview workflow (PR open/sync triggers deploy to a per-PR workspace). |
|
|
24
24
|
| [`setup action`](#setup-action) | Generate a per-app composite action for use with setup coordinate (monorepo multi-app deploys). |
|
|
25
25
|
| [`setup coordinate`](#setup-coordinate) | Generate a coordinator workflow that orchestrates multiple --action-generated composite actions. |
|
|
26
|
+
| [`setup renovate`](#setup-renovate) | Generate a Renovate config for Tailor dependency and workflow updates. |
|
|
26
27
|
| [`setup check`](#setup-check) | Audit generated workflows for drift against the current config/repo (read-only). |
|
|
27
28
|
| [`setup delete`](#setup-delete) | Delete managed workflow/action file(s) and their .github/tailor.lock entries. |
|
|
28
29
|
|
|
@@ -159,6 +160,18 @@ tailor setup preview [options]
|
|
|
159
160
|
|
|
160
161
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
161
162
|
|
|
163
|
+
### setup renovate
|
|
164
|
+
|
|
165
|
+
Generate a Renovate config for Tailor dependency and workflow updates.
|
|
166
|
+
|
|
167
|
+
**Usage**
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
tailor setup renovate
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
174
|
+
|
|
162
175
|
### setup tag
|
|
163
176
|
|
|
164
177
|
Generate a tag-target deploy workflow (tag push triggers deploy).
|
package/docs/cli/tailordb.md
CHANGED
|
@@ -119,12 +119,15 @@ tailor tailordb migration generate [options]
|
|
|
119
119
|
|
|
120
120
|
**Options**
|
|
121
121
|
|
|
122
|
-
| Option
|
|
123
|
-
|
|
|
124
|
-
| `--yes`
|
|
125
|
-
| `--config <CONFIG>`
|
|
126
|
-
| `--name <NAME>`
|
|
127
|
-
| `--init`
|
|
122
|
+
| Option | Alias | Description | Required | Default | Env |
|
|
123
|
+
| ------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------- | -------------------- |
|
|
124
|
+
| `--yes` | `-y` | Skip confirmation prompts | No | `false` | - |
|
|
125
|
+
| `--config <CONFIG>` | `-c` | Path to Tailor config file | No | `"tailor.config.ts"` | `TAILOR_CONFIG_PATH` |
|
|
126
|
+
| `--name <NAME>` | `-n` | Optional description for the migration | No | - | - |
|
|
127
|
+
| `--init` | - | Delete existing migrations and start fresh | No | `false` | - |
|
|
128
|
+
| `--rename <RENAME>` | - | Record a field or type rename instead of remove + add (format: "Type.oldField:newField" or "OldType:NewType"; repeatable). Renames require a migration script that copies the data. | No | - | - |
|
|
129
|
+
| `--drop <DROP>` | - | Confirm that a removed field or type is a genuine removal, not a rename (format: "Type.field" or "Type"; repeatable). Required in non-interactive runs for a removal with rename candidates. | No | - | - |
|
|
130
|
+
| `--expand-contract <EXPAND_CONTRACT>` | - | Convert a field type through a temporary field (format: "Type.field"; repeatable). Generates two migrations. | No | - | - |
|
|
128
131
|
|
|
129
132
|
See [Global Options](../cli-reference.md#global-options) for options available to all commands.
|
|
130
133
|
|
package/docs/cli-reference.md
CHANGED
|
@@ -391,13 +391,14 @@ Commands for setting up project infrastructure.
|
|
|
391
391
|
|
|
392
392
|
| Command | Description |
|
|
393
393
|
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
|
|
394
|
-
| [setup](./cli/setup.md#setup) |
|
|
394
|
+
| [setup](./cli/setup.md#setup) | Set up repository automation for your project. (beta) |
|
|
395
395
|
| [setup action](./cli/setup.md#setup-action) | Generate a per-app composite action for use with setup coordinate (monorepo multi-app deploys). |
|
|
396
396
|
| [setup branch](./cli/setup.md#setup-branch) | Generate a branch-target deploy workflow (push to branch triggers deploy). |
|
|
397
397
|
| [setup check](./cli/setup.md#setup-check) | Audit generated workflows for drift against the current config/repo (read-only). |
|
|
398
398
|
| [setup coordinate](./cli/setup.md#setup-coordinate) | Generate a coordinator workflow that orchestrates multiple --action-generated composite actions. |
|
|
399
399
|
| [setup delete](./cli/setup.md#setup-delete) | Delete managed workflow/action file(s) and their .github/tailor.lock entries. |
|
|
400
400
|
| [setup preview](./cli/setup.md#setup-preview) | Generate a preview workflow (PR open/sync triggers deploy to a per-PR workspace). |
|
|
401
|
+
| [setup renovate](./cli/setup.md#setup-renovate) | Generate a Renovate config for Tailor dependency and workflow updates. |
|
|
401
402
|
| [setup tag](./cli/setup.md#setup-tag) | Generate a tag-target deploy workflow (tag push triggers deploy). |
|
|
402
403
|
|
|
403
404
|
### [Upgrade Commands](./cli/upgrade.md)
|
package/docs/github-actions.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# GitHub Actions Integration
|
|
2
2
|
|
|
3
|
-
`tailor setup` generates
|
|
4
|
-
|
|
3
|
+
`tailor setup` generates GitHub repository automation for your Tailor Platform
|
|
4
|
+
application, including deploy workflows and Renovate configuration.
|
|
5
5
|
|
|
6
6
|
> **Beta:** This command is under active development. CLI flags, the generated
|
|
7
7
|
> workflow, and the `.github/tailor.lock` schema may change before general
|
|
@@ -14,16 +14,13 @@ lives):
|
|
|
14
14
|
|
|
15
15
|
```bash
|
|
16
16
|
# Branch target: deploy to stg on every push to main
|
|
17
|
-
tailor setup
|
|
17
|
+
tailor setup branch --name my-app-stg
|
|
18
18
|
|
|
19
19
|
# Tag target: deploy to production when a tag is pushed, with an approval gate
|
|
20
|
-
tailor setup
|
|
21
|
-
--
|
|
20
|
+
tailor setup tag --name my-app-prod \
|
|
21
|
+
--branch main --environment production
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
`setup` defaults to the GitHub provider; `--provider github` (`-p github`) is
|
|
25
|
-
accepted but optional, and other providers are not yet supported.
|
|
26
|
-
|
|
27
24
|
After running the command, follow the **Next steps** printed to the terminal to
|
|
28
25
|
set the required secrets, set the `TAILOR_PLATFORM_WORKSPACE_ID` variable, and
|
|
29
26
|
commit the generated files.
|
|
@@ -44,9 +41,9 @@ The branch target fires on pull requests and pushes to the branch you specify
|
|
|
44
41
|
(defaulting to the repository's default branch when `--branch` is omitted):
|
|
45
42
|
|
|
46
43
|
```bash
|
|
47
|
-
tailor setup
|
|
44
|
+
tailor setup branch --name my-app-stg
|
|
48
45
|
# Equivalent to:
|
|
49
|
-
tailor setup
|
|
46
|
+
tailor setup branch --name my-app-stg --branch main
|
|
50
47
|
```
|
|
51
48
|
|
|
52
49
|
What it does:
|
|
@@ -69,7 +66,7 @@ Pass `--erd-preview` on a branch target to add TailorDB ERD preview artifacts
|
|
|
69
66
|
to pull requests:
|
|
70
67
|
|
|
71
68
|
```bash
|
|
72
|
-
tailor setup
|
|
69
|
+
tailor setup branch --name my-app-stg --erd-preview
|
|
73
70
|
```
|
|
74
71
|
|
|
75
72
|
The generated workflow runs `tailor tailordb erd`, which is provided by the
|
|
@@ -90,11 +87,10 @@ ERD preview does not use Tailor Platform credentials. Fork pull requests still
|
|
|
90
87
|
build artifacts, but the comment step is skipped because fork tokens cannot
|
|
91
88
|
write PR comments.
|
|
92
89
|
|
|
93
|
-
`--erd-preview` is only available for branch targets
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
all-added or all-removed viewer artifacts. Re-run `setup` after adding or
|
|
90
|
+
`--erd-preview` is only available for branch targets. The namespace list is
|
|
91
|
+
recorded in `.github/tailor.lock`; the pull request workflow compares the head
|
|
92
|
+
and base lock files so newly added or removed namespaces can still produce
|
|
93
|
+
all-added or all-removed viewer artifacts. Re-run `setup branch` after adding or
|
|
98
94
|
removing TailorDB namespaces. `setup check` reports drift when the recorded ERD
|
|
99
95
|
preview namespaces no longer match the current config.
|
|
100
96
|
|
|
@@ -104,8 +100,8 @@ The tag target fires when a tag matching `--tag-pattern` (default `v*`) is
|
|
|
104
100
|
pushed:
|
|
105
101
|
|
|
106
102
|
```bash
|
|
107
|
-
tailor setup
|
|
108
|
-
--tag
|
|
103
|
+
tailor setup tag --name my-app-prod \
|
|
104
|
+
--tag-pattern "v*" --branch main --environment production
|
|
109
105
|
```
|
|
110
106
|
|
|
111
107
|
What it does:
|
|
@@ -131,7 +127,7 @@ What it does:
|
|
|
131
127
|
| Branch | The branch that triggers the workflow (push + PR base). Defaults to the repo's default branch. |
|
|
132
128
|
| Tag | The branch whose history the tag must be reachable from. Omit to disable the guard entirely. |
|
|
133
129
|
|
|
134
|
-
The workspace name (`--
|
|
130
|
+
The workspace name (`--name`, or the config `name` when omitted) must
|
|
135
131
|
be 3–63 characters of lowercase letters, numbers, and hyphens, and cannot start
|
|
136
132
|
or end with a hyphen. It is used for the generated file name, the workflow
|
|
137
133
|
`name:`, the plan label, and the default GitHub Environment name; it does not
|
|
@@ -174,7 +170,7 @@ environment is planned.)
|
|
|
174
170
|
|
|
175
171
|
## Generated files
|
|
176
172
|
|
|
177
|
-
Running
|
|
173
|
+
Running a workflow setup subcommand creates or updates:
|
|
178
174
|
|
|
179
175
|
### `.github/workflows/tailor-<workspace-name>.yml`
|
|
180
176
|
|
|
@@ -276,7 +272,7 @@ you can deploy any commit regardless of branch membership.
|
|
|
276
272
|
For a monorepo where your SDK app lives in a subdirectory, pass `--dir`:
|
|
277
273
|
|
|
278
274
|
```bash
|
|
279
|
-
tailor setup
|
|
275
|
+
tailor setup branch --name my-app --dir apps/backend
|
|
280
276
|
```
|
|
281
277
|
|
|
282
278
|
The generated workflow adds a `paths` filter on `apps/backend/**` so the
|
|
@@ -341,11 +337,11 @@ A typical setup with staging and production:
|
|
|
341
337
|
|
|
342
338
|
```bash
|
|
343
339
|
# Staging: main → stg (deploy on every push to main)
|
|
344
|
-
tailor setup
|
|
340
|
+
tailor setup branch --name my-app-stg
|
|
345
341
|
|
|
346
342
|
# Production: tagged commits → prod, with approval gate and branch guard
|
|
347
|
-
tailor setup
|
|
348
|
-
--
|
|
343
|
+
tailor setup tag --name my-app-prod \
|
|
344
|
+
--branch main --environment production
|
|
349
345
|
```
|
|
350
346
|
|
|
351
347
|
Then provision each workspace and set its id on the matching environment (the
|
|
@@ -364,6 +360,41 @@ gh secret set TAILOR_PLATFORM_MACHINE_USER_CLIENT_SECRET --env production
|
|
|
364
360
|
|
|
365
361
|
Commit both workflow files and `.github/tailor.lock`.
|
|
366
362
|
|
|
363
|
+
## Keeping dependencies and actions updated
|
|
364
|
+
|
|
365
|
+
Run this command once from the repository root to add Renovate configuration:
|
|
366
|
+
|
|
367
|
+
```bash
|
|
368
|
+
tailor setup renovate
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
It generates `renovate.json`, which extends Tailor's shared Renovate preset. The
|
|
372
|
+
preset groups `@tailor-platform/*` package updates into one pull request and
|
|
373
|
+
lets Renovate update the SHA-pinned GitHub Actions used by generated workflows.
|
|
374
|
+
Enable Renovate for the repository by following the
|
|
375
|
+
[Renovate onboarding guide](https://docs.renovatebot.com/getting-started/installing-onboarding/),
|
|
376
|
+
then commit the generated file.
|
|
377
|
+
|
|
378
|
+
If the repository already has Renovate configuration, the command adds
|
|
379
|
+
`github>tailor-inc/renovate-config` to its `extends` array in place instead of
|
|
380
|
+
writing a new file, leaving your other settings untouched. It checks Renovate's
|
|
381
|
+
standard root, `.github`, `.gitlab`, and `.renovaterc` locations, including the
|
|
382
|
+
deprecated `package.json` configuration. When that configuration already extends
|
|
383
|
+
the preset, the command reports that Renovate is set up and changes nothing.
|
|
384
|
+
|
|
385
|
+
Configuration written in JSON5 or JSONC — with comments or trailing commas —
|
|
386
|
+
cannot be edited without losing those comments, so the command leaves it
|
|
387
|
+
unchanged and asks you to add the preset to its `extends` array yourself.
|
|
388
|
+
|
|
389
|
+
`renovate.json` is yours to edit — it is not tracked in `.github/tailor.lock`.
|
|
390
|
+
Add your own rules freely; re-running `tailor setup renovate` does not overwrite
|
|
391
|
+
them. To remove it, delete the file.
|
|
392
|
+
|
|
393
|
+
Renovate updates the SDK dependency and action pins, but it does not regenerate
|
|
394
|
+
the workflow template. After an SDK update, `tailor setup check --ci` reports a
|
|
395
|
+
template-version warning until you re-run the relevant workflow setup
|
|
396
|
+
subcommand.
|
|
397
|
+
|
|
367
398
|
## Checking for drift
|
|
368
399
|
|
|
369
400
|
`tailor setup check` audits the workflows recorded in
|
|
@@ -374,12 +405,26 @@ newer template is available, `tailor.config.ts` is no longer under the recorded
|
|
|
374
405
|
trigger. It exits non-zero when it finds drift, so you can run it in CI. Each
|
|
375
406
|
finding names a stable rule key for future suppression.
|
|
376
407
|
|
|
408
|
+
Workflows generated by `setup branch`, `setup tag`, `setup preview`, and
|
|
409
|
+
`setup coordinate` self-audit: each contains a `tailor-drift-check` step that
|
|
410
|
+
runs the check in CI. Preview workflows run it alongside each preview deploy,
|
|
411
|
+
so pull requests that deploy no preview (drafts, fork PRs, and unlabeled PRs
|
|
412
|
+
in label-triggered mode) skip the check. A single run audits every target
|
|
413
|
+
recorded in `.github/tailor.lock`, so per-app composite actions generated by
|
|
414
|
+
`setup action` are covered by their coordinator's step and do not carry one of
|
|
415
|
+
their own.
|
|
416
|
+
|
|
417
|
+
Drift findings are advisory by default. Set the repository variable
|
|
418
|
+
`TAILOR_PLATFORM_FAIL_ON_DRIFT` to `true` to make unsuppressed findings fail
|
|
419
|
+
the job. Execution and configuration errors fail regardless of this variable.
|
|
420
|
+
|
|
377
421
|
## Updating the generated workflow
|
|
378
422
|
|
|
379
|
-
When you upgrade the SDK, re-run
|
|
380
|
-
template improvements. If the SDK detects that you
|
|
381
|
-
section, it stops and asks you to use `--force` to
|
|
382
|
-
move your customizations into your own steps before
|
|
423
|
+
When you upgrade the SDK, re-run the relevant workflow setup subcommand with
|
|
424
|
+
the same flags to pick up template improvements. If the SDK detects that you
|
|
425
|
+
have hand-edited a managed section, it stops and asks you to use `--force` to
|
|
426
|
+
overwrite your edits, or to move your customizations into your own steps before
|
|
427
|
+
regenerating.
|
|
383
428
|
|
|
384
429
|
The `.github/tailor.lock` file records the flags used at generation time,
|
|
385
430
|
so you can check what arguments were used previously.
|
package/docs/migration/v2.md
CHANGED
|
@@ -8,6 +8,60 @@ Run the codemods, then finish anything reported as not migrated automatically:
|
|
|
8
8
|
npx @tailor-platform/sdk-codemod --from <current-version> --to <target-version>
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
+
## Type-only imports → `import type`
|
|
12
|
+
|
|
13
|
+
**Migration:** Manual
|
|
14
|
+
|
|
15
|
+
The v2 CLI runs TypeScript by stripping types from each file in isolation,
|
|
16
|
+
with no cross-file type information. A plain (non-`type`) import of a
|
|
17
|
+
type-only export therefore survives stripping and fails when the module
|
|
18
|
+
loads:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
SyntaxError: The requested module './types.ts' does not provide an export named 'Row'
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`tailor generate` / `tailor deploy` stop at this error before doing any work.
|
|
25
|
+
Import types with `import type` (or the inline `type` modifier), and
|
|
26
|
+
re-export them with `export type`, in every module the CLI loads. Generated
|
|
27
|
+
Kysely types (`DB`, `Insertable`, `Selectable`, table row types) are almost
|
|
28
|
+
entirely type-only, so v1 projects typically hit this in many files at once.
|
|
29
|
+
Set `"verbatimModuleSyntax": true` in tsconfig.json to catch every violation
|
|
30
|
+
at typecheck; projects scaffolded by v2 `tailor init` enable it by default.
|
|
31
|
+
|
|
32
|
+
Before:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { DB, getDB } from "./generated/db";
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
After:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { type DB, getDB } from "./generated/db";
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
<details>
|
|
45
|
+
<summary>Prompt for an AI agent (to perform this migration)</summary>
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
In Tailor SDK v2 the CLI loads TypeScript by stripping types from each file
|
|
49
|
+
in isolation, so type-only exports do not exist at runtime and plain imports
|
|
50
|
+
of them fail to load with "does not provide an export named '<name>'".
|
|
51
|
+
Migrate the project so every type-only import and re-export is marked:
|
|
52
|
+
|
|
53
|
+
1. Add `"verbatimModuleSyntax": true` to compilerOptions in tsconfig.json.
|
|
54
|
+
2. Run `tsc --noEmit` and fix every reported violation: add the `type`
|
|
55
|
+
modifier to type-only named imports (`import type { Row }` or
|
|
56
|
+
`import { type Row, marker }`) and change type-only re-exports to
|
|
57
|
+
`export type { ... }`.
|
|
58
|
+
|
|
59
|
+
Only add `type` modifiers; do not reorder, remove, or otherwise change
|
|
60
|
+
imports that are used as values.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
</details>
|
|
64
|
+
|
|
11
65
|
## defineGenerators → definePlugins
|
|
12
66
|
|
|
13
67
|
**Migration:** Partially automatic
|