@tailor-platform/sdk-codemod 0.4.0-next.9 → 0.4.1
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 +280 -0
- package/dist/codemods/v2/exec-job-function-rename/scripts/transform.js +95 -0
- package/dist/codemods/v2/idp-publish-events-rename/scripts/transform.js +186 -0
- package/dist/codemods/v2/sdk-skills-shim/scripts/transform.js +4 -3
- package/dist/codemods/v2/seed-exec-to-cli-plugin/scripts/transform.js +125 -0
- package/dist/codemods/v2/workflow-trigger-rename/scripts/transform.js +3 -2
- package/dist/index.js +264 -12
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,277 @@
|
|
|
1
1
|
# @tailor-platform/sdk-codemod
|
|
2
2
|
|
|
3
|
+
## 0.4.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1957](https://github.com/tailor-platform/sdk/pull/1957) [`a465547`](https://github.com/tailor-platform/sdk/commit/a465547df712ca8c607c1e42cf12c15fe3e830d1) Thanks [@toiroakr](https://github.com/toiroakr)! - Invoke the CLI as `npx @tailor-platform/sdk <command>` wherever an invocation is written for you. `npx` resolves a command it cannot find locally as a package name, so `npx tailor` fell through to an unrelated `tailor` package on npm whenever the SDK was not installed in the project — including in CI, where npm installs without prompting. Omitting the version specifier keeps using the project's installed SDK when there is one.
|
|
8
|
+
|
|
9
|
+
- Setup examples in the README, the quickstart, and the scaffolded project READMEs now use the package-runner form. Bun examples use `bun tailor <command>`, which resolves the local binary without fetching from the registry.
|
|
10
|
+
- Workflows generated by `tailor setup` use `npx @tailor-platform/sdk` for npm projects and `bun run tailor` for Bun projects. `tailor setup check` reports the template as outdated so existing projects regenerate; re-run `tailor setup` to pick it up.
|
|
11
|
+
- The `v2/seed-exec-to-cli-plugin` and `v2/sdk-skills-shim` codemods write the package-runner form when the invocation they produce goes through a runner that installs from the registry (`npx`, `bunx`, `pnpm`/`yarn dlx`, `npm exec`). A runner that resolves project binaries, such as `pnpm exec`, still gets the bare `tailor` binary.
|
|
12
|
+
|
|
13
|
+
## 0.4.0
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`23904bc`](https://github.com/tailor-platform/sdk/commit/23904bcb1807f96ecd3026e72d9b4de44eb8705f) Thanks [@toiroakr](https://github.com/toiroakr)! - Add the `v2/principal-unify` codemod so `tailor-sdk upgrade` can migrate SDK principal APIs to `TailorPrincipal`.
|
|
18
|
+
|
|
19
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`20aa5a9`](https://github.com/tailor-platform/sdk/commit/20aa5a95167d370b4b3cc7352cb60a22a695d673) Thanks [@toiroakr](https://github.com/toiroakr)! - Remove the APIs that were marked `@deprecated` on the way to v2, so 2.0.0 ships without deprecated aliases. Each removal has migration coverage in `tailor upgrade`:
|
|
20
|
+
|
|
21
|
+
- `@tailor-platform/sdk/cli` no longer re-exports `kyselyTypePlugin`, `enumConstantsPlugin`, `fileUtilsPlugin`, and `seedPlugin`. Import them from `@tailor-platform/sdk/plugin/kysely-type`, `/plugin/enum-constants`, `/plugin/file-utils`, and `/plugin/seed` (codemod `v2/plugin-cli-import`).
|
|
22
|
+
- `tailor.workflow.startJobFunction` and the `StartJobFunctionOptions` type are removed; use the canonical `execJobFunction` / `ExecJobFunctionOptions` (new codemod `v2/exec-job-function-rename`). `mockWorkflow()` no longer exposes the `startJobFunction` alias — assert on its `execJobFunction` mock instead — and `v2/workflow-trigger-rename` now rewrites `triggerJobFunction` straight to `execJobFunction`.
|
|
23
|
+
- `@tailor-platform/sdk/test` no longer exports the platform-global mocks `setupTailordbMock`, `setupWorkflowMock`, `setupWaitPointMock`, `setupInvokerMock`, and `setupTailorErrorsMock`, nor the bundled-output helper `createImportMain`. Use the `tailor-runtime` environment from `@tailor-platform/sdk/vitest` with `mockTailordb` / `mockWorkflow` (migration guidance: `v2/sdk-test-mocks-to-vitest`). `createTailorDBHook`, `createStandardSchema`, and `unauthenticatedTailorUser` are unchanged.
|
|
24
|
+
- The programmatic CLI functions no longer accept name-keyed options: `GetWorkflowOptions`, `StartWorkflowOptions`, `ListWorkflowExecutionsOptions`, `GetExecutorOptions`, `TriggerExecutorOptions`, `ListExecutorJobsOptions`, `GetExecutorJobOptions`, and `WatchExecutorJobOptions` are removed along with the overloads that took them. Pass the definition itself — `startWorkflow({ workflow: myWorkflow, invoker: "admin" })`, `watchExecutorJob({ executor: myExecutor, jobId })` — which also types `arg` and `payload` from the definition (migration guidance: `v2/cli-typed-options`). The name-keyed entry points remain available as CLI commands (`tailor workflow start <name>`, `tailor executor trigger <name>`).
|
|
25
|
+
|
|
26
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`b3ff0b4`](https://github.com/tailor-platform/sdk/commit/b3ff0b43bfbfc69eea797541292eff840e1d8f87) Thanks [@toiroakr](https://github.com/toiroakr)! - The `v2/seed-exec-to-cli-plugin` migration now rewrites generated seed runner invocations automatically. `node <distPath>/exec.mjs [options] [types...]` becomes `tailor seed apply [options] [types...]` and `node <distPath>/exec.mjs validate` becomes `tailor seed validate`, in package.json scripts, shell scripts, CI configs, docs, and TypeScript sources, carrying node's `--env-file` / `--env-file-if-exists` over to the CLI flag form in both the `=` and space-separated spellings. Each invocation must sit on one line, so a command split across YAML sequence items or markdown bullets is reported for review rather than rewritten. Files that `fork()` the runner are left untouched and reported with their exact line, because replacing the forked child with a CLI call also unwinds the surrounding `await`/Promise plumbing; the migration prompt now covers that rewrite and the stale `exec.mjs` deletion.
|
|
27
|
+
|
|
28
|
+
### Patch Changes
|
|
29
|
+
|
|
30
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`0379fe8`](https://github.com/tailor-platform/sdk/commit/0379fe8c2e7acb927d94f56204b39cf58fa4ac2a) Thanks [@toiroakr](https://github.com/toiroakr)! - Rewrite `tailor-sdk apply` to `tailor-sdk deploy` in source files that contain embedded CLI command strings.
|
|
31
|
+
|
|
32
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`6519a54`](https://github.com/tailor-platform/sdk/commit/6519a5434f0cc664a609ef2cae2398b19cad4673) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename auth attribute module augmentation from `AttributeMap` to `Attributes`.
|
|
33
|
+
|
|
34
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`5e35c59`](https://github.com/tailor-platform/sdk/commit/5e35c59032156eadeb45ac4c1b1453ecad79163c) Thanks [@toiroakr](https://github.com/toiroakr)! - Add LLM-assisted review support to the codemod runner. A codemod can declare `suspiciousPatterns` plus a `prompt`; after running, files whose post-transform content still matches a suspicious pattern are reported as `llmReviews` (in the JSON output and on stderr) together with the codemod's migration prompt. This surfaces the cases a deterministic transform cannot safely complete (e.g. a value reached through a variable) so they can be finished with an LLM. The `auth.invoker(...)` codemod adopts this for its non-literal-argument cases.
|
|
35
|
+
|
|
36
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`8b918f6`](https://github.com/tailor-platform/sdk/commit/8b918f68867240b5713c5f8340836971d1c30882) Thanks [@toiroakr](https://github.com/toiroakr)! - Generate the v2 migration guide (`packages/sdk/docs/migration/v2.md`) from the codemod registry, which is the single source of truth. Each entry renders its name, automation level (Automatic / Partially automatic / Manual), description, optional before/after `examples`, and — for changes the codemods cannot fully migrate on their own — the LLM/manual migration prompt. Run `pnpm codemod:docs:update` to regenerate and `pnpm codemod:docs:check` (wired into `pnpm check`) to verify it is in sync.
|
|
37
|
+
|
|
38
|
+
`scriptPath` is now optional, so the registry can also describe codemod-less ("manual") migrations that ship only guidance (`examples` / `prompt` / `suspiciousPatterns`) with no automatic transform. A manual entry with a `prompt` but no scoping pattern is surfaced as a project-wide `llmReviews` entry at runtime.
|
|
39
|
+
|
|
40
|
+
Add a `sdk-codemod list` command that prints every registered rule (id, name, kind, version range).
|
|
41
|
+
|
|
42
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`bfb9451`](https://github.com/tailor-platform/sdk/commit/bfb945122720cec94be23484e23d7ce7607257d8) Thanks [@toiroakr](https://github.com/toiroakr)! - Reduce false-positive v2 codemod warnings and LLM-review prompts from source comments, string literals, and identifier substring matches.
|
|
43
|
+
|
|
44
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`752ca9d`](https://github.com/tailor-platform/sdk/commit/752ca9dea12c7ba56ac1ed8091efc3fb6e7812be) Thanks [@toiroakr](https://github.com/toiroakr)! - Report the codemod runner identity in the JSON summary, including the source checkout commit and local build command when run from a branch build, so prerelease migration validation can distinguish exact npm packages from branch-head behavior.
|
|
45
|
+
|
|
46
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`1a055c9`](https://github.com/tailor-platform/sdk/commit/1a055c9909ac951f807fc2249c9abc1d5805398f) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename the TailorDB schema builder from `db.type()` to `db.table()`.
|
|
47
|
+
|
|
48
|
+
Update TailorDB definitions:
|
|
49
|
+
|
|
50
|
+
```diff
|
|
51
|
+
import { db } from "@tailor-platform/sdk";
|
|
52
|
+
|
|
53
|
+
-export const user = db.type("User", {
|
|
54
|
+
+export const user = db.table("User", {
|
|
55
|
+
name: db.string(),
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`982dee1`](https://github.com/tailor-platform/sdk/commit/982dee1bb73d8ca1faf35f7d256eba0c5ed86957) Thanks [@toiroakr](https://github.com/toiroakr)! - Make the deprecation process mechanical: an `@deprecated` tag in the SDK now states the version it shipped in and the codemod that migrates callers off it (`@deprecated since 2.1.0 — use {@link newApi} instead. codemod: v2/old-to-new`), and `pnpm check:deprecations` fails when a tag misses either half, names a codemod that is not registered, or outlives its codemod's boundary — so the release PR that bumps to a major turns red while an API due for removal is still declared, instead of the alias shipping and being noticed releases later. While the shipping version is still undecided the tag carries the literal `NEXT_RELEASE`, which the release workflow rewrites to the version the release PR bumps to — the same step that already resolves `prereleaseUntil: V2_NEXT_PENDING` codemod boundaries.
|
|
60
|
+
|
|
61
|
+
Registered codemods are validated more strictly too: a `since` that is not valid semver, or that is not older than `until`, now fails fast instead of surfacing as a semver error partway through `tailor upgrade` or as a codemod whose empty version range silently matches nothing.
|
|
62
|
+
|
|
63
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`039389d`](https://github.com/tailor-platform/sdk/commit/039389d17ddf3014fc53ffdb756ec6ea1425826c) Thanks [@toiroakr](https://github.com/toiroakr)! - Generate the `Env` interface in `tailor.d.ts` from the type of each `defineConfig({ env })` value instead of the value itself. The resolved value used to be written in as a literal type, so running `generate` or `deploy` with real environment variables loaded stamped those values into a file that is normally committed.
|
|
64
|
+
|
|
65
|
+
```diff
|
|
66
|
+
interface Env {
|
|
67
|
+
- API_BASE: "https://api.example.com";
|
|
68
|
+
- RETRIES: 3;
|
|
69
|
+
- VERBOSE: true;
|
|
70
|
+
+ API_BASE: string;
|
|
71
|
+
+ RETRIES: number;
|
|
72
|
+
+ VERBOSE: boolean;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`env` keys that aren't valid TypeScript identifiers (for example `"API-BASE"`) are now quoted as well; previously they were emitted bare and produced a `tailor.d.ts` that failed to parse.
|
|
77
|
+
|
|
78
|
+
Run `tailor generate` after upgrading to refresh the file. Code that relied on the literal narrowing — comparing `env.STAGE` against a literal union, for example — has to widen its own types or read the value through a local narrowing check. If a `tailor.d.ts` you already committed contains a sensitive value, treat that value as exposed and rotate it; keep secrets in [Secret Manager](https://github.com/tailor-platform/sdk/blob/main/packages/sdk/docs/services/secret.md) rather than `env`.
|
|
79
|
+
|
|
80
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`a6038e2`](https://github.com/tailor-platform/sdk/commit/a6038e25151bf32694cc2d20fd3845b1ed959ccc) Thanks [@toiroakr](https://github.com/toiroakr)! - Move the TailorDB `erdSite` setting out of the core config schema into the ERD plugin's own configuration. `db.<namespace>.erdSite` is no longer accepted in `tailor.config.ts`; configure the ERD deploy target on the plugin instead:
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { definePlugins } from "@tailor-platform/sdk";
|
|
84
|
+
import { tailordbErdPlugin } from "@tailor-platform/sdk-plugin-tailordb-erd";
|
|
85
|
+
|
|
86
|
+
export const plugins = definePlugins(
|
|
87
|
+
// TailorDB namespace name → static website name
|
|
88
|
+
tailordbErdPlugin({ sites: { tailordb: "my-erd-site" } }),
|
|
89
|
+
);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The `tailor tailordb erd` commands resolve deploy targets from `tailordbErdPlugin({ sites })` and now validate each namespace against `config.db` and each site name against `staticWebsites`, so typos surface when the config is loaded instead of at deploy time. The `v2/erd-site-to-plugin` codemod migrates existing configs automatically. For programmatic users, `loadTailorDBNamespaces()` additionally returns the config module's registered `plugins`, and namespace selector callbacks receive them as a second argument.
|
|
93
|
+
|
|
94
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`4022203`](https://github.com/tailor-platform/sdk/commit/40222035a5de08e1d0d3e7b8d96047fdbd2b2d19) Thanks [@toiroakr](https://github.com/toiroakr)! - `executeScript` now takes its `arg` as a JSON-serializable value instead of a pre-serialized JSON string. Pass the value directly (e.g. `arg: { a: 1 }`) instead of `arg: JSON.stringify({ a: 1 })`.
|
|
95
|
+
|
|
96
|
+
Add the `v2/execute-script-arg` codemod, which unwraps `JSON.stringify(...)` passed as the `executeScript` `arg` option. Indirect forms (a stringified value held in a variable, etc.) cannot be rewritten automatically and are surfaced as an LLM-assisted review task with a migration prompt.
|
|
97
|
+
|
|
98
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`078418a`](https://github.com/tailor-platform/sdk/commit/078418afde150fc971aa7fec7eb87ffff014e134) Thanks [@toiroakr](https://github.com/toiroakr)! - Reduce noisy `executeScript` LLM-review prompts by flagging files only when unresolved `arg` stringification remains likely.
|
|
99
|
+
|
|
100
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`54f4d08`](https://github.com/tailor-platform/sdk/commit/54f4d085e077913ae3a923bcb520362b9e57d876) Thanks [@toiroakr](https://github.com/toiroakr)! - `seedPlugin` no longer generates the `exec.mjs` seed runner. Seeding and validation move to the `tailor seed` commands provided by the `@tailor-platform/sdk-plugin-seed` CLI plugin: install it with `npm install -D @tailor-platform/sdk-plugin-seed`, replace `node <distPath>/exec.mjs` with `tailor seed apply` and `node <distPath>/exec.mjs validate` with `tailor seed validate`, and delete the stale generated `exec.mjs`. Seed data and schema generation (`data/*.jsonl`, `data/*.schema.ts`) is unchanged. Because the plugin reads the config at run time, `machineUserName` changes in seedPlugin options now take effect without regenerating. `@tailor-platform/sdk/cli` gains `loadSeedContext` (and `SeedContext` types) for this, `SeedData` is now JSON-typed, and `executeScript` accepts a plain object `invoker` (`ScriptInvoker`).
|
|
101
|
+
|
|
102
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`c8778f2`](https://github.com/tailor-platform/sdk/commit/c8778f22b4306705b085602b7c221f4166c31447) 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`.
|
|
103
|
+
|
|
104
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`e79dc3f`](https://github.com/tailor-platform/sdk/commit/e79dc3fd6862f7f00df08ef8f2b8721f562afa8c) Thanks [@toiroakr](https://github.com/toiroakr)! - Apply the v2 `rename-bin` codemod to SDK CLI command strings in TypeScript and JavaScript source files.
|
|
105
|
+
|
|
106
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`d69add3`](https://github.com/tailor-platform/sdk/commit/d69add3f24e944dd7153eef9da6e0c36a5e4a989) Thanks [@toiroakr](https://github.com/toiroakr)! - Run v2 codemods when the target version is a v2 prerelease.
|
|
107
|
+
|
|
108
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`b6340d0`](https://github.com/tailor-platform/sdk/commit/b6340d086822fbf5bd6fffa16a7dba47ccc3a59a) Thanks [@toiroakr](https://github.com/toiroakr)! - Derive default TailorDB forward relation names from the relation field name by removing a trailing `ID`, `Id`, or `id`, instead of deriving them from the target table name.
|
|
109
|
+
|
|
110
|
+
The v2 migration review identifies non-self relations without `toward.as`. Add an explicit name to preserve the v1 GraphQL field name, or update consumers to use the new field-based name.
|
|
111
|
+
|
|
112
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`8cb5bcd`](https://github.com/tailor-platform/sdk/commit/8cb5bcdfe4d2494790b2b9ad72c7e1c43715f9e8) Thanks [@toiroakr](https://github.com/toiroakr)! - Flag `tailor generate --watch` / `-W` invocations and programmatic `generate({ watch })` usage for manual review as part of the v2 migration (the flag and its dependency watcher are removed in `@tailor-platform/sdk` v2).
|
|
113
|
+
|
|
114
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`d1405c0`](https://github.com/tailor-platform/sdk/commit/d1405c0b0dbd6205c1817c79b239fe980906c19b) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename the `defineIdp` option `publishUserEvents` to `publishEvents`, so all four services that publish events use one field name. A codemod rewrites the option key on `defineIdp` calls, including aliased and namespace imports, and rewrites a shorthand `{ publishUserEvents }` to `{ publishEvents: publishUserEvents }` so it keeps reading the same local. Occurrences it cannot rewrite — an options object built outside the call, a computed key, or a type declaration of the option — are reported for manual migration.
|
|
115
|
+
|
|
116
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`cd48fda`](https://github.com/tailor-platform/sdk/commit/cd48fdab46746aa2e8f5d8dd43073e3b4832c07c) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename resolver, executor, workflow trigger, and typed workflow start machine-user options from `authInvoker` to `invoker`.
|
|
117
|
+
|
|
118
|
+
Update create-sdk templates and the v2 auth invoker codemod to generate the new `invoker` option.
|
|
119
|
+
|
|
120
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`28c0dde`](https://github.com/tailor-platform/sdk/commit/28c0dde9a33e4db39b04b083e22feb837e3605a7) Thanks [@toiroakr](https://github.com/toiroakr)! - Limit the `openDownloadStream` migration review prompt to files that reference deprecated download stream APIs.
|
|
121
|
+
|
|
122
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`6374ec6`](https://github.com/tailor-platform/sdk/commit/6374ec64f3602c35ed2b2e45ba2260591327fafb) Thanks [@toiroakr](https://github.com/toiroakr)! - Replace `tailor skills install` with project-local `tailor skills add`, `list`, `remove`, and `sync` commands for bundled Tailor SDK agent skills.
|
|
123
|
+
|
|
124
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`d9d9c49`](https://github.com/tailor-platform/sdk/commit/d9d9c49ab4c98034c64b0e5c6ba9cf106341a6c3) Thanks [@toiroakr](https://github.com/toiroakr)! - Flag files that need project-specific review after the v2 principal migration, including resolver helper adapters and nullable `caller` follow-ups.
|
|
125
|
+
|
|
126
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`244fe8d`](https://github.com/tailor-platform/sdk/commit/244fe8d703b35f4aceaf31f918f94fc84e3be789) Thanks [@toiroakr](https://github.com/toiroakr)! - Report precise file-local findings for `principal-unify` review follow-ups, including nullable caller call sites and `context.user` helper adapters.
|
|
127
|
+
|
|
128
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`5059c27`](https://github.com/tailor-platform/sdk/commit/5059c273d3f14c92239a17d3a7eeb44e0822ed99) Thanks [@toiroakr](https://github.com/toiroakr)! - Fix `v2/principal-unify` review findings for nested SDK field parser invoker values and destructured context helper messages.
|
|
129
|
+
|
|
130
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`7240c25`](https://github.com/tailor-platform/sdk/commit/7240c252546dc69989755a6f5af26c6062c36883) Thanks [@toiroakr](https://github.com/toiroakr)! - Remove the deprecated `auth.getConnectionToken()` helper from values returned by `defineAuth()`. Use `authconnection.getConnectionToken(...)` from `@tailor-platform/sdk/runtime` in resolvers, executors, and workflows instead. The v2 codemod rewrites direct `auth.getConnectionToken(...)` calls when the `auth` binding is imported from `tailor.config`.
|
|
131
|
+
|
|
132
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`304a24a`](https://github.com/tailor-platform/sdk/commit/304a24af51cc130268a7f8145a10dc6b165f8d46) Thanks [@toiroakr](https://github.com/toiroakr)! - Remove the v1 runtime globals compatibility layer. Importing from `@tailor-platform/sdk` no longer activates the ambient `tailor.*` / `tailordb.*` declarations; opt into globals with `@tailor-platform/sdk/runtime/globals` or use the typed wrappers from `@tailor-platform/sdk/runtime`.
|
|
133
|
+
|
|
134
|
+
The capital-cased `Tailordb.*` namespace is removed. If your project still references `Tailordb.QueryResult`, `Tailordb.CommandType`, `Tailordb.Client`, or `typeof Tailordb.Client`, migrate before upgrading: run `pnpm dlx @tailor-platform/sdk-codemod v2/tailordb-namespace` to rewrite them to lowercase `tailordb.*`, then add `import "@tailor-platform/sdk/runtime/globals"` so the rewritten references resolve.
|
|
135
|
+
|
|
136
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`88db10e`](https://github.com/tailor-platform/sdk/commit/88db10ef57fa575731e1ed557ea74b86edcf5c5c) Thanks [@toiroakr](https://github.com/toiroakr)! - Remove deprecated CLI aliases for the v2 command surface. Use `tailor-sdk deploy` instead of `tailor-sdk apply`, `tailor-sdk crashreport` instead of `tailor-sdk crash-report`, and the hyphenated `--machine-user` option instead of the hidden `--machineuser` alias.
|
|
137
|
+
|
|
138
|
+
Fix the v2 CLI rename codemod to migrate the hidden `--machineuser` option to `--machine-user`.
|
|
139
|
+
|
|
140
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`160b406`](https://github.com/tailor-platform/sdk/commit/160b4061ee38675df85dd74af23b7041fe8e4944) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename the CLI binary from `tailor-sdk` to `tailor`.
|
|
141
|
+
|
|
142
|
+
The output directory default changes from `.tailor-sdk` to `.tailor`, and the GitHub Actions lock file path changes from `.github/tailor-sdk.lock` to `.github/tailor.lock`.
|
|
143
|
+
|
|
144
|
+
Run the `v2/rename-bin` codemod to migrate `tailor-sdk` invocations in package.json scripts, shell scripts, CI workflows, and documentation:
|
|
145
|
+
|
|
146
|
+
```sh
|
|
147
|
+
npx @tailor-platform/sdk-codemod --from 1.x --to 2.0.0
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`8b03f82`](https://github.com/tailor-platform/sdk/commit/8b03f827642e64f3b3af5a05ecdef405028a803a) Thanks [@toiroakr](https://github.com/toiroakr)! - Standardize SDK-owned environment variables on the `TAILOR_*` namespace.
|
|
151
|
+
|
|
152
|
+
Replace the removed SDK-specific environment variables with their new names: `TAILOR_CONFIG_PATH`, `TAILOR_DTS_PATH`, `TAILOR_CI_ALLOW_ID_INJECTION`, `TAILOR_DEPLOY_BUILD_ONLY`, `TAILOR_BUILD_OUTPUT_DIR`, `TAILOR_SKILLS_SOURCE`, `TAILOR_TEMPLATE_SDK_VERSION`, `TAILOR_PLATFORM_URL`, `TAILOR_PLATFORM_OAUTH2_CLIENT_ID`, `TAILOR_INLINE_SOURCEMAP`, `TAILOR_QUERY_NEWLINE_ON_ENTER`, and `TAILOR_APP_LOG_LEVEL`. The deprecated `TAILOR_TOKEN` fallback is removed; use `TAILOR_PLATFORM_TOKEN`. The v2 codemod rewrites unambiguous removed SDK environment variable names and flags generic names such as `LOG_LEVEL` and `PLATFORM_URL` for manual review.
|
|
153
|
+
|
|
154
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`1a8945d`](https://github.com/tailor-platform/sdk/commit/1a8945d183b990aaf1dfb1dd9ca9813a7277a118) 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.
|
|
155
|
+
|
|
156
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`3dcd82d`](https://github.com/tailor-platform/sdk/commit/3dcd82d54d6c059df90f2dc4788a7059fe4004ab) Thanks [@toiroakr](https://github.com/toiroakr)! - Restore Tailor field outputs for UUID, date, datetime, time, and decimal fields to plain string-compatible types and remove the strict scalar string migration guidance.
|
|
157
|
+
|
|
158
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`fe1721e`](https://github.com/tailor-platform/sdk/commit/fe1721efa04f15d3d1ac3287c30c4c550220403e) Thanks [@toiroakr](https://github.com/toiroakr)! - Flag JavaScript files and embedded code strings that still reference ambient Tailor runtime globals during v2 migration review.
|
|
159
|
+
|
|
160
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`5fc3a1d`](https://github.com/tailor-platform/sdk/commit/5fc3a1d027767d60e8a427adf1ff7e5f43dab331) Thanks [@toiroakr](https://github.com/toiroakr)! - Flag files that still reference ambient Tailor runtime globals so the v2 migration can opt them into `@tailor-platform/sdk/runtime/globals`.
|
|
161
|
+
|
|
162
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`df3a772`](https://github.com/tailor-platform/sdk/commit/df3a77257823e9e8e7b7c89e418b3113964e9b20) Thanks [@toiroakr](https://github.com/toiroakr)! - Automatically migrate simple direct `tailor.idp.Client` runtime global usage to the typed `idp.Client` wrapper during v2 upgrades.
|
|
163
|
+
|
|
164
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`04ca361`](https://github.com/tailor-platform/sdk/commit/04ca3619c4d2d88afe8ee3b25d4ba47ac799de51) Thanks [@toiroakr](https://github.com/toiroakr)! - Remove flat value and default exports from `@tailor-platform/sdk/runtime/*` subpath modules. Import each subpath through its self-named namespace export instead, for example `import { iconv } from "@tailor-platform/sdk/runtime/iconv"`.
|
|
165
|
+
|
|
166
|
+
The aggregate `@tailor-platform/sdk/runtime` entry remains named-only, and its deprecated `file.deleteFile` alias is removed in favor of `file.delete`. The v2 codemod rewrites straightforward namespace-star subpath imports, flat named value imports, and aggregate `file.deleteFile` calls to the new namespace-object style.
|
|
167
|
+
|
|
168
|
+
`TailorContextAPI` and `TailorWorkflowAPI` now describe the SDK wrapper objects. Code that types the platform-provided `globalThis.tailor.context` or `globalThis.tailor.workflow` objects directly must use `PlatformContextAPI` or `PlatformWorkflowAPI` instead.
|
|
169
|
+
|
|
170
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`c051dab`](https://github.com/tailor-platform/sdk/commit/c051dab12c233de65313c4fcee96a26c604ec5da) Thanks [@toiroakr](https://github.com/toiroakr)! - Mention the `--upsert` flag in the `v2/seed-exec-to-cli-plugin` migration guide's `tailor seed apply` option list.
|
|
171
|
+
|
|
172
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`eba2728`](https://github.com/tailor-platform/sdk/commit/eba2728a7b473da7caa134cbfdfc53a714d9d328) Thanks [@toiroakr](https://github.com/toiroakr)! - Keep v2 codemods from reusing type-only runtime helper imports when adding runtime value imports.
|
|
173
|
+
|
|
174
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`add2079`](https://github.com/tailor-platform/sdk/commit/add2079f4c89bcb950c0c7f55312880993b3dc7b) Thanks [@toiroakr](https://github.com/toiroakr)! - Add the `v2/tailor-output-ignore-dir` codemod so SDK upgrades rewrite exact `.tailor-sdk/` ignore-file entries to `.tailor/` while leaving other `.tailor-sdk` paths unchanged.
|
|
175
|
+
|
|
176
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`b5a0d70`](https://github.com/tailor-platform/sdk/commit/b5a0d70f8e29d58f77809ef2514be9065e0a954f) Thanks [@toiroakr](https://github.com/toiroakr)! - Unify function principal context around `TailorPrincipal`.
|
|
177
|
+
|
|
178
|
+
Resolver contexts now use `caller` and `invoker` as `TailorPrincipal | null`, workflow and executor invokers also use `TailorPrincipal | null`, and event executor `actor` uses `TailorPrincipal | null` with `id`/`type` fields. The legacy `TailorUser`, `TailorInvoker`, `TailorActor`, `TailorActorType`, and `unauthenticatedTailorUser` exports are removed.
|
|
179
|
+
|
|
180
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`f1ec5b5`](https://github.com/tailor-platform/sdk/commit/f1ec5b5fbedce73d217830e2c6ac4a243b830a2d) Thanks [@toiroakr](https://github.com/toiroakr)! - Redesign TailorDB hooks and validators with several breaking changes:
|
|
181
|
+
|
|
182
|
+
- Add shared `now` timestamp to all hooks — multiple fields stamped with the same `Date`
|
|
183
|
+
- Field-level hooks: `{ value, data, invoker }` → create `{ input, invoker, now }` / update `{ input, oldValue, invoker, now }` (`data` removed, `oldValue` added for update only)
|
|
184
|
+
- Type-level hooks: per-field mapping (`Hooks<F>`) → single `{ create, update }` object (`TypeHook<F>`) returning partial field overrides
|
|
185
|
+
- Type-level create hooks no longer receive `oldRecord`; update hooks receive non-nullable `oldRecord`
|
|
186
|
+
- Field-level validators: return type changed from `boolean` to `string | void` (return error message or void to pass); `[fn, message]` tuple form removed
|
|
187
|
+
- Type-level validators: `Validators<F>` per-field record → `TypeValidateFn<F>` single function with `issues(field, message)` callback
|
|
188
|
+
- Add `.default(value)` on fields to set a create-time default (makes required fields optional in create input)
|
|
189
|
+
- Remove exported types: `Hooks<F>`, `Validators<F>`, `ValidateConfig`
|
|
190
|
+
|
|
191
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`bf11bf8`](https://github.com/tailor-platform/sdk/commit/bf11bf8d3bad6195c86ed289c764490dc6d680ee) Thanks [@toiroakr](https://github.com/toiroakr)! - Update politty to v0.11.3
|
|
192
|
+
|
|
193
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`eeb235d`](https://github.com/tailor-platform/sdk/commit/eeb235debe910c05f755f036486878e7c763cb7e) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename `defineWaitPoint` and `defineWaitPoints` to `createWaitPoint` and `createWaitPoints`.
|
|
194
|
+
|
|
195
|
+
These functions create runtime instances with `.wait()` and `.resolve()` methods that call the platform API at runtime, so the `create*` prefix is more accurate. Update any usages:
|
|
196
|
+
|
|
197
|
+
```diff
|
|
198
|
+
-import { defineWaitPoint, defineWaitPoints } from "@tailor-platform/sdk";
|
|
199
|
+
+import { createWaitPoint, createWaitPoints } from "@tailor-platform/sdk";
|
|
200
|
+
|
|
201
|
+
-export const approval = defineWaitPoint<Payload, Result>("approval");
|
|
202
|
+
+export const approval = createWaitPoint<Payload, Result>("approval");
|
|
203
|
+
|
|
204
|
+
-export const waitPoints = defineWaitPoints((define) => ({ ... }));
|
|
205
|
+
+export const waitPoints = createWaitPoints((define) => ({ ... }));
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`93b68ac`](https://github.com/tailor-platform/sdk/commit/93b68ace83dcb0af2a8b0afa8aa3336cb18c818b) 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:
|
|
209
|
+
|
|
210
|
+
```diff
|
|
211
|
+
const inventory = checkInventory.trigger({ orderId: input.orderId });
|
|
212
|
+
+const inventory = checkInventory.start({ orderId: input.orderId });
|
|
213
|
+
|
|
214
|
+
-const workflowRunId = await orderProcessingWorkflow.trigger(args, { invoker: "manager" });
|
|
215
|
+
+const workflowRunId = await orderProcessingWorkflow.start(args, { invoker: "manager" });
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
`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.
|
|
219
|
+
|
|
220
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`93b68ac`](https://github.com/tailor-platform/sdk/commit/93b68ace83dcb0af2a8b0afa8aa3336cb18c818b) 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:
|
|
221
|
+
|
|
222
|
+
```diff
|
|
223
|
+
import { workflow } from "@tailor-platform/sdk/runtime";
|
|
224
|
+
|
|
225
|
+
-await workflow.triggerWorkflow("myWorkflow", { data: "value" });
|
|
226
|
+
+await workflow.startWorkflow("myWorkflow", { data: "value" });
|
|
227
|
+
-workflow.triggerJobFunction("myJob", { data: "value" });
|
|
228
|
+
+workflow.startJobFunction("myJob", { data: "value" });
|
|
229
|
+
-await workflow.resumeWorkflow("execution-id");
|
|
230
|
+
+await workflow.resumeWorkflowExecution("execution-id");
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Run the `v2/workflow-trigger-rename` codemod to migrate call sites automatically.
|
|
234
|
+
|
|
235
|
+
## 0.4.0-next.10
|
|
236
|
+
|
|
237
|
+
### Minor Changes
|
|
238
|
+
|
|
239
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`a4cdee0`](https://github.com/tailor-platform/sdk/commit/a4cdee079707105213f8e5833dcaa613f39c8464) Thanks [@toiroakr](https://github.com/toiroakr)! - Remove the APIs that were marked `@deprecated` on the way to v2, so 2.0.0 ships without deprecated aliases. Each removal has migration coverage in `tailor upgrade`:
|
|
240
|
+
|
|
241
|
+
- `@tailor-platform/sdk/cli` no longer re-exports `kyselyTypePlugin`, `enumConstantsPlugin`, `fileUtilsPlugin`, and `seedPlugin`. Import them from `@tailor-platform/sdk/plugin/kysely-type`, `/plugin/enum-constants`, `/plugin/file-utils`, and `/plugin/seed` (codemod `v2/plugin-cli-import`).
|
|
242
|
+
- `tailor.workflow.startJobFunction` and the `StartJobFunctionOptions` type are removed; use the canonical `execJobFunction` / `ExecJobFunctionOptions` (new codemod `v2/exec-job-function-rename`). `mockWorkflow()` no longer exposes the `startJobFunction` alias — assert on its `execJobFunction` mock instead — and `v2/workflow-trigger-rename` now rewrites `triggerJobFunction` straight to `execJobFunction`.
|
|
243
|
+
- `@tailor-platform/sdk/test` no longer exports the platform-global mocks `setupTailordbMock`, `setupWorkflowMock`, `setupWaitPointMock`, `setupInvokerMock`, and `setupTailorErrorsMock`, nor the bundled-output helper `createImportMain`. Use the `tailor-runtime` environment from `@tailor-platform/sdk/vitest` with `mockTailordb` / `mockWorkflow` (migration guidance: `v2/sdk-test-mocks-to-vitest`). `createTailorDBHook`, `createStandardSchema`, and `unauthenticatedTailorUser` are unchanged.
|
|
244
|
+
- The programmatic CLI functions no longer accept name-keyed options: `GetWorkflowOptions`, `StartWorkflowOptions`, `ListWorkflowExecutionsOptions`, `GetExecutorOptions`, `TriggerExecutorOptions`, `ListExecutorJobsOptions`, `GetExecutorJobOptions`, and `WatchExecutorJobOptions` are removed along with the overloads that took them. Pass the definition itself — `startWorkflow({ workflow: myWorkflow, invoker: "admin" })`, `watchExecutorJob({ executor: myExecutor, jobId })` — which also types `arg` and `payload` from the definition (migration guidance: `v2/cli-typed-options`). The name-keyed entry points remain available as CLI commands (`tailor workflow start <name>`, `tailor executor trigger <name>`).
|
|
245
|
+
|
|
246
|
+
- [#1912](https://github.com/tailor-platform/sdk/pull/1912) [`d9f8a52`](https://github.com/tailor-platform/sdk/commit/d9f8a528e2f9f597a71a4c42f004f050d9ef9643) Thanks [@dqn](https://github.com/dqn)! - The `v2/seed-exec-to-cli-plugin` migration now rewrites generated seed runner invocations automatically. `node <distPath>/exec.mjs [options] [types...]` becomes `tailor seed apply [options] [types...]` and `node <distPath>/exec.mjs validate` becomes `tailor seed validate`, in package.json scripts, shell scripts, CI configs, docs, and TypeScript sources, carrying node's `--env-file` / `--env-file-if-exists` over to the CLI flag form in both the `=` and space-separated spellings. Each invocation must sit on one line, so a command split across YAML sequence items or markdown bullets is reported for review rather than rewritten. Files that `fork()` the runner are left untouched and reported with their exact line, because replacing the forked child with a CLI call also unwinds the surrounding `await`/Promise plumbing; the migration prompt now covers that rewrite and the stale `exec.mjs` deletion.
|
|
247
|
+
|
|
248
|
+
### Patch Changes
|
|
249
|
+
|
|
250
|
+
- [#1923](https://github.com/tailor-platform/sdk/pull/1923) [`1015816`](https://github.com/tailor-platform/sdk/commit/101581679c4b586a5bfdcb4d72a292b56a81bc2c) Thanks [@toiroakr](https://github.com/toiroakr)! - Make the deprecation process mechanical: an `@deprecated` tag in the SDK now states the version it shipped in and the codemod that migrates callers off it (`@deprecated since 2.1.0 — use {@link newApi} instead. codemod: v2/old-to-new`), and `pnpm check:deprecations` fails when a tag misses either half, names a codemod that is not registered, or outlives its codemod's boundary — so the release PR that bumps to a major turns red while an API due for removal is still declared, instead of the alias shipping and being noticed releases later. While the shipping version is still undecided the tag carries the literal `NEXT_RELEASE`, which the release workflow rewrites to the version the release PR bumps to — the same step that already resolves `prereleaseUntil: V2_NEXT_PENDING` codemod boundaries.
|
|
251
|
+
|
|
252
|
+
Registered codemods are validated more strictly too: a `since` that is not valid semver, or that is not older than `until`, now fails fast instead of surfacing as a semver error partway through `tailor upgrade` or as a codemod whose empty version range silently matches nothing.
|
|
253
|
+
|
|
254
|
+
- [#1915](https://github.com/tailor-platform/sdk/pull/1915) [`dc691ec`](https://github.com/tailor-platform/sdk/commit/dc691ec1e2181400c6715233f0588a1b5150038f) Thanks [@toiroakr](https://github.com/toiroakr)! - Generate the `Env` interface in `tailor.d.ts` from the type of each `defineConfig({ env })` value instead of the value itself. The resolved value used to be written in as a literal type, so running `generate` or `deploy` with real environment variables loaded stamped those values into a file that is normally committed.
|
|
255
|
+
|
|
256
|
+
```diff
|
|
257
|
+
interface Env {
|
|
258
|
+
- API_BASE: "https://api.example.com";
|
|
259
|
+
- RETRIES: 3;
|
|
260
|
+
- VERBOSE: true;
|
|
261
|
+
+ API_BASE: string;
|
|
262
|
+
+ RETRIES: number;
|
|
263
|
+
+ VERBOSE: boolean;
|
|
264
|
+
}
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
`env` keys that aren't valid TypeScript identifiers (for example `"API-BASE"`) are now quoted as well; previously they were emitted bare and produced a `tailor.d.ts` that failed to parse.
|
|
268
|
+
|
|
269
|
+
Run `tailor generate` after upgrading to refresh the file. Code that relied on the literal narrowing — comparing `env.STAGE` against a literal union, for example — has to widen its own types or read the value through a local narrowing check. If a `tailor.d.ts` you already committed contains a sensitive value, treat that value as exposed and rotate it; keep secrets in [Secret Manager](https://github.com/tailor-platform/sdk/blob/main/packages/sdk/docs/services/secret.md) rather than `env`.
|
|
270
|
+
|
|
271
|
+
- [#1926](https://github.com/tailor-platform/sdk/pull/1926) [`a7343a5`](https://github.com/tailor-platform/sdk/commit/a7343a5976ece5ae66febe713ae04e97dfd9bee5) Thanks [@toiroakr](https://github.com/toiroakr)! - Rename the `defineIdp` option `publishUserEvents` to `publishEvents`, so all four services that publish events use one field name. A codemod rewrites the option key on `defineIdp` calls, including aliased and namespace imports, and rewrites a shorthand `{ publishUserEvents }` to `{ publishEvents: publishUserEvents }` so it keeps reading the same local. Occurrences it cannot rewrite — an options object built outside the call, a computed key, or a type declaration of the option — are reported for manual migration.
|
|
272
|
+
|
|
273
|
+
- [#1808](https://github.com/tailor-platform/sdk/pull/1808) [`d8564db`](https://github.com/tailor-platform/sdk/commit/d8564db44a1a59e5269f1f6236fdb75005270063) Thanks [@toiroakr](https://github.com/toiroakr)! - Mention the `--upsert` flag in the `v2/seed-exec-to-cli-plugin` migration guide's `tailor seed apply` option list.
|
|
274
|
+
|
|
3
275
|
## 0.4.0-next.9
|
|
4
276
|
|
|
5
277
|
### Patch Changes
|
|
@@ -261,6 +533,14 @@
|
|
|
261
533
|
|
|
262
534
|
- [#1435](https://github.com/tailor-platform/sdk/pull/1435) [`49c0cc9`](https://github.com/tailor-platform/sdk/commit/49c0cc99171d7e317a50a18804a21067d89f9493) Thanks [@dqn](https://github.com/dqn)! - Add the `v2/plugin-cli-import` codemod so `tailor-sdk upgrade` rewrites deprecated plugin imports from `@tailor-platform/sdk/cli` (`kyselyTypePlugin`, `enumConstantsPlugin`, `fileUtilsPlugin`, `seedPlugin`) to their dedicated `@tailor-platform/sdk/plugin/*` subpaths, splitting any non-plugin specifiers onto a separate import.
|
|
263
535
|
|
|
536
|
+
## 0.3.9
|
|
537
|
+
|
|
538
|
+
### Patch Changes
|
|
539
|
+
|
|
540
|
+
- [#1901](https://github.com/tailor-platform/sdk/pull/1901) [`7d1974f`](https://github.com/tailor-platform/sdk/commit/7d1974f52952a8f39a7adfc06644404b2510f1c3) Thanks [@renovate](https://github.com/apps/renovate)! - fix(deps): update dependency politty to v0.11.6
|
|
541
|
+
|
|
542
|
+
- [#1903](https://github.com/tailor-platform/sdk/pull/1903) [`83c5bc4`](https://github.com/tailor-platform/sdk/commit/83c5bc453a77a734599b665ebe2873ff6b305f1d) Thanks [@renovate](https://github.com/apps/renovate)! - fix(deps): update dependency @ast-grep/napi to v0.45.0
|
|
543
|
+
|
|
264
544
|
## 0.3.8
|
|
265
545
|
|
|
266
546
|
### Patch Changes
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { a as importSource, c as localDeclarationNames, i as importBindings, o as importSpecNames, r as findImportStatements } from "../../../ast-grep-helpers-CXtWn3RB.js";
|
|
2
|
+
import { Lang, parse } from "@ast-grep/napi";
|
|
3
|
+
//#region codemods/v2/exec-job-function-rename/scripts/transform.ts
|
|
4
|
+
const DEPRECATED_METHOD = "startJobFunction";
|
|
5
|
+
const CANONICAL_METHOD = "execJobFunction";
|
|
6
|
+
const DEPRECATED_OPTIONS = "StartJobFunctionOptions";
|
|
7
|
+
const CANONICAL_OPTIONS = "ExecJobFunctionOptions";
|
|
8
|
+
const WORKFLOW_MODULE_SOURCES = /* @__PURE__ */ new Set(["@tailor-platform/sdk/runtime", "@tailor-platform/sdk/runtime/workflow"]);
|
|
9
|
+
function quickFilter(source) {
|
|
10
|
+
return source.includes(DEPRECATED_METHOD) || source.includes(DEPRECATED_OPTIONS);
|
|
11
|
+
}
|
|
12
|
+
function sourceLang(filePath, source) {
|
|
13
|
+
const lower = filePath.toLowerCase();
|
|
14
|
+
if (lower.endsWith(".tsx") || lower.endsWith(".jsx")) return Lang.Tsx;
|
|
15
|
+
return source.includes("</") || source.includes("/>") ? Lang.Tsx : Lang.TypeScript;
|
|
16
|
+
}
|
|
17
|
+
function collectWorkflowLocals(root, imports) {
|
|
18
|
+
const locals = /* @__PURE__ */ new Set();
|
|
19
|
+
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);
|
|
20
|
+
const declaredNames = localDeclarationNames(root);
|
|
21
|
+
for (const name of locals) if (declaredNames.has(name)) locals.delete(name);
|
|
22
|
+
return locals;
|
|
23
|
+
}
|
|
24
|
+
function tailorIsAmbientGlobal(root, imports) {
|
|
25
|
+
if (localDeclarationNames(root).has("tailor")) return false;
|
|
26
|
+
return !imports.some((stmt) => importBindings(stmt).some((b) => b.localName === "tailor"));
|
|
27
|
+
}
|
|
28
|
+
function isAmbientTailorWorkflow(object) {
|
|
29
|
+
if (!object || object.kind() !== "member_expression") return false;
|
|
30
|
+
const base = object.field("object");
|
|
31
|
+
const property = object.field("property");
|
|
32
|
+
return base?.kind() === "identifier" && base.text() === "tailor" && property?.text() === "workflow";
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Rename `StartJobFunctionOptions` import specifiers from the runtime module,
|
|
36
|
+
* plus the type references that resolve to them when the import is not aliased.
|
|
37
|
+
* @param root - Parsed file root
|
|
38
|
+
* @param imports - Top-level import statements
|
|
39
|
+
* @returns Edits renaming the deprecated options type
|
|
40
|
+
*/
|
|
41
|
+
function optionsTypeEdits(root, imports) {
|
|
42
|
+
const edits = [];
|
|
43
|
+
for (const importStmt of imports) {
|
|
44
|
+
const source = importSource(importStmt);
|
|
45
|
+
if (source === null || !WORKFLOW_MODULE_SOURCES.has(source)) continue;
|
|
46
|
+
const specs = importStmt.findAll({ rule: { kind: "import_specifier" } });
|
|
47
|
+
if (specs.some((spec) => importSpecNames(spec)?.importedName === CANONICAL_OPTIONS)) continue;
|
|
48
|
+
for (const spec of specs) {
|
|
49
|
+
const names = importSpecNames(spec);
|
|
50
|
+
if (names?.importedName !== DEPRECATED_OPTIONS) continue;
|
|
51
|
+
const importedNode = spec.children().find((child) => child.kind() === "identifier");
|
|
52
|
+
if (!importedNode) continue;
|
|
53
|
+
edits.push(importedNode.replace(CANONICAL_OPTIONS));
|
|
54
|
+
if (names.localName !== DEPRECATED_OPTIONS) continue;
|
|
55
|
+
for (const reference of root.findAll({ rule: {
|
|
56
|
+
kind: "type_identifier",
|
|
57
|
+
regex: `^${DEPRECATED_OPTIONS}$`
|
|
58
|
+
} })) edits.push(reference.replace(CANONICAL_OPTIONS));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return edits;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Rewrite `.startJobFunction(` member accesses — on the ambient
|
|
65
|
+
* `tailor.workflow` global or on a `workflow` value imported from
|
|
66
|
+
* `@tailor-platform/sdk/runtime(/workflow)` — to the canonical
|
|
67
|
+
* `execJobFunction`, and rename the `StartJobFunctionOptions` type alias.
|
|
68
|
+
* @param source - File contents
|
|
69
|
+
* @param filePath - Absolute path to the file
|
|
70
|
+
* @returns Transformed source or null when nothing matched.
|
|
71
|
+
*/
|
|
72
|
+
function transform(source, filePath) {
|
|
73
|
+
if (!quickFilter(source)) return null;
|
|
74
|
+
const root = parse(sourceLang(filePath ?? "", source), source).root();
|
|
75
|
+
const imports = findImportStatements(root);
|
|
76
|
+
const workflowLocals = collectWorkflowLocals(root, imports);
|
|
77
|
+
const tailorIsAmbient = tailorIsAmbientGlobal(root, imports);
|
|
78
|
+
const edits = optionsTypeEdits(root, imports);
|
|
79
|
+
for (const member of root.findAll({ rule: { kind: "member_expression" } })) {
|
|
80
|
+
const property = member.field("property");
|
|
81
|
+
if (!property || property.kind() !== "property_identifier") continue;
|
|
82
|
+
if (property.text() !== DEPRECATED_METHOD) continue;
|
|
83
|
+
const object = member.field("object");
|
|
84
|
+
if (!object) continue;
|
|
85
|
+
const isWorkflowImportReceiver = object.kind() === "identifier" && workflowLocals.has(object.text());
|
|
86
|
+
const isAmbientReceiver = tailorIsAmbient && isAmbientTailorWorkflow(object);
|
|
87
|
+
if (!isWorkflowImportReceiver && !isAmbientReceiver) continue;
|
|
88
|
+
edits.push(property.replace(CANONICAL_METHOD));
|
|
89
|
+
}
|
|
90
|
+
if (edits.length === 0) return null;
|
|
91
|
+
const result = root.commitEdits(edits);
|
|
92
|
+
return result === source ? null : result;
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { transform as default };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { a as importSource, c as localDeclarationNames, i as importBindings, l as stringValue, r as findImportStatements, s as isTypeOnlyImport } from "../../../ast-grep-helpers-CXtWn3RB.js";
|
|
2
|
+
import { Lang, parse } from "@ast-grep/napi";
|
|
3
|
+
//#region codemods/v2/idp-publish-events-rename/scripts/transform.ts
|
|
4
|
+
const SDK_MODULE = "@tailor-platform/sdk";
|
|
5
|
+
const DEFINE_IDP = "defineIdp";
|
|
6
|
+
const LEGACY_KEY = "publishUserEvents";
|
|
7
|
+
const NEW_KEY = "publishEvents";
|
|
8
|
+
function sourceLang(filePath, source) {
|
|
9
|
+
return filePath.endsWith(".tsx") || filePath.endsWith(".jsx") || source.includes("</") ? Lang.Tsx : Lang.TypeScript;
|
|
10
|
+
}
|
|
11
|
+
function collectDefineIdpNames(root) {
|
|
12
|
+
const direct = /* @__PURE__ */ new Set();
|
|
13
|
+
const namespaces = /* @__PURE__ */ new Set();
|
|
14
|
+
for (const importStmt of findImportStatements(root)) {
|
|
15
|
+
if (importSource(importStmt) !== SDK_MODULE || isTypeOnlyImport(importStmt)) continue;
|
|
16
|
+
for (const binding of importBindings(importStmt)) if (binding.importedName === DEFINE_IDP) direct.add(binding.localName);
|
|
17
|
+
for (const namespaceImport of importStmt.findAll({ rule: { kind: "namespace_import" } })) for (const identifier of namespaceImport.children()) if (identifier.kind() === "identifier") namespaces.add(identifier.text());
|
|
18
|
+
}
|
|
19
|
+
return {
|
|
20
|
+
direct,
|
|
21
|
+
namespaces
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function memberProperty(member) {
|
|
25
|
+
return member.children().findLast((child) => child.kind() === "property_identifier" || child.kind() === "identifier") ?? null;
|
|
26
|
+
}
|
|
27
|
+
function isDefineIdpCall(call, names) {
|
|
28
|
+
const callee = call.children()[0];
|
|
29
|
+
if (!callee) return false;
|
|
30
|
+
if (callee.kind() === "identifier") return names.direct.has(callee.text());
|
|
31
|
+
if (callee.kind() !== "member_expression") return false;
|
|
32
|
+
const object = callee.field("object");
|
|
33
|
+
return object?.kind() === "identifier" && names.namespaces.has(object.text()) && memberProperty(callee)?.text() === DEFINE_IDP;
|
|
34
|
+
}
|
|
35
|
+
function objectArguments(call) {
|
|
36
|
+
const args = call.children().find((child) => child.kind() === "arguments");
|
|
37
|
+
if (!args) return [];
|
|
38
|
+
return args.children().filter((child) => child.kind() === "object");
|
|
39
|
+
}
|
|
40
|
+
function findLegacyEntries(object) {
|
|
41
|
+
const entries = [];
|
|
42
|
+
for (const child of object.children()) {
|
|
43
|
+
if (child.kind() === "shorthand_property_identifier" && child.text() === LEGACY_KEY) {
|
|
44
|
+
entries.push({
|
|
45
|
+
node: child,
|
|
46
|
+
shorthand: true
|
|
47
|
+
});
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
if (child.kind() !== "pair") continue;
|
|
51
|
+
const key = child.children()[0];
|
|
52
|
+
if (!key) continue;
|
|
53
|
+
if (key.kind() !== "property_identifier" && key.kind() !== "string") continue;
|
|
54
|
+
if (stringValue(key) !== LEGACY_KEY) continue;
|
|
55
|
+
entries.push({
|
|
56
|
+
node: key,
|
|
57
|
+
shorthand: false
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return entries;
|
|
61
|
+
}
|
|
62
|
+
function renameEdit(entry) {
|
|
63
|
+
if (entry.shorthand) return entry.node.replace(`${NEW_KEY}: ${LEGACY_KEY}`);
|
|
64
|
+
const text = entry.node.text();
|
|
65
|
+
if (entry.node.kind() !== "string") return entry.node.replace(NEW_KEY);
|
|
66
|
+
const quote = text.startsWith("'") ? "'" : text.startsWith("`") ? "`" : "\"";
|
|
67
|
+
return entry.node.replace(`${quote}${NEW_KEY}${quote}`);
|
|
68
|
+
}
|
|
69
|
+
function parseRoot(source, filePath) {
|
|
70
|
+
try {
|
|
71
|
+
return parse(sourceLang(filePath, source), source).root();
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function shadowsDefineIdp(root, names) {
|
|
77
|
+
const declared = localDeclarationNames(root);
|
|
78
|
+
return [...names.direct, ...names.namespaces].some((name) => declared.has(name));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Rename the `publishUserEvents` option to `publishEvents` on `defineIdp` calls.
|
|
82
|
+
* @param source - File contents
|
|
83
|
+
* @param filePath - Path to the file being transformed
|
|
84
|
+
* @returns Transformed source, or null when nothing matched
|
|
85
|
+
*/
|
|
86
|
+
function transform(source, filePath = "") {
|
|
87
|
+
if (!source.includes(LEGACY_KEY) || !source.includes(SDK_MODULE)) return null;
|
|
88
|
+
const root = parseRoot(source, filePath);
|
|
89
|
+
if (!root) return null;
|
|
90
|
+
const names = collectDefineIdpNames(root);
|
|
91
|
+
if (names.direct.size === 0 && names.namespaces.size === 0) return null;
|
|
92
|
+
if (shadowsDefineIdp(root, names)) return null;
|
|
93
|
+
const edits = [];
|
|
94
|
+
for (const call of root.findAll({ rule: { kind: "call_expression" } })) {
|
|
95
|
+
if (!isDefineIdpCall(call, names)) continue;
|
|
96
|
+
for (const object of objectArguments(call)) for (const entry of findLegacyEntries(object)) edits.push(renameEdit(entry));
|
|
97
|
+
}
|
|
98
|
+
return edits.length > 0 ? root.commitEdits(edits) : null;
|
|
99
|
+
}
|
|
100
|
+
function lineOf(node) {
|
|
101
|
+
return node.range().start.line + 1;
|
|
102
|
+
}
|
|
103
|
+
function excerptOf(node) {
|
|
104
|
+
return node.text().split("\n", 1)[0].trim();
|
|
105
|
+
}
|
|
106
|
+
function coversIndex(ranges, index) {
|
|
107
|
+
return ranges.some((range) => index >= range.start && index < range.end);
|
|
108
|
+
}
|
|
109
|
+
/** Quoted keys, e.g. `{ "publishUserEvents": true }`, whose node kind is a string. */
|
|
110
|
+
function quotedLegacyKeys(root) {
|
|
111
|
+
return root.findAll({ rule: { kind: "pair" } }).flatMap((pair) => {
|
|
112
|
+
const key = pair.children()[0];
|
|
113
|
+
return key?.kind() === "string" && stringValue(key) === LEGACY_KEY ? [key] : [];
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/** Computed keys whose value cannot be read statically, e.g. `[key]: value`. */
|
|
117
|
+
function computedKeyEntries(object) {
|
|
118
|
+
return object.children().filter((child) => child.kind() === "pair").flatMap((pair) => {
|
|
119
|
+
const key = pair.children()[0];
|
|
120
|
+
return key?.kind() === "computed_property_name" ? [key] : [];
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Report `publishUserEvents` occurrences the transform cannot rewrite.
|
|
125
|
+
*
|
|
126
|
+
* Occurrences nested deeper inside a `defineIdp` options object belong to a
|
|
127
|
+
* different option shape (e.g. `userAuthPolicy`) and are left alone, so only
|
|
128
|
+
* what the transform genuinely missed is reported.
|
|
129
|
+
* @param source - File contents
|
|
130
|
+
* @param filePath - Path to the file being reviewed
|
|
131
|
+
* @param relativePath - Repository-relative path reported to the user
|
|
132
|
+
* @returns Findings for occurrences needing a manual rename
|
|
133
|
+
*/
|
|
134
|
+
function reviewFindings(source, filePath, relativePath) {
|
|
135
|
+
if (!source.includes(LEGACY_KEY) || !source.includes(SDK_MODULE)) return [];
|
|
136
|
+
const root = parseRoot(source, filePath);
|
|
137
|
+
if (!root) return [];
|
|
138
|
+
const names = collectDefineIdpNames(root);
|
|
139
|
+
const hasDefineIdp = names.direct.size > 0 || names.namespaces.size > 0;
|
|
140
|
+
if (hasDefineIdp && shadowsDefineIdp(root, names)) return [{
|
|
141
|
+
file: relativePath,
|
|
142
|
+
line: 1,
|
|
143
|
+
message: `A local declaration shadows the SDK ${DEFINE_IDP} import; rename ${LEGACY_KEY} to ${NEW_KEY} by hand.`,
|
|
144
|
+
excerpt: LEGACY_KEY
|
|
145
|
+
}];
|
|
146
|
+
const rewritten = /* @__PURE__ */ new Set();
|
|
147
|
+
const optionRanges = [];
|
|
148
|
+
const findings = [];
|
|
149
|
+
if (hasDefineIdp) for (const call of root.findAll({ rule: { kind: "call_expression" } })) {
|
|
150
|
+
if (!isDefineIdpCall(call, names)) continue;
|
|
151
|
+
for (const object of objectArguments(call)) {
|
|
152
|
+
const range = object.range();
|
|
153
|
+
optionRanges.push({
|
|
154
|
+
start: range.start.index,
|
|
155
|
+
end: range.end.index
|
|
156
|
+
});
|
|
157
|
+
for (const entry of findLegacyEntries(object)) rewritten.add(entry.node.range().start.index);
|
|
158
|
+
for (const key of computedKeyEntries(object)) findings.push({
|
|
159
|
+
file: relativePath,
|
|
160
|
+
line: lineOf(key),
|
|
161
|
+
message: `A computed ${DEFINE_IDP} option key may be ${LEGACY_KEY}; rename it to ${NEW_KEY} if so.`,
|
|
162
|
+
excerpt: excerptOf(key)
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const residual = [...root.findAll({ rule: { any: [{
|
|
167
|
+
kind: "property_identifier",
|
|
168
|
+
regex: `^${LEGACY_KEY}$`
|
|
169
|
+
}, {
|
|
170
|
+
kind: "shorthand_property_identifier",
|
|
171
|
+
regex: `^${LEGACY_KEY}$`
|
|
172
|
+
}] } }), ...quotedLegacyKeys(root)];
|
|
173
|
+
for (const node of residual) {
|
|
174
|
+
const index = node.range().start.index;
|
|
175
|
+
if (rewritten.has(index) || coversIndex(optionRanges, index)) continue;
|
|
176
|
+
findings.push({
|
|
177
|
+
file: relativePath,
|
|
178
|
+
line: lineOf(node),
|
|
179
|
+
message: `Rename the IdP option ${LEGACY_KEY} to ${NEW_KEY}.`,
|
|
180
|
+
excerpt: excerptOf(node)
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
return findings;
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
export { transform as default, reviewFindings };
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import * as path from "pathe";
|
|
2
2
|
//#region codemods/v2/sdk-skills-shim/scripts/transform.ts
|
|
3
|
-
const SHIM_PATTERN =
|
|
4
|
-
const
|
|
3
|
+
const SHIM_PATTERN = new RegExp(`((?<![\\w.-])(?:npx|bunx|(?:pnpm|yarn)[ \\t]+dlx|npm[ \\t]+exec)(?:[ \\t]+-{1,2}[\\w-]*)*[ \\t]+)?\\btailor-sdk-skills(?:@[^\\s'"\`]+)?(?:[ \\t]+install)?\\b(?!-)`, "g");
|
|
4
|
+
const CLI_BINARY = "tailor";
|
|
5
|
+
const CLI_PACKAGE = "@tailor-platform/sdk";
|
|
5
6
|
function replaceShim(value) {
|
|
6
|
-
return value.replace(SHIM_PATTERN,
|
|
7
|
+
return value.replace(SHIM_PATTERN, (_match, runner) => `${runner ?? ""}${runner == null ? CLI_BINARY : CLI_PACKAGE} skills add`);
|
|
7
8
|
}
|
|
8
9
|
function transformText(source) {
|
|
9
10
|
if (!SHIM_PATTERN.test(source)) return null;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import * as path from "pathe";
|
|
2
|
+
//#region codemods/v2/seed-exec-to-cli-plugin/scripts/transform.ts
|
|
3
|
+
const NODE_BINARY = "(?<![\\w.-])node(?![\\w-])";
|
|
4
|
+
const ARG_VALUE = `(?:[^\\s'"\`;&|]+|'[^']*'|"(?:(?:\\\\.)|[^"\\\\])*")`;
|
|
5
|
+
const SPACE = String.raw`(?:[^\S\n\r]|\\\r?\n)+`;
|
|
6
|
+
const VALUE_NODE_FLAG = "(?:--env-file|--env-file-if-exists|--import|--require|-r)";
|
|
7
|
+
const BOOLEAN_NODE_FLAG = "(?:--[^\\s'\"`;&|]+|-[^\\s'\"`;&|=-][^\\s'\"`;&|=]*)";
|
|
8
|
+
const NODE_FLAGS = `(?:(?:${SPACE}${VALUE_NODE_FLAG}(?:=${ARG_VALUE}|${SPACE}${ARG_VALUE}))|(?:${SPACE}${BOOLEAN_NODE_FLAG}))*`;
|
|
9
|
+
const RUNNER_PATH = `(?:[\\w.@~-]+/)+exec\\.mjs`;
|
|
10
|
+
const RUNNER_PATTERN = new RegExp(`${NODE_BINARY}(${NODE_FLAGS})${SPACE}(['"]?)(?:\\./)?${RUNNER_PATH}\\2(${SPACE}validate(?![-\\w=.:/]))?`, "g");
|
|
11
|
+
const FORK_PATTERN = /(?<![\w.$])fork\s*\(/;
|
|
12
|
+
const FORK_RUNNER_PATTERN = new RegExp(`${FORK_PATTERN.source}\\s*(['"\`])${RUNNER_PATH}\\1`, "gs");
|
|
13
|
+
const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
14
|
+
".ts",
|
|
15
|
+
".tsx",
|
|
16
|
+
".mts",
|
|
17
|
+
".cts",
|
|
18
|
+
".js",
|
|
19
|
+
".jsx",
|
|
20
|
+
".mjs",
|
|
21
|
+
".cjs"
|
|
22
|
+
]);
|
|
23
|
+
const NODE_FLAG_PATTERN = new RegExp(`(${VALUE_NODE_FLAG})(?:=(${ARG_VALUE})|${SPACE}(${ARG_VALUE}))|(${BOOLEAN_NODE_FLAG})`, "g");
|
|
24
|
+
const ENV_FILE_FLAG = /^--env-file(?:-if-exists)?$/;
|
|
25
|
+
const RUNNER_PREFIX_PATTERN = new RegExp(`(?<![\\w.-])(pnpm|npm|yarn|bunx|bun|npx)(?:${SPACE}(run|exec|dlx))?${SPACE}$`);
|
|
26
|
+
const RUNNER_PREFIX_WINDOW = 64;
|
|
27
|
+
const CLI_BINARY = "tailor";
|
|
28
|
+
const CLI_PACKAGE = "@tailor-platform/sdk";
|
|
29
|
+
const PACKAGE_RUNNER = `npx ${CLI_PACKAGE}`;
|
|
30
|
+
/** Whether a runner installs names it cannot resolve from the project. */
|
|
31
|
+
function installsMissingNames(runner, subcommand) {
|
|
32
|
+
if (runner === "npx" || runner === "bunx") return true;
|
|
33
|
+
if (subcommand === "dlx") return true;
|
|
34
|
+
return runner === "npm" && subcommand === "exec";
|
|
35
|
+
}
|
|
36
|
+
/** Translate the leading `node` flags into flags the CLI command accepts. */
|
|
37
|
+
function carriedOverFlags(nodeFlags) {
|
|
38
|
+
return [...nodeFlags.matchAll(NODE_FLAG_PATTERN)].filter((match) => match[1] != null && ENV_FILE_FLAG.test(match[1])).map((match) => ` ${match[1]} ${match[2] ?? match[3]}`).join("");
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Rewrite runner invocations. The runner spells validation as its first
|
|
42
|
+
* positional argument, so a consumed `validate` selects the subcommand.
|
|
43
|
+
*/
|
|
44
|
+
function rewrite(value, inventedHead = CLI_BINARY) {
|
|
45
|
+
return value.replace(RUNNER_PATTERN, (_match, nodeFlags, _quote, validate, offset) => {
|
|
46
|
+
const command = validate ? "validate" : "apply";
|
|
47
|
+
const before = value.slice(Math.max(0, offset - RUNNER_PREFIX_WINDOW), offset);
|
|
48
|
+
const existing = RUNNER_PREFIX_PATTERN.exec(before);
|
|
49
|
+
return `${existing ? installsMissingNames(existing[1], existing[2]) ? CLI_PACKAGE : CLI_BINARY : inventedHead} seed ${command}${carriedOverFlags(nodeFlags)}`;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function transformText(source) {
|
|
53
|
+
const updated = rewrite(source);
|
|
54
|
+
return updated === source ? null : updated;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Source files reach the plugin through a package runner rather than the bare
|
|
58
|
+
* binary, since the plugin executable is resolved from the project's
|
|
59
|
+
* node_modules rather than the PATH.
|
|
60
|
+
*/
|
|
61
|
+
function transformSourceText(source) {
|
|
62
|
+
const updated = rewrite(source, PACKAGE_RUNNER);
|
|
63
|
+
if (FORK_PATTERN.test(source) && updated.includes("exec.mjs")) return null;
|
|
64
|
+
return updated === source ? null : updated;
|
|
65
|
+
}
|
|
66
|
+
function transformPackageJson(source) {
|
|
67
|
+
let parsed;
|
|
68
|
+
try {
|
|
69
|
+
parsed = JSON.parse(source);
|
|
70
|
+
} catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const scripts = parsed.scripts;
|
|
74
|
+
if (typeof scripts !== "object" || scripts == null || Array.isArray(scripts)) return null;
|
|
75
|
+
let modified = false;
|
|
76
|
+
for (const [name, value] of Object.entries(scripts)) {
|
|
77
|
+
if (typeof value !== "string") continue;
|
|
78
|
+
const updated = rewrite(value);
|
|
79
|
+
if (updated !== value) {
|
|
80
|
+
scripts[name] = updated;
|
|
81
|
+
modified = true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!modified) return null;
|
|
85
|
+
const trailing = source.endsWith("\n") ? "\n" : "";
|
|
86
|
+
return JSON.stringify(parsed, null, 2) + trailing;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Rewrite generated seed runner invocations to the `tailor seed` CLI plugin.
|
|
90
|
+
* @param source - File contents
|
|
91
|
+
* @param filePath - Absolute path to the file (used to dispatch package.json vs source vs text)
|
|
92
|
+
* @returns Transformed source or null when nothing matched.
|
|
93
|
+
*/
|
|
94
|
+
function transform(source, filePath) {
|
|
95
|
+
if (!source.includes("exec.mjs")) return null;
|
|
96
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
97
|
+
if (ext === ".json") return transformPackageJson(source);
|
|
98
|
+
if (SOURCE_EXTENSIONS.has(ext)) return transformSourceText(source);
|
|
99
|
+
return transformText(source);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Report `fork()` call sites the transform declined, so the migration surfaces
|
|
103
|
+
* the async-plumbing rewrite instead of silently leaving a stale invocation.
|
|
104
|
+
* @param source - Post-transform file contents
|
|
105
|
+
* @param filePath - Absolute path to the file
|
|
106
|
+
* @param relativePath - Path relative to the transformed project root
|
|
107
|
+
* @returns Locations that need manual migration.
|
|
108
|
+
*/
|
|
109
|
+
function reviewFindings(source, filePath, relativePath) {
|
|
110
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
111
|
+
if (!SOURCE_EXTENSIONS.has(ext)) return [];
|
|
112
|
+
if (!source.includes("exec.mjs") || !FORK_PATTERN.test(source)) return [];
|
|
113
|
+
const lines = source.split(/\r\n|\n|\r/);
|
|
114
|
+
return [...source.matchAll(FORK_RUNNER_PATTERN)].map((match) => {
|
|
115
|
+
const index = source.slice(0, match.index).split(/\r\n|\n|\r/).length - 1;
|
|
116
|
+
return {
|
|
117
|
+
file: relativePath,
|
|
118
|
+
line: index + 1,
|
|
119
|
+
message: "Replace the fork()-based seed runner call with execSync(\"npx @tailor-platform/sdk seed apply\"), forwarding env/stdio, and unwind the surrounding await/Promise plumbing.",
|
|
120
|
+
excerpt: lines[index].trim()
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
//#endregion
|
|
125
|
+
export { transform as default, reviewFindings };
|
|
@@ -3,7 +3,7 @@ import { Lang, parse } from "@ast-grep/napi";
|
|
|
3
3
|
//#region codemods/v2/workflow-trigger-rename/scripts/transform.ts
|
|
4
4
|
const RENAMES = {
|
|
5
5
|
triggerWorkflow: "startWorkflow",
|
|
6
|
-
triggerJobFunction: "
|
|
6
|
+
triggerJobFunction: "execJobFunction",
|
|
7
7
|
resumeWorkflow: "resumeWorkflowExecution"
|
|
8
8
|
};
|
|
9
9
|
const WORKFLOW_MODULE_SOURCES = /* @__PURE__ */ new Set(["@tailor-platform/sdk/runtime", "@tailor-platform/sdk/runtime/workflow"]);
|
|
@@ -83,7 +83,8 @@ function findInvokerOptionEdit(member) {
|
|
|
83
83
|
}
|
|
84
84
|
/**
|
|
85
85
|
* Rewrite `.triggerWorkflow(`, `.triggerJobFunction(`, and `.resumeWorkflow(`
|
|
86
|
-
* member accesses to their canonical `
|
|
86
|
+
* member accesses to their canonical `startWorkflow`/`execJobFunction`/
|
|
87
|
+
* `resumeWorkflowExecution` names,
|
|
87
88
|
* either on the ambient `tailor.workflow` global or on a `workflow` value
|
|
88
89
|
* imported from `@tailor-platform/sdk/runtime(/workflow)`.
|
|
89
90
|
* @param source - File contents
|
package/dist/index.js
CHANGED
|
@@ -121,6 +121,7 @@ const V2_NEXT_5 = "2.0.0-next.5";
|
|
|
121
121
|
const V2_NEXT_6 = "2.0.0-next.6";
|
|
122
122
|
const V2_NEXT_7 = "2.0.0-next.7";
|
|
123
123
|
const V2_NEXT_9 = "2.0.0-next.9";
|
|
124
|
+
const V2_NEXT_11 = "2.0.0-next.11";
|
|
124
125
|
/** All registered codemods, in registration order. */
|
|
125
126
|
const allCodemods = [
|
|
126
127
|
{
|
|
@@ -204,13 +205,16 @@ const allCodemods = [
|
|
|
204
205
|
examples: [{
|
|
205
206
|
lang: "sh",
|
|
206
207
|
before: "npx tailor-sdk-skills",
|
|
207
|
-
after: "tailor skills add"
|
|
208
|
+
after: "npx @tailor-platform/sdk skills add"
|
|
208
209
|
}],
|
|
209
210
|
prompt: [
|
|
210
211
|
"The standalone tailor-sdk-skills binary is removed in v2; call the skills add",
|
|
211
212
|
"subcommand on the main tailor CLI instead. Replace any remaining",
|
|
212
213
|
"tailor-sdk-skills invocations the codemod did not rewrite with",
|
|
213
|
-
"`tailor skills add
|
|
214
|
+
"`tailor skills add`, or `npx @tailor-platform/sdk skills add` when the",
|
|
215
|
+
"invocation runs through a package runner (npx, bunx, pnpm/yarn dlx, npm exec)",
|
|
216
|
+
"— those resolve a package name, and `npx tailor` reaches an unrelated",
|
|
217
|
+
"`tailor` package on npm."
|
|
214
218
|
].join("\n")
|
|
215
219
|
},
|
|
216
220
|
{
|
|
@@ -676,6 +680,39 @@ const allCodemods = [
|
|
|
676
680
|
after: "await executeScript({ ...opts, arg: { a: 1 } });"
|
|
677
681
|
}]
|
|
678
682
|
},
|
|
683
|
+
{
|
|
684
|
+
id: "v2/idp-publish-events-rename",
|
|
685
|
+
name: "defineIdp publishUserEvents → publishEvents",
|
|
686
|
+
description: "Rename the `defineIdp` option `publishUserEvents` to `publishEvents`, matching the field name TailorDB types, resolvers, and workflows already use.",
|
|
687
|
+
since: "1.5.0",
|
|
688
|
+
until: "2.0.0",
|
|
689
|
+
prereleaseUntil: V2_NEXT_11,
|
|
690
|
+
scriptPath: "v2/idp-publish-events-rename/scripts/transform.js",
|
|
691
|
+
examples: [{
|
|
692
|
+
before: "import { defineIdp } from \"@tailor-platform/sdk\";\n\nexport const idp = defineIdp(\"my-idp\", {\n clients: [\"my-client\"],\n publishUserEvents: true,\n});",
|
|
693
|
+
after: "import { defineIdp } from \"@tailor-platform/sdk\";\n\nexport const idp = defineIdp(\"my-idp\", {\n clients: [\"my-client\"],\n publishEvents: true,\n});"
|
|
694
|
+
}, {
|
|
695
|
+
caption: "A shorthand option keeps reading the same local:",
|
|
696
|
+
before: "defineIdp(\"my-idp\", { clients, publishUserEvents });",
|
|
697
|
+
after: "defineIdp(\"my-idp\", { clients, publishEvents: publishUserEvents });"
|
|
698
|
+
}],
|
|
699
|
+
prompt: [
|
|
700
|
+
"In Tailor SDK v2, the IdP option `publishUserEvents` is renamed to",
|
|
701
|
+
"`publishEvents`, so all four services that publish events use one field name.",
|
|
702
|
+
"The codemod rewrites the option key on `defineIdp` calls whose callee resolves",
|
|
703
|
+
"to the SDK export, including aliased and namespace imports, and rewrites a",
|
|
704
|
+
"shorthand `{ publishUserEvents }` to `{ publishEvents: publishUserEvents }` so",
|
|
705
|
+
"it keeps reading the same local.",
|
|
706
|
+
"",
|
|
707
|
+
"Also review, and migrate by hand:",
|
|
708
|
+
"- An options object built in a variable or spread into the call — the codemod",
|
|
709
|
+
" only rewrites object literals passed directly to `defineIdp`.",
|
|
710
|
+
"- A computed key (e.g. `[key]: value`) that resolves to `publishUserEvents`.",
|
|
711
|
+
"- Type annotations or interfaces that declare the option themselves.",
|
|
712
|
+
"- A file where a local declaration shadows the `defineIdp` import; the codemod",
|
|
713
|
+
" skips it because the call may not be the SDK export."
|
|
714
|
+
].join("\n")
|
|
715
|
+
},
|
|
679
716
|
{
|
|
680
717
|
id: "v2/wait-point-rename",
|
|
681
718
|
name: "defineWaitPoint/defineWaitPoints → createWaitPoint/createWaitPoints",
|
|
@@ -691,8 +728,8 @@ const allCodemods = [
|
|
|
691
728
|
},
|
|
692
729
|
{
|
|
693
730
|
id: "v2/workflow-trigger-rename",
|
|
694
|
-
name: "workflow.triggerWorkflow/triggerJobFunction/resumeWorkflow → startWorkflow/
|
|
695
|
-
description: "Rename tailor.workflow call sites from the pre-alignment triggerWorkflow/triggerJobFunction/resumeWorkflow names to the canonical startWorkflow/
|
|
731
|
+
name: "workflow.triggerWorkflow/triggerJobFunction/resumeWorkflow → startWorkflow/execJobFunction/resumeWorkflowExecution",
|
|
732
|
+
description: "Rename tailor.workflow call sites from the pre-alignment triggerWorkflow/triggerJobFunction/resumeWorkflow names to the canonical startWorkflow/execJobFunction/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.",
|
|
696
733
|
since: "1.0.0",
|
|
697
734
|
until: "2.0.0",
|
|
698
735
|
prereleaseUntil: V2_NEXT_6,
|
|
@@ -714,7 +751,7 @@ const allCodemods = [
|
|
|
714
751
|
prompt: [
|
|
715
752
|
"The pre-alignment tailor.workflow names triggerWorkflow, triggerJobFunction, and",
|
|
716
753
|
"resumeWorkflow are removed from the SDK's type surface in v2; use the canonical",
|
|
717
|
-
"startWorkflow,
|
|
754
|
+
"startWorkflow, execJobFunction, and resumeWorkflowExecution names instead. The",
|
|
718
755
|
"codemod rewrites direct member-access call sites on the ambient tailor.workflow",
|
|
719
756
|
"global and on a workflow value imported from @tailor-platform/sdk/runtime or",
|
|
720
757
|
"@tailor-platform/sdk/runtime/workflow (including aliased imports). It skips a",
|
|
@@ -731,12 +768,45 @@ const allCodemods = [
|
|
|
731
768
|
"- Destructured references (e.g. const { triggerWorkflow } = workflow) — the",
|
|
732
769
|
" codemod only rewrites direct member-access calls.",
|
|
733
770
|
"- Imported TriggerWorkflowOptions / TriggerJobFunctionOptions types — rename",
|
|
734
|
-
" them to StartWorkflowOptions /
|
|
771
|
+
" them to StartWorkflowOptions / ExecJobFunctionOptions.",
|
|
735
772
|
"- An invoker option passed via a variable or spread (not a literal object) —",
|
|
736
773
|
" the codemod only inspects literal object arguments; rename the invoker key",
|
|
737
774
|
" to authInvoker in the options object's own definition."
|
|
738
775
|
].join("\n")
|
|
739
776
|
},
|
|
777
|
+
{
|
|
778
|
+
id: "v2/exec-job-function-rename",
|
|
779
|
+
name: "workflow.startJobFunction → execJobFunction",
|
|
780
|
+
description: "`tailor.workflow.startJobFunction` and the `StartJobFunctionOptions` type are removed in v2. Use the canonical `execJobFunction` / `ExecJobFunctionOptions`: `Exec*` blocks and returns the job's result, while `Start*` returns only an execution ID. The codemod rewrites member-access call sites on the ambient `tailor.workflow` global and on a `workflow` value imported from @tailor-platform/sdk/runtime(/workflow), and renames `StartJobFunctionOptions` imports along with the type references that resolve to them.",
|
|
781
|
+
since: "1.0.0",
|
|
782
|
+
until: "2.0.0",
|
|
783
|
+
prereleaseUntil: V2_NEXT_11,
|
|
784
|
+
scriptPath: "v2/exec-job-function-rename/scripts/transform.js",
|
|
785
|
+
filePatterns: ["**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"],
|
|
786
|
+
legacyPatterns: ["startJobFunction", "StartJobFunctionOptions"],
|
|
787
|
+
examples: [{
|
|
788
|
+
before: "import { workflow } from \"@tailor-platform/sdk/runtime\";\n\nconst result = workflow.startJobFunction(\"myJob\", { data: \"value\" });",
|
|
789
|
+
after: "import { workflow } from \"@tailor-platform/sdk/runtime\";\n\nconst result = workflow.execJobFunction(\"myJob\", { data: \"value\" });"
|
|
790
|
+
}],
|
|
791
|
+
prompt: [
|
|
792
|
+
"startJobFunction is removed from the SDK's workflow runtime surface in v2;",
|
|
793
|
+
"execJobFunction is the canonical name for a blocking job call that returns the",
|
|
794
|
+
"job's result. The codemod rewrites direct member-access calls on the ambient",
|
|
795
|
+
"tailor.workflow global and on a workflow value imported from",
|
|
796
|
+
"@tailor-platform/sdk/runtime or @tailor-platform/sdk/runtime/workflow (including",
|
|
797
|
+
"aliased imports), and renames the StartJobFunctionOptions type. It skips a file",
|
|
798
|
+
"entirely when a local declaration shadows the workflow import or the ambient",
|
|
799
|
+
"tailor name, to avoid rewriting an unrelated same-named value.",
|
|
800
|
+
"",
|
|
801
|
+
"Also review, and migrate by hand:",
|
|
802
|
+
"- Destructured references (e.g. const { startJobFunction } = workflow) — the",
|
|
803
|
+
" codemod only rewrites direct member-access calls.",
|
|
804
|
+
"- mockWorkflow().startJobFunction in tests — assert on the execJobFunction vi.fn",
|
|
805
|
+
" instead; the alias was the same mock function.",
|
|
806
|
+
"- A file that already imports ExecJobFunctionOptions alongside the removed type —",
|
|
807
|
+
" rename the remaining references by hand and drop the duplicate specifier."
|
|
808
|
+
].join("\n")
|
|
809
|
+
},
|
|
740
810
|
{
|
|
741
811
|
id: "v2/open-download-stream",
|
|
742
812
|
name: "openDownloadStream → downloadStream",
|
|
@@ -885,6 +955,15 @@ const allCodemods = [
|
|
|
885
955
|
" where they describe this SDK verb specifically, not unrelated event terminology."
|
|
886
956
|
].join("\n")
|
|
887
957
|
},
|
|
958
|
+
{
|
|
959
|
+
id: "v2/publish-events-recomputed-per-deploy",
|
|
960
|
+
name: "publishEvents recomputed from the executors in each deploy",
|
|
961
|
+
description: "An unset `publishEvents` is recomputed on every `deploy` from the executors taking part in the run, in both directions: adding a subscribing trigger turns publishing on, and removing the last one turns it back off. Previously a workflow or job kept publishing once it had been enabled, so a workflow whose subscribing trigger is already gone stops publishing on the next `deploy` — declare `publishEvents: true` on it if something outside this project consumes those events. `deploy` also stops instead of applying when a subscription cannot be satisfied: when a trigger names a resource no config in the run declares, when a workflow or job combines `publishEvents: false` with a subscribing trigger, and when a config that resolves without an `id` subscribes across configs. Each of those errors names the resource and both ways to resolve it.",
|
|
962
|
+
since: "1.0.0",
|
|
963
|
+
until: "2.0.0",
|
|
964
|
+
prereleaseUntil: V2_NEXT_11,
|
|
965
|
+
notice: true
|
|
966
|
+
},
|
|
888
967
|
{
|
|
889
968
|
id: "v2/cli-token-keyring-storage",
|
|
890
969
|
name: "CLI tokens stored in the OS keyring",
|
|
@@ -1179,12 +1258,18 @@ const allCodemods = [
|
|
|
1179
1258
|
{
|
|
1180
1259
|
id: "v2/seed-exec-to-cli-plugin",
|
|
1181
1260
|
name: "Generated seed exec.mjs → tailor seed CLI plugin",
|
|
1182
|
-
description: "`seedPlugin` no longer generates the `exec.mjs` seed runner. Seeding and validation move to the `tailor seed` commands provided by the `@tailor-platform/sdk-plugin-seed` CLI plugin: install it as a devDependency, replace `node <distPath>/exec.mjs` invocations with `tailor seed apply` and `node <distPath>/exec.mjs validate` with `tailor seed validate`, and delete the stale generated `<distPath>/exec.mjs` file. Seed data and schema generation (`data/*.jsonl`, `data/*.schema.ts`) is unchanged, and the `tailor seed apply` options mirror the old script (`--machine-user`, `--namespace`, `--skip-idp`, `--truncate`, `--yes`, type-name arguments).",
|
|
1261
|
+
description: "`seedPlugin` no longer generates the `exec.mjs` seed runner. Seeding and validation move to the `tailor seed` commands provided by the `@tailor-platform/sdk-plugin-seed` CLI plugin: install it as a devDependency, replace `node <distPath>/exec.mjs` invocations with `tailor seed apply` and `node <distPath>/exec.mjs validate` with `tailor seed validate`, and delete the stale generated `<distPath>/exec.mjs` file. Seed data and schema generation (`data/*.jsonl`, `data/*.schema.ts`) is unchanged, and the `tailor seed apply` options mirror the old script (`--machine-user`, `--namespace`, `--skip-idp`, `--truncate`, `--yes`, type-name arguments), plus a new `--upsert` flag to update existing rows instead of failing on duplicate ids.",
|
|
1183
1262
|
since: "1.0.0",
|
|
1184
1263
|
until: "2.0.0",
|
|
1185
1264
|
prereleaseUntil: V2_NEXT_9,
|
|
1186
|
-
|
|
1187
|
-
|
|
1265
|
+
scriptPath: "v2/seed-exec-to-cli-plugin/scripts/transform.js",
|
|
1266
|
+
filePatterns: [
|
|
1267
|
+
"**/package.json",
|
|
1268
|
+
"**/*.{sh,bash,zsh,yml,yaml}",
|
|
1269
|
+
"**/*.md",
|
|
1270
|
+
"**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}"
|
|
1271
|
+
],
|
|
1272
|
+
suspiciousPatterns: [/[\w./@~${}-]+\/exec\.mjs/],
|
|
1188
1273
|
sourceStringSuspiciousPatterns: ["exec.mjs"],
|
|
1189
1274
|
examples: [{
|
|
1190
1275
|
before: "\"seed\": \"node ./seed/exec.mjs\",\n\"seed:validate\": \"node ./seed/exec.mjs validate\"",
|
|
@@ -1199,11 +1284,122 @@ const allCodemods = [
|
|
|
1199
1284
|
" @tailor-platform/sdk.",
|
|
1200
1285
|
"- Replace `node <distPath>/exec.mjs [options] [types...]` invocations with",
|
|
1201
1286
|
" `tailor seed apply [options] [types...]` (same options: --machine-user/-m,",
|
|
1202
|
-
" --namespace/-n, --skip-idp, --truncate, --yes, and type-name arguments
|
|
1287
|
+
" --namespace/-n, --skip-idp, --truncate, --yes, and type-name arguments,",
|
|
1288
|
+
" plus a new --upsert flag to update existing rows instead of failing on",
|
|
1289
|
+
" duplicate ids).",
|
|
1203
1290
|
"- Replace `node <distPath>/exec.mjs validate [path]` with",
|
|
1204
1291
|
" `tailor seed validate [path]`.",
|
|
1292
|
+
"- Rewrite `fork(\"<distPath>/exec.mjs\", ...)` call sites (test setup files",
|
|
1293
|
+
" typically fork the runner and await a hand-rolled Promise around",
|
|
1294
|
+
" `child.on(\"close\", ...)`). The plugin is a CLI-dispatched binary rather",
|
|
1295
|
+
" than a forkable JS module, so call it synchronously instead —",
|
|
1296
|
+
" `execSync(\"npx @tailor-platform/sdk seed apply\", { env, stdio: \"inherit\" })` — keeping",
|
|
1297
|
+
" the original `env` and `stdio` forwarding, and unwind the surrounding",
|
|
1298
|
+
" Promise wrapper (drop the now-unused `await`, and the `async` keyword when",
|
|
1299
|
+
" nothing else in the function awaits). Note that `execSync` throws on a",
|
|
1300
|
+
" nonzero exit, replacing the wrapper's explicit reject.",
|
|
1205
1301
|
"- Delete the stale generated `<distPath>/exec.mjs` file; keep the data/",
|
|
1206
|
-
" directory (JSONL data and generated schemas) as-is."
|
|
1302
|
+
" directory (JSONL data and generated schemas) as-is. Nothing removes it",
|
|
1303
|
+
" automatically, and a leftover runner keeps working while no longer being",
|
|
1304
|
+
" regenerated."
|
|
1305
|
+
].join("\n")
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
id: "v2/sdk-test-mocks-to-vitest",
|
|
1309
|
+
name: "@tailor-platform/sdk/test global mocks → @tailor-platform/sdk/vitest",
|
|
1310
|
+
description: "The global platform mocks exported from `@tailor-platform/sdk/test` (`setupTailordbMock`, `setupWorkflowMock`, `setupWaitPointMock`, `setupInvokerMock`, `setupTailorErrorsMock`) and the bundled-output helper `createImportMain` are removed in v2. Use the `tailor-runtime` environment from `@tailor-platform/sdk/vitest` together with `mockTailordb` / `mockWorkflow`: the environment injects `TailorErrors` for you, `setWaitHandler` / `setResolveHandler` replace the wait-point stubs, and the invoker is driven through `globalThis.tailor.context.getInvoker` (or passed directly to `.body()` when testing the TypeScript source). No codemod ships for this migration: it replaces per-test global stubs with a Vitest environment plus disposable mocks, which changes the Vitest config, the setup shape, and the assertions of every affected test. The other `@tailor-platform/sdk/test` exports (`createTailorDBHook`, `createStandardSchema`, `unauthenticatedTailorUser`) are unchanged.",
|
|
1311
|
+
since: "1.0.0",
|
|
1312
|
+
until: "2.0.0",
|
|
1313
|
+
prereleaseUntil: V2_NEXT_11,
|
|
1314
|
+
suspiciousPatterns: [
|
|
1315
|
+
"setupTailordbMock",
|
|
1316
|
+
"setupWorkflowMock",
|
|
1317
|
+
"setupWaitPointMock",
|
|
1318
|
+
"setupInvokerMock",
|
|
1319
|
+
"setupTailorErrorsMock",
|
|
1320
|
+
"createImportMain"
|
|
1321
|
+
],
|
|
1322
|
+
examples: [{
|
|
1323
|
+
caption: "Job mocks move from a global stub to a disposable mock:",
|
|
1324
|
+
before: "import { setupWorkflowMock } from \"@tailor-platform/sdk/test\";\n\nconst { startedJobs } = setupWorkflowMock(() => ({ ok: true }));",
|
|
1325
|
+
after: "import { mockWorkflow } from \"@tailor-platform/sdk/vitest\";\n\nusing wf = mockWorkflow();\nwf.setJobHandler(() => ({ ok: true }));\n// wf.startedJobs replaces the returned startedJobs array"
|
|
1326
|
+
}],
|
|
1327
|
+
prompt: [
|
|
1328
|
+
"The global platform mocks from @tailor-platform/sdk/test are removed in v2.",
|
|
1329
|
+
"Migrate each affected test to the tailor-runtime Vitest environment:",
|
|
1330
|
+
"",
|
|
1331
|
+
"1. Add the environment for the test files that need platform globals — set",
|
|
1332
|
+
" environment: \"tailor-runtime\" in the Vitest project config, or add the",
|
|
1333
|
+
" // @vitest-environment tailor-runtime docblock to the file. The environment",
|
|
1334
|
+
" ships in @tailor-platform/sdk/vitest and installs TailorErrors and the base",
|
|
1335
|
+
" tailor/tailordb globals, so setupTailorErrorsMock has no replacement — delete it.",
|
|
1336
|
+
"2. Replace setupTailordbMock(resolver) with using db = mockTailordb() and",
|
|
1337
|
+
" configure query results on that mock; read its recorded calls instead of the",
|
|
1338
|
+
" returned executedQueries / createdClients arrays.",
|
|
1339
|
+
"3. Replace setupWorkflowMock(handler) with using wf = mockWorkflow() plus",
|
|
1340
|
+
" wf.setJobHandler(handler) (or wf.enqueueResult(...) for order-based results),",
|
|
1341
|
+
" and read wf.startedJobs.",
|
|
1342
|
+
"4. Replace setupWaitPointMock({ onWait, onResolve }) with the same mockWorkflow()",
|
|
1343
|
+
" handle: wf.setWaitHandler / wf.setResolveHandler, asserting on wf.waitCalls /",
|
|
1344
|
+
" wf.resolveCalls.",
|
|
1345
|
+
"5. Replace setupInvokerMock(invoker) with",
|
|
1346
|
+
" vi.spyOn(globalThis.tailor.context, \"getInvoker\").mockReturnValue(raw) for a",
|
|
1347
|
+
" bundled test, or pass invoker directly to .body() when unit-testing a",
|
|
1348
|
+
" resolver/executor/workflow job against the TypeScript source.",
|
|
1349
|
+
"6. Drop createImportMain and the tests that import bundled output through it.",
|
|
1350
|
+
" Bundling integrity is the SDK's responsibility: unit-test the TypeScript",
|
|
1351
|
+
" source and cover deployed behavior with E2E tests instead.",
|
|
1352
|
+
"",
|
|
1353
|
+
"See the SDK testing guide for the full environment setup."
|
|
1354
|
+
].join("\n")
|
|
1355
|
+
},
|
|
1356
|
+
{
|
|
1357
|
+
id: "v2/cli-typed-options",
|
|
1358
|
+
name: "Programmatic CLI name options → workflow/executor definitions",
|
|
1359
|
+
description: "The name-keyed option types exported from `@tailor-platform/sdk/cli` — `GetWorkflowOptions`, `StartWorkflowOptions`, `ListWorkflowExecutionsOptions`, `GetExecutorOptions`, `TriggerExecutorOptions`, `ListExecutorJobsOptions`, `GetExecutorJobOptions`, `WatchExecutorJobOptions` — are removed in v2, together with the function overloads that accepted them. Pass the workflow or executor definition itself instead: `{ workflow: myWorkflow, invoker: \"admin\" }` / `{ executor: myExecutor }`, matching the `*TypedOptions` shape that types `arg` and `payload` from the definition. No codemod ships for this migration: rewriting a name string into a definition requires importing the module that defines the workflow or executor, which a source-local transform cannot resolve.",
|
|
1360
|
+
since: "1.0.0",
|
|
1361
|
+
until: "2.0.0",
|
|
1362
|
+
prereleaseUntil: V2_NEXT_11,
|
|
1363
|
+
suspiciousPatterns: [
|
|
1364
|
+
["@tailor-platform/sdk/cli", "executorName"],
|
|
1365
|
+
["@tailor-platform/sdk/cli", "workflowName"],
|
|
1366
|
+
["@tailor-platform/sdk/cli", "GetWorkflowOptions"],
|
|
1367
|
+
["@tailor-platform/sdk/cli", "StartWorkflowOptions"],
|
|
1368
|
+
["@tailor-platform/sdk/cli", "ListWorkflowExecutionsOptions"],
|
|
1369
|
+
["@tailor-platform/sdk/cli", "GetExecutorOptions"],
|
|
1370
|
+
["@tailor-platform/sdk/cli", "TriggerExecutorOptions"],
|
|
1371
|
+
["@tailor-platform/sdk/cli", "ListExecutorJobsOptions"],
|
|
1372
|
+
["@tailor-platform/sdk/cli", "GetExecutorJobOptions"],
|
|
1373
|
+
["@tailor-platform/sdk/cli", "WatchExecutorJobOptions"]
|
|
1374
|
+
],
|
|
1375
|
+
examples: [{
|
|
1376
|
+
before: "import { startWorkflow } from \"@tailor-platform/sdk/cli\";\n\nconst { executionId } = await startWorkflow({ name: \"user-sync\", machineUser: \"admin\" });",
|
|
1377
|
+
after: "import { startWorkflow } from \"@tailor-platform/sdk/cli\";\nimport userSync from \"./workflows/userSync\";\n\nconst { executionId } = await startWorkflow({ workflow: userSync, invoker: \"admin\" });"
|
|
1378
|
+
}, {
|
|
1379
|
+
caption: "Executor commands take the executor definition:",
|
|
1380
|
+
before: "const result = await watchExecutorJob({ executorName: \"daily-sync\", jobId });",
|
|
1381
|
+
after: "const result = await watchExecutorJob({ executor: dailySync, jobId });"
|
|
1382
|
+
}],
|
|
1383
|
+
prompt: [
|
|
1384
|
+
"The programmatic CLI functions in @tailor-platform/sdk/cli no longer accept a",
|
|
1385
|
+
"workflow or executor name; they take the definition object instead. For each",
|
|
1386
|
+
"flagged call site:",
|
|
1387
|
+
"",
|
|
1388
|
+
"1. Import the workflow or executor definition — the module whose default export",
|
|
1389
|
+
" is createWorkflow(...) or whose export is createExecutor(...) with that name.",
|
|
1390
|
+
"2. Replace name: \"my-workflow\" with workflow: myWorkflow, and",
|
|
1391
|
+
" executorName: \"my-executor\" with executor: myExecutor. For",
|
|
1392
|
+
" listWorkflowExecutions, workflowName becomes workflow.",
|
|
1393
|
+
"3. startWorkflow's machine user moves from machineUser to the required",
|
|
1394
|
+
" invoker, typed against the machine users declared in tailor.config.ts.",
|
|
1395
|
+
"4. Replace imported option types with the *TypedOptions equivalent",
|
|
1396
|
+
" (e.g. GetWorkflowOptions → GetWorkflowTypedOptions<typeof myWorkflow>).",
|
|
1397
|
+
" Note that arg (startWorkflow) and payload (triggerExecutor) are now typed",
|
|
1398
|
+
" from the definition, so a mistyped argument becomes a type error.",
|
|
1399
|
+
"",
|
|
1400
|
+
"When the name is only known at runtime (read from argv or an environment",
|
|
1401
|
+
"variable), the CLI command itself — `tailor workflow start <name>` /",
|
|
1402
|
+
"`tailor executor trigger <name>` — remains the name-keyed entry point."
|
|
1207
1403
|
].join("\n")
|
|
1208
1404
|
},
|
|
1209
1405
|
{
|
|
@@ -1221,6 +1417,40 @@ const allCodemods = [
|
|
|
1221
1417
|
since: "1.0.0",
|
|
1222
1418
|
until: "2.0.0",
|
|
1223
1419
|
notice: true
|
|
1420
|
+
},
|
|
1421
|
+
{
|
|
1422
|
+
id: "v2/dts-env-value-types",
|
|
1423
|
+
name: "tailor.d.ts Env uses value types instead of literal values",
|
|
1424
|
+
description: "The `Env` interface in `tailor.d.ts` is generated from the type of each `defineConfig({ env })` value (`string`, `number`, or `boolean`) instead of the value itself, so the generated file no longer carries whatever the config resolved to when it was generated. Keys that aren't valid TypeScript identifiers are quoted, which previously produced a file that failed to parse. Run `tailor generate` to refresh the file, then widen any code that depended on the old literal types. If a `tailor.d.ts` you already committed contains a sensitive value, treat that value as exposed and rotate it; keep secrets in Secret Manager rather than `env`.",
|
|
1425
|
+
since: "1.0.0",
|
|
1426
|
+
until: "2.0.0",
|
|
1427
|
+
prereleaseUntil: V2_NEXT_11,
|
|
1428
|
+
examples: [{
|
|
1429
|
+
lang: "ts",
|
|
1430
|
+
caption: "An env value can no longer stand in for a literal union; narrow it explicitly:",
|
|
1431
|
+
before: "const stage: \"production\" | \"staging\" = env.STAGE;",
|
|
1432
|
+
after: "const stage = env.STAGE === \"staging\" ? \"staging\" : \"production\";"
|
|
1433
|
+
}],
|
|
1434
|
+
prompt: [
|
|
1435
|
+
"Tailor SDK v2 generates the `Env` interface in `tailor.d.ts` from the type of",
|
|
1436
|
+
"each `defineConfig({ env })` value (`string`, `number`, `boolean`) instead of",
|
|
1437
|
+
"the resolved value, so `Env` properties no longer carry literal types.",
|
|
1438
|
+
"",
|
|
1439
|
+
"Run `tailor generate` first to refresh `tailor.d.ts`, then review the places",
|
|
1440
|
+
"that depended on the old literal types:",
|
|
1441
|
+
"",
|
|
1442
|
+
"- An env value assigned or passed where a literal union is required, e.g.",
|
|
1443
|
+
" `const stage: \"production\" | \"staging\" = env.STAGE`. Narrow it with a",
|
|
1444
|
+
" comparison or a validation helper instead of relying on the declared type.",
|
|
1445
|
+
"- A generic argument, conditional type, or template-literal type parameterized",
|
|
1446
|
+
" by an env value.",
|
|
1447
|
+
"- `as const` / `satisfies` assertions that assumed one specific literal.",
|
|
1448
|
+
"",
|
|
1449
|
+
"Plain comparisons (`env.STAGE === \"production\"`) and arithmetic on numeric env",
|
|
1450
|
+
"values keep working and need no change. Do not restore the old behavior by",
|
|
1451
|
+
"editing `tailor.d.ts`: it is generated and will be overwritten, and embedding",
|
|
1452
|
+
"env values there is what leaked configured secrets into version control."
|
|
1453
|
+
].join("\n")
|
|
1224
1454
|
}
|
|
1225
1455
|
];
|
|
1226
1456
|
/**
|
|
@@ -1238,23 +1468,45 @@ function reachesCodemodBoundary(toVersion, codemod) {
|
|
|
1238
1468
|
const boundary = parse(codemod.until);
|
|
1239
1469
|
return target.prerelease.length > 0 && target.major === boundary.major && target.minor === boundary.minor && target.patch === boundary.patch;
|
|
1240
1470
|
}
|
|
1471
|
+
/**
|
|
1472
|
+
* The version a codemod's migration is due by: its `prereleaseUntil` while that
|
|
1473
|
+
* names a concrete prerelease, and `until` otherwise.
|
|
1474
|
+
* @param codemod - The registered codemod
|
|
1475
|
+
* @returns The version its boundary sits at
|
|
1476
|
+
*/
|
|
1241
1477
|
function effectiveCodemodBoundary(codemod) {
|
|
1242
1478
|
if (codemod.prereleaseUntil === "pending") return codemod.until;
|
|
1243
1479
|
return codemod.prereleaseUntil ?? codemod.until;
|
|
1244
1480
|
}
|
|
1245
1481
|
function assertCodemodBoundaries(codemods) {
|
|
1246
1482
|
for (const codemod of codemods) {
|
|
1483
|
+
if (valid(codemod.since) === null) throw new Error(`Codemod ${codemod.id} since must be a valid semver version: ${codemod.since}`);
|
|
1247
1484
|
const boundary = parse(codemod.until);
|
|
1248
1485
|
if (boundary === null) throw new Error(`Codemod ${codemod.id} until must be a valid semver version: ${codemod.until}`);
|
|
1249
1486
|
if (boundary.prerelease.length > 0) throw new Error(`Codemod ${codemod.id} until must be a stable version: ${codemod.until}`);
|
|
1250
|
-
if (codemod.prereleaseUntil === void 0 || codemod.prereleaseUntil === "pending")
|
|
1487
|
+
if (codemod.prereleaseUntil === void 0 || codemod.prereleaseUntil === "pending") {
|
|
1488
|
+
assertNonEmptyRange(codemod);
|
|
1489
|
+
continue;
|
|
1490
|
+
}
|
|
1251
1491
|
const prereleaseBoundary = parse(codemod.prereleaseUntil);
|
|
1252
1492
|
if (prereleaseBoundary === null) throw new Error(`Codemod ${codemod.id} prereleaseUntil must be a valid semver version: ${codemod.prereleaseUntil}`);
|
|
1253
1493
|
if (prereleaseBoundary.prerelease.length === 0) throw new Error(`Codemod ${codemod.id} prereleaseUntil must be a prerelease version: ${codemod.prereleaseUntil}`);
|
|
1254
1494
|
if (prereleaseBoundary.major !== boundary.major || prereleaseBoundary.minor !== boundary.minor || prereleaseBoundary.patch !== boundary.patch) throw new Error(`Codemod ${codemod.id} prereleaseUntil must target the same version as until: ${codemod.prereleaseUntil}`);
|
|
1495
|
+
assertNonEmptyRange(codemod);
|
|
1255
1496
|
}
|
|
1256
1497
|
}
|
|
1257
1498
|
/**
|
|
1499
|
+
* A codemod applies while `since <= from < boundary`, so a `since` at or past the
|
|
1500
|
+
* boundary leaves an empty range and the codemod can never apply. The boundary is
|
|
1501
|
+
* `prereleaseUntil` once that names a concrete prerelease, which is earlier than
|
|
1502
|
+
* `until` — comparing against `until` alone would let that case through.
|
|
1503
|
+
* @param codemod - The registered codemod, with its boundaries already validated
|
|
1504
|
+
*/
|
|
1505
|
+
function assertNonEmptyRange(codemod) {
|
|
1506
|
+
const boundary = effectiveCodemodBoundary(codemod);
|
|
1507
|
+
if (!lt(codemod.since, boundary)) throw new Error(`Codemod ${codemod.id} since must be older than the boundary it applies up to: ${codemod.since} >= ${boundary}`);
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1258
1510
|
* Get codemod packages applicable for a version range.
|
|
1259
1511
|
* A codemod applies when: since <= fromVersion < boundary <= toVersion.
|
|
1260
1512
|
* A target prerelease reaches `until` only when the codemod declares `prereleaseUntil`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tailor-platform/sdk-codemod",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Codemod runner for Tailor Platform SDK upgrades",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
],
|
|
17
17
|
"type": "module",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@ast-grep/napi": "0.
|
|
19
|
+
"@ast-grep/napi": "0.45.0",
|
|
20
20
|
"chalk": "5.6.2",
|
|
21
21
|
"diff": "9.0.0",
|
|
22
22
|
"pathe": "2.0.3",
|
|
23
23
|
"picomatch": "4.0.5",
|
|
24
24
|
"pkg-types": "2.3.1",
|
|
25
|
-
"politty": "0.11.
|
|
25
|
+
"politty": "0.11.6",
|
|
26
26
|
"semver": "7.8.5",
|
|
27
27
|
"zod": "4.4.3"
|
|
28
28
|
},
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
"@types/node": "24.13.3",
|
|
31
31
|
"@types/picomatch": "4.0.3",
|
|
32
32
|
"@types/semver": "7.7.1",
|
|
33
|
-
"eslint-plugin-zod": "4.
|
|
34
|
-
"oxlint": "1.
|
|
35
|
-
"tsdown": "0.22.
|
|
33
|
+
"eslint-plugin-zod": "4.9.0",
|
|
34
|
+
"oxlint": "1.76.0",
|
|
35
|
+
"tsdown": "0.22.14",
|
|
36
36
|
"typescript": "6.0.3",
|
|
37
37
|
"vitest": "4.1.10"
|
|
38
38
|
},
|