diff --git a/.changeset/dedupe-pnpm-peer-variant-step-ids.md b/.changeset/dedupe-pnpm-peer-variant-step-ids.md new file mode 100644 index 0000000000..993fdd3b5a --- /dev/null +++ b/.changeset/dedupe-pnpm-peer-variant-step-ids.md @@ -0,0 +1,5 @@ +--- +'@workflow/builders': patch +--- + +Deduplicate identical pnpm peer-variant copies of a package instead of failing the build with a duplicate step/workflow ID error. Different implementations that map to the same ID still fail. diff --git a/.changeset/pre.json b/.changeset/pre.json index 122547c4da..8b8409d2a9 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -149,6 +149,7 @@ "date-subclass-vm", "decouple-vm-seed-from-startedat", "dedupe-otel-api", + "dedupe-pnpm-peer-variant-step-ids", "dense-stream-viewer", "deployment-id-latest-noop-non-vercel", "deprecate-storage-runs-observability", @@ -161,6 +162,7 @@ "display-occurred-at", "docs-event-sourcing-duplicate-events", "docs-migration-guides-redirects", + "docs-next-16-3-3", "docs-rendered-link-lint", "docs-step-executed-multiple-times", "docs-v5-whats-new-pages", @@ -286,6 +288,7 @@ "great-mails-argue", "great-news-beg", "green-streams-decode", + "guard-astro-sveltekit-writes", "guard-step-consumer-events", "gzip-ref-compression-core", "gzip-ref-compression-world-vercel", @@ -329,9 +332,13 @@ "lazy-discovery-default", "lazy-discovery-hmr", "lazy-hook-replay-preload", + "lazy-hook-resume-durable-abort", + "lazy-hook-resume-vitest", "lazy-hook-resumption", "lazy-inline-step-start", "lazy-next-step-imports", + "lazy-only-hook-resume-world", + "lazy-only-hook-resume", "lazy-resume-deployment-affinity", "lazy-stream-key-request-diagnostics", "lazy-vercel-world-bundle", @@ -418,6 +425,7 @@ "prewarm-next-swc-cache", "private-member-dce", "proud-friends-decide", + "prune-workflow-sandbox", "python-workbench-app", "queue-client-0-5-0", "queue-namespace-primitive", @@ -425,6 +433,7 @@ "quick-local-replay", "quickjs-baseline-snapshot", "quickjs-hook-capability", + "quickjs-hook-dispose-token", "quickjs-hook-retention", "quickjs-host-serde", "quickjs-inline-steps", @@ -446,6 +455,7 @@ "real-pens-cut", "reconnect-object-streams", "recover-invalid-tool-input", + "red-masks-rule", "reject-empty-hook-token", "relative-time-card", "remove-client-mode", @@ -464,6 +474,7 @@ "rename-set-attributes", "repair-ui-message-stream-framing", "replay-consumed-event-clock", + "replay-cost-telemetry", "replay-divergence-redelivery", "replay-lineage-execution-context", "replay-timeout-excludes-step-bodies", @@ -477,6 +488,8 @@ "resilient-step-dispatch-off", "resilient-step-dispatch", "resizable-trace-detail-panel", + "retain-vms-across-attributes", + "retain-vms-across-hooks", "retain-workflow-vm", "retained-vm-guest-code-gate", "retire-step-build-output", @@ -518,9 +531,11 @@ "silly-pears-jam", "silver-coins-deny", "silver-comics-care", + "sixty-lands-matter", "sixty-plants-shout", "skip-changeset-release-deploys", "skip-community-worlds-main", + "skip-perm-tests-when-dac-bypassed", "skip-unchanged-generated-writes", "skip-world-local-nov-ghosts", "slot-event-ids", @@ -648,6 +663,7 @@ "wild-taxes-guess", "windows-events-consumer-poll", "windows-inline-sourcemaps", + "windows-step-registration-cleanup", "wise-frogs-thank", "wise-planes-tell", "witty-pugs-applaud", diff --git a/.changeset/skip-perm-tests-when-dac-bypassed.md b/.changeset/skip-perm-tests-when-dac-bypassed.md index e69de29bb2..a845151cc8 100644 --- a/.changeset/skip-perm-tests-when-dac-bypassed.md +++ b/.changeset/skip-perm-tests-when-dac-bypassed.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/.changeset/tidy-local-shutdown.md b/.changeset/tidy-local-shutdown.md new file mode 100644 index 0000000000..3b4fef7d76 --- /dev/null +++ b/.changeset/tidy-local-shutdown.md @@ -0,0 +1,5 @@ +--- +'@workflow/world-local': patch +--- + +Abort active local queue deliveries when the World closes, including when transport timeouts are disabled. diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md index be91c13bc2..8697113626 100644 --- a/packages/astro/CHANGELOG.md +++ b/packages/astro/CHANGELOG.md @@ -1,5 +1,25 @@ # @workflow/astro +## 5.0.0-beta.46 + +### Patch Changes + +- [#3688](https://github.com/vercel/workflow/pull/3688) [`0750fe8`](https://github.com/vercel/workflow/commit/0750fe8958f50ee354cd24fe3f02a37c801bc4dc) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - Stop rewriting generated files whose content is unchanged, so a no-op rebuild no longer invalidates them in the dev server. + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f)]: + - @workflow/builders@5.0.0-beta.46 + - @workflow/rollup@5.0.0-beta.46 + - @workflow/vite@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/builders@5.0.0-beta.45 + - @workflow/rollup@5.0.0-beta.45 + - @workflow/vite@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/astro/package.json b/packages/astro/package.json index e8c26b22f4..63f50b98af 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/astro", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Astro integration for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/builders/CHANGELOG.md b/packages/builders/CHANGELOG.md index 7bc8c6995c..32a207f256 100644 --- a/packages/builders/CHANGELOG.md +++ b/packages/builders/CHANGELOG.md @@ -1,5 +1,25 @@ # @workflow/builders +## 5.0.0-beta.46 + +### Patch Changes + +- [#3795](https://github.com/vercel/workflow/pull/3795) [`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f) Thanks [@TooTallNate](https://github.com/TooTallNate)! - Deduplicate identical pnpm peer-variant copies of a package instead of failing the build with a duplicate step/workflow ID error. Different implementations that map to the same ID still fail. + +- Updated dependencies [[`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/core@5.0.0-beta.46 + - @workflow/errors@5.0.0-beta.18 + +## 5.0.0-beta.45 + +### Patch Changes + +- [#3550](https://github.com/vercel/workflow/pull/3550) [`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c) Thanks [@NathanColosimo](https://github.com/NathanColosimo)! - Keep schema-only World modules out of workflow VM bundles, prevent unknown attribute deletions from offsetting new keys, and safely ignore prototype-like event type names. + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/core@5.0.0-beta.45 + - @workflow/errors@5.0.0-beta.18 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/builders/package.json b/packages/builders/package.json index 567cf8c2ab..06ad41b615 100644 --- a/packages/builders/package.json +++ b/packages/builders/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/builders", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Shared builder infrastructure for Workflow SDK", "type": "module", "main": "./dist/index.js", diff --git a/packages/builders/src/base-builder.ts b/packages/builders/src/base-builder.ts index 9a965c0c25..3a18648ac2 100644 --- a/packages/builders/src/base-builder.ts +++ b/packages/builders/src/base-builder.ts @@ -32,6 +32,11 @@ import { type DiscoveredEntries, fastDiscoverEntries, } from './fast-discovery.js'; +import { + hashManifestSource, + type ManifestEntryLocation, + mergeWorkflowManifest, +} from './manifest-ids.js'; import { getImportPath, resolveModuleSpecifier, @@ -185,81 +190,18 @@ function moduleIdentityKey(file: string, moduleSpecifierRoot: string): string { return file.replace(/\\/g, '/'); } -type ManifestEntryLocation = { - filePath: string; - name: string; -}; - type CachedManifestTransform = { size: number; mtimeMs: number; manifest: WorkflowManifest; + /** + * Fingerprint of the source contents that produced `manifest`, used to + * deduplicate equivalent copies of the same module across files (see + * `mergeWorkflowManifest` in `manifest-ids.ts`). + */ + contentHash: string; }; -function formatIdLocation(location: ManifestEntryLocation): string { - return `${location.filePath}#${location.name}`; -} - -function assertUniqueManifestIds( - entriesByFile: Record> | undefined, - ids: Map, - getId: (entry: TEntry) => string, - label: 'step' | 'workflow' -): void { - for (const [filePath, entries] of Object.entries(entriesByFile || {})) { - for (const [name, data] of Object.entries(entries)) { - const id = getId(data); - const existing = ids.get(id); - const current = { filePath, name }; - if ( - existing && - (existing.filePath !== current.filePath || - existing.name !== current.name) - ) { - const idName = label === 'step' ? 'workflow step ID' : 'workflow ID'; - const functionName = `${label} function`; - const capitalizedLabel = label === 'step' ? 'Step' : 'Workflow'; - throw new WorkflowBuildError( - `Duplicate ${idName} "${id}" generated for ${formatIdLocation(existing)} and ${formatIdLocation(current)}.`, - { - hint: - `${capitalizedLabel} IDs must be unique across a build. ` + - `If you own one of the colliding files, rename the ${functionName} or export ` + - `the package file through a unique package subpath. If the collision is in a ` + - `transitive dependency you don't control, file an issue with the upstream ` + - `package or pin to a non-colliding version.`, - } - ); - } - ids.set(id, current); - } - } -} - -function mergeWorkflowManifest( - target: WorkflowManifest, - incoming: WorkflowManifest, - stepIds: Map, - workflowIds: Map -): void { - assertUniqueManifestIds( - incoming.steps, - stepIds, - (data) => data.stepId, - 'step' - ); - assertUniqueManifestIds( - incoming.workflows, - workflowIds, - (data) => data.workflowId, - 'workflow' - ); - - target.workflows = Object.assign(target.workflows || {}, incoming.workflows); - target.steps = Object.assign(target.steps || {}, incoming.steps); - target.classes = Object.assign(target.classes || {}, incoming.classes); -} - /** * Base class for workflow builders. Provides common build logic for transforming * workflow source files into deployable bundles using esbuild and SWC. @@ -784,7 +726,7 @@ export abstract class BaseBuilder { private async getCachedManifestTransform( file: string, mode: 'workflow' | 'step' - ): Promise { + ): Promise<{ manifest: WorkflowManifest; contentHash: string }> { const stats = await stat(file); const cacheKey = `${mode}:${file}`; const cached = this.manifestTransformCache.get(cacheKey); @@ -793,7 +735,7 @@ export abstract class BaseBuilder { cached.size === stats.size && cached.mtimeMs === stats.mtimeMs ) { - return cached.manifest; + return { manifest: cached.manifest, contentHash: cached.contentHash }; } const source = await readFile(file, 'utf8'); @@ -806,12 +748,14 @@ export abstract class BaseBuilder { this.transformProjectRoot, this.moduleSpecifierRoot ); + const contentHash = hashManifestSource(source); this.manifestTransformCache.set(cacheKey, { size: stats.size, mtimeMs: stats.mtimeMs, manifest: workflowManifest, + contentHash, }); - return workflowManifest; + return { manifest: workflowManifest, contentHash }; } protected createRouteImportSpecifier(file: string, routeDir: string): string { @@ -912,15 +856,14 @@ export const __steps_registered = true; const workflowIds = new Map(); await Promise.all( manifestFiles.map(async (file) => { - const fileManifest = await this.getCachedManifestTransform( - file, - 'step' - ); + const { manifest: fileManifest, contentHash } = + await this.getCachedManifestTransform(file, 'step'); mergeWorkflowManifest( workflowManifest, fileManifest, stepIds, - workflowIds + workflowIds, + contentHash ); }) ); @@ -1239,10 +1182,8 @@ export const __steps_registered = true; await Promise.all( workflowOnlyFiles.map(async (workflowFile) => { try { - const fileManifest = await this.getCachedManifestTransform( - workflowFile, - 'workflow' - ); + const { manifest: fileManifest } = + await this.getCachedManifestTransform(workflowFile, 'workflow'); if (fileManifest.workflows) { workflowManifest.workflows = Object.assign( workflowManifest.workflows || {}, diff --git a/packages/builders/src/manifest-ids.test.ts b/packages/builders/src/manifest-ids.test.ts new file mode 100644 index 0000000000..a9a0b38a47 --- /dev/null +++ b/packages/builders/src/manifest-ids.test.ts @@ -0,0 +1,194 @@ +import { describe, expect, it } from 'vitest'; +import type { WorkflowManifest } from './apply-swc-transform.js'; +import { + hashManifestSource, + type ManifestEntryLocation, + mergeWorkflowManifest, +} from './manifest-ids.js'; + +function createMaps() { + return { + stepIds: new Map(), + workflowIds: new Map(), + }; +} + +function stepManifest(filePath: string, name: string, stepId: string) { + return { + steps: { + [filePath]: { + [name]: { stepId }, + }, + }, + } satisfies WorkflowManifest; +} + +function workflowManifest(filePath: string, name: string, workflowId: string) { + return { + workflows: { + [filePath]: { + [name]: { workflowId }, + }, + }, + } satisfies WorkflowManifest; +} + +const PEER_A_FILE = + 'node_modules/.pnpm/pkg@1.0.0_peer-a@1.0.0/node_modules/pkg/dist/steps.js'; +const PEER_B_FILE = + 'node_modules/.pnpm/pkg@1.0.0_peer-b@2.0.0/node_modules/pkg/dist/steps.js'; +const STEP_ID = 'step//pkg/steps@1.0.0//doWork'; +const WORKFLOW_ID = 'workflow//pkg/steps@1.0.0//orchestrate'; + +describe('mergeWorkflowManifest duplicate ID handling', () => { + it('throws when two different files emit the same step ID with different contents', () => { + const { stepIds, workflowIds } = createMaps(); + const target: WorkflowManifest = {}; + + mergeWorkflowManifest( + target, + stepManifest(PEER_A_FILE, 'doWork', STEP_ID), + stepIds, + workflowIds, + hashManifestSource('export const doWork = 1;') + ); + + expect(() => + mergeWorkflowManifest( + target, + stepManifest(PEER_B_FILE, 'doWork', STEP_ID), + stepIds, + workflowIds, + hashManifestSource('export const doWork = 2;') + ) + ).toThrow(/Duplicate workflow step ID/); + }); + + it('deduplicates identical copies of the same module emitting the same step ID', () => { + const { stepIds, workflowIds } = createMaps(); + const target: WorkflowManifest = {}; + const contentHash = hashManifestSource('export const doWork = 1;'); + + mergeWorkflowManifest( + target, + stepManifest(PEER_A_FILE, 'doWork', STEP_ID), + stepIds, + workflowIds, + contentHash + ); + mergeWorkflowManifest( + target, + stepManifest(PEER_B_FILE, 'doWork', STEP_ID), + stepIds, + workflowIds, + contentHash + ); + + // The first registration wins in the ID map... + expect(stepIds.get(STEP_ID)?.filePath).toBe(PEER_A_FILE); + // ...but both file entries stay in the manifest (both copies register + // the same ID at runtime, which is harmless for identical code). + expect(Object.keys(target.steps ?? {})).toEqual([PEER_A_FILE, PEER_B_FILE]); + }); + + it('deduplicates identical copies emitting the same workflow ID', () => { + const { stepIds, workflowIds } = createMaps(); + const target: WorkflowManifest = {}; + const contentHash = hashManifestSource('export const orchestrate = 1;'); + + mergeWorkflowManifest( + target, + workflowManifest(PEER_A_FILE, 'orchestrate', WORKFLOW_ID), + stepIds, + workflowIds, + contentHash + ); + expect(() => + mergeWorkflowManifest( + target, + workflowManifest(PEER_B_FILE, 'orchestrate', WORKFLOW_ID), + stepIds, + workflowIds, + contentHash + ) + ).not.toThrow(); + expect(workflowIds.get(WORKFLOW_ID)?.filePath).toBe(PEER_A_FILE); + }); + + it('throws when the same workflow ID comes from different contents', () => { + const { stepIds, workflowIds } = createMaps(); + const target: WorkflowManifest = {}; + + mergeWorkflowManifest( + target, + workflowManifest(PEER_A_FILE, 'orchestrate', WORKFLOW_ID), + stepIds, + workflowIds, + hashManifestSource('a') + ); + expect(() => + mergeWorkflowManifest( + target, + workflowManifest(PEER_B_FILE, 'orchestrate', WORKFLOW_ID), + stepIds, + workflowIds, + hashManifestSource('b') + ) + ).toThrow(/Duplicate workflow ID/); + }); + + it('throws when content hashes are unavailable, even for equal names', () => { + const { stepIds, workflowIds } = createMaps(); + const target: WorkflowManifest = {}; + + mergeWorkflowManifest( + target, + stepManifest(PEER_A_FILE, 'doWork', STEP_ID), + stepIds, + workflowIds + ); + expect(() => + mergeWorkflowManifest( + target, + stepManifest(PEER_B_FILE, 'doWork', STEP_ID), + stepIds, + workflowIds + ) + ).toThrow(/Duplicate workflow step ID/); + }); + + it('throws when identical contents map the same ID to different symbol names', () => { + const { stepIds, workflowIds } = createMaps(); + const target: WorkflowManifest = {}; + const contentHash = hashManifestSource('shared'); + + mergeWorkflowManifest( + target, + stepManifest(PEER_A_FILE, 'doWork', STEP_ID), + stepIds, + workflowIds, + contentHash + ); + expect(() => + mergeWorkflowManifest( + target, + stepManifest(PEER_B_FILE, 'doOtherWork', STEP_ID), + stepIds, + workflowIds, + contentHash + ) + ).toThrow(/Duplicate workflow step ID/); + }); + + it('allows re-merging the same file without error', () => { + const { stepIds, workflowIds } = createMaps(); + const target: WorkflowManifest = {}; + const manifest = stepManifest(PEER_A_FILE, 'doWork', STEP_ID); + const contentHash = hashManifestSource('export const doWork = 1;'); + + mergeWorkflowManifest(target, manifest, stepIds, workflowIds, contentHash); + expect(() => + mergeWorkflowManifest(target, manifest, stepIds, workflowIds, contentHash) + ).not.toThrow(); + }); +}); diff --git a/packages/builders/src/manifest-ids.ts b/packages/builders/src/manifest-ids.ts new file mode 100644 index 0000000000..e45ded64c9 --- /dev/null +++ b/packages/builders/src/manifest-ids.ts @@ -0,0 +1,125 @@ +import { createHash } from 'node:crypto'; +import { WorkflowBuildError } from '@workflow/errors'; +import type { WorkflowManifest } from './apply-swc-transform.js'; + +/** + * Location (and identity fingerprint) of a manifest entry that produced a + * workflow/step ID during a build. Shared by the duplicate-ID checks in + * `swc-esbuild-plugin.ts` (esbuild bundling path) and `base-builder.ts` + * (source registration path). + */ +export type ManifestEntryLocation = { + filePath: string; + name: string; + /** + * Fingerprint (SHA-256) of the source file contents that produced this + * entry. Used to recognize equivalent duplicate copies of the same module + * (see `assertUniqueManifestIds`). `undefined` when the caller cannot + * provide the source contents, which disables deduplication and preserves + * the collision error. + */ + contentHash?: string; +}; + +/** + * Hash source file contents for manifest-entry equivalence comparison. + */ +export function hashManifestSource(source: string): string { + return createHash('sha256').update(source).digest('hex'); +} + +function formatIdLocation(location: ManifestEntryLocation): string { + return `${location.filePath}#${location.name}`; +} + +function assertUniqueManifestIds( + entriesByFile: Record> | undefined, + ids: Map, + getId: (entry: TEntry) => string, + label: 'step' | 'workflow', + contentHash: string | undefined +): void { + for (const [filePath, entries] of Object.entries(entriesByFile || {})) { + for (const [name, data] of Object.entries(entries)) { + const id = getId(data); + const existing = ids.get(id); + const current = { filePath, name, contentHash }; + if ( + existing && + (existing.filePath !== current.filePath || + existing.name !== current.name) + ) { + // Two *different* files generated the same ID. If both files have + // identical contents and the ID belongs to the same symbol, they are + // duplicate copies of the same logical module rather than a genuine + // collision. The main producer of such copies is pnpm, which + // materializes one package version once per peer-dependency + // resolution (node_modules/.pnpm/pkg@1.0.0_peer-a@.../ and + // .../pkg@1.0.0_peer-b@.../ hard-link the same store files), while + // the canonical ID intentionally describes the logical module + // (`name/subpath@version`) and ignores installation topology. + // Registering equivalent definitions is harmless — they run the same + // code under the same ID — so keep the first one and continue. + if ( + existing.name === current.name && + existing.contentHash !== undefined && + existing.contentHash === current.contentHash + ) { + continue; + } + const idName = label === 'step' ? 'workflow step ID' : 'workflow ID'; + const functionName = `${label} function`; + const capitalizedLabel = label === 'step' ? 'Step' : 'Workflow'; + throw new WorkflowBuildError( + `Duplicate ${idName} "${id}" generated for ${formatIdLocation(existing)} and ${formatIdLocation(current)}.`, + { + hint: + `${capitalizedLabel} IDs must be unique across a build. ` + + `If you own one of the colliding files, rename the ${functionName} or export ` + + `the package file through a unique package subpath. If the collision is in a ` + + `transitive dependency you don't control, file an issue with the upstream ` + + `package or pin to a non-colliding version.`, + } + ); + } + ids.set(id, current); + } + } +} + +/** + * Merge one file's transform manifest into the build-wide manifest, failing + * the build on genuine duplicate step/workflow IDs while deduplicating + * equivalent copies of the same module (e.g. pnpm peer-dependency variants + * of one package version). + * + * @param contentHash - Fingerprint of the source file that produced + * `incoming` (see {@link hashManifestSource}). Callers merge one file's + * manifest at a time, so a single hash covers every incoming entry. + */ +export function mergeWorkflowManifest( + target: WorkflowManifest, + incoming: WorkflowManifest, + stepIds: Map, + workflowIds: Map, + contentHash?: string +): void { + assertUniqueManifestIds( + incoming.steps, + stepIds, + (data) => data.stepId, + 'step', + contentHash + ); + assertUniqueManifestIds( + incoming.workflows, + workflowIds, + (data) => data.workflowId, + 'workflow', + contentHash + ); + + target.workflows = Object.assign(target.workflows || {}, incoming.workflows); + target.steps = Object.assign(target.steps || {}, incoming.steps); + target.classes = Object.assign(target.classes || {}, incoming.classes); +} diff --git a/packages/builders/src/step-source-registration.test.ts b/packages/builders/src/step-source-registration.test.ts index 694f6357ea..6b55b707f9 100644 --- a/packages/builders/src/step-source-registration.test.ts +++ b/packages/builders/src/step-source-registration.test.ts @@ -117,4 +117,101 @@ describe('step source registration', () => { expect(generated).toContain('import "../src/serde.ts";'); expect(Object.keys(manifest.classes ?? {})).toContain('src/serde.ts'); }); + + /** + * pnpm materializes the same package version once per peer-dependency + * resolution (e.g. `.pnpm/step-pkg@1.0.0_peer-a@1.0.0/...` and + * `.pnpm/step-pkg@1.0.0_peer-b@2.0.0/...`), with byte-identical files. + * Both copies generate the same canonical step ID. + */ + function writePnpmVirtualInstance( + peerSuffix: string, + stepSource: string + ): string { + const pkgDir = join( + testRoot, + 'node_modules', + '.pnpm', + `step-pkg@1.0.0_${peerSuffix}`, + 'node_modules', + 'step-pkg' + ); + writeFile( + join(pkgDir, 'package.json'), + JSON.stringify({ + name: 'step-pkg', + version: '1.0.0', + exports: { '.': './index.js' }, + }) + ); + const stepFile = join(pkgDir, 'index.js'); + writeFile(stepFile, stepSource); + return stepFile; + } + + it('deduplicates identical pnpm peer-variant package copies', async () => { + const stepSource = `export async function runPackagedStep() { + 'use step'; + return 1; +} +`; + const copyA = writePnpmVirtualInstance('peer-a@1.0.0', stepSource); + const copyB = writePnpmVirtualInstance('peer-b@2.0.0', stepSource); + const outfile = join(testRoot, '.workflow', 'steps.js'); + mkdirSync(dirname(outfile), { recursive: true }); + + const discoveredEntries: DiscoveredEntries = { + discoveredSteps: new Set([copyA, copyB]), + discoveredWorkflows: new Set(), + discoveredSerdeFiles: new Set(), + }; + + const { manifest } = await createBuilder( + testRoot + ).createSourceStepRegistrations([copyA, copyB], outfile, discoveredEntries); + + // Both copies land in the manifest under the same canonical step ID. + const stepEntries = Object.values(manifest.steps ?? {}); + expect(stepEntries).toHaveLength(2); + for (const entries of stepEntries) { + expect(entries.runPackagedStep.stepId).toBe( + 'step//step-pkg@1.0.0//runPackagedStep' + ); + } + }); + + it('still rejects pnpm-style package copies whose implementations differ', async () => { + const copyA = writePnpmVirtualInstance( + 'peer-a@1.0.0', + `export async function runPackagedStep() { + 'use step'; + return 1; +} +` + ); + const copyB = writePnpmVirtualInstance( + 'peer-b@2.0.0', + `export async function runPackagedStep() { + 'use step'; + return 2; +} +` + ); + const outfile = join(testRoot, '.workflow', 'steps.js'); + mkdirSync(dirname(outfile), { recursive: true }); + + const discoveredEntries: DiscoveredEntries = { + discoveredSteps: new Set([copyA, copyB]), + discoveredWorkflows: new Set(), + discoveredSerdeFiles: new Set(), + }; + + await expect( + createBuilder(testRoot).createSourceStepRegistrations( + [copyA, copyB], + outfile, + discoveredEntries + ) + ).rejects.toThrow(/Duplicate workflow step ID/); + }); }); diff --git a/packages/builders/src/swc-esbuild-plugin.test.ts b/packages/builders/src/swc-esbuild-plugin.test.ts index c61a677f3d..e21e7d0351 100644 --- a/packages/builders/src/swc-esbuild-plugin.test.ts +++ b/packages/builders/src/swc-esbuild-plugin.test.ts @@ -211,6 +211,119 @@ describe('createSwcPlugin externalizeNonSteps', () => { expect(onAfterTransform).toHaveBeenCalledOnce(); }); + it('deduplicates identical pnpm peer-variant copies emitting the same step id', async () => { + // pnpm materializes the same package version once per peer-dependency + // resolution. Both copies are byte-identical and generate the same + // canonical step ID, which must not fail the build. + const source = `export const sendMessage = true;`; + const firstCopy = join( + testRoot, + 'node_modules/.pnpm/shared-package@1.0.0_peer-a@1.0.0/node_modules/shared-package/index.ts' + ); + const secondCopy = join( + testRoot, + 'node_modules/.pnpm/shared-package@1.0.0_peer-b@2.0.0/node_modules/shared-package/index.ts' + ); + const onAfterTransform = vi.fn(); + const workflowManifest = {}; + + writeFile(firstCopy, source); + writeFile(secondCopy, source); + + applySwcTransformMock.mockImplementation( + async (filename: string, fileSource: string) => ({ + code: fileSource, + workflowManifest: { + steps: { + [filename]: { + sendMessage: { + stepId: 'step//shared-package@1.0.0//sendMessage', + }, + }, + }, + }, + }) + ); + + const result = await esbuild.build({ + entryPoints: [firstCopy, secondCopy], + absWorkingDir: testRoot, + outdir: join(testRoot, 'out'), + bundle: true, + format: 'esm', + platform: 'node', + write: false, + plugins: [ + createSwcPlugin({ + mode: 'step', + workflowManifest, + onAfterTransform, + }), + ], + }); + + expect(result.errors).toHaveLength(0); + expect(onAfterTransform).toHaveBeenCalledTimes(2); + // Both copies stay in the manifest under the same step ID. + const steps = ( + workflowManifest as { + steps?: Record>; + } + ).steps; + expect(Object.keys(steps ?? {})).toHaveLength(2); + for (const entries of Object.values(steps ?? {})) { + expect(entries.sendMessage.stepId).toBe( + 'step//shared-package@1.0.0//sendMessage' + ); + } + }); + + it('fails the build when pnpm-style copies with different contents emit the same step id', async () => { + const firstCopy = join( + testRoot, + 'node_modules/.pnpm/shared-package@1.0.0_peer-a@1.0.0/node_modules/shared-package/index.ts' + ); + const secondCopy = join( + testRoot, + 'node_modules/.pnpm/shared-package@1.0.0_peer-b@2.0.0/node_modules/shared-package/index.ts' + ); + + writeFile(firstCopy, `export const sendMessage = 1;`); + writeFile(secondCopy, `export const sendMessage = 2;`); + + applySwcTransformMock.mockImplementation( + async (filename: string, fileSource: string) => ({ + code: fileSource, + workflowManifest: { + steps: { + [filename]: { + sendMessage: { + stepId: 'step//shared-package@1.0.0//sendMessage', + }, + }, + }, + }, + }) + ); + + await expect( + esbuild.build({ + entryPoints: [firstCopy, secondCopy], + absWorkingDir: testRoot, + outdir: join(testRoot, 'out'), + bundle: true, + format: 'esm', + platform: 'node', + write: false, + plugins: [ + createSwcPlugin({ + mode: 'step', + }), + ], + }) + ).rejects.toThrow(/Duplicate workflow step ID/); + }); + it('fails the build when two files emit the same workflow id', async () => { const srcDir = join(testRoot, 'src'); const firstWorkflowFile = join(srcDir, 'confirmation.ts'); diff --git a/packages/builders/src/swc-esbuild-plugin.ts b/packages/builders/src/swc-esbuild-plugin.ts index 569f85e0ba..f4630e5d03 100644 --- a/packages/builders/src/swc-esbuild-plugin.ts +++ b/packages/builders/src/swc-esbuild-plugin.ts @@ -1,7 +1,6 @@ import { readFile } from 'node:fs/promises'; import { relative } from 'node:path'; import { promisify } from 'node:util'; -import { WorkflowBuildError } from '@workflow/errors'; import enhancedResolveOrig from 'enhanced-resolve'; import type { Plugin } from 'esbuild'; import { @@ -12,6 +11,11 @@ import { jsTsRegex, parentHasChild, } from './discover-entries-esbuild-plugin.js'; +import { + hashManifestSource, + type ManifestEntryLocation, + mergeWorkflowManifest, +} from './manifest-ids.js'; import { resolveModuleSpecifier } from './module-specifier.js'; import { resolveWorkflowAliasRelativePath } from './workflow-alias.js'; @@ -115,84 +119,12 @@ function normalizePath(path: string): string { return path.replace(/\\/g, '/'); } -type IdLocation = { - filePath: string; - name: string; -}; - -function formatIdLocation(location: IdLocation): string { - return `${location.filePath}#${location.name}`; -} - -function assertUniqueManifestIds( - entriesByFile: WorkflowManifest['steps'] | WorkflowManifest['workflows'], - ids: Map, - getId: (data: { stepId: string } | { workflowId: string }) => string, - label: 'step' | 'workflow' -): void { - const entriesByFileList = Object.entries(entriesByFile || {}) as Array< - [string, Record] - >; - for (const [filePath, entries] of entriesByFileList) { - for (const [name, data] of Object.entries(entries)) { - const id = getId(data); - const existing = ids.get(id); - const current = { filePath, name }; - if ( - existing && - (existing.filePath !== current.filePath || - existing.name !== current.name) - ) { - const idName = label === 'step' ? 'workflow step ID' : 'workflow ID'; - const functionName = `${label} function`; - const capitalizedLabel = label === 'step' ? 'Step' : 'Workflow'; - throw new WorkflowBuildError( - `Duplicate ${idName} "${id}" generated for ${formatIdLocation(existing)} and ${formatIdLocation(current)}.`, - { - hint: - `${capitalizedLabel} IDs must be unique across a build. ` + - `If you own one of the colliding files, rename the ${functionName} or export ` + - `the package file through a unique package subpath. If the collision is in a ` + - `transitive dependency you don't control, file an issue with the upstream ` + - `package or pin to a non-colliding version.`, - } - ); - } - ids.set(id, current); - } - } -} - -function mergeWorkflowManifest( - target: WorkflowManifest, - incoming: WorkflowManifest, - stepIds: Map, - workflowIds: Map -): void { - assertUniqueManifestIds( - incoming.steps, - stepIds, - (data) => (data as { stepId: string }).stepId, - 'step' - ); - assertUniqueManifestIds( - incoming.workflows, - workflowIds, - (data) => (data as { workflowId: string }).workflowId, - 'workflow' - ); - - target.workflows = Object.assign(target.workflows || {}, incoming.workflows); - target.steps = Object.assign(target.steps || {}, incoming.steps); - target.classes = Object.assign(target.classes || {}, incoming.classes); -} - export function createSwcPlugin(options: SwcPluginOptions): Plugin { return { name: 'swc-workflow-plugin', setup(build) { - let stepIdsForCurrentBuild = new Map(); - let workflowIdsForCurrentBuild = new Map(); + let stepIdsForCurrentBuild = new Map(); + let workflowIdsForCurrentBuild = new Map(); build.onStart(() => { stepIdsForCurrentBuild = new Map(); @@ -529,11 +461,21 @@ export function createSwcPlugin(options: SwcPluginOptions): Plugin { options.workflowManifest = {}; } + // Fingerprint the source so equivalent duplicate copies of the + // same module (e.g. pnpm peer-dependency variants of one package + // version) can be deduplicated instead of failing the build with + // a duplicate-ID error. + const contentHash = + workflowManifest.steps || workflowManifest.workflows + ? hashManifestSource(normalizedSource) + : undefined; + mergeWorkflowManifest( options.workflowManifest, workflowManifest, stepIdsForCurrentBuild, - workflowIdsForCurrentBuild + workflowIdsForCurrentBuild, + contentHash ); await options.onAfterTransform?.({ diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index b958a8e57b..6e11590bea 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,31 @@ # @workflow/cli +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/builders@5.0.0-beta.46 + - @workflow/core@5.0.0-beta.46 + - @workflow/world@5.0.0-beta.31 + - @workflow/web@5.0.0-beta.46 + - @workflow/errors@5.0.0-beta.18 + - @workflow/world-local@5.0.0-beta.40 + - @workflow/world-vercel@5.0.0-beta.42 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/builders@5.0.0-beta.45 + - @workflow/core@5.0.0-beta.45 + - @workflow/world@5.0.0-beta.30 + - @workflow/web@5.0.0-beta.45 + - @workflow/errors@5.0.0-beta.18 + - @workflow/world-local@5.0.0-beta.39 + - @workflow/world-vercel@5.0.0-beta.41 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/cli/package.json b/packages/cli/package.json index fbbe0ad1d9..229f3d6249 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/cli", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Command-line interface for Workflow SDK", "type": "module", "bin": { diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index eb66dad09b..f23d877b42 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -1,5 +1,41 @@ # @workflow/core +## 5.0.0-beta.46 + +### Patch Changes + +- [#3794](https://github.com/vercel/workflow/pull/3794) [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - Keep the eager `hook_received` write for the internal resume that records a step-issued abort, so it stays committed before the step completes. + +- [#3794](https://github.com/vercel/workflow/pull/3794) [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - `resumeHook()` no longer writes the `hook_received` event itself on the lazy path: the queue consumer creates it from the queue message, so a resume costs one round trip. A resume against an already-ended run now resolves instead of throwing `HookNotFoundError`. + +- [#3609](https://github.com/vercel/workflow/pull/3609) [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912) Thanks [@NathanColosimo](https://github.com/NathanColosimo)! - Retain workflow VMs across workflow attribute writes. + +- [#3604](https://github.com/vercel/workflow/pull/3604) [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e) Thanks [@NathanColosimo](https://github.com/NathanColosimo)! - Retain workflow VMs across safe step boundaries that also contain open hooks, and bound guest-code serialization diagnostics to five samples plus an exact count. + +- Updated dependencies [[`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d)]: + - @workflow/world@5.0.0-beta.31 + - @workflow/errors@5.0.0-beta.18 + - @workflow/world-local@5.0.0-beta.40 + - @workflow/world-vercel@5.0.0-beta.42 + +## 5.0.0-beta.45 + +### Patch Changes + +- [#3550](https://github.com/vercel/workflow/pull/3550) [`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c) Thanks [@NathanColosimo](https://github.com/NathanColosimo)! - Keep schema-only World modules out of workflow VM bundles, prevent unknown attribute deletions from offsetting new keys, and safely ignore prototype-like event type names. + +- [#3773](https://github.com/vercel/workflow/pull/3773) [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - Send the disposed hook's token on `hook_disposed` from the QuickJS engine, matching the node:vm engine + +- [#3490](https://github.com/vercel/workflow/pull/3490) [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a) Thanks [@shalabhc](https://github.com/shalabhc)! - Report replay cost for every step-to-step transition, not just a run's first step, and flag whether a retained VM served the batch + +- [#3682](https://github.com/vercel/workflow/pull/3682) [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - Fail the dev HMR e2e cleanup when a deleted workflow fixture is still imported by the generated step registrations, restoring the fixture so the dev server keeps serving the rest of the suite. + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/world@5.0.0-beta.30 + - @workflow/errors@5.0.0-beta.18 + - @workflow/world-local@5.0.0-beta.39 + - @workflow/world-vercel@5.0.0-beta.41 + ## 5.0.0-beta.44 ### Minor Changes diff --git a/packages/core/package.json b/packages/core/package.json index f5f5bd01f5..3426118f15 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/core", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Core runtime and engine for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/nest/CHANGELOG.md b/packages/nest/CHANGELOG.md index a0370957d4..3a4d3cba37 100644 --- a/packages/nest/CHANGELOG.md +++ b/packages/nest/CHANGELOG.md @@ -1,5 +1,19 @@ # @workflow/nest +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f)]: + - @workflow/builders@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/builders@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/nest/package.json b/packages/nest/package.json index 06d42f5b81..e304c906ed 100644 --- a/packages/nest/package.json +++ b/packages/nest/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/nest", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "NestJS integration for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/next/CHANGELOG.md b/packages/next/CHANGELOG.md index 9afa5f42c9..921f0886bc 100644 --- a/packages/next/CHANGELOG.md +++ b/packages/next/CHANGELOG.md @@ -1,5 +1,21 @@ # @workflow/next +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/builders@5.0.0-beta.46 + - @workflow/core@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/builders@5.0.0-beta.45 + - @workflow/core@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/next/package.json b/packages/next/package.json index 4677646741..bc689a40c3 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/next", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Next.js integration for Workflow SDK", "type": "commonjs", "main": "dist/index.js", diff --git a/packages/nitro/CHANGELOG.md b/packages/nitro/CHANGELOG.md index 69c1c24b0b..703fb59f55 100644 --- a/packages/nitro/CHANGELOG.md +++ b/packages/nitro/CHANGELOG.md @@ -1,5 +1,27 @@ # @workflow/nitro +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/builders@5.0.0-beta.46 + - @workflow/core@5.0.0-beta.46 + - @workflow/rollup@5.0.0-beta.46 + - @workflow/vite@5.0.0-beta.46 + - @workflow/web@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/builders@5.0.0-beta.45 + - @workflow/core@5.0.0-beta.45 + - @workflow/rollup@5.0.0-beta.45 + - @workflow/vite@5.0.0-beta.45 + - @workflow/web@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/nitro/package.json b/packages/nitro/package.json index 69b6a2e93c..c798bfb21e 100644 --- a/packages/nitro/package.json +++ b/packages/nitro/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/nitro", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Nitro integration for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/nuxt/CHANGELOG.md b/packages/nuxt/CHANGELOG.md index bbabc12552..ffa6feacf3 100644 --- a/packages/nuxt/CHANGELOG.md +++ b/packages/nuxt/CHANGELOG.md @@ -1,5 +1,19 @@ # @workflow/nuxt +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies []: + - @workflow/nitro@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies []: + - @workflow/nitro@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index 8d0b336cab..c40b82e52e 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/nuxt", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Nuxt integration for Workflow SDK", "license": "Apache-2.0", "type": "module", diff --git a/packages/rollup/CHANGELOG.md b/packages/rollup/CHANGELOG.md index 74ea971e2f..030bc20164 100644 --- a/packages/rollup/CHANGELOG.md +++ b/packages/rollup/CHANGELOG.md @@ -1,5 +1,19 @@ # @workflow/rollup +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f)]: + - @workflow/builders@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/builders@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/rollup/package.json b/packages/rollup/package.json index de44fe3737..13011e92fa 100644 --- a/packages/rollup/package.json +++ b/packages/rollup/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/rollup", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Rollup plugin for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/sveltekit/CHANGELOG.md b/packages/sveltekit/CHANGELOG.md index 18be241776..9ce70e64ad 100644 --- a/packages/sveltekit/CHANGELOG.md +++ b/packages/sveltekit/CHANGELOG.md @@ -1,5 +1,25 @@ # @workflow/sveltekit +## 5.0.0-beta.46 + +### Patch Changes + +- [#3688](https://github.com/vercel/workflow/pull/3688) [`0750fe8`](https://github.com/vercel/workflow/commit/0750fe8958f50ee354cd24fe3f02a37c801bc4dc) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - Stop rewriting generated files whose content is unchanged, so a no-op rebuild no longer invalidates them in the dev server. + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f)]: + - @workflow/builders@5.0.0-beta.46 + - @workflow/rollup@5.0.0-beta.46 + - @workflow/vite@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/builders@5.0.0-beta.45 + - @workflow/rollup@5.0.0-beta.45 + - @workflow/vite@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index abe9bd47f1..50976df6a7 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/sveltekit", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "SvelteKit integration for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/vite/CHANGELOG.md b/packages/vite/CHANGELOG.md index 67da52544a..5584504f81 100644 --- a/packages/vite/CHANGELOG.md +++ b/packages/vite/CHANGELOG.md @@ -1,5 +1,19 @@ # @workflow/vite +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f)]: + - @workflow/builders@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/builders@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/vite/package.json b/packages/vite/package.json index 71bd49bec8..22c6436312 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -1,7 +1,7 @@ { "name": "@workflow/vite", "description": "Vite plugin for Workflow SDK", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "type": "module", "main": "dist/index.js", "files": [ diff --git a/packages/vitest/CHANGELOG.md b/packages/vitest/CHANGELOG.md index 52b2142018..4fac95e077 100644 --- a/packages/vitest/CHANGELOG.md +++ b/packages/vitest/CHANGELOG.md @@ -1,5 +1,29 @@ # @workflow/vitest +## 5.0.0-beta.46 + +### Patch Changes + +- [#3794](https://github.com/vercel/workflow/pull/3794) [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - `waitForHook()` accepts `notHookId` to skip a hook the caller already resumed, whose `hook_received` may not be written yet. + +- Updated dependencies [[`f806f8c`](https://github.com/vercel/workflow/commit/f806f8c258fb9ba45fec8b0e4919f55b0bf81a3f), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/builders@5.0.0-beta.46 + - @workflow/core@5.0.0-beta.46 + - @workflow/world@5.0.0-beta.31 + - @workflow/rollup@5.0.0-beta.46 + - @workflow/world-local@5.0.0-beta.40 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/builders@5.0.0-beta.45 + - @workflow/core@5.0.0-beta.45 + - @workflow/world@5.0.0-beta.30 + - @workflow/rollup@5.0.0-beta.45 + - @workflow/world-local@5.0.0-beta.39 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/vitest/package.json b/packages/vitest/package.json index 0c34ee2ed7..f8949cc134 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/vitest", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Vitest plugin for testing Workflow SDK workflows", "type": "module", "main": "./dist/index.js", diff --git a/packages/web-shared/CHANGELOG.md b/packages/web-shared/CHANGELOG.md index b48cca344c..f76136e97a 100644 --- a/packages/web-shared/CHANGELOG.md +++ b/packages/web-shared/CHANGELOG.md @@ -1,5 +1,21 @@ # @workflow/web-shared +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/core@5.0.0-beta.46 + - @workflow/world@5.0.0-beta.31 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/core@5.0.0-beta.45 + - @workflow/world@5.0.0-beta.30 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/web-shared/package.json b/packages/web-shared/package.json index 6e670db183..4c8fb0ef88 100644 --- a/packages/web-shared/package.json +++ b/packages/web-shared/package.json @@ -1,7 +1,7 @@ { "name": "@workflow/web-shared", "description": "Shared components for Workflow Observability UI", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "private": false, "files": [ "dist", diff --git a/packages/web/CHANGELOG.md b/packages/web/CHANGELOG.md index 63ed6774df..9da9638561 100644 --- a/packages/web/CHANGELOG.md +++ b/packages/web/CHANGELOG.md @@ -1,5 +1,19 @@ # @workflow/web +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies []: + - @workflow/world-local@5.0.0-beta.40 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies []: + - @workflow/world-local@5.0.0-beta.39 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/web/package.json b/packages/web/package.json index e8313d15d8..315b475a1e 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -1,7 +1,7 @@ { "name": "@workflow/web", "description": "Workflow Observability UI", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "type": "module", "private": false, "files": [ diff --git a/packages/workflow/CHANGELOG.md b/packages/workflow/CHANGELOG.md index c3d32be0af..5bf6722cd0 100644 --- a/packages/workflow/CHANGELOG.md +++ b/packages/workflow/CHANGELOG.md @@ -1,5 +1,39 @@ # workflow +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`0750fe8`](https://github.com/vercel/workflow/commit/0750fe8958f50ee354cd24fe3f02a37c801bc4dc), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/astro@5.0.0-beta.46 + - @workflow/sveltekit@5.0.0-beta.46 + - @workflow/core@5.0.0-beta.46 + - @workflow/cli@5.0.0-beta.46 + - @workflow/nest@5.0.0-beta.46 + - @workflow/next@5.0.0-beta.46 + - @workflow/nitro@5.0.0-beta.46 + - @workflow/rollup@5.0.0-beta.46 + - @workflow/typescript-plugin@5.0.0-beta.5 + - @workflow/errors@5.0.0-beta.18 + - @workflow/nuxt@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/core@5.0.0-beta.45 + - @workflow/astro@5.0.0-beta.45 + - @workflow/cli@5.0.0-beta.45 + - @workflow/nest@5.0.0-beta.45 + - @workflow/next@5.0.0-beta.45 + - @workflow/nitro@5.0.0-beta.45 + - @workflow/rollup@5.0.0-beta.45 + - @workflow/sveltekit@5.0.0-beta.45 + - @workflow/typescript-plugin@5.0.0-beta.5 + - @workflow/errors@5.0.0-beta.18 + - @workflow/nuxt@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Minor Changes diff --git a/packages/workflow/package.json b/packages/workflow/package.json index 12dfda96a3..7e3336bd28 100644 --- a/packages/workflow/package.json +++ b/packages/workflow/package.json @@ -1,6 +1,6 @@ { "name": "workflow", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Workflow SDK - Build durable, resilient, and observable workflows", "main": "dist/typescript-plugin.cjs", "type": "module", diff --git a/packages/world-local/CHANGELOG.md b/packages/world-local/CHANGELOG.md index e86ba366b3..737e82d8b1 100644 --- a/packages/world-local/CHANGELOG.md +++ b/packages/world-local/CHANGELOG.md @@ -1,5 +1,21 @@ # @workflow/world-local +## 5.0.0-beta.40 + +### Patch Changes + +- Updated dependencies [[`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d)]: + - @workflow/world@5.0.0-beta.31 + - @workflow/errors@5.0.0-beta.18 + +## 5.0.0-beta.39 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/world@5.0.0-beta.30 + - @workflow/errors@5.0.0-beta.18 + ## 5.0.0-beta.38 ### Minor Changes diff --git a/packages/world-local/package.json b/packages/world-local/package.json index 466660b4ff..13dc6b65dd 100644 --- a/packages/world-local/package.json +++ b/packages/world-local/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/world-local", - "version": "5.0.0-beta.38", + "version": "5.0.0-beta.40", "description": "Local development World implementation for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/world-local/src/queue.test.ts b/packages/world-local/src/queue.test.ts index acf51ca08e..a243eaca77 100644 --- a/packages/world-local/src/queue.test.ts +++ b/packages/world-local/src/queue.test.ts @@ -557,6 +557,40 @@ describe('queue transport timeouts', () => { }); }); + it('aborts an in-flight delivery when the queue closes', async () => { + let requestReceived = false; + server = createServer(() => { + requestReceived = true; + }); + await new Promise((resolve) => { + server?.listen(0, '127.0.0.1', resolve); + }); + const { port } = server.address() as AddressInfo; + + process.env.WORKFLOW_LOCAL_HEADERS_TIMEOUT_MS = '0'; + process.env.WORKFLOW_LOCAL_BODY_TIMEOUT_MS = '0'; + const localQueue = createQueue({ + baseUrl: `http://127.0.0.1:${port}`, + }); + + await localQueue.queue('__wkf_workflow_test' as any, workflowPayload); + await vi.waitFor(() => expect(requestReceived).toBe(true)); + const closePromise = localQueue.close(); + let timeout: ReturnType | undefined; + const outcome = await Promise.race([ + closePromise.then(() => 'closed' as const), + new Promise<'timed-out'>((resolve) => { + timeout = setTimeout(() => resolve('timed-out'), 1_000); + }), + ]); + clearTimeout(timeout); + if (outcome === 'timed-out') { + server.closeAllConnections(); + await closePromise; + } + expect(outcome).toBe('closed'); + }); + it('redelivers when a handler accepts a request but never responds', async () => { let requests = 0; server = createServer((_request, response) => { diff --git a/packages/world-local/src/queue.ts b/packages/world-local/src/queue.ts index 84ddefde8d..62ba4bf25d 100644 --- a/packages/world-local/src/queue.ts +++ b/packages/world-local/src/queue.ts @@ -259,6 +259,7 @@ export function createQueue(config: Partial): LocalQueue { headers: new Headers(headers), body, agents: nodeHttpAgents, + signal: closeSignal, headersTimeoutMs: agentOptions.headersTimeout, bodyTimeoutMs: agentOptions.bodyTimeout, }) @@ -269,6 +270,7 @@ export function createQueue(config: Partial): LocalQueue { dispatcher: httpAgent, headers, body, + signal: closeSignal, } as any); } delivery++; diff --git a/packages/world-postgres/CHANGELOG.md b/packages/world-postgres/CHANGELOG.md index 5c7c910453..acfef903ea 100644 --- a/packages/world-postgres/CHANGELOG.md +++ b/packages/world-postgres/CHANGELOG.md @@ -1,5 +1,23 @@ # @workflow/world-postgres +## 5.0.0-beta.38 + +### Patch Changes + +- Updated dependencies [[`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d)]: + - @workflow/world@5.0.0-beta.31 + - @workflow/errors@5.0.0-beta.18 + - @workflow/world-local@5.0.0-beta.40 + +## 5.0.0-beta.37 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/world@5.0.0-beta.30 + - @workflow/errors@5.0.0-beta.18 + - @workflow/world-local@5.0.0-beta.39 + ## 5.0.0-beta.36 ### Minor Changes diff --git a/packages/world-postgres/package.json b/packages/world-postgres/package.json index 9159e30088..6402297829 100644 --- a/packages/world-postgres/package.json +++ b/packages/world-postgres/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/world-postgres", - "version": "5.0.0-beta.36", + "version": "5.0.0-beta.38", "description": "A reference World implementation based on PostgreSQL", "type": "module", "main": "dist/index.js", diff --git a/packages/world-testing/CHANGELOG.md b/packages/world-testing/CHANGELOG.md index b48b40e44b..659945823d 100644 --- a/packages/world-testing/CHANGELOG.md +++ b/packages/world-testing/CHANGELOG.md @@ -1,5 +1,25 @@ # @workflow/world-testing +## 5.0.0-beta.46 + +### Patch Changes + +- Updated dependencies [[`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d), [`82e2678`](https://github.com/vercel/workflow/commit/82e267893917e06f5d3ce316baefc27cd024a912), [`556f3f0`](https://github.com/vercel/workflow/commit/556f3f080a33f8673cf3c08805997dba4e4d865e)]: + - @workflow/core@5.0.0-beta.46 + - @workflow/world@5.0.0-beta.31 + - @workflow/cli@5.0.0-beta.46 + - workflow@5.0.0-beta.46 + +## 5.0.0-beta.45 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c), [`27cab14`](https://github.com/vercel/workflow/commit/27cab14adcc6f748500fca19cf78feeb60a125e7), [`f7fb012`](https://github.com/vercel/workflow/commit/f7fb0126528fac2168492c3143fe0379b6f5ef1a), [`5841558`](https://github.com/vercel/workflow/commit/584155897f75e712a1c2bc199d6d12027cd18dab)]: + - @workflow/core@5.0.0-beta.45 + - @workflow/world@5.0.0-beta.30 + - @workflow/cli@5.0.0-beta.45 + - workflow@5.0.0-beta.45 + ## 5.0.0-beta.44 ### Patch Changes diff --git a/packages/world-testing/package.json b/packages/world-testing/package.json index 401b014b39..9d71bab087 100644 --- a/packages/world-testing/package.json +++ b/packages/world-testing/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/world-testing", - "version": "5.0.0-beta.44", + "version": "5.0.0-beta.46", "description": "Testing utilities and World implementation for Workflow SDK", "main": "dist/src/index.mjs", "files": [ diff --git a/packages/world-vercel/CHANGELOG.md b/packages/world-vercel/CHANGELOG.md index b683e80f52..52d38f5bf5 100644 --- a/packages/world-vercel/CHANGELOG.md +++ b/packages/world-vercel/CHANGELOG.md @@ -1,5 +1,21 @@ # @workflow/world-vercel +## 5.0.0-beta.42 + +### Patch Changes + +- Updated dependencies [[`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d)]: + - @workflow/world@5.0.0-beta.31 + - @workflow/errors@5.0.0-beta.18 + +## 5.0.0-beta.41 + +### Patch Changes + +- Updated dependencies [[`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c)]: + - @workflow/world@5.0.0-beta.30 + - @workflow/errors@5.0.0-beta.18 + ## 5.0.0-beta.40 ### Minor Changes diff --git a/packages/world-vercel/package.json b/packages/world-vercel/package.json index 4179e1b03f..6315ca4500 100644 --- a/packages/world-vercel/package.json +++ b/packages/world-vercel/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/world-vercel", - "version": "5.0.0-beta.40", + "version": "5.0.0-beta.42", "description": "Vercel platform World implementation for Workflow SDK", "type": "module", "main": "dist/index.js", diff --git a/packages/world/CHANGELOG.md b/packages/world/CHANGELOG.md index 0f5102863a..c71ff99942 100644 --- a/packages/world/CHANGELOG.md +++ b/packages/world/CHANGELOG.md @@ -1,5 +1,17 @@ # @workflow/world +## 5.0.0-beta.31 + +### Patch Changes + +- [#3794](https://github.com/vercel/workflow/pull/3794) [`d9e0777`](https://github.com/vercel/workflow/commit/d9e0777eb8b1ce5f3be3fe865bc5a17fdbdb9d5d) Thanks [@VaguelySerious](https://github.com/VaguelySerious)! - Document that `hookInput` and the `(runId, resumeId)` dedup contract now cover repeated deliveries of one resume rather than a producer/consumer race, and accept `lazy` as a hook-resume strategy. + +## 5.0.0-beta.30 + +### Major Changes + +- [#3550](https://github.com/vercel/workflow/pull/3550) [`d62b444`](https://github.com/vercel/workflow/commit/d62b44473b43e183e71386fe84b33f5e7bb5445c) Thanks [@NathanColosimo](https://github.com/NathanColosimo)! - Keep schema-only World modules out of workflow VM bundles, prevent unknown attribute deletions from offsetting new keys, and safely ignore prototype-like event type names. + ## 5.0.0-beta.29 ### Minor Changes diff --git a/packages/world/package.json b/packages/world/package.json index e4593cce84..3f01c5e51d 100644 --- a/packages/world/package.json +++ b/packages/world/package.json @@ -1,6 +1,6 @@ { "name": "@workflow/world", - "version": "5.0.0-beta.29", + "version": "5.0.0-beta.31", "description": "The Workflows World interface", "type": "module", "main": "dist/index.js",