@workflow/world-local 5.0.0-beta.10 → 5.0.0-beta.3
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/dist/config.d.ts +17 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +18 -13
- package/dist/config.js.map +1 -1
- package/dist/fs.d.ts +102 -2
- package/dist/fs.d.ts.map +1 -1
- package/dist/fs.js +291 -24
- package/dist/fs.js.map +1 -1
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +82 -5
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +91 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +268 -0
- package/dist/init.js.map +1 -0
- package/dist/instrumentObject.d.ts +8 -0
- package/dist/instrumentObject.d.ts.map +1 -0
- package/dist/instrumentObject.js +66 -0
- package/dist/instrumentObject.js.map +1 -0
- package/dist/queue.d.ts +8 -1
- package/dist/queue.d.ts.map +1 -1
- package/dist/queue.js +164 -53
- package/dist/queue.js.map +1 -1
- package/dist/storage/events-storage.d.ts +7 -0
- package/dist/storage/events-storage.d.ts.map +1 -0
- package/dist/storage/events-storage.js +760 -0
- package/dist/storage/events-storage.js.map +1 -0
- package/dist/storage/filters.d.ts +22 -0
- package/dist/storage/filters.d.ts.map +1 -0
- package/dist/storage/filters.js +33 -0
- package/dist/storage/filters.js.map +1 -0
- package/dist/storage/helpers.d.ts +18 -0
- package/dist/storage/helpers.d.ts.map +1 -0
- package/dist/storage/helpers.js +44 -0
- package/dist/storage/helpers.js.map +1 -0
- package/dist/storage/hooks-storage.d.ts +12 -0
- package/dist/storage/hooks-storage.d.ts.map +1 -0
- package/dist/storage/hooks-storage.js +93 -0
- package/dist/storage/hooks-storage.js.map +1 -0
- package/dist/storage/index.d.ts +12 -0
- package/dist/storage/index.d.ts.map +1 -0
- package/dist/storage/index.js +32 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/storage/legacy.d.ts +13 -0
- package/dist/storage/legacy.d.ts.map +1 -0
- package/dist/storage/legacy.js +77 -0
- package/dist/storage/legacy.js.map +1 -0
- package/dist/storage/runs-storage.d.ts +7 -0
- package/dist/storage/runs-storage.d.ts.map +1 -0
- package/dist/storage/runs-storage.js +59 -0
- package/dist/storage/runs-storage.js.map +1 -0
- package/dist/storage/steps-storage.d.ts +7 -0
- package/dist/storage/steps-storage.d.ts.map +1 -0
- package/dist/storage/steps-storage.js +52 -0
- package/dist/storage/steps-storage.js.map +1 -0
- package/dist/storage.d.ts +9 -2
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +8 -455
- package/dist/storage.js.map +1 -1
- package/dist/streamer.d.ts +4 -2
- package/dist/streamer.d.ts.map +1 -1
- package/dist/streamer.js +456 -104
- package/dist/streamer.js.map +1 -1
- package/dist/telemetry.d.ts +28 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +71 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/test-helpers.d.ts +54 -0
- package/dist/test-helpers.d.ts.map +1 -0
- package/dist/test-helpers.js +118 -0
- package/dist/test-helpers.js.map +1 -0
- package/dist/util.js.map +1 -1
- package/package.json +12 -11
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n access,\n constants,\n mkdir,\n readFile,\n unlink,\n writeFile,\n} from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n/** Package name - hardcoded since it doesn't change */\nconst PACKAGE_NAME = '@workflow/world-local';\n\ninterface PackageInfo {\n name: string;\n version: string;\n}\n\nlet cachedPackageInfo: PackageInfo | null = null;\n\n/**\n * Get the directory path for this module.\n * Works in ESM and falls back to a constant in CJS contexts (which shouldn't happen)\n */\nfunction getModuleDir(): string | null {\n // In bundled CJS contexts, import.meta.url may be undefined or empty\n if (typeof import.meta.url === 'string' && import.meta.url) {\n return path.dirname(fileURLToPath(import.meta.url));\n }\n return null;\n}\n\n/**\n * Returns the package name and version from package.json.\n * The result is cached after the first read.\n *\n * In bundled contexts where package.json cannot be read,\n * returns 'bundled' as the version.\n */\nexport async function getPackageInfo(): Promise<PackageInfo> {\n if (cachedPackageInfo) {\n return cachedPackageInfo;\n }\n\n const moduleDir = getModuleDir();\n if (moduleDir) {\n try {\n const content = await readFile(\n path.join(moduleDir, '../package.json'),\n 'utf-8'\n );\n cachedPackageInfo = JSON.parse(content) as PackageInfo;\n return cachedPackageInfo;\n } catch {\n // Fall through to bundled fallback\n }\n }\n\n // Bundled context - package.json not accessible\n cachedPackageInfo = {\n name: PACKAGE_NAME,\n version: 'bundled',\n };\n return cachedPackageInfo;\n}\n\n/** Filename for storing version information in the data directory */\nconst VERSION_FILENAME = 'version.txt';\n\n/**\n * Represents a parsed semantic version with optional prerelease tag.\n */\nexport interface ParsedVersion {\n major: number;\n minor: number;\n patch: number;\n prerelease?: string;\n raw: string;\n}\n\n/**\n * Error thrown when the data directory cannot be accessed or created.\n */\nexport class DataDirAccessError extends Error {\n readonly dataDir: string;\n readonly code?: string;\n\n constructor(message: string, dataDir: string, code?: string) {\n super(message);\n this.name = 'DataDirAccessError';\n this.dataDir = dataDir;\n this.code = code;\n }\n}\n\n/**\n * Error thrown when data directory version is incompatible.\n */\nexport class DataDirVersionError extends Error {\n readonly oldVersion: ParsedVersion;\n readonly newVersion: ParsedVersion;\n readonly suggestedVersion?: string;\n\n constructor(\n message: string,\n oldVersion: ParsedVersion,\n newVersion: ParsedVersion,\n suggestedVersion?: string\n ) {\n super(message);\n this.name = 'DataDirVersionError';\n this.oldVersion = oldVersion;\n this.newVersion = newVersion;\n this.suggestedVersion = suggestedVersion;\n }\n}\n\n/**\n * Parses a version string into its components.\n *\n * @param versionString - Version string like \"4.0.1\" or \"4.0.1-beta.20\"\n * @returns Parsed version object with major, minor, patch, and optional prerelease\n */\nexport function parseVersion(versionString: string): ParsedVersion {\n // Match: major.minor.patch with optional prerelease\n const match = versionString.match(/^(\\d+)\\.(\\d+)\\.(\\d+)(?:-(.+))?$/);\n\n if (!match) {\n throw new Error(`Invalid version string: \"${versionString}\"`);\n }\n\n return {\n major: parseInt(match[1], 10),\n minor: parseInt(match[2], 10),\n patch: parseInt(match[3], 10),\n prerelease: match[4],\n raw: versionString,\n };\n}\n\n/**\n * Formats a parsed version back to a string.\n */\nexport function formatVersion(version: ParsedVersion): string {\n const base = `${version.major}.${version.minor}.${version.patch}`;\n return version.prerelease ? `${base}-${version.prerelease}` : base;\n}\n\n/**\n * Parses the version file content to extract package name and version.\n *\n * @param content - Content like \"@workflow/world-local@4.0.1-beta.20\"\n * @returns Object with packageName and version\n */\nexport function parseVersionFile(content: string): {\n packageName: string;\n version: ParsedVersion;\n} {\n const trimmed = content.trim();\n const lastAtIndex = trimmed.lastIndexOf('@');\n\n if (lastAtIndex <= 0) {\n throw new Error(`Invalid version file content: \"${content}\"`);\n }\n\n const packageName = trimmed.substring(0, lastAtIndex);\n const versionString = trimmed.substring(lastAtIndex + 1);\n\n return {\n packageName,\n version: parseVersion(versionString),\n };\n}\n\n/**\n * Formats the version file content.\n */\nexport function formatVersionFile(\n packageName: string,\n version: ParsedVersion\n): string {\n return `${packageName}@${formatVersion(version)}`;\n}\n\n/**\n * Handles version upgrades between old and new versions.\n * This function is called when the data directory was created with a different version.\n *\n * @param oldVersion - The version that created the data directory\n * @param newVersion - The current package version\n * @throws {DataDirVersionError} If the versions are incompatible\n */\nexport function upgradeVersion(\n oldVersion: ParsedVersion,\n newVersion: ParsedVersion\n): void {\n console.log(\n `[world-local] Upgrading from version ${formatVersion(oldVersion)} to ${formatVersion(newVersion)}`\n );\n}\n\n/**\n * Ensures the data directory exists and is writable.\n * Creates the directory if it doesn't exist.\n *\n * @param dataDir - The path to the data directory\n * @throws {DataDirAccessError} If the directory cannot be created or accessed\n */\nexport async function ensureDataDir(dataDir: string): Promise<void> {\n const absolutePath = path.resolve(dataDir);\n\n // Try to create the directory if it doesn't exist\n try {\n await mkdir(absolutePath, { recursive: true });\n } catch (error: unknown) {\n const nodeError = error as NodeJS.ErrnoException;\n // EEXIST is fine - directory already exists\n if (nodeError.code !== 'EEXIST') {\n throw new DataDirAccessError(\n `Failed to create data directory \"${absolutePath}\": ${nodeError.message}`,\n absolutePath,\n nodeError.code\n );\n }\n }\n\n // Verify the directory is accessible (readable)\n try {\n await access(absolutePath, constants.R_OK);\n } catch (error: unknown) {\n const nodeError = error as NodeJS.ErrnoException;\n throw new DataDirAccessError(\n `Data directory \"${absolutePath}\" is not readable: ${nodeError.message}`,\n absolutePath,\n nodeError.code\n );\n }\n\n // Verify the directory is writable by attempting to write a temp file\n const testFile = path.join(\n absolutePath,\n `.workflow-write-test-${Date.now()}`\n );\n try {\n await writeFile(testFile, '');\n // Clean up test file — ENOENT during cleanup is harmless (may race\n // with another process performing the same check concurrently)\n await unlink(testFile).catch((e: NodeJS.ErrnoException) => {\n if (e.code !== 'ENOENT') throw e;\n });\n } catch (error: unknown) {\n const nodeError = error as NodeJS.ErrnoException;\n throw new DataDirAccessError(\n `Data directory \"${absolutePath}\" is not writable: ${nodeError.message}`,\n absolutePath,\n nodeError.code\n );\n }\n}\n\n/**\n * Reads the version from the data directory's version file.\n *\n * @param dataDir - Path to the data directory\n * @returns The parsed version info, or null if the file doesn't exist\n */\nasync function readVersionFile(dataDir: string): Promise<{\n packageName: string;\n version: ParsedVersion;\n} | null> {\n const versionFilePath = path.join(path.resolve(dataDir), VERSION_FILENAME);\n\n try {\n const content = await readFile(versionFilePath, 'utf-8');\n return parseVersionFile(content);\n } catch (error: unknown) {\n const nodeError = error as NodeJS.ErrnoException;\n if (nodeError.code === 'ENOENT') {\n return null;\n }\n throw error;\n }\n}\n\n/**\n * Writes the current version to the data directory's version file.\n *\n * @param dataDir - Path to the data directory\n * @param version - The version to write\n */\nasync function writeVersionFile(\n dataDir: string,\n version: ParsedVersion\n): Promise<void> {\n const versionFilePath = path.join(path.resolve(dataDir), VERSION_FILENAME);\n const packageInfo = await getPackageInfo();\n const content = formatVersionFile(packageInfo.name, version);\n await writeFile(versionFilePath, content);\n}\n\n/**\n * Gets the suggested downgrade version based on the old version.\n * If a specific version is suggested in the error, use that.\n * Otherwise, suggest the previous minor version if patch is 0,\n * or previous major version if minor is also 0.\n */\nfunction getSuggestedDowngradeVersion(\n oldVersion: ParsedVersion,\n suggestedVersion?: string\n): string {\n if (suggestedVersion) {\n return suggestedVersion;\n }\n\n // Suggest the old version as the downgrade target\n return formatVersion(oldVersion);\n}\n\n/**\n * Initializes the data directory, ensuring it exists, is accessible,\n * and handles version compatibility.\n *\n * @param dataDir - The path to the data directory\n * @throws {DataDirAccessError} If the directory cannot be created or accessed\n */\nexport async function initDataDir(dataDir: string): Promise<void> {\n // First ensure the directory exists and is accessible\n await ensureDataDir(dataDir);\n\n const packageInfo = await getPackageInfo();\n const currentVersion = parseVersion(packageInfo.version);\n\n // Read existing version file\n const existingVersionInfo = await readVersionFile(dataDir);\n\n if (existingVersionInfo === null) {\n // New data directory - write the current version\n await writeVersionFile(dataDir, currentVersion);\n return;\n }\n\n const { version: oldVersion } = existingVersionInfo;\n\n // Check if versions are the same (no upgrade needed)\n if (formatVersion(oldVersion) === formatVersion(currentVersion)) {\n return;\n }\n\n // Attempt upgrade\n try {\n upgradeVersion(oldVersion, currentVersion);\n // Upgrade succeeded - write the new version\n await writeVersionFile(dataDir, currentVersion);\n } catch (error: unknown) {\n const suggestedVersion =\n error instanceof DataDirVersionError ? error.suggestedVersion : undefined;\n\n const downgradeTarget = getSuggestedDowngradeVersion(\n oldVersion,\n suggestedVersion\n );\n\n console.error(\n `[world-local] Failed to upgrade data directory from version ${formatVersion(oldVersion)} to ${formatVersion(currentVersion)}:`,\n error instanceof Error ? error.message : error\n );\n console.error(\n `[world-local] Data is not compatible with the current version. ` +\n `Please downgrade to ${packageInfo.name}@${downgradeTarget}`\n );\n\n throw error;\n }\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps all methods of an object with tracing spans.
|
|
3
|
+
* @param prefix - Prefix for span names (e.g., "world.runs")
|
|
4
|
+
* @param o - Object with methods to instrument
|
|
5
|
+
* @returns Instrumented object with same interface
|
|
6
|
+
*/
|
|
7
|
+
export declare function instrumentObject<T extends object>(prefix: string, o: T): T;
|
|
8
|
+
//# sourceMappingURL=instrumentObject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentObject.d.ts","sourceRoot":"","sources":["../src/instrumentObject.ts"],"names":[],"mappings":"AAkCA;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAsC1E"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility to instrument object methods with tracing.
|
|
3
|
+
* This mirrors world-vercel's implementation for consistent observability.
|
|
4
|
+
*/
|
|
5
|
+
import { trace, getSpanKind, PeerService, RpcSystem, RpcService, RpcMethod, } from './telemetry.js';
|
|
6
|
+
/** Configuration for peer service attribution */
|
|
7
|
+
const WORLD_LOCAL_SERVICE = {
|
|
8
|
+
peerService: 'world-local',
|
|
9
|
+
rpcSystem: 'local',
|
|
10
|
+
rpcService: 'world-local',
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Extracts the event type from arguments for events.create calls.
|
|
14
|
+
* The event data is the second argument and contains eventType.
|
|
15
|
+
*/
|
|
16
|
+
function extractEventType(args) {
|
|
17
|
+
if (args.length >= 2 && typeof args[1] === 'object' && args[1] !== null) {
|
|
18
|
+
const data = args[1];
|
|
19
|
+
if (typeof data.eventType === 'string') {
|
|
20
|
+
return data.eventType;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Wraps all methods of an object with tracing spans.
|
|
27
|
+
* @param prefix - Prefix for span names (e.g., "world.runs")
|
|
28
|
+
* @param o - Object with methods to instrument
|
|
29
|
+
* @returns Instrumented object with same interface
|
|
30
|
+
*/
|
|
31
|
+
export function instrumentObject(prefix, o) {
|
|
32
|
+
const handlers = {};
|
|
33
|
+
for (const key of Object.keys(o)) {
|
|
34
|
+
if (typeof o[key] !== 'function') {
|
|
35
|
+
handlers[key] = o[key];
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const f = o[key];
|
|
39
|
+
const methodName = String(key);
|
|
40
|
+
// @ts-expect-error - dynamic function wrapping
|
|
41
|
+
handlers[key] = async (...args) => {
|
|
42
|
+
// Build span name - for events.create, include the event type
|
|
43
|
+
let spanName = `${prefix}.${methodName}`;
|
|
44
|
+
if (prefix === 'world.events' && methodName === 'create') {
|
|
45
|
+
const eventType = extractEventType(args);
|
|
46
|
+
if (eventType) {
|
|
47
|
+
spanName = `${prefix}.${methodName} ${eventType}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return trace(spanName, { kind: await getSpanKind('INTERNAL') }, async (span) => {
|
|
51
|
+
// Add peer service attributes for service maps
|
|
52
|
+
// Use spanName for rpc.method so Datadog shows event type in resource
|
|
53
|
+
span?.setAttributes({
|
|
54
|
+
...PeerService(WORLD_LOCAL_SERVICE.peerService),
|
|
55
|
+
...RpcSystem(WORLD_LOCAL_SERVICE.rpcSystem),
|
|
56
|
+
...RpcService(WORLD_LOCAL_SERVICE.rpcService),
|
|
57
|
+
...RpcMethod(spanName),
|
|
58
|
+
});
|
|
59
|
+
return f(...args);
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return handlers;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=instrumentObject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"instrumentObject.js","sourceRoot":"","sources":["../src/instrumentObject.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,KAAK,EACL,WAAW,EACX,WAAW,EACX,SAAS,EACT,UAAU,EACV,SAAS,GACV,MAAM,gBAAgB,CAAC;AAExB,iDAAiD;AACjD,MAAM,mBAAmB,GAAG;IAC1B,WAAW,EAAE,aAAa;IAC1B,SAAS,EAAE,OAAO;IAClB,UAAU,EAAE,aAAa;CAC1B,CAAC;AAEF;;;GAGG;AACH,SAAS,gBAAgB,CAAC,IAAe;IACvC,IAAI,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACxE,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAA4B,CAAC;QAChD,IAAI,OAAO,IAAI,CAAC,SAAS,KAAK,QAAQ,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC,SAAS,CAAC;QACxB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAmB,MAAc,EAAE,CAAI;IACrE,MAAM,QAAQ,GAAG,EAAO,CAAC;IACzB,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAgB,EAAE,CAAC;QAChD,IAAI,OAAO,CAAC,CAAC,GAAG,CAAC,KAAK,UAAU,EAAE,CAAC;YACjC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YACjB,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAC/B,+CAA+C;YAC/C,QAAQ,CAAC,GAAG,CAAC,GAAG,KAAK,EAAE,GAAG,IAAe,EAAE,EAAE;gBAC3C,8DAA8D;gBAC9D,IAAI,QAAQ,GAAG,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;gBACzC,IAAI,MAAM,KAAK,cAAc,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;oBACzD,MAAM,SAAS,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;oBACzC,IAAI,SAAS,EAAE,CAAC;wBACd,QAAQ,GAAG,GAAG,MAAM,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;oBACpD,CAAC;gBACH,CAAC;gBAED,OAAO,KAAK,CACV,QAAQ,EACR,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC,UAAU,CAAC,EAAE,EACvC,KAAK,EAAE,IAAI,EAAE,EAAE;oBACb,+CAA+C;oBAC/C,sEAAsE;oBACtE,IAAI,EAAE,aAAa,CAAC;wBAClB,GAAG,WAAW,CAAC,mBAAmB,CAAC,WAAW,CAAC;wBAC/C,GAAG,SAAS,CAAC,mBAAmB,CAAC,SAAS,CAAC;wBAC3C,GAAG,UAAU,CAAC,mBAAmB,CAAC,UAAU,CAAC;wBAC7C,GAAG,SAAS,CAAC,QAAQ,CAAC;qBACvB,CAAC,CAAC;oBACH,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;gBACpB,CAAC,CACF,CAAC;YACJ,CAAC,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["/**\n * Utility to instrument object methods with tracing.\n * This mirrors world-vercel's implementation for consistent observability.\n */\nimport {\n trace,\n getSpanKind,\n PeerService,\n RpcSystem,\n RpcService,\n RpcMethod,\n} from './telemetry.js';\n\n/** Configuration for peer service attribution */\nconst WORLD_LOCAL_SERVICE = {\n peerService: 'world-local',\n rpcSystem: 'local',\n rpcService: 'world-local',\n};\n\n/**\n * Extracts the event type from arguments for events.create calls.\n * The event data is the second argument and contains eventType.\n */\nfunction extractEventType(args: unknown[]): string | undefined {\n if (args.length >= 2 && typeof args[1] === 'object' && args[1] !== null) {\n const data = args[1] as Record<string, unknown>;\n if (typeof data.eventType === 'string') {\n return data.eventType;\n }\n }\n return undefined;\n}\n\n/**\n * Wraps all methods of an object with tracing spans.\n * @param prefix - Prefix for span names (e.g., \"world.runs\")\n * @param o - Object with methods to instrument\n * @returns Instrumented object with same interface\n */\nexport function instrumentObject<T extends object>(prefix: string, o: T): T {\n const handlers = {} as T;\n for (const key of Object.keys(o) as (keyof T)[]) {\n if (typeof o[key] !== 'function') {\n handlers[key] = o[key];\n } else {\n const f = o[key];\n const methodName = String(key);\n // @ts-expect-error - dynamic function wrapping\n handlers[key] = async (...args: unknown[]) => {\n // Build span name - for events.create, include the event type\n let spanName = `${prefix}.${methodName}`;\n if (prefix === 'world.events' && methodName === 'create') {\n const eventType = extractEventType(args);\n if (eventType) {\n spanName = `${prefix}.${methodName} ${eventType}`;\n }\n }\n\n return trace(\n spanName,\n { kind: await getSpanKind('INTERNAL') },\n async (span) => {\n // Add peer service attributes for service maps\n // Use spanName for rpc.method so Datadog shows event type in resource\n span?.setAttributes({\n ...PeerService(WORLD_LOCAL_SERVICE.peerService),\n ...RpcSystem(WORLD_LOCAL_SERVICE.rpcSystem),\n ...RpcService(WORLD_LOCAL_SERVICE.rpcService),\n ...RpcMethod(spanName),\n });\n return f(...args);\n }\n );\n };\n }\n }\n return handlers;\n}\n"]}
|
package/dist/queue.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { type Queue } from '@workflow/world';
|
|
2
2
|
import type { Config } from './config.js';
|
|
3
|
-
export
|
|
3
|
+
export type DirectHandler = (req: Request) => Promise<Response>;
|
|
4
|
+
export type LocalQueue = Queue & {
|
|
5
|
+
/** Close the HTTP agent and release resources. */
|
|
6
|
+
close(): Promise<void>;
|
|
7
|
+
/** Register a direct in-process handler for a queue prefix, bypassing HTTP. */
|
|
8
|
+
registerHandler(prefix: '__wkf_step_' | '__wkf_workflow_', handler: DirectHandler): void;
|
|
9
|
+
};
|
|
10
|
+
export declare function createQueue(config: Partial<Config>): LocalQueue;
|
|
4
11
|
//# sourceMappingURL=queue.d.ts.map
|
package/dist/queue.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,KAAK,EAAkB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAEA,OAAO,EAAa,KAAK,KAAK,EAAkB,MAAM,iBAAiB,CAAC;AAKxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAiD1C,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAEhE,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG;IAC/B,kDAAkD;IAClD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,+EAA+E;IAC/E,eAAe,CACb,MAAM,EAAE,aAAa,GAAG,iBAAiB,EACzC,OAAO,EAAE,aAAa,GACrB,IAAI,CAAC;CACT,CAAC;AAeF,wBAAgB,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,UAAU,CAoP/D"}
|
package/dist/queue.js
CHANGED
|
@@ -1,26 +1,80 @@
|
|
|
1
1
|
import { setTimeout } from 'node:timers/promises';
|
|
2
|
-
import { JsonTransport } from '@vercel/queue';
|
|
3
2
|
import { MessageId, ValidQueueName } from '@workflow/world';
|
|
3
|
+
import { Sema } from 'async-sema';
|
|
4
4
|
import { monotonicFactory } from 'ulid';
|
|
5
5
|
import { Agent } from 'undici';
|
|
6
|
-
import z from 'zod';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
7
|
import { resolveBaseUrl } from './config.js';
|
|
8
|
+
import { jsonReplacer, jsonReviver } from './fs.js';
|
|
9
|
+
import { getPackageInfo } from './init.js';
|
|
10
|
+
/**
|
|
11
|
+
* JSON transport that preserves Uint8Array values using the same
|
|
12
|
+
* replacer/reviver that world-local uses for filesystem storage.
|
|
13
|
+
* Uint8Array → { __type: 'Uint8Array', data: '<base64>' } in JSON.
|
|
14
|
+
*/
|
|
15
|
+
class TypedJsonTransport {
|
|
16
|
+
contentType = 'application/json';
|
|
17
|
+
serialize(value) {
|
|
18
|
+
return Buffer.from(JSON.stringify(value, jsonReplacer));
|
|
19
|
+
}
|
|
20
|
+
async deserialize(stream) {
|
|
21
|
+
const chunks = [];
|
|
22
|
+
const reader = stream.getReader();
|
|
23
|
+
while (true) {
|
|
24
|
+
const { done, value } = await reader.read();
|
|
25
|
+
if (done)
|
|
26
|
+
break;
|
|
27
|
+
if (value)
|
|
28
|
+
chunks.push(value);
|
|
29
|
+
}
|
|
30
|
+
const text = Buffer.concat(chunks).toString();
|
|
31
|
+
return JSON.parse(text, jsonReviver);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
8
34
|
// For local queue, there is no technical limit on the message visibility lifespan,
|
|
9
35
|
// but the environment variable can be used for testing purposes to set a max visibility limit.
|
|
10
36
|
const LOCAL_QUEUE_MAX_VISIBILITY = parseInt(process.env.WORKFLOW_LOCAL_QUEUE_MAX_VISIBILITY ?? '0', 10) ||
|
|
11
37
|
Infinity;
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
38
|
+
// Maximum safe delay for setTimeout in Node.js (2^31 - 1 milliseconds ≈ 24.85 days)
|
|
39
|
+
// Larger values cause "TimeoutOverflowWarning: X does not fit into a 32-bit signed integer"
|
|
40
|
+
// When the clamped timeout fires, the handler will recalculate remaining time from
|
|
41
|
+
// persistent state and return another timeoutSeconds if needed.
|
|
42
|
+
const MAX_SAFE_TIMEOUT_MS = 2147483647;
|
|
43
|
+
// The local workers share the same Node.js process and event loop,
|
|
44
|
+
// so we need to limit concurrency to avoid overwhelming the system.
|
|
45
|
+
const DEFAULT_CONCURRENCY_LIMIT = 1000;
|
|
46
|
+
const WORKFLOW_LOCAL_QUEUE_CONCURRENCY = parseInt(process.env.WORKFLOW_LOCAL_QUEUE_CONCURRENCY ?? '0', 10) ||
|
|
47
|
+
DEFAULT_CONCURRENCY_LIMIT;
|
|
48
|
+
function getQueueRoute(queueName) {
|
|
49
|
+
if (queueName.startsWith('__wkf_step_')) {
|
|
50
|
+
return { pathname: 'step', prefix: '__wkf_step_' };
|
|
51
|
+
}
|
|
52
|
+
if (queueName.startsWith('__wkf_workflow_')) {
|
|
53
|
+
return { pathname: 'flow', prefix: '__wkf_workflow_' };
|
|
54
|
+
}
|
|
55
|
+
throw new Error('Unknown queue name prefix');
|
|
56
|
+
}
|
|
16
57
|
export function createQueue(config) {
|
|
17
|
-
|
|
58
|
+
// Create a custom agent optimized for high-concurrency local workflows:
|
|
59
|
+
// - headersTimeout: 0 allows long-running steps
|
|
60
|
+
// - connections: 1000 allows many parallel connections to the same host
|
|
61
|
+
// - pipelining: 1 (default) for HTTP/1.1 compatibility
|
|
62
|
+
// - keepAliveTimeout: 30s keeps connections warm for rapid step execution
|
|
63
|
+
const httpAgent = new Agent({
|
|
64
|
+
headersTimeout: 0,
|
|
65
|
+
connections: 1000,
|
|
66
|
+
keepAliveTimeout: 30_000,
|
|
67
|
+
});
|
|
68
|
+
const transport = new TypedJsonTransport();
|
|
18
69
|
const generateId = monotonicFactory();
|
|
70
|
+
const semaphore = new Sema(WORKFLOW_LOCAL_QUEUE_CONCURRENCY);
|
|
19
71
|
/**
|
|
20
72
|
* holds inflight messages by idempotency key to ensure
|
|
21
73
|
* that we don't queue the same message multiple times
|
|
22
74
|
*/
|
|
23
75
|
const inflightMessages = new Map();
|
|
76
|
+
/** Direct in-process handlers by queue prefix, bypassing HTTP when set. */
|
|
77
|
+
const directHandlers = new Map();
|
|
24
78
|
const queue = async (queueName, message, opts) => {
|
|
25
79
|
const cleanup = [];
|
|
26
80
|
if (opts?.idempotencyKey) {
|
|
@@ -30,17 +84,13 @@ export function createQueue(config) {
|
|
|
30
84
|
}
|
|
31
85
|
}
|
|
32
86
|
const body = transport.serialize(message);
|
|
33
|
-
|
|
34
|
-
if (queueName.startsWith('__wkf_step_')) {
|
|
35
|
-
pathname = `step`;
|
|
36
|
-
}
|
|
37
|
-
else if (queueName.startsWith('__wkf_workflow_')) {
|
|
38
|
-
pathname = `flow`;
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
throw new Error('Unknown queue name prefix');
|
|
42
|
-
}
|
|
87
|
+
const { pathname, prefix } = getQueueRoute(queueName);
|
|
43
88
|
const messageId = MessageId.parse(`msg_${generateId()}`);
|
|
89
|
+
// Extract identifiers from the message for structured logging.
|
|
90
|
+
// Workflow messages have `runId`, step messages have `workflowRunId` + `stepId`.
|
|
91
|
+
const msg = message;
|
|
92
|
+
const runId = (msg.runId ?? msg.workflowRunId ?? undefined);
|
|
93
|
+
const stepId = (msg.stepId ?? undefined);
|
|
44
94
|
if (opts?.idempotencyKey) {
|
|
45
95
|
const key = opts.idempotencyKey;
|
|
46
96
|
inflightMessages.set(key, messageId);
|
|
@@ -49,46 +99,96 @@ export function createQueue(config) {
|
|
|
49
99
|
});
|
|
50
100
|
}
|
|
51
101
|
(async () => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
102
|
+
const token = semaphore.tryAcquire();
|
|
103
|
+
if (!token) {
|
|
104
|
+
console.warn(`[world-local]: concurrency limit (${WORKFLOW_LOCAL_QUEUE_CONCURRENCY}) reached, waiting for queue to free up`);
|
|
105
|
+
await semaphore.acquire();
|
|
106
|
+
}
|
|
107
|
+
// Safety limit to prevent infinite loops in the local queue.
|
|
108
|
+
// The actual max delivery enforcement happens in the workflow/step handlers
|
|
109
|
+
// (at MAX_QUEUE_DELIVERIES = 48), so this just needs to be comfortably higher.
|
|
110
|
+
const MAX_LOCAL_SAFETY_LIMIT = 256;
|
|
111
|
+
try {
|
|
112
|
+
for (let attempt = 0; attempt < MAX_LOCAL_SAFETY_LIMIT; attempt++) {
|
|
113
|
+
const headers = {
|
|
114
|
+
...opts?.headers,
|
|
62
115
|
'content-type': 'application/json',
|
|
63
116
|
'x-vqs-queue-name': queueName,
|
|
64
117
|
'x-vqs-message-id': messageId,
|
|
65
118
|
'x-vqs-message-attempt': String(attempt + 1),
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
119
|
+
};
|
|
120
|
+
const directHandler = directHandlers.get(prefix);
|
|
121
|
+
let response;
|
|
122
|
+
if (directHandler) {
|
|
123
|
+
const req = new Request(`http://localhost/.well-known/workflow/v1/${pathname}`, {
|
|
124
|
+
method: 'POST',
|
|
125
|
+
headers,
|
|
126
|
+
body,
|
|
127
|
+
});
|
|
128
|
+
response = await directHandler(req);
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const baseUrl = await resolveBaseUrl(config);
|
|
132
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- undici v7 dispatcher types don't match @types/node's RequestInit
|
|
133
|
+
response = await fetch(`${baseUrl}/.well-known/workflow/v1/${pathname}`, {
|
|
134
|
+
method: 'POST',
|
|
135
|
+
duplex: 'half',
|
|
136
|
+
dispatcher: httpAgent,
|
|
137
|
+
headers,
|
|
138
|
+
body,
|
|
139
|
+
});
|
|
79
140
|
}
|
|
80
|
-
|
|
141
|
+
const text = await response.text();
|
|
142
|
+
if (response.ok) {
|
|
143
|
+
try {
|
|
144
|
+
const timeoutSeconds = Number(JSON.parse(text).timeoutSeconds);
|
|
145
|
+
if (Number.isFinite(timeoutSeconds) && timeoutSeconds >= 0) {
|
|
146
|
+
// Clamp to MAX_SAFE_TIMEOUT_MS to avoid Node.js setTimeout overflow warning.
|
|
147
|
+
// When this fires early, the handler recalculates remaining time from
|
|
148
|
+
// persistent state and returns another timeoutSeconds if needed.
|
|
149
|
+
if (timeoutSeconds > 0) {
|
|
150
|
+
const timeoutMs = Math.min(timeoutSeconds * 1000, MAX_SAFE_TIMEOUT_MS);
|
|
151
|
+
await setTimeout(timeoutMs);
|
|
152
|
+
}
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch { }
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
console.error(`[world-local] Queue message failed (attempt ${attempt + 1}, HTTP ${response.status})`, {
|
|
160
|
+
queueName,
|
|
161
|
+
messageId,
|
|
162
|
+
...(runId && { runId }),
|
|
163
|
+
...(stepId && { stepId }),
|
|
164
|
+
handlerError: text,
|
|
165
|
+
});
|
|
166
|
+
// 5s linear backoff to approximate VQS retry timing in local dev.
|
|
167
|
+
// VQS uses 5s linear for attempts 1–32, then exponential, but for
|
|
168
|
+
// local dev linear 5s is sufficient — the handler enforces the real
|
|
169
|
+
// cap at MAX_QUEUE_DELIVERIES (48) which keeps total time under ~4min.
|
|
170
|
+
await setTimeout(5000);
|
|
81
171
|
}
|
|
82
|
-
console.error(`[
|
|
172
|
+
console.error(`[world-local] Queue message exhausted safety limit (${MAX_LOCAL_SAFETY_LIMIT} attempts)`, {
|
|
83
173
|
queueName,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
body: body.toString(),
|
|
174
|
+
messageId,
|
|
175
|
+
...(runId && { runId }),
|
|
176
|
+
...(stepId && { stepId }),
|
|
88
177
|
});
|
|
89
178
|
}
|
|
90
|
-
|
|
91
|
-
|
|
179
|
+
finally {
|
|
180
|
+
semaphore.release();
|
|
181
|
+
}
|
|
182
|
+
})()
|
|
183
|
+
.catch((err) => {
|
|
184
|
+
// Silently ignore client disconnect errors (e.g., browser refresh during streaming)
|
|
185
|
+
// These are expected and should not cause unhandled rejection warnings
|
|
186
|
+
const isAbortError = err?.name === 'AbortError' || err?.name === 'ResponseAborted';
|
|
187
|
+
if (!isAbortError) {
|
|
188
|
+
console.error('[local world] Queue operation failed:', err);
|
|
189
|
+
}
|
|
190
|
+
})
|
|
191
|
+
.finally(() => {
|
|
92
192
|
for (const fn of cleanup) {
|
|
93
193
|
fn();
|
|
94
194
|
}
|
|
@@ -116,15 +216,15 @@ export function createQueue(config) {
|
|
|
116
216
|
if (!queueName.startsWith(prefix)) {
|
|
117
217
|
return Response.json({ error: 'Unhandled queue' }, { status: 400 });
|
|
118
218
|
}
|
|
119
|
-
const body = await new
|
|
219
|
+
const body = await new TypedJsonTransport().deserialize(req.body);
|
|
120
220
|
try {
|
|
121
221
|
const result = await handler(body, { attempt, queueName, messageId });
|
|
122
222
|
let timeoutSeconds = null;
|
|
123
223
|
if (typeof result?.timeoutSeconds === 'number') {
|
|
124
224
|
timeoutSeconds = Math.min(result.timeoutSeconds, LOCAL_QUEUE_MAX_VISIBILITY);
|
|
125
225
|
}
|
|
126
|
-
if (timeoutSeconds) {
|
|
127
|
-
return Response.json({ timeoutSeconds }
|
|
226
|
+
if (timeoutSeconds != null) {
|
|
227
|
+
return Response.json({ timeoutSeconds });
|
|
128
228
|
}
|
|
129
229
|
return Response.json({ ok: true });
|
|
130
230
|
}
|
|
@@ -134,8 +234,19 @@ export function createQueue(config) {
|
|
|
134
234
|
};
|
|
135
235
|
};
|
|
136
236
|
const getDeploymentId = async () => {
|
|
137
|
-
|
|
237
|
+
const packageInfo = await getPackageInfo();
|
|
238
|
+
return `dpl_local@${packageInfo.version}`;
|
|
239
|
+
};
|
|
240
|
+
return {
|
|
241
|
+
queue,
|
|
242
|
+
createQueueHandler,
|
|
243
|
+
getDeploymentId,
|
|
244
|
+
registerHandler(prefix, handler) {
|
|
245
|
+
directHandlers.set(prefix, handler);
|
|
246
|
+
},
|
|
247
|
+
async close() {
|
|
248
|
+
await httpAgent.close();
|
|
249
|
+
},
|
|
138
250
|
};
|
|
139
|
-
return { queue, createQueueHandler, getDeploymentId };
|
|
140
251
|
}
|
|
141
252
|
//# sourceMappingURL=queue.js.map
|
package/dist/queue.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"queue.js","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"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","sourcesContent":["import { setTimeout } from 'node:timers/promises';\nimport type { Transport } from '@vercel/queue';\nimport { MessageId, type Queue, ValidQueueName } from '@workflow/world';\nimport { Sema } from 'async-sema';\nimport { monotonicFactory } from 'ulid';\nimport { Agent } from 'undici';\nimport { z } from 'zod/v4';\nimport type { Config } from './config.js';\nimport { resolveBaseUrl } from './config.js';\nimport { jsonReplacer, jsonReviver } from './fs.js';\nimport { getPackageInfo } from './init.js';\n\n/**\n * JSON transport that preserves Uint8Array values using the same\n * replacer/reviver that world-local uses for filesystem storage.\n * Uint8Array → { __type: 'Uint8Array', data: '<base64>' } in JSON.\n */\nclass TypedJsonTransport implements Transport<unknown> {\n readonly contentType = 'application/json';\n\n serialize(value: unknown): Buffer {\n return Buffer.from(JSON.stringify(value, jsonReplacer));\n }\n\n async deserialize(stream: ReadableStream<Uint8Array>): Promise<unknown> {\n const chunks: Uint8Array[] = [];\n const reader = stream.getReader();\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) chunks.push(value);\n }\n const text = Buffer.concat(chunks).toString();\n return JSON.parse(text, jsonReviver);\n }\n}\n\n// For local queue, there is no technical limit on the message visibility lifespan,\n// but the environment variable can be used for testing purposes to set a max visibility limit.\nconst LOCAL_QUEUE_MAX_VISIBILITY =\n parseInt(process.env.WORKFLOW_LOCAL_QUEUE_MAX_VISIBILITY ?? '0', 10) ||\n Infinity;\n\n// Maximum safe delay for setTimeout in Node.js (2^31 - 1 milliseconds ≈ 24.85 days)\n// Larger values cause \"TimeoutOverflowWarning: X does not fit into a 32-bit signed integer\"\n// When the clamped timeout fires, the handler will recalculate remaining time from\n// persistent state and return another timeoutSeconds if needed.\nconst MAX_SAFE_TIMEOUT_MS = 2147483647;\n\n// The local workers share the same Node.js process and event loop,\n// so we need to limit concurrency to avoid overwhelming the system.\nconst DEFAULT_CONCURRENCY_LIMIT = 1000;\nconst WORKFLOW_LOCAL_QUEUE_CONCURRENCY =\n parseInt(process.env.WORKFLOW_LOCAL_QUEUE_CONCURRENCY ?? '0', 10) ||\n DEFAULT_CONCURRENCY_LIMIT;\n\nexport type DirectHandler = (req: Request) => Promise<Response>;\n\nexport type LocalQueue = Queue & {\n /** Close the HTTP agent and release resources. */\n close(): Promise<void>;\n /** Register a direct in-process handler for a queue prefix, bypassing HTTP. */\n registerHandler(\n prefix: '__wkf_step_' | '__wkf_workflow_',\n handler: DirectHandler\n ): void;\n};\n\nfunction getQueueRoute(queueName: ValidQueueName): {\n pathname: 'flow' | 'step';\n prefix: '__wkf_step_' | '__wkf_workflow_';\n} {\n if (queueName.startsWith('__wkf_step_')) {\n return { pathname: 'step', prefix: '__wkf_step_' };\n }\n if (queueName.startsWith('__wkf_workflow_')) {\n return { pathname: 'flow', prefix: '__wkf_workflow_' };\n }\n throw new Error('Unknown queue name prefix');\n}\n\nexport function createQueue(config: Partial<Config>): LocalQueue {\n // Create a custom agent optimized for high-concurrency local workflows:\n // - headersTimeout: 0 allows long-running steps\n // - connections: 1000 allows many parallel connections to the same host\n // - pipelining: 1 (default) for HTTP/1.1 compatibility\n // - keepAliveTimeout: 30s keeps connections warm for rapid step execution\n const httpAgent = new Agent({\n headersTimeout: 0,\n connections: 1000,\n keepAliveTimeout: 30_000,\n });\n const transport = new TypedJsonTransport();\n const generateId = monotonicFactory();\n const semaphore = new Sema(WORKFLOW_LOCAL_QUEUE_CONCURRENCY);\n\n /**\n * holds inflight messages by idempotency key to ensure\n * that we don't queue the same message multiple times\n */\n const inflightMessages = new Map<string, MessageId>();\n /** Direct in-process handlers by queue prefix, bypassing HTTP when set. */\n const directHandlers = new Map<string, DirectHandler>();\n\n const queue: Queue['queue'] = async (queueName, message, opts) => {\n const cleanup = [] as (() => void)[];\n\n if (opts?.idempotencyKey) {\n const existing = inflightMessages.get(opts.idempotencyKey);\n if (existing) {\n return { messageId: existing };\n }\n }\n\n const body = transport.serialize(message);\n const { pathname, prefix } = getQueueRoute(queueName);\n const messageId = MessageId.parse(`msg_${generateId()}`);\n\n // Extract identifiers from the message for structured logging.\n // Workflow messages have `runId`, step messages have `workflowRunId` + `stepId`.\n const msg = message as Record<string, unknown>;\n const runId = (msg.runId ?? msg.workflowRunId ?? undefined) as\n | string\n | undefined;\n const stepId = (msg.stepId ?? undefined) as string | undefined;\n\n if (opts?.idempotencyKey) {\n const key = opts.idempotencyKey;\n inflightMessages.set(key, messageId);\n cleanup.push(() => {\n inflightMessages.delete(key);\n });\n }\n\n (async () => {\n const token = semaphore.tryAcquire();\n if (!token) {\n console.warn(\n `[world-local]: concurrency limit (${WORKFLOW_LOCAL_QUEUE_CONCURRENCY}) reached, waiting for queue to free up`\n );\n await semaphore.acquire();\n }\n // Safety limit to prevent infinite loops in the local queue.\n // The actual max delivery enforcement happens in the workflow/step handlers\n // (at MAX_QUEUE_DELIVERIES = 48), so this just needs to be comfortably higher.\n const MAX_LOCAL_SAFETY_LIMIT = 256;\n try {\n for (let attempt = 0; attempt < MAX_LOCAL_SAFETY_LIMIT; attempt++) {\n const headers: Record<string, string> = {\n ...opts?.headers,\n 'content-type': 'application/json',\n 'x-vqs-queue-name': queueName,\n 'x-vqs-message-id': messageId,\n 'x-vqs-message-attempt': String(attempt + 1),\n };\n const directHandler = directHandlers.get(prefix);\n let response: Response;\n\n if (directHandler) {\n const req = new Request(\n `http://localhost/.well-known/workflow/v1/${pathname}`,\n {\n method: 'POST',\n headers,\n body,\n }\n );\n response = await directHandler(req);\n } else {\n const baseUrl = await resolveBaseUrl(config);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- undici v7 dispatcher types don't match @types/node's RequestInit\n response = await fetch(\n `${baseUrl}/.well-known/workflow/v1/${pathname}`,\n {\n method: 'POST',\n duplex: 'half',\n dispatcher: httpAgent,\n headers,\n body,\n } as any\n );\n }\n\n const text = await response.text();\n\n if (response.ok) {\n try {\n const timeoutSeconds = Number(JSON.parse(text).timeoutSeconds);\n if (Number.isFinite(timeoutSeconds) && timeoutSeconds >= 0) {\n // Clamp to MAX_SAFE_TIMEOUT_MS to avoid Node.js setTimeout overflow warning.\n // When this fires early, the handler recalculates remaining time from\n // persistent state and returns another timeoutSeconds if needed.\n if (timeoutSeconds > 0) {\n const timeoutMs = Math.min(\n timeoutSeconds * 1000,\n MAX_SAFE_TIMEOUT_MS\n );\n await setTimeout(timeoutMs);\n }\n continue;\n }\n } catch {}\n return;\n }\n\n console.error(\n `[world-local] Queue message failed (attempt ${attempt + 1}, HTTP ${response.status})`,\n {\n queueName,\n messageId,\n ...(runId && { runId }),\n ...(stepId && { stepId }),\n handlerError: text,\n }\n );\n\n // 5s linear backoff to approximate VQS retry timing in local dev.\n // VQS uses 5s linear for attempts 1–32, then exponential, but for\n // local dev linear 5s is sufficient — the handler enforces the real\n // cap at MAX_QUEUE_DELIVERIES (48) which keeps total time under ~4min.\n await setTimeout(5000);\n }\n\n console.error(\n `[world-local] Queue message exhausted safety limit (${MAX_LOCAL_SAFETY_LIMIT} attempts)`,\n {\n queueName,\n messageId,\n ...(runId && { runId }),\n ...(stepId && { stepId }),\n }\n );\n } finally {\n semaphore.release();\n }\n })()\n .catch((err) => {\n // Silently ignore client disconnect errors (e.g., browser refresh during streaming)\n // These are expected and should not cause unhandled rejection warnings\n const isAbortError =\n err?.name === 'AbortError' || err?.name === 'ResponseAborted';\n if (!isAbortError) {\n console.error('[local world] Queue operation failed:', err);\n }\n })\n .finally(() => {\n for (const fn of cleanup) {\n fn();\n }\n });\n\n return { messageId };\n };\n\n const HeaderParser = z.object({\n 'x-vqs-queue-name': ValidQueueName,\n 'x-vqs-message-id': MessageId,\n 'x-vqs-message-attempt': z.coerce.number(),\n });\n\n const createQueueHandler: Queue['createQueueHandler'] = (prefix, handler) => {\n return async (req) => {\n const headers = HeaderParser.safeParse(Object.fromEntries(req.headers));\n\n if (!headers.success || !req.body) {\n return Response.json(\n {\n error: !req.body\n ? 'Missing request body'\n : 'Missing required headers',\n },\n { status: 400 }\n );\n }\n\n const queueName = headers.data['x-vqs-queue-name'];\n const messageId = headers.data['x-vqs-message-id'];\n const attempt = headers.data['x-vqs-message-attempt'];\n\n if (!queueName.startsWith(prefix)) {\n return Response.json({ error: 'Unhandled queue' }, { status: 400 });\n }\n\n const body = await new TypedJsonTransport().deserialize(req.body);\n try {\n const result = await handler(body, { attempt, queueName, messageId });\n\n let timeoutSeconds: number | null = null;\n if (typeof result?.timeoutSeconds === 'number') {\n timeoutSeconds = Math.min(\n result.timeoutSeconds,\n LOCAL_QUEUE_MAX_VISIBILITY\n );\n }\n\n if (timeoutSeconds != null) {\n return Response.json({ timeoutSeconds });\n }\n\n return Response.json({ ok: true });\n } catch (error) {\n return Response.json(String(error), { status: 500 });\n }\n };\n };\n\n const getDeploymentId: Queue['getDeploymentId'] = async () => {\n const packageInfo = await getPackageInfo();\n return `dpl_local@${packageInfo.version}`;\n };\n\n return {\n queue,\n createQueueHandler,\n getDeploymentId,\n registerHandler(\n prefix: '__wkf_step_' | '__wkf_workflow_',\n handler: DirectHandler\n ) {\n directHandlers.set(prefix, handler);\n },\n async close() {\n await httpAgent.close();\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Storage } from '@workflow/world';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the events storage implementation using the filesystem.
|
|
4
|
+
* Implements the Storage['events'] interface with create, list, and listByCorrelationId operations.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createEventsStorage(basedir: string, tag?: string): Storage['events'];
|
|
7
|
+
//# sourceMappingURL=events-storage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events-storage.d.ts","sourceRoot":"","sources":["../../src/storage/events-storage.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAMV,OAAO,EAGR,MAAM,iBAAiB,CAAC;AAmDzB;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,QAAQ,CAAC,CA8+BnB"}
|