@tailor-platform/sdk-codemod 0.3.0-next.6 → 0.3.0-next.7
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 +35 -0
- package/dist/codemods/v2/workflow-trigger-rename/scripts/transform.js +122 -0
- package/dist/index.js +112 -20
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @tailor-platform/sdk-codemod
|
|
2
2
|
|
|
3
|
+
## 0.3.0-next.7
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1787](https://github.com/tailor-platform/sdk/pull/1787) [`898d0b0`](https://github.com/tailor-platform/sdk/commit/898d0b0f809d15ea883a32a78a247eda4ca7caa7) Thanks [@toiroakr](https://github.com/toiroakr)! - Fix `tailor upgrade` reporting zero codemods across several v2 prerelease boundaries. `v2/db-type-to-table` and `v2/runtime-subpath-namespace` now trigger at `2.0.0-next.4` (where they actually shipped) instead of `2.0.0-next.3`, and `v2/forward-relation-name`, `v2/tailordb-validate-simplify`, and `v2/tailordb-hook-redesign` now trigger at `2.0.0-next.5` instead of `2.0.0-next.4`.
|
|
8
|
+
|
|
9
|
+
- [#1787](https://github.com/tailor-platform/sdk/pull/1787) [`6653afd`](https://github.com/tailor-platform/sdk/commit/6653afd5a0be52f8c9a1dc6fa50e445f0f678dc0) Thanks [@toiroakr](https://github.com/toiroakr)! - Add a `V2_NEXT_PENDING` placeholder `prereleaseUntil` for codemods whose exact `2.0.0-next.N` release boundary isn't known yet at implementation time, plus a `pnpm codemod:resolve-pending` step (wired into the release workflow) that resolves it to the real version constant once the release PR bumps `@tailor-platform/sdk`'s version. Prevents codemod boundaries from drifting out of sync with the version they actually ship in, which previously required a manual follow-up fix after each release.
|
|
10
|
+
|
|
11
|
+
- [#1782](https://github.com/tailor-platform/sdk/pull/1782) [`c971797`](https://github.com/tailor-platform/sdk/commit/c971797c9bfa035a43771c46f2b1c3bd93f989a9) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename `Workflow.trigger()` (returned by `createWorkflow()`) and `WorkflowJob.trigger()` (returned by `createWorkflowJob()`) to `.start()`, aligning the SDK's ergonomic verb with the platform's `start*` RPC vocabulary:
|
|
12
|
+
|
|
13
|
+
```diff
|
|
14
|
+
const inventory = checkInventory.trigger({ orderId: input.orderId });
|
|
15
|
+
+const inventory = checkInventory.start({ orderId: input.orderId });
|
|
16
|
+
|
|
17
|
+
-const workflowRunId = await orderProcessingWorkflow.trigger(args, { invoker: "manager" });
|
|
18
|
+
+const workflowRunId = await orderProcessingWorkflow.start(args, { invoker: "manager" });
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
`mockWorkflow()`'s `wf.job(definition)` / `wf.workflow(definition)` now return a mock of the `.start` method, and `wf.setTriggerHandler` / `wf.triggeredJobs` are renamed to `wf.setStartHandler` / `wf.startedJobs`. No codemod ships for the `.trigger()` → `.start()` call-site rename itself — see the `v2/workflow-start-rename` migration guide entry for manual migration steps.
|
|
22
|
+
|
|
23
|
+
- [#1782](https://github.com/tailor-platform/sdk/pull/1782) [`c971797`](https://github.com/tailor-platform/sdk/commit/c971797c9bfa035a43771c46f2b1c3bd93f989a9) Thanks [@toiroakr](https://github.com/toiroakr)! - Remove the pre-alignment `tailor.workflow` names `triggerWorkflow`, `triggerJobFunction`, and `resumeWorkflow` (and their `TriggerWorkflowOptions` / `TriggerJobFunctionOptions` option types) from `@tailor-platform/sdk/runtime`, the ambient `@tailor-platform/sdk/runtime/globals` types, and the `mockWorkflow()` test facade. Use the canonical names instead:
|
|
24
|
+
|
|
25
|
+
```diff
|
|
26
|
+
import { workflow } from "@tailor-platform/sdk/runtime";
|
|
27
|
+
|
|
28
|
+
-await workflow.triggerWorkflow("myWorkflow", { data: "value" });
|
|
29
|
+
+await workflow.startWorkflow("myWorkflow", { data: "value" });
|
|
30
|
+
-workflow.triggerJobFunction("myJob", { data: "value" });
|
|
31
|
+
+workflow.startJobFunction("myJob", { data: "value" });
|
|
32
|
+
-await workflow.resumeWorkflow("execution-id");
|
|
33
|
+
+await workflow.resumeWorkflowExecution("execution-id");
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Run the `v2/workflow-trigger-rename` codemod to migrate call sites automatically.
|
|
37
|
+
|
|
3
38
|
## 0.3.0-next.6
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { c as localDeclarationNames, i as importBindings, r as findImportStatements } from "../../../ast-grep-helpers-CXtWn3RB.js";
|
|
2
|
+
import { Lang, parse } from "@ast-grep/napi";
|
|
3
|
+
//#region codemods/v2/workflow-trigger-rename/scripts/transform.ts
|
|
4
|
+
const RENAMES = {
|
|
5
|
+
triggerWorkflow: "startWorkflow",
|
|
6
|
+
triggerJobFunction: "startJobFunction",
|
|
7
|
+
resumeWorkflow: "resumeWorkflowExecution"
|
|
8
|
+
};
|
|
9
|
+
const WORKFLOW_MODULE_SOURCES = /* @__PURE__ */ new Set(["@tailor-platform/sdk/runtime", "@tailor-platform/sdk/runtime/workflow"]);
|
|
10
|
+
function quickFilter(source) {
|
|
11
|
+
return Object.keys(RENAMES).some((name) => source.includes(name));
|
|
12
|
+
}
|
|
13
|
+
function sourceLang(filePath, source) {
|
|
14
|
+
const lower = filePath.toLowerCase();
|
|
15
|
+
if (lower.endsWith(".tsx") || lower.endsWith(".jsx")) return Lang.Tsx;
|
|
16
|
+
return source.includes("</") || source.includes("/>") ? Lang.Tsx : Lang.TypeScript;
|
|
17
|
+
}
|
|
18
|
+
function collectWorkflowLocals(root, imports) {
|
|
19
|
+
const locals = /* @__PURE__ */ new Set();
|
|
20
|
+
for (const importStmt of imports) for (const binding of importBindings(importStmt)) if (binding.importedName === "workflow" && WORKFLOW_MODULE_SOURCES.has(binding.source)) locals.add(binding.localName);
|
|
21
|
+
const declaredNames = localDeclarationNames(root);
|
|
22
|
+
for (const name of locals) if (declaredNames.has(name)) locals.delete(name);
|
|
23
|
+
return locals;
|
|
24
|
+
}
|
|
25
|
+
function tailorIsAmbientGlobal(root, imports) {
|
|
26
|
+
if (localDeclarationNames(root).has("tailor")) return false;
|
|
27
|
+
return !imports.some((stmt) => importBindings(stmt).some((b) => b.localName === "tailor"));
|
|
28
|
+
}
|
|
29
|
+
function isAmbientTailorWorkflow(object) {
|
|
30
|
+
if (!object || object.kind() !== "member_expression") return false;
|
|
31
|
+
const base = object.field("object");
|
|
32
|
+
const property = object.field("property");
|
|
33
|
+
return base?.kind() === "identifier" && base.text() === "tailor" && property?.text() === "workflow";
|
|
34
|
+
}
|
|
35
|
+
function expressionArguments(args) {
|
|
36
|
+
return args.children().filter((child) => ![
|
|
37
|
+
"(",
|
|
38
|
+
")",
|
|
39
|
+
","
|
|
40
|
+
].includes(child.kind()));
|
|
41
|
+
}
|
|
42
|
+
function thirdArgument(member) {
|
|
43
|
+
const call = member.parent();
|
|
44
|
+
if (call?.kind() !== "call_expression") return null;
|
|
45
|
+
const args = call.field("arguments");
|
|
46
|
+
if (!args) return null;
|
|
47
|
+
return expressionArguments(args)[2] ?? null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* A `triggerWorkflow(name, args, options)` call whose third argument is not a
|
|
51
|
+
* literal object (e.g. a variable), or is an object literal that spreads one
|
|
52
|
+
* (`{ ...rest }`), cannot be safely renamed: we cannot tell whether it carries
|
|
53
|
+
* an `invoker` key that also needs renaming to `authInvoker`, and renaming
|
|
54
|
+
* just the method name would erase the `triggerWorkflow` token that flags the
|
|
55
|
+
* call for manual review, while the option silently stops working at
|
|
56
|
+
* runtime. Such calls are left entirely unrenamed.
|
|
57
|
+
* @param member - The `.triggerWorkflow` member-expression node being considered
|
|
58
|
+
* @returns Whether the call must be skipped
|
|
59
|
+
*/
|
|
60
|
+
function hasUnsafeThirdArgument(member) {
|
|
61
|
+
const optionsArg = thirdArgument(member);
|
|
62
|
+
if (optionsArg === null) return false;
|
|
63
|
+
if (optionsArg.kind() !== "object") return true;
|
|
64
|
+
return optionsArg.children().some((child) => child.kind() === "spread_element");
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* `triggerWorkflow`'s removed SDK wrapper converted an `invoker` option to
|
|
68
|
+
* the platform's `authInvoker` shape before calling through; `startWorkflow`
|
|
69
|
+
* expects `authInvoker` directly. Build an edit renaming a literal `invoker`
|
|
70
|
+
* key (or shorthand) in the third argument of a `triggerWorkflow(...)` call
|
|
71
|
+
* being renamed to `startWorkflow`, so the option keeps working.
|
|
72
|
+
* @param member - The `.triggerWorkflow` member-expression node being renamed
|
|
73
|
+
* @returns An edit renaming the `invoker` key, or null when not applicable
|
|
74
|
+
*/
|
|
75
|
+
function findInvokerOptionEdit(member) {
|
|
76
|
+
const optionsArg = thirdArgument(member);
|
|
77
|
+
if (!optionsArg || optionsArg.kind() !== "object") return null;
|
|
78
|
+
for (const child of optionsArg.children()) if (child.kind() === "pair") {
|
|
79
|
+
const key = child.field("key");
|
|
80
|
+
if (key?.kind() === "property_identifier" && key.text() === "invoker") return key.replace("authInvoker");
|
|
81
|
+
} else if (child.kind() === "shorthand_property_identifier" && child.text() === "invoker") return child.replace("authInvoker: invoker");
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Rewrite `.triggerWorkflow(`, `.triggerJobFunction(`, and `.resumeWorkflow(`
|
|
86
|
+
* member accesses to their canonical `start*`/`resumeWorkflowExecution` names,
|
|
87
|
+
* either on the ambient `tailor.workflow` global or on a `workflow` value
|
|
88
|
+
* imported from `@tailor-platform/sdk/runtime(/workflow)`.
|
|
89
|
+
* @param source - File contents
|
|
90
|
+
* @param filePath - Absolute path to the file
|
|
91
|
+
* @returns Transformed source or null when nothing matched.
|
|
92
|
+
*/
|
|
93
|
+
function transform(source, filePath) {
|
|
94
|
+
if (!quickFilter(source)) return null;
|
|
95
|
+
const root = parse(sourceLang(filePath ?? "", source), source).root();
|
|
96
|
+
const imports = findImportStatements(root);
|
|
97
|
+
const workflowLocals = collectWorkflowLocals(root, imports);
|
|
98
|
+
const tailorIsAmbient = tailorIsAmbientGlobal(root, imports);
|
|
99
|
+
const edits = [];
|
|
100
|
+
for (const member of root.findAll({ rule: { kind: "member_expression" } })) {
|
|
101
|
+
const property = member.field("property");
|
|
102
|
+
if (!property || property.kind() !== "property_identifier") continue;
|
|
103
|
+
const newName = RENAMES[property.text()];
|
|
104
|
+
if (!newName) continue;
|
|
105
|
+
const object = member.field("object");
|
|
106
|
+
if (!object) continue;
|
|
107
|
+
const isWorkflowImportReceiver = object.kind() === "identifier" && workflowLocals.has(object.text());
|
|
108
|
+
const isAmbientReceiver = tailorIsAmbient && isAmbientTailorWorkflow(object);
|
|
109
|
+
if (!isWorkflowImportReceiver && !isAmbientReceiver) continue;
|
|
110
|
+
if (newName === "startWorkflow") {
|
|
111
|
+
if (hasUnsafeThirdArgument(member)) continue;
|
|
112
|
+
edits.push(property.replace(newName));
|
|
113
|
+
const invokerEdit = findInvokerOptionEdit(member);
|
|
114
|
+
if (invokerEdit) edits.push(invokerEdit);
|
|
115
|
+
} else edits.push(property.replace(newName));
|
|
116
|
+
}
|
|
117
|
+
if (edits.length === 0) return null;
|
|
118
|
+
const result = root.commitEdits(edits);
|
|
119
|
+
return result === source ? null : result;
|
|
120
|
+
}
|
|
121
|
+
//#endregion
|
|
122
|
+
export { transform as default };
|
package/dist/index.js
CHANGED
|
@@ -116,8 +116,9 @@ const RENAME_BIN_QUOTED_LEGACY_COMMAND_PATTERN = new RegExp([
|
|
|
116
116
|
].join(""));
|
|
117
117
|
const V2_NEXT_1 = "2.0.0-next.1";
|
|
118
118
|
const V2_NEXT_2 = "2.0.0-next.2";
|
|
119
|
-
const V2_NEXT_3 = "2.0.0-next.3";
|
|
120
119
|
const V2_NEXT_4 = "2.0.0-next.4";
|
|
120
|
+
const V2_NEXT_5 = "2.0.0-next.5";
|
|
121
|
+
const V2_NEXT_6 = "2.0.0-next.6";
|
|
121
122
|
/** All registered codemods, in registration order. */
|
|
122
123
|
const allCodemods = [
|
|
123
124
|
{
|
|
@@ -417,7 +418,7 @@ const allCodemods = [
|
|
|
417
418
|
{
|
|
418
419
|
id: "v2/auth-invoker-unwrap",
|
|
419
420
|
name: "auth.invoker(\"name\") → invoker: \"name\"",
|
|
420
|
-
description: "Rename statically identified SDK `authInvoker` options to `invoker`, replace `auth.invoker(\"name\")` there with the bare `\"name\"` string, and drop the `auth` import when no other reference remains. Ambiguous workflow `.
|
|
421
|
+
description: "Rename statically identified SDK `authInvoker` options to `invoker`, replace `auth.invoker(\"name\")` there with the bare `\"name\"` string, and drop the `auth` import when no other reference remains. Ambiguous workflow `.start()` calls are left for manual review. The `auth.invoker()` helper is removed in v2 because importing `auth` from `tailor.config.ts` into runtime files pulls Node-only modules into the bundle.",
|
|
421
422
|
since: "1.0.0",
|
|
422
423
|
until: "2.0.0",
|
|
423
424
|
prereleaseUntil: V2_NEXT_2,
|
|
@@ -450,8 +451,8 @@ const allCodemods = [
|
|
|
450
451
|
" machine user name string; platform/runtime authInvoker payloads still expect",
|
|
451
452
|
" the object form.",
|
|
452
453
|
"2. Rename remaining authInvoker option keys to invoker only for SDK resolver,",
|
|
453
|
-
" executor, workflow.
|
|
454
|
-
" payload keys such as tailor.workflow.
|
|
454
|
+
" executor, workflow.start(), or startWorkflow() options. Keep platform/runtime",
|
|
455
|
+
" payload keys such as tailor.workflow.startWorkflow(..., { authInvoker: ... }).",
|
|
455
456
|
"3. After removing every auth.invoker usage in a file, delete the now-unused auth",
|
|
456
457
|
" import (keeping it pulls Node-only config modules into runtime bundles); leave",
|
|
457
458
|
" the import if auth is still referenced elsewhere.",
|
|
@@ -502,7 +503,7 @@ const allCodemods = [
|
|
|
502
503
|
description: "Rewrite `@tailor-platform/sdk/runtime/*` namespace-star and flat value imports to self-named namespace imports, and aggregate `file.deleteFile` calls to `file.delete`. `TailorContextAPI` and `TailorWorkflowAPI` now describe SDK wrappers; direct platform globals use `PlatformContextAPI` and `PlatformWorkflowAPI`.",
|
|
503
504
|
since: "1.0.0",
|
|
504
505
|
until: "2.0.0",
|
|
505
|
-
prereleaseUntil:
|
|
506
|
+
prereleaseUntil: V2_NEXT_4,
|
|
506
507
|
scriptPath: "v2/runtime-subpath-namespace/scripts/transform.js",
|
|
507
508
|
filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
|
|
508
509
|
legacyPatterns: [
|
|
@@ -574,7 +575,7 @@ const allCodemods = [
|
|
|
574
575
|
description: "Rename TailorDB schema builder calls from `db.type()` to `db.table()`. TailorDB schema definitions now use table terminology in SDK projects.",
|
|
575
576
|
since: "1.0.0",
|
|
576
577
|
until: "2.0.0",
|
|
577
|
-
prereleaseUntil:
|
|
578
|
+
prereleaseUntil: V2_NEXT_4,
|
|
578
579
|
scriptPath: "v2/db-type-to-table/scripts/transform.js",
|
|
579
580
|
filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
|
|
580
581
|
legacyPatterns: ["db.type"],
|
|
@@ -600,7 +601,7 @@ const allCodemods = [
|
|
|
600
601
|
description: "Review TailorDB relations that omit `toward.as`. Their forward GraphQL field names now derive from the relation field name with a trailing `ID`, `Id`, or `id` removed, instead of from the target table name.",
|
|
601
602
|
since: "1.0.0",
|
|
602
603
|
until: "2.0.0",
|
|
603
|
-
prereleaseUntil:
|
|
604
|
+
prereleaseUntil: V2_NEXT_5,
|
|
604
605
|
scriptPath: "v2/forward-relation-name/scripts/transform.js",
|
|
605
606
|
filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
|
|
606
607
|
suspiciousPatterns: [
|
|
@@ -686,6 +687,54 @@ const allCodemods = [
|
|
|
686
687
|
after: "import { createWaitPoints } from \"@tailor-platform/sdk\";\n\nexport const { approval } = createWaitPoints((define) => ({\n approval: define<{ message: string }, { approved: boolean }>(),\n}));"
|
|
687
688
|
}]
|
|
688
689
|
},
|
|
690
|
+
{
|
|
691
|
+
id: "v2/workflow-trigger-rename",
|
|
692
|
+
name: "workflow.triggerWorkflow/triggerJobFunction/resumeWorkflow → startWorkflow/startJobFunction/resumeWorkflowExecution",
|
|
693
|
+
description: "Rename tailor.workflow call sites from the pre-alignment triggerWorkflow/triggerJobFunction/resumeWorkflow names to the canonical startWorkflow/startJobFunction/resumeWorkflowExecution names, on both the ambient tailor.workflow global and a workflow value imported from @tailor-platform/sdk/runtime(/workflow). For a renamed triggerWorkflow call, also renames a literal `invoker` option key to `authInvoker` — startWorkflow's options expect the platform shape directly, unlike the removed triggerWorkflow wrapper, which converted invoker to authInvoker internally.",
|
|
694
|
+
since: "1.0.0",
|
|
695
|
+
until: "2.0.0",
|
|
696
|
+
prereleaseUntil: V2_NEXT_6,
|
|
697
|
+
scriptPath: "v2/workflow-trigger-rename/scripts/transform.js",
|
|
698
|
+
filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
|
|
699
|
+
legacyPatterns: [
|
|
700
|
+
"triggerWorkflow",
|
|
701
|
+
"triggerJobFunction",
|
|
702
|
+
"resumeWorkflow"
|
|
703
|
+
],
|
|
704
|
+
examples: [{
|
|
705
|
+
before: "import { workflow } from \"@tailor-platform/sdk/runtime\";\n\nawait workflow.triggerWorkflow(\"myWorkflow\", { data: \"value\" });",
|
|
706
|
+
after: "import { workflow } from \"@tailor-platform/sdk/runtime\";\n\nawait workflow.startWorkflow(\"myWorkflow\", { data: \"value\" });"
|
|
707
|
+
}, {
|
|
708
|
+
caption: "A literal invoker option is renamed to authInvoker:",
|
|
709
|
+
before: "await workflow.triggerWorkflow(\"myWorkflow\", { data: \"value\" }, { invoker: myInvoker });",
|
|
710
|
+
after: "await workflow.startWorkflow(\"myWorkflow\", { data: \"value\" }, { authInvoker: myInvoker });"
|
|
711
|
+
}],
|
|
712
|
+
prompt: [
|
|
713
|
+
"The pre-alignment tailor.workflow names triggerWorkflow, triggerJobFunction, and",
|
|
714
|
+
"resumeWorkflow are removed from the SDK's type surface in v2; use the canonical",
|
|
715
|
+
"startWorkflow, startJobFunction, and resumeWorkflowExecution names instead. The",
|
|
716
|
+
"codemod rewrites direct member-access call sites on the ambient tailor.workflow",
|
|
717
|
+
"global and on a workflow value imported from @tailor-platform/sdk/runtime or",
|
|
718
|
+
"@tailor-platform/sdk/runtime/workflow (including aliased imports). It skips a",
|
|
719
|
+
"file entirely when a local declaration shadows the workflow import or the",
|
|
720
|
+
"ambient tailor name, to avoid rewriting an unrelated same-named value — review",
|
|
721
|
+
"those manually.",
|
|
722
|
+
"",
|
|
723
|
+
"For a renamed triggerWorkflow call, the codemod also renames a literal invoker",
|
|
724
|
+
"option key (including shorthand { invoker }) to authInvoker, since startWorkflow",
|
|
725
|
+
"expects the platform's authInvoker shape directly while triggerWorkflow's removed",
|
|
726
|
+
"wrapper converted invoker to authInvoker internally.",
|
|
727
|
+
"",
|
|
728
|
+
"Also review, and migrate by hand:",
|
|
729
|
+
"- Destructured references (e.g. const { triggerWorkflow } = workflow) — the",
|
|
730
|
+
" codemod only rewrites direct member-access calls.",
|
|
731
|
+
"- Imported TriggerWorkflowOptions / TriggerJobFunctionOptions types — rename",
|
|
732
|
+
" them to StartWorkflowOptions / StartJobFunctionOptions.",
|
|
733
|
+
"- An invoker option passed via a variable or spread (not a literal object) —",
|
|
734
|
+
" the codemod only inspects literal object arguments; rename the invoker key",
|
|
735
|
+
" to authInvoker in the options object's own definition."
|
|
736
|
+
].join("\n")
|
|
737
|
+
},
|
|
689
738
|
{
|
|
690
739
|
id: "v2/open-download-stream",
|
|
691
740
|
name: "openDownloadStream → downloadStream",
|
|
@@ -781,23 +830,57 @@ const allCodemods = [
|
|
|
781
830
|
},
|
|
782
831
|
{
|
|
783
832
|
id: "v2/workflow-trigger-dispatch",
|
|
784
|
-
name: "Workflow
|
|
785
|
-
description: "Workflow job `.trigger()` now aligns with the platform runtime: it returns the job result directly instead of a Promise wrapper, and tests no longer run job bodies locally. Mock
|
|
833
|
+
name: "Workflow job start() and start tests",
|
|
834
|
+
description: "Workflow job `.start()` (previously `.trigger()`) now aligns with the platform runtime: it returns the job result directly instead of a Promise wrapper, and tests no longer run job bodies locally. Mock start responses with `mockWorkflow()` (`setJobHandler` / `enqueueResult`, assert via `startedJobs`), or use `runWorkflowLocally()` for a full-chain local run.",
|
|
786
835
|
since: "1.0.0",
|
|
787
836
|
until: "2.0.0",
|
|
788
837
|
prereleaseUntil: V2_NEXT_1,
|
|
789
838
|
suspiciousPatterns: [".trigger("],
|
|
790
839
|
examples: [{
|
|
791
840
|
caption: "Tests must mock the workflow runtime instead of running bodies locally:",
|
|
792
|
-
before: "const result = await orderJob.
|
|
793
|
-
after: "using wf = mockWorkflow();\nwf.setJobHandler((jobName) => (jobName === \"order-job\" ? { status: \"done\" } : null));\nconst result = await orderJob.
|
|
841
|
+
before: "const result = await orderJob.start({ id });\nexpect(result.status).toBe(\"done\");",
|
|
842
|
+
after: "using wf = mockWorkflow();\nwf.setJobHandler((jobName) => (jobName === \"order-job\" ? { status: \"done\" } : null));\nconst result = await orderJob.start({ id });\nexpect(result.status).toBe(\"done\");"
|
|
794
843
|
}],
|
|
795
844
|
prompt: [
|
|
796
|
-
"Workflow job .
|
|
845
|
+
"Workflow job .start() now uses the platform workflow runtime instead of running",
|
|
797
846
|
"the job body locally. In tests, acquire `using wf = mockWorkflow()` and provide",
|
|
798
|
-
"
|
|
799
|
-
"full-chain local run; an unmocked
|
|
800
|
-
"
|
|
847
|
+
"start responses (setJobHandler / enqueueResult), or use runWorkflowLocally() for a",
|
|
848
|
+
"full-chain local run; an unmocked start now throws. Outside tests, treat the",
|
|
849
|
+
"start result as the job output directly (no Promise wrapper to unwrap)."
|
|
850
|
+
].join("\n")
|
|
851
|
+
},
|
|
852
|
+
{
|
|
853
|
+
id: "v2/workflow-start-rename",
|
|
854
|
+
name: "Workflow.trigger()/WorkflowJob.trigger() → .start()",
|
|
855
|
+
description: "Rename `Workflow.trigger()` (returned by `createWorkflow()`) and `WorkflowJob.trigger()` (returned by `createWorkflowJob()`) to `.start()`, aligning the SDK's ergonomic verb with the platform's `start*` RPC vocabulary. No codemod ships for this rename: distinguishing a workflow/job `.trigger()` call from an unrelated object's own `.trigger()` method requires resolving the receiver back to a `createWorkflow`/`createWorkflowJob` result across files, which the SDK's own CLI bundler already does for build-time rewriting. Reusing that logic in a standalone script is a nontrivial lift, and — unlike the bundler, which fails loudly when it cannot rewrite a call — a codemod false positive would silently rewrite an unrelated `.trigger()` call with no error. For the call-site volume this rename typically involves, manual review guided by the prompt below is the safer trade-off.",
|
|
856
|
+
since: "1.0.0",
|
|
857
|
+
until: "2.0.0",
|
|
858
|
+
prereleaseUntil: "2.0.0-next.7",
|
|
859
|
+
filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
|
|
860
|
+
suspiciousPatterns: [".trigger("],
|
|
861
|
+
examples: [{
|
|
862
|
+
before: ["const inventory = checkInventory.trigger({ orderId: input.orderId });", "const workflowRunId = await orderProcessingWorkflow.trigger(args, { invoker: \"manager\" });"].join("\n"),
|
|
863
|
+
after: ["const inventory = checkInventory.start({ orderId: input.orderId });", "const workflowRunId = await orderProcessingWorkflow.start(args, { invoker: \"manager\" });"].join("\n")
|
|
864
|
+
}],
|
|
865
|
+
prompt: [
|
|
866
|
+
"In Tailor SDK v2, the ergonomic .trigger() method on a createWorkflow() or",
|
|
867
|
+
"createWorkflowJob() result is renamed to .start(). This is unrelated to the",
|
|
868
|
+
"separate tailor.workflow.triggerWorkflow/triggerJobFunction/resumeWorkflow removal",
|
|
869
|
+
"(see the workflow-trigger-rename codemod) — this rename targets the SDK's own",
|
|
870
|
+
"ergonomic wrapper, not the low-level platform call.",
|
|
871
|
+
"",
|
|
872
|
+
"For each flagged `.trigger(` call in these files:",
|
|
873
|
+
"1. Confirm the receiver is a workflow or job object — typically a local const",
|
|
874
|
+
" assigned from createWorkflow(...)/createWorkflowJob(...), a named import of one,",
|
|
875
|
+
" or the default import of a workflow module. Skip receivers that are unrelated",
|
|
876
|
+
" objects with their own .trigger() method (state machines, event emitters, etc.).",
|
|
877
|
+
"2. Rename the call from .trigger(...) to .start(...); the argument list is unchanged.",
|
|
878
|
+
"3. Update any mock/test code that reads WorkflowJob['trigger'] / Workflow['trigger']",
|
|
879
|
+
" as a type, or that mocks the ergonomic method via a wrapper — for example,",
|
|
880
|
+
" `wf.job(definition)` / `wf.workflow(definition)` from mockWorkflow() now return a",
|
|
881
|
+
" mock of the `.start` method.",
|
|
882
|
+
"4. Update prose/docs/comments that say \"trigger the workflow/job\" to \"start\" only",
|
|
883
|
+
" where they describe this SDK verb specifically, not unrelated event terminology."
|
|
801
884
|
].join("\n")
|
|
802
885
|
},
|
|
803
886
|
{
|
|
@@ -898,7 +981,7 @@ const allCodemods = [
|
|
|
898
981
|
description: "Field-level `ValidateFn` is simplified from `(args: { value, data, invoker }) => boolean` to `(args: { value }) => string | void` — the function now returns the error message directly instead of a separate `[fn, message]` tuple. The `ValidateConfig` tuple form and `Validators<F>` record syntax on `db.type().validate()` are removed. Type-level validation uses `db.type().validate((args, issues) => void)` with `{ newRecord, oldRecord, invoker }` args and an `issues(field, message)` callback for cross-field rules.",
|
|
899
982
|
since: "1.0.0",
|
|
900
983
|
until: "2.0.0",
|
|
901
|
-
prereleaseUntil:
|
|
984
|
+
prereleaseUntil: V2_NEXT_5,
|
|
902
985
|
suspiciousPatterns: [
|
|
903
986
|
"ValidateConfig",
|
|
904
987
|
"Validators<",
|
|
@@ -944,7 +1027,7 @@ const allCodemods = [
|
|
|
944
1027
|
description: "Field-level `HookFn` args change from `{ value, data, invoker }` to create `{ input, invoker, now }` / update `{ input, oldValue, invoker, now }` — `value` is renamed to `input`, matching the `input` arg on type-level hooks (same pre-hook data, narrowed to one field); `data` (the full record) is removed; `oldValue` (previous field value) is added for update hooks only; `now` (operation timestamp) is shared across all hooks. Type-level hooks on `db.type().hooks()` change from per-field mapping `{ fieldName: { create, update } }` (`Hooks<F>`) to a single `{ create, update }` object (`TypeHook<F>`) — create hooks take `{ input, invoker, now }`, update hooks take `{ input, oldRecord, invoker, now }` (oldRecord is always non-null). Both return partial field overrides.",
|
|
945
1028
|
since: "1.0.0",
|
|
946
1029
|
until: "2.0.0",
|
|
947
|
-
prereleaseUntil:
|
|
1030
|
+
prereleaseUntil: V2_NEXT_5,
|
|
948
1031
|
suspiciousPatterns: [
|
|
949
1032
|
"Hooks<",
|
|
950
1033
|
"HookFn<",
|
|
@@ -994,7 +1077,7 @@ const allCodemods = [
|
|
|
994
1077
|
description: "Review and remove `tailor generate --watch` / `-W` invocations and the `watch` option on `GenerateOptions`. The flag, its dependency watcher, and the self-restart-on-change logic are removed; `generate` now always performs a single generation pass.",
|
|
995
1078
|
since: "1.0.0",
|
|
996
1079
|
until: "2.0.0",
|
|
997
|
-
prereleaseUntil:
|
|
1080
|
+
prereleaseUntil: V2_NEXT_6,
|
|
998
1081
|
filePatterns: [
|
|
999
1082
|
"**/package.json",
|
|
1000
1083
|
"**/*.{sh,bash,zsh,yml,yaml}",
|
|
@@ -1031,6 +1114,14 @@ const allCodemods = [
|
|
|
1031
1114
|
since: "1.0.0",
|
|
1032
1115
|
until: "2.0.0",
|
|
1033
1116
|
notice: true
|
|
1117
|
+
},
|
|
1118
|
+
{
|
|
1119
|
+
id: "v2/remove-legacy-bundle-cleanup",
|
|
1120
|
+
name: "Legacy bundle artifact cleanup removed from deploy",
|
|
1121
|
+
description: "`tailor deploy` no longer deletes on-disk bundle artifacts (`.entry.js` files, workflow-job bundles, and the `hooks-validate-scripts/` directory) left in the SDK output directory (`.tailor` by default) by SDK versions that predate the current in-memory bundling approach. Current bundlers no longer write these files. No source change is required; if such stale files remain from a very old SDK version, delete only those specific files/directories manually — do not delete the output directory itself, since it also holds deploy state (e.g. `secrets-state/`, `*.context.json`) that existing secrets and Auth Connections depend on.",
|
|
1122
|
+
since: "1.0.0",
|
|
1123
|
+
until: "2.0.0",
|
|
1124
|
+
notice: true
|
|
1034
1125
|
}
|
|
1035
1126
|
];
|
|
1036
1127
|
/**
|
|
@@ -1043,12 +1134,13 @@ function resolveCodemodScript(scriptPath) {
|
|
|
1043
1134
|
}
|
|
1044
1135
|
function reachesCodemodBoundary(toVersion, codemod) {
|
|
1045
1136
|
if (gte(toVersion, codemod.until)) return true;
|
|
1046
|
-
if (codemod.prereleaseUntil === void 0 || !gte(toVersion, codemod.prereleaseUntil)) return false;
|
|
1137
|
+
if (codemod.prereleaseUntil === void 0 || codemod.prereleaseUntil === "pending" || !gte(toVersion, codemod.prereleaseUntil)) return false;
|
|
1047
1138
|
const target = parse(toVersion);
|
|
1048
1139
|
const boundary = parse(codemod.until);
|
|
1049
1140
|
return target.prerelease.length > 0 && target.major === boundary.major && target.minor === boundary.minor && target.patch === boundary.patch;
|
|
1050
1141
|
}
|
|
1051
1142
|
function effectiveCodemodBoundary(codemod) {
|
|
1143
|
+
if (codemod.prereleaseUntil === "pending") return codemod.until;
|
|
1052
1144
|
return codemod.prereleaseUntil ?? codemod.until;
|
|
1053
1145
|
}
|
|
1054
1146
|
function assertCodemodBoundaries(codemods) {
|
|
@@ -1056,7 +1148,7 @@ function assertCodemodBoundaries(codemods) {
|
|
|
1056
1148
|
const boundary = parse(codemod.until);
|
|
1057
1149
|
if (boundary === null) throw new Error(`Codemod ${codemod.id} until must be a valid semver version: ${codemod.until}`);
|
|
1058
1150
|
if (boundary.prerelease.length > 0) throw new Error(`Codemod ${codemod.id} until must be a stable version: ${codemod.until}`);
|
|
1059
|
-
if (codemod.prereleaseUntil === void 0) continue;
|
|
1151
|
+
if (codemod.prereleaseUntil === void 0 || codemod.prereleaseUntil === "pending") continue;
|
|
1060
1152
|
const prereleaseBoundary = parse(codemod.prereleaseUntil);
|
|
1061
1153
|
if (prereleaseBoundary === null) throw new Error(`Codemod ${codemod.id} prereleaseUntil must be a valid semver version: ${codemod.prereleaseUntil}`);
|
|
1062
1154
|
if (prereleaseBoundary.prerelease.length === 0) throw new Error(`Codemod ${codemod.id} prereleaseUntil must be a prerelease version: ${codemod.prereleaseUntil}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/sdk-codemod",
|
|
3
|
-
"version": "0.3.0-next.
|
|
3
|
+
"version": "0.3.0-next.7",
|
|
4
4
|
"description": "Codemod runner for Tailor Platform SDK upgrades",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@types/semver": "7.7.1",
|
|
33
33
|
"eslint-plugin-zod": "4.7.0",
|
|
34
34
|
"oxlint": "1.73.0",
|
|
35
|
-
"tsdown": "0.22.
|
|
35
|
+
"tsdown": "0.22.7",
|
|
36
36
|
"typescript": "6.0.3",
|
|
37
37
|
"vitest": "4.1.10"
|
|
38
38
|
},
|