deepline 0.1.243 → 0.1.244
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/README.md +1 -1
- package/dist/bundling-sources/sdk/src/plays/bundle-play-file.ts +5 -25
- package/dist/bundling-sources/sdk/src/release.ts +23 -21
- package/dist/bundling-sources/sdk/src/types.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/backend.ts +2 -21
- package/dist/bundling-sources/shared_libs/play-runtime/governor/governor.ts +5 -6
- package/dist/bundling-sources/shared_libs/play-runtime/governor/policy.ts +6 -13
- package/dist/bundling-sources/shared_libs/play-runtime/governor/rate-state-backend.ts +9 -26
- package/dist/bundling-sources/shared_libs/play-runtime/internal-step-ids.ts +1 -2
- package/dist/bundling-sources/shared_libs/play-runtime/map-row-identity.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/output-size-limits.ts +191 -29
- package/dist/bundling-sources/shared_libs/play-runtime/play-latency-trace.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/providers.ts +1 -36
- package/dist/bundling-sources/shared_libs/play-runtime/run-ledger.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runner-backends/index.ts +0 -7
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +1 -12
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-pg.ts +2 -3
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver.ts +5 -15
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backend.ts +6 -21
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +3 -4
- package/dist/bundling-sources/shared_libs/plays/artifact-kind-guard.ts +16 -29
- package/dist/bundling-sources/shared_libs/plays/artifact-types.ts +4 -8
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +21 -712
- package/dist/bundling-sources/shared_libs/plays/bundling/limits.ts +1 -18
- package/dist/cli/index.js +29 -71
- package/dist/cli/index.mjs +29 -71
- package/dist/{compiler-manifest-CYcwzSOJ.d.ts → compiler-manifest-DlE7dnRm.d.mts} +2 -8
- package/dist/{compiler-manifest-CYcwzSOJ.d.mts → compiler-manifest-DlE7dnRm.d.ts} +2 -8
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +24 -22
- package/dist/index.mjs +24 -22
- package/dist/plays/bundle-play-file.d.mts +7 -22
- package/dist/plays/bundle-play-file.d.ts +7 -22
- package/dist/plays/bundle-play-file.mjs +26 -614
- package/package.json +2 -2
- package/dist/bundling-sources/apps/play-runner-workers/src/coordinator-entry.ts +0 -4504
- package/dist/bundling-sources/apps/play-runner-workers/src/dedup-do.ts +0 -1386
- package/dist/bundling-sources/apps/play-runner-workers/src/durable-object-deploy-handoff.ts +0 -30
- package/dist/bundling-sources/apps/play-runner-workers/src/entry.ts +0 -8385
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/README.md +0 -21
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/batching.ts +0 -251
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/coordinator-progress.ts +0 -289
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/csv-rows.ts +0 -85
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/customer-console.ts +0 -23
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/dataset-handles.ts +0 -528
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/harness-receipt-store.ts +0 -229
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/ledger-event-batches.ts +0 -81
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/live-progress.ts +0 -22
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-chunk-plan.ts +0 -920
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/map-latency-profile.ts +0 -90
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/output-datasets.ts +0 -475
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/receipts.ts +0 -570
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/result-dataset-persistence.ts +0 -50
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/row-isolation.ts +0 -5
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/run-work-dispatcher.ts +0 -519
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -107
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-dispatch.ts +0 -2541
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-http-errors.ts +0 -7
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/tool-receipts.ts +0 -227
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/work-budget.ts +0 -130
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/worker-platform-budget.ts +0 -39
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime/workflow-preview.ts +0 -26
- package/dist/bundling-sources/apps/play-runner-workers/src/runtime-api-retry.ts +0 -23
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-instance-create.ts +0 -47
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry-state.ts +0 -167
- package/dist/bundling-sources/apps/play-runner-workers/src/workflow-retry.ts +0 -91
- package/dist/bundling-sources/sdk/src/plays/harness-stub.ts +0 -329
- package/dist/bundling-sources/sdk/src/worker-play-entry.ts +0 -240
- package/dist/bundling-sources/shared_libs/play-runtime/governor/coordinator-rate-state-backend.ts +0 -252
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -217
|
@@ -29,7 +29,7 @@ import type {
|
|
|
29
29
|
} from '../artifact-types';
|
|
30
30
|
import { buildPlayContractCompatibility } from '../contracts';
|
|
31
31
|
import { validatePlaySourceFilesHaveNoInlineSecrets } from '../secret-guardrails';
|
|
32
|
-
import {
|
|
32
|
+
import { MAX_PLAY_BUNDLE_BYTES } from './limits';
|
|
33
33
|
|
|
34
34
|
const PLAY_BUNDLE_CACHE_VERSION = 25;
|
|
35
35
|
const PLAY_ARTIFACT_CACHE_DIR = join(
|
|
@@ -48,7 +48,6 @@ const SOURCE_EXTENSIONS = [
|
|
|
48
48
|
'.cjs',
|
|
49
49
|
'.json',
|
|
50
50
|
];
|
|
51
|
-
const WORKERS_PLAY_ENTRY_VIRTUAL = 'deepline-play-entry';
|
|
52
51
|
const PLAY_SOURCE_FILE_PATTERN = /\.play\.(?:[cm]?[jt]sx?)$/i;
|
|
53
52
|
const NODE_BUILTIN_SET = new Set(
|
|
54
53
|
builtinModules.flatMap((name) =>
|
|
@@ -96,10 +95,6 @@ export type PlayBundlingAdapter = {
|
|
|
96
95
|
sdkPackageJson: string;
|
|
97
96
|
sdkEntryFile: string;
|
|
98
97
|
sdkTypesEntryFile?: string;
|
|
99
|
-
sdkWorkersEntryFile: string;
|
|
100
|
-
workersHarnessEntryFile: string;
|
|
101
|
-
workersHarnessFilesDir: string;
|
|
102
|
-
workersRuntimeFingerprintDirs?: string[];
|
|
103
98
|
discoverPackagedLocalFiles(
|
|
104
99
|
filePath: string,
|
|
105
100
|
): Promise<PlayLocalFileDiscoveryResult>;
|
|
@@ -1014,106 +1009,6 @@ function extractDefinedPlayMetadata(
|
|
|
1014
1009
|
return null;
|
|
1015
1010
|
}
|
|
1016
1011
|
|
|
1017
|
-
function canonicalizeRootPlayNameForWorkersRuntimeHash(
|
|
1018
|
-
sourceCode: string,
|
|
1019
|
-
): string {
|
|
1020
|
-
const source = stripCommentsToSpaces(sourceCode);
|
|
1021
|
-
const callPattern =
|
|
1022
|
-
/(?:\b[A-Za-z_$][\w$]*\s*\.\s*)?\b(?:definePlay|defineWorkflow)\s*\(/g;
|
|
1023
|
-
const match = callPattern.exec(source);
|
|
1024
|
-
if (!match) return sourceCode;
|
|
1025
|
-
|
|
1026
|
-
const openParen = match.index + match[0].length - 1;
|
|
1027
|
-
const firstArgStart = openParen + 1;
|
|
1028
|
-
const firstNonSpace = source.slice(firstArgStart).search(/\S/);
|
|
1029
|
-
if (firstNonSpace < 0) return sourceCode;
|
|
1030
|
-
|
|
1031
|
-
const argIndex = firstArgStart + firstNonSpace;
|
|
1032
|
-
const quote = source[argIndex];
|
|
1033
|
-
if (quote === '"' || quote === "'") {
|
|
1034
|
-
const literalMatch = source
|
|
1035
|
-
.slice(argIndex)
|
|
1036
|
-
.match(/^(['"])(?:\\.|(?!\1)[\s\S])*\1/);
|
|
1037
|
-
if (!literalMatch) return sourceCode;
|
|
1038
|
-
const replacement = `${quote}__deepline_runtime_play_name__${quote}`;
|
|
1039
|
-
return `${sourceCode.slice(0, argIndex)}${replacement}${sourceCode.slice(argIndex + literalMatch[0].length)}`;
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
if (quote !== '{') return sourceCode;
|
|
1043
|
-
const closeBrace = findMatchingBrace(source, argIndex);
|
|
1044
|
-
if (closeBrace < 0) return sourceCode;
|
|
1045
|
-
const objectSource = source.slice(argIndex + 1, closeBrace);
|
|
1046
|
-
const idMatch = objectSource.match(
|
|
1047
|
-
/(^|[,{\s])((?:id|['"]id['"])\s*:\s*)(['"])([\s\S]*?)\3/,
|
|
1048
|
-
);
|
|
1049
|
-
if (!idMatch || idMatch.index === undefined) return sourceCode;
|
|
1050
|
-
const idValueStart =
|
|
1051
|
-
argIndex +
|
|
1052
|
-
1 +
|
|
1053
|
-
idMatch.index +
|
|
1054
|
-
idMatch[1]!.length +
|
|
1055
|
-
idMatch[2]!.length +
|
|
1056
|
-
idMatch[3]!.length;
|
|
1057
|
-
return `${sourceCode.slice(0, idValueStart)}__deepline_runtime_play_name__${sourceCode.slice(idValueStart + idMatch[4]!.length)}`;
|
|
1058
|
-
}
|
|
1059
|
-
|
|
1060
|
-
function workersRuntimeGraphFilePath(input: {
|
|
1061
|
-
entryFile: string;
|
|
1062
|
-
filePath: string;
|
|
1063
|
-
adapter: PlayBundlingAdapter;
|
|
1064
|
-
}): string {
|
|
1065
|
-
if (input.filePath === input.entryFile) return '<entry>';
|
|
1066
|
-
const entryRelative = relative(dirname(input.entryFile), input.filePath);
|
|
1067
|
-
if (entryRelative && !entryRelative.startsWith('..')) {
|
|
1068
|
-
return entryRelative.replaceAll('\\', '/');
|
|
1069
|
-
}
|
|
1070
|
-
return `<project>/${relative(input.adapter.projectRoot, input.filePath).replaceAll('\\', '/')}`;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
function buildWorkersRuntimeGraphHash(input: {
|
|
1074
|
-
analysis: SourceGraphAnalysis;
|
|
1075
|
-
entryFile: string;
|
|
1076
|
-
adapter: PlayBundlingAdapter;
|
|
1077
|
-
exportName: string;
|
|
1078
|
-
}): string {
|
|
1079
|
-
const sourceFiles = Object.entries(input.analysis.sourceFiles)
|
|
1080
|
-
.map(([filePath, contents]) => ({
|
|
1081
|
-
filePath: workersRuntimeGraphFilePath({
|
|
1082
|
-
entryFile: input.entryFile,
|
|
1083
|
-
filePath,
|
|
1084
|
-
adapter: input.adapter,
|
|
1085
|
-
}),
|
|
1086
|
-
hash: sha256(
|
|
1087
|
-
filePath === input.entryFile
|
|
1088
|
-
? canonicalizeRootPlayNameForWorkersRuntimeHash(contents)
|
|
1089
|
-
: contents,
|
|
1090
|
-
),
|
|
1091
|
-
}))
|
|
1092
|
-
.sort((left, right) => left.filePath.localeCompare(right.filePath));
|
|
1093
|
-
|
|
1094
|
-
return sha256(
|
|
1095
|
-
JSON.stringify({
|
|
1096
|
-
entryFile: '<entry>',
|
|
1097
|
-
entryExport: input.exportName,
|
|
1098
|
-
localFiles: sourceFiles,
|
|
1099
|
-
nodeBuiltins: [...input.analysis.importPolicy.nodeBuiltins].sort(),
|
|
1100
|
-
packages: input.analysis.importPolicy.packages
|
|
1101
|
-
.map(({ name, version }) => ({ name, version }))
|
|
1102
|
-
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
1103
|
-
importedPlayDependencies: input.analysis.importedPlayDependencies
|
|
1104
|
-
.map((dependency) => ({
|
|
1105
|
-
filePath: workersRuntimeGraphFilePath({
|
|
1106
|
-
entryFile: input.entryFile,
|
|
1107
|
-
filePath: dependency.filePath,
|
|
1108
|
-
adapter: input.adapter,
|
|
1109
|
-
}),
|
|
1110
|
-
playName: dependency.playName,
|
|
1111
|
-
}))
|
|
1112
|
-
.sort((left, right) => left.filePath.localeCompare(right.filePath)),
|
|
1113
|
-
}),
|
|
1114
|
-
);
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
1012
|
function readPackageVersionFromPackageJson(
|
|
1118
1013
|
packageJsonPath: string,
|
|
1119
1014
|
packageName: string,
|
|
@@ -1193,13 +1088,8 @@ function findPackageJsonPath(
|
|
|
1193
1088
|
: null;
|
|
1194
1089
|
}
|
|
1195
1090
|
|
|
1196
|
-
function localSdkAliasPlugin(
|
|
1197
|
-
adapter
|
|
1198
|
-
options?: { workersRuntime?: boolean },
|
|
1199
|
-
): Plugin | null {
|
|
1200
|
-
const entryFile = options?.workersRuntime
|
|
1201
|
-
? adapter.sdkWorkersEntryFile
|
|
1202
|
-
: adapter.sdkEntryFile;
|
|
1091
|
+
function localSdkAliasPlugin(adapter: PlayBundlingAdapter): Plugin | null {
|
|
1092
|
+
const entryFile = adapter.sdkEntryFile;
|
|
1203
1093
|
if (!existsSync(entryFile)) {
|
|
1204
1094
|
return null;
|
|
1205
1095
|
}
|
|
@@ -1217,308 +1107,6 @@ function localSdkAliasPlugin(
|
|
|
1217
1107
|
};
|
|
1218
1108
|
}
|
|
1219
1109
|
|
|
1220
|
-
/**
|
|
1221
|
-
* Resolves the virtual `deepline-play-entry` import (used by the Workers
|
|
1222
|
-
* harness) to the user's play source file. Lets the harness statically import
|
|
1223
|
-
* the play without the bundler needing to know its path ahead of time.
|
|
1224
|
-
*/
|
|
1225
|
-
function workersPlayEntryAliasPlugin(playFilePath: string): Plugin {
|
|
1226
|
-
return {
|
|
1227
|
-
name: 'deepline-workers-play-entry-alias',
|
|
1228
|
-
setup(buildContext) {
|
|
1229
|
-
buildContext.onResolve(
|
|
1230
|
-
{ filter: new RegExp(`^${WORKERS_PLAY_ENTRY_VIRTUAL}$`) },
|
|
1231
|
-
() => ({ path: playFilePath }),
|
|
1232
|
-
);
|
|
1233
|
-
},
|
|
1234
|
-
};
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
const CUSTOMER_CONSOLE_CAPTURE_GLOBAL = '__deeplineCaptureCustomerConsole';
|
|
1238
|
-
|
|
1239
|
-
function sourceLoaderForPath(path: string): 'ts' | 'tsx' | 'js' | 'jsx' {
|
|
1240
|
-
const extension = extname(path).toLowerCase();
|
|
1241
|
-
if (extension === '.tsx') return 'tsx';
|
|
1242
|
-
if (extension === '.jsx') return 'jsx';
|
|
1243
|
-
if (extension === '.js' || extension === '.mjs' || extension === '.cjs') {
|
|
1244
|
-
return 'js';
|
|
1245
|
-
}
|
|
1246
|
-
return 'ts';
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
/**
|
|
1250
|
-
* Give the customer's entry module a lexical console without replacing the
|
|
1251
|
-
* Worker's process-wide console. Runtime diagnostics therefore keep flowing
|
|
1252
|
-
* to Cloudflare while console.* calls authored in the play join its Run Log
|
|
1253
|
-
* Stream. The lazy global lookup is required because ESM dependencies are
|
|
1254
|
-
* evaluated before the harness installs the request-scoped capture function.
|
|
1255
|
-
*/
|
|
1256
|
-
function workersCustomerConsolePlugin(
|
|
1257
|
-
customerSourceFilePaths: readonly string[],
|
|
1258
|
-
): Plugin {
|
|
1259
|
-
const customerSourceFiles = new Set(
|
|
1260
|
-
customerSourceFilePaths
|
|
1261
|
-
.filter((path) => extname(path).toLowerCase() !== '.json')
|
|
1262
|
-
.map((path) => resolve(path)),
|
|
1263
|
-
);
|
|
1264
|
-
return {
|
|
1265
|
-
name: 'deepline-workers-customer-console',
|
|
1266
|
-
setup(buildContext) {
|
|
1267
|
-
buildContext.onLoad({ filter: /./ }, (args) => {
|
|
1268
|
-
if (!customerSourceFiles.has(resolve(args.path))) return undefined;
|
|
1269
|
-
const source = readFileSync(args.path, 'utf8');
|
|
1270
|
-
const declaresOwnConsole =
|
|
1271
|
-
/(?:^|\n)\s*(?:(?:const|let|var|class|function)\s+console\b|import[^\n]*\bconsole\b)/m.test(
|
|
1272
|
-
source,
|
|
1273
|
-
);
|
|
1274
|
-
if (declaresOwnConsole) {
|
|
1275
|
-
return {
|
|
1276
|
-
contents: source,
|
|
1277
|
-
loader: sourceLoaderForPath(args.path),
|
|
1278
|
-
resolveDir: dirname(args.path),
|
|
1279
|
-
};
|
|
1280
|
-
}
|
|
1281
|
-
const prelude = `
|
|
1282
|
-
const console = new Proxy(globalThis.console, {
|
|
1283
|
-
get(target, property) {
|
|
1284
|
-
const capture = globalThis.${CUSTOMER_CONSOLE_CAPTURE_GLOBAL};
|
|
1285
|
-
if (typeof capture === 'function') {
|
|
1286
|
-
return (...args) => capture(String(property), args);
|
|
1287
|
-
}
|
|
1288
|
-
const value = Reflect.get(target, property);
|
|
1289
|
-
return typeof value === 'function' ? value.bind(target) : value;
|
|
1290
|
-
},
|
|
1291
|
-
});
|
|
1292
|
-
`;
|
|
1293
|
-
return {
|
|
1294
|
-
contents: `${prelude}\n${source}`,
|
|
1295
|
-
loader: sourceLoaderForPath(args.path),
|
|
1296
|
-
resolveDir: dirname(args.path),
|
|
1297
|
-
};
|
|
1298
|
-
});
|
|
1299
|
-
},
|
|
1300
|
-
};
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
function workersNamedPlayEntryAliasPlugin(
|
|
1304
|
-
playFilePath: string,
|
|
1305
|
-
exportName: string,
|
|
1306
|
-
): Plugin {
|
|
1307
|
-
return {
|
|
1308
|
-
name: 'deepline-workers-named-play-entry-alias',
|
|
1309
|
-
setup(buildContext) {
|
|
1310
|
-
buildContext.onResolve(
|
|
1311
|
-
{ filter: new RegExp(`^${WORKERS_PLAY_ENTRY_VIRTUAL}$`) },
|
|
1312
|
-
() => ({
|
|
1313
|
-
path: `${playFilePath}.${exportName}.entry.ts`,
|
|
1314
|
-
namespace: 'deepline-named-play-entry',
|
|
1315
|
-
}),
|
|
1316
|
-
);
|
|
1317
|
-
buildContext.onLoad(
|
|
1318
|
-
{ filter: /.*/, namespace: 'deepline-named-play-entry' },
|
|
1319
|
-
() => ({
|
|
1320
|
-
contents: `export { ${exportName} as default } from ${JSON.stringify(playFilePath)};\n`,
|
|
1321
|
-
loader: 'ts',
|
|
1322
|
-
resolveDir: dirname(playFilePath),
|
|
1323
|
-
}),
|
|
1324
|
-
);
|
|
1325
|
-
},
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
|
|
1329
|
-
/**
|
|
1330
|
-
* Cloudflare Workers' `nodejs_compat` flag covers most node builtins (path,
|
|
1331
|
-
* crypto, buffer, async_hooks, ...) but NOT `node:fs` / `node:fs/promises` /
|
|
1332
|
-
* `node:os` (no filesystem, no OS in a V8 isolate). The SDK's config-loading
|
|
1333
|
-
* and tool-output utilities reference these even when the play never invokes
|
|
1334
|
-
* them — which is the case for plays that don't read CLI config at runtime.
|
|
1335
|
-
*
|
|
1336
|
-
* This plugin substitutes those specific imports with a tiny stub module that
|
|
1337
|
-
* has no top-level side effects and throws clearly if anything actually calls
|
|
1338
|
-
* into them. That lets the deploy validation pass while still surfacing a
|
|
1339
|
-
* loud error if a play unexpectedly depends on a node-only API.
|
|
1340
|
-
*/
|
|
1341
|
-
function workersNodeBuiltinStubPlugin(): Plugin {
|
|
1342
|
-
// These are the node builtins NOT exposed by Cloudflare's nodejs_compat.
|
|
1343
|
-
// Keep this list narrow — anything supported (path, crypto, etc.) should
|
|
1344
|
-
// pass through as `external: ['node:*']` in the build config.
|
|
1345
|
-
const UNSUPPORTED = new Set([
|
|
1346
|
-
'node:fs',
|
|
1347
|
-
'node:fs/promises',
|
|
1348
|
-
'node:os',
|
|
1349
|
-
'node:child_process',
|
|
1350
|
-
]);
|
|
1351
|
-
return {
|
|
1352
|
-
name: 'deepline-workers-node-builtin-stub',
|
|
1353
|
-
setup(buildContext) {
|
|
1354
|
-
buildContext.onResolve({ filter: /^node:/ }, (args) => {
|
|
1355
|
-
if (!UNSUPPORTED.has(args.path)) return null;
|
|
1356
|
-
return { path: args.path, namespace: 'deepline-workers-node-stub' };
|
|
1357
|
-
});
|
|
1358
|
-
buildContext.onLoad(
|
|
1359
|
-
{ filter: /.*/, namespace: 'deepline-workers-node-stub' },
|
|
1360
|
-
(args) => {
|
|
1361
|
-
const builtinName = args.path;
|
|
1362
|
-
// CommonJS module.exports = Proxy. esbuild's CJS↔ESM interop maps
|
|
1363
|
-
// any named import (e.g. `import { readFileSync } from 'node:fs'`)
|
|
1364
|
-
// to a property access on this Proxy. Property access returns a
|
|
1365
|
-
// function-like Proxy that throws on call. So:
|
|
1366
|
-
// - import resolves at bundle time (deploy validation passes)
|
|
1367
|
-
// - import binding evaluates to a no-arg-throw function
|
|
1368
|
-
// - calling it gives a clear error
|
|
1369
|
-
const stubSource = `
|
|
1370
|
-
const message = ${JSON.stringify(
|
|
1371
|
-
`Workers backend: ${builtinName} is not available in Cloudflare Workers ` +
|
|
1372
|
-
'(no filesystem / no OS). Run this play on Daytona or local-process backend ' +
|
|
1373
|
-
'if it needs node builtins.',
|
|
1374
|
-
)};
|
|
1375
|
-
function makeThrower(name) {
|
|
1376
|
-
return new Proxy(function() { throw new Error(message + ' (called: ' + name + ')'); }, {
|
|
1377
|
-
get(_t, prop) {
|
|
1378
|
-
if (prop === '__esModule') return true;
|
|
1379
|
-
if (typeof prop === 'symbol') return undefined;
|
|
1380
|
-
return makeThrower(name + '.' + String(prop));
|
|
1381
|
-
},
|
|
1382
|
-
apply() { throw new Error(message + ' (called: ' + name + ')'); },
|
|
1383
|
-
construct() { throw new Error(message + ' (constructed: ' + name + ')'); },
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
module.exports = makeThrower(${JSON.stringify(builtinName)});
|
|
1387
|
-
`;
|
|
1388
|
-
return { contents: stubSource, loader: 'js' };
|
|
1389
|
-
},
|
|
1390
|
-
);
|
|
1391
|
-
},
|
|
1392
|
-
};
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
/**
|
|
1396
|
-
* Stub every `zod/v4/locales/<lang>.js` module EXCEPT English with an
|
|
1397
|
-
* empty default export so non-English locale strings don't get bundled
|
|
1398
|
-
* into per-play Workers.
|
|
1399
|
-
*
|
|
1400
|
-
* Why this exists:
|
|
1401
|
-
* `zod/v4/core/index.js` does `export * as locales from "../locales/index.js"`
|
|
1402
|
-
* and `zod/v4/locales/index.js` re-exports every individual locale
|
|
1403
|
-
* module (he, ru, ta, th, be, km, ka, uk, hy, bg, ur, ar, mk, fa, ps,
|
|
1404
|
-
* lt, …). esbuild follows the static re-exports and bundles every
|
|
1405
|
-
* locale, ~5–9 KB each. A bundle audit (`scripts/audit-play-bundle.ts`)
|
|
1406
|
-
* on `03-tool-basic.play.ts` showed ~22 of these locale modules
|
|
1407
|
-
* present, totaling ~150–200 KB of dead weight.
|
|
1408
|
-
*
|
|
1409
|
-
* Plays only ever surface English error messages to user/CLI. The
|
|
1410
|
-
* non-English locale data is unreachable in our codepath, but
|
|
1411
|
-
* esbuild's tree-shaking can't prove that across `export * as`
|
|
1412
|
-
* re-exports. So we stub each non-English locale at load time with
|
|
1413
|
-
* an empty default export. zod's runtime falls back to its built-in
|
|
1414
|
-
* English messages when a requested locale's data is missing or
|
|
1415
|
-
* empty.
|
|
1416
|
-
*
|
|
1417
|
-
* What this saves (measured, fresh per-play bundle):
|
|
1418
|
-
* ~150–200 KB → cold V8 compile time drops proportionally
|
|
1419
|
-
* (~50–70 ms on CF edge per cold play).
|
|
1420
|
-
*
|
|
1421
|
-
* Safety:
|
|
1422
|
-
* - English (`en.js`) is NEVER stubbed — that's the language zod
|
|
1423
|
-
* and our error surfaces actually use.
|
|
1424
|
-
* - The locales/index.js wrapper is left intact; its re-exports
|
|
1425
|
-
* resolve to empty `{}` modules but the import shape stays
|
|
1426
|
-
* stable for any code that does `import { locales } from "zod"`.
|
|
1427
|
-
* - If a future codepath needs a non-English locale, this plugin
|
|
1428
|
-
* would silently swallow the data; that would be a real bug, so
|
|
1429
|
-
* we log a one-time warning at bundle time when a non-English
|
|
1430
|
-
* locale is stubbed (only emitted to stderr in dev to keep CI
|
|
1431
|
-
* output clean).
|
|
1432
|
-
*/
|
|
1433
|
-
function zodNonEnglishLocaleStubPlugin(): Plugin {
|
|
1434
|
-
// Match any zod v4 locale module path EXCEPT en + en variants.
|
|
1435
|
-
// The filter uses a coarse regex; the namespace handler then
|
|
1436
|
-
// double-checks with a precise basename test before stubbing.
|
|
1437
|
-
const LOCALE_PATH_FILTER =
|
|
1438
|
-
/[\\/]zod[\\/]v4[\\/]locales[\\/][^\\/]+\.(?:c?js|mjs)$/;
|
|
1439
|
-
const NAMESPACE = 'deepline-zod-locale-stub';
|
|
1440
|
-
return {
|
|
1441
|
-
name: 'deepline-zod-non-english-locale-stub',
|
|
1442
|
-
setup(buildContext) {
|
|
1443
|
-
buildContext.onResolve({ filter: LOCALE_PATH_FILTER }, (args) => {
|
|
1444
|
-
// Resolve relatively first (esbuild needs an absolute path), then
|
|
1445
|
-
// decide whether to stub. We do this in onResolve so we can check
|
|
1446
|
-
// the filename and let `en` flow through unmodified.
|
|
1447
|
-
const norm = args.path.replace(/\\/g, '/');
|
|
1448
|
-
const file = norm.slice(norm.lastIndexOf('/') + 1);
|
|
1449
|
-
// Allow English variants — `en.js`, `en.cjs`, future `en-US.js`, etc.
|
|
1450
|
-
if (/^en(?:[-_][A-Za-z]+)?\.(?:c?js|mjs)$/.test(file)) {
|
|
1451
|
-
return null;
|
|
1452
|
-
}
|
|
1453
|
-
// Anything else: stub with an empty default export.
|
|
1454
|
-
return { path: args.path, namespace: NAMESPACE };
|
|
1455
|
-
});
|
|
1456
|
-
buildContext.onLoad({ filter: /.*/, namespace: NAMESPACE }, () => ({
|
|
1457
|
-
// zod locales export a default object literal. Empty object is
|
|
1458
|
-
// structurally compatible — accessing any locale key returns
|
|
1459
|
-
// undefined and zod falls back to its built-in English.
|
|
1460
|
-
contents: 'export default {};',
|
|
1461
|
-
loader: 'js',
|
|
1462
|
-
}));
|
|
1463
|
-
},
|
|
1464
|
-
};
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
/**
|
|
1468
|
-
* Hard banlist of `node:*` modules whose presence in a workers_edge bundle
|
|
1469
|
-
* would either escape the V8 isolate boundary (filesystem, network sockets,
|
|
1470
|
-
* subprocess control) or open up confused-deputy paths (vm/repl/worker
|
|
1471
|
-
* threads). These are blocked at bundle time so the per-graphHash CF Worker
|
|
1472
|
-
* never sees code that could attempt to call them.
|
|
1473
|
-
*
|
|
1474
|
-
* `nodejs_compat` covers the supported subset (crypto, stream, buffer, util,
|
|
1475
|
-
* path, url, http, https) — those imports continue to pass through and
|
|
1476
|
-
* resolve to workerd-shimmed implementations.
|
|
1477
|
-
*/
|
|
1478
|
-
const WORKERS_BANNED_NODE_MODULES = new Set([
|
|
1479
|
-
'node:fs',
|
|
1480
|
-
'node:fs/promises',
|
|
1481
|
-
'node:net',
|
|
1482
|
-
'node:child_process',
|
|
1483
|
-
'node:cluster',
|
|
1484
|
-
'node:tls',
|
|
1485
|
-
'node:dgram',
|
|
1486
|
-
'node:dns',
|
|
1487
|
-
'node:dns/promises',
|
|
1488
|
-
'node:repl',
|
|
1489
|
-
'node:vm',
|
|
1490
|
-
'node:worker_threads',
|
|
1491
|
-
]);
|
|
1492
|
-
|
|
1493
|
-
function workersNodeImportBanlistPlugin(adapter: PlayBundlingAdapter): Plugin {
|
|
1494
|
-
return {
|
|
1495
|
-
name: 'deepline-workers-node-import-banlist',
|
|
1496
|
-
setup(buildContext) {
|
|
1497
|
-
buildContext.onResolve({ filter: /^node:/ }, (args) => {
|
|
1498
|
-
if (!WORKERS_BANNED_NODE_MODULES.has(args.path)) return null;
|
|
1499
|
-
// SDK internals (sdk/src/*.ts) intentionally reference a small set
|
|
1500
|
-
// of node builtins (e.g. config loaders, tool-output writers) that
|
|
1501
|
-
// never run in the V8 isolate path; they're substituted by the
|
|
1502
|
-
// workersNodeBuiltinStubPlugin's throwing stub. Only reject when
|
|
1503
|
-
// the import comes from outside the SDK source tree -- i.e. user
|
|
1504
|
-
// play code or third-party deps that the play pulls in.
|
|
1505
|
-
const importer = args.importer ?? '';
|
|
1506
|
-
if (importer.startsWith(adapter.sdkSourceRoot)) {
|
|
1507
|
-
return null;
|
|
1508
|
-
}
|
|
1509
|
-
return {
|
|
1510
|
-
errors: [
|
|
1511
|
-
{
|
|
1512
|
-
text: `Module "${args.path}" is not allowed in workers_edge plays. See AGENTS.md for the V8 isolate boundary.`,
|
|
1513
|
-
detail: { importer: args.importer, kind: args.kind },
|
|
1514
|
-
},
|
|
1515
|
-
],
|
|
1516
|
-
};
|
|
1517
|
-
});
|
|
1518
|
-
},
|
|
1519
|
-
};
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
1110
|
function buildImportedPlayProxyModule(playName: string): string {
|
|
1523
1111
|
const serializedName = JSON.stringify(playName);
|
|
1524
1112
|
return `
|
|
@@ -1842,99 +1430,11 @@ async function analyzeSourceGraph(
|
|
|
1842
1430
|
};
|
|
1843
1431
|
}
|
|
1844
1432
|
|
|
1845
|
-
/**
|
|
1846
|
-
* Fingerprint of Worker runtime sources bundled into every esm_workers play
|
|
1847
|
-
* artifact. Harness, shared runtime, or provider-owned batching edits must
|
|
1848
|
-
* invalidate the bundle cache and force a fresh CF deploy. Computed fresh on
|
|
1849
|
-
* every bundle call so dev edits are picked up on the next `play run` without
|
|
1850
|
-
* restarting the dev server. No caching: that's deliberate — caching the
|
|
1851
|
-
* fingerprint is exactly the stale-state bug this exists to prevent.
|
|
1852
|
-
*/
|
|
1853
|
-
async function computeWorkersHarnessFingerprintWithAdapter(
|
|
1854
|
-
adapter: PlayBundlingAdapter,
|
|
1855
|
-
): Promise<string> {
|
|
1856
|
-
const { readdir } = await import('node:fs/promises');
|
|
1857
|
-
const addFilePart = async (
|
|
1858
|
-
parts: Array<{ name: string; hash: string }>,
|
|
1859
|
-
rootDir: string,
|
|
1860
|
-
filePath: string,
|
|
1861
|
-
) => {
|
|
1862
|
-
const contents = await readFile(filePath, 'utf-8');
|
|
1863
|
-
parts.push({
|
|
1864
|
-
name: `${basename(rootDir)}:${filePath.slice(rootDir.length + 1)}`,
|
|
1865
|
-
hash: sha256(contents),
|
|
1866
|
-
});
|
|
1867
|
-
};
|
|
1868
|
-
const collectTsFilesRecursive = async (
|
|
1869
|
-
rootDir: string,
|
|
1870
|
-
parts: Array<{ name: string; hash: string }>,
|
|
1871
|
-
) => {
|
|
1872
|
-
if (!(await fileExists(rootDir))) return;
|
|
1873
|
-
const filePaths: string[] = [];
|
|
1874
|
-
const visitDir = async (dir: string) => {
|
|
1875
|
-
const entries = await readdir(dir, { withFileTypes: true });
|
|
1876
|
-
for (const entry of entries) {
|
|
1877
|
-
const childPath = join(dir, entry.name);
|
|
1878
|
-
if (entry.isDirectory()) {
|
|
1879
|
-
await visitDir(childPath);
|
|
1880
|
-
continue;
|
|
1881
|
-
}
|
|
1882
|
-
if (entry.isFile() && /\.[cm]?ts$/.test(entry.name)) {
|
|
1883
|
-
filePaths.push(childPath);
|
|
1884
|
-
}
|
|
1885
|
-
}
|
|
1886
|
-
};
|
|
1887
|
-
await visitDir(rootDir);
|
|
1888
|
-
for (const filePath of filePaths.sort()) {
|
|
1889
|
-
await addFilePart(parts, rootDir, filePath);
|
|
1890
|
-
}
|
|
1891
|
-
};
|
|
1892
|
-
const collectIntegrationBatchingFiles = async (
|
|
1893
|
-
rootDir: string,
|
|
1894
|
-
parts: Array<{ name: string; hash: string }>,
|
|
1895
|
-
) => {
|
|
1896
|
-
if (!(await fileExists(rootDir))) return;
|
|
1897
|
-
const entries = await readdir(rootDir, { withFileTypes: true });
|
|
1898
|
-
const filePaths: string[] = [];
|
|
1899
|
-
for (const entry of entries) {
|
|
1900
|
-
if (
|
|
1901
|
-
entry.isFile() &&
|
|
1902
|
-
(entry.name === 'play-runtime-batching-registry.ts' ||
|
|
1903
|
-
/^batching.*\.ts$/.test(entry.name))
|
|
1904
|
-
) {
|
|
1905
|
-
filePaths.push(join(rootDir, entry.name));
|
|
1906
|
-
}
|
|
1907
|
-
if (entry.isDirectory()) {
|
|
1908
|
-
const batchingFile = join(rootDir, entry.name, 'batching.ts');
|
|
1909
|
-
if (await fileExists(batchingFile)) {
|
|
1910
|
-
filePaths.push(batchingFile);
|
|
1911
|
-
}
|
|
1912
|
-
}
|
|
1913
|
-
}
|
|
1914
|
-
for (const filePath of filePaths.sort()) {
|
|
1915
|
-
await addFilePart(parts, rootDir, filePath);
|
|
1916
|
-
}
|
|
1917
|
-
};
|
|
1918
|
-
|
|
1919
|
-
const parts: Array<{ name: string; hash: string }> = [];
|
|
1920
|
-
await collectTsFilesRecursive(adapter.workersHarnessFilesDir, parts);
|
|
1921
|
-
for (const dir of adapter.workersRuntimeFingerprintDirs ?? []) {
|
|
1922
|
-
if (basename(dir) === 'integrations') {
|
|
1923
|
-
await collectIntegrationBatchingFiles(dir, parts);
|
|
1924
|
-
} else {
|
|
1925
|
-
await collectTsFilesRecursive(dir, parts);
|
|
1926
|
-
}
|
|
1927
|
-
}
|
|
1928
|
-
return sha256(JSON.stringify(parts));
|
|
1929
|
-
}
|
|
1930
|
-
|
|
1931
1433
|
function artifactCachePath(
|
|
1932
1434
|
graphHash: string,
|
|
1933
1435
|
artifactKind: PlayArtifactKind,
|
|
1934
1436
|
adapter: PlayBundlingAdapter,
|
|
1935
1437
|
): string {
|
|
1936
|
-
// Cache key includes artifactKind so a play can have both cjs_node20 and
|
|
1937
|
-
// esm_workers builds cached side-by-side without one stomping on the other.
|
|
1938
1438
|
return join(
|
|
1939
1439
|
adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR,
|
|
1940
1440
|
`${graphHash}.${artifactKind}.json`,
|
|
@@ -2003,25 +1503,11 @@ function normalizeSourceMapForRuntime(
|
|
|
2003
1503
|
export function getBundleSizeErrorForBytes(
|
|
2004
1504
|
filePath: string,
|
|
2005
1505
|
bundleBytes: number,
|
|
2006
|
-
|
|
1506
|
+
_artifactKind: PlayArtifactKind,
|
|
2007
1507
|
): string | null {
|
|
2008
1508
|
if (bundleBytes > MAX_PLAY_BUNDLE_BYTES) {
|
|
2009
1509
|
return `${filePath} Play bundle exceeds the 30 MiB limit (${bundleBytes} bytes > ${MAX_PLAY_BUNDLE_BYTES} bytes).`;
|
|
2010
1510
|
}
|
|
2011
|
-
if (
|
|
2012
|
-
artifactKind === PLAY_ARTIFACT_KINDS.esmWorkers &&
|
|
2013
|
-
bundleBytes > MAX_ESM_WORKERS_BUNDLE_BYTES
|
|
2014
|
-
) {
|
|
2015
|
-
const mib = (bundleBytes / 1024 / 1024).toFixed(2);
|
|
2016
|
-
const limitMib = (MAX_ESM_WORKERS_BUNDLE_BYTES / 1024 / 1024).toFixed(2);
|
|
2017
|
-
return (
|
|
2018
|
-
`${filePath} Cloudflare Workers bundle is ${mib} MiB, above the workerd ` +
|
|
2019
|
-
`local-mode threshold of ${limitMib} MiB. Bundles past this size silently ` +
|
|
2020
|
-
`hang without executing the workflow body. Reduce dependencies (top ` +
|
|
2021
|
-
`offenders are usually date-fns, lodash, large schema libs) or split the ` +
|
|
2022
|
-
`play into smaller pieces with ctx.runPlay.`
|
|
2023
|
-
);
|
|
2024
|
-
}
|
|
2025
1511
|
return null;
|
|
2026
1512
|
}
|
|
2027
1513
|
|
|
@@ -2038,14 +1524,7 @@ function getBundleSizeError(
|
|
|
2038
1524
|
}
|
|
2039
1525
|
|
|
2040
1526
|
export type BundlePlayFileOptions = {
|
|
2041
|
-
/**
|
|
2042
|
-
* Which artifact to produce. Defaults to `cjs_node20` (Daytona / local-process
|
|
2043
|
-
* runner). Pass `esm_workers` to produce a Cloudflare Worker bundle that
|
|
2044
|
-
* combines the play with the Workers harness.
|
|
2045
|
-
*
|
|
2046
|
-
* The CLI selects this from the execution profile or an explicit flag. Each
|
|
2047
|
-
* kind is cached independently on disk.
|
|
2048
|
-
*/
|
|
1527
|
+
/** Must be `cjs_node20`; retained as an explicit compile-contract assertion. */
|
|
2049
1528
|
target?: PlayArtifactKind;
|
|
2050
1529
|
exportName?: string;
|
|
2051
1530
|
};
|
|
@@ -2057,20 +1536,7 @@ export type BundlePlayFileCoreOptions = BundlePlayFileOptions & {
|
|
|
2057
1536
|
type EsbuildBundleOutput = {
|
|
2058
1537
|
bundledCode: string;
|
|
2059
1538
|
sourceMapText: string;
|
|
2060
|
-
outputExtension: 'cjs'
|
|
2061
|
-
};
|
|
2062
|
-
|
|
2063
|
-
type PlayArtifactTargetAdapter = {
|
|
2064
|
-
artifactKind: PlayArtifactKind;
|
|
2065
|
-
codeFormat: PlayBundleArtifact['codeFormat'];
|
|
2066
|
-
includeWorkersHarnessInGraphHash: boolean;
|
|
2067
|
-
runEsbuild(input: {
|
|
2068
|
-
entryFile: string;
|
|
2069
|
-
customerSourceFilePaths: string[];
|
|
2070
|
-
importedPlayDependencies: ImportedPlayDependency[];
|
|
2071
|
-
adapter: PlayBundlingAdapter;
|
|
2072
|
-
exportName: string;
|
|
2073
|
-
}): Promise<EsbuildBundleOutput | string[]>;
|
|
1539
|
+
outputExtension: 'cjs';
|
|
2074
1540
|
};
|
|
2075
1541
|
|
|
2076
1542
|
async function runEsbuildForCjsNode(
|
|
@@ -2125,141 +1591,6 @@ async function runEsbuildForCjsNode(
|
|
|
2125
1591
|
};
|
|
2126
1592
|
}
|
|
2127
1593
|
|
|
2128
|
-
async function runEsbuildForEsmWorkers(
|
|
2129
|
-
playEntryFile: string,
|
|
2130
|
-
customerSourceFilePaths: string[],
|
|
2131
|
-
importedPlayDependencies: ImportedPlayDependency[],
|
|
2132
|
-
adapter: PlayBundlingAdapter,
|
|
2133
|
-
exportName: string,
|
|
2134
|
-
): Promise<EsbuildBundleOutput | string[]> {
|
|
2135
|
-
const sdkAliasPlugin = localSdkAliasPlugin(adapter, { workersRuntime: true });
|
|
2136
|
-
const playProxyPlugin = importedPlayProxyPlugin(importedPlayDependencies);
|
|
2137
|
-
const playEntryAlias =
|
|
2138
|
-
exportName === 'default'
|
|
2139
|
-
? workersPlayEntryAliasPlugin(playEntryFile)
|
|
2140
|
-
: workersNamedPlayEntryAliasPlugin(playEntryFile, exportName);
|
|
2141
|
-
const customerConsolePlugin = workersCustomerConsolePlugin(
|
|
2142
|
-
customerSourceFilePaths,
|
|
2143
|
-
);
|
|
2144
|
-
const result = await build({
|
|
2145
|
-
// Entry is the Workers harness; it imports the play via the virtual
|
|
2146
|
-
// `deepline-play-entry` alias resolved by workersPlayEntryAliasPlugin.
|
|
2147
|
-
entryPoints: [adapter.workersHarnessEntryFile],
|
|
2148
|
-
absWorkingDir: adapter.projectRoot,
|
|
2149
|
-
bundle: true,
|
|
2150
|
-
format: 'esm',
|
|
2151
|
-
nodePaths: [adapter.nodeModulesDir],
|
|
2152
|
-
// Browser platform with workerd + worker conditions matches Cloudflare's
|
|
2153
|
-
// V8-isolate runtime. Avoids accidentally pulling node-only branches of
|
|
2154
|
-
// dual-publish packages.
|
|
2155
|
-
platform: 'browser',
|
|
2156
|
-
conditions: ['workerd', 'worker', 'browser', 'import', 'default'],
|
|
2157
|
-
mainFields: ['module', 'main'],
|
|
2158
|
-
target: ['es2022'],
|
|
2159
|
-
outfile: 'play-worker.mjs',
|
|
2160
|
-
write: false,
|
|
2161
|
-
sourcemap: 'external',
|
|
2162
|
-
sourcesContent: false,
|
|
2163
|
-
logLevel: 'silent',
|
|
2164
|
-
legalComments: 'none',
|
|
2165
|
-
// Aggressive minify + treeshake: a tiny play (<1KB source) was producing
|
|
2166
|
-
// an ~870KB bundle, dominated by zod's locale files (~260KB unused) and
|
|
2167
|
-
// dead-code branches across `shared_libs/play-runtime/*` and the SDK.
|
|
2168
|
-
// Both DCE on with these flags. workerd compiles each unique-graphHash
|
|
2169
|
-
// bundle on first dispatch, so bundle bytes translate ~linearly into
|
|
2170
|
-
// per-play cold latency on workers_edge. External sourcemap remains
|
|
2171
|
-
// unchanged (`sourcemap: 'external'`), so debugging is unaffected.
|
|
2172
|
-
minify: true,
|
|
2173
|
-
treeShaking: true,
|
|
2174
|
-
// Most node:* builtins are provided by Cloudflare's `nodejs_compat` flag.
|
|
2175
|
-
// The unsupported subset (fs, fs/promises, os, child_process) gets
|
|
2176
|
-
// replaced with throwing stubs by workersNodeBuiltinStubPlugin so deploy
|
|
2177
|
-
// validation passes; anything supported (path, crypto, buffer, etc.) is
|
|
2178
|
-
// marked external and resolved at runtime by the Workers runtime.
|
|
2179
|
-
external: ['node:*', 'cloudflare:workers'],
|
|
2180
|
-
plugins: [
|
|
2181
|
-
// Banlist runs first so a forbidden import errors out before any other
|
|
2182
|
-
// resolver (esp. the workersNodeBuiltinStubPlugin which would silently
|
|
2183
|
-
// turn it into a throwing-stub).
|
|
2184
|
-
workersNodeImportBanlistPlugin(adapter),
|
|
2185
|
-
sdkAliasPlugin,
|
|
2186
|
-
playProxyPlugin,
|
|
2187
|
-
playEntryAlias,
|
|
2188
|
-
customerConsolePlugin,
|
|
2189
|
-
workersNodeBuiltinStubPlugin(),
|
|
2190
|
-
// Strip non-English zod locale data from the bundle. zod's locales
|
|
2191
|
-
// are re-exported as a static namespace from `zod/v4/core`, so
|
|
2192
|
-
// tree-shaking can't drop them; this plugin replaces each
|
|
2193
|
-
// non-English locale module with an empty default export at bundle
|
|
2194
|
-
// time. ~150–200 KB savings on every per-play bundle, with no
|
|
2195
|
-
// behavior change (we only surface English messages anyway).
|
|
2196
|
-
// If the bundle suddenly grows back, check whether a new dep added
|
|
2197
|
-
// its own zod copy or whether zod's locale layout changed.
|
|
2198
|
-
zodNonEnglishLocaleStubPlugin(),
|
|
2199
|
-
].filter((plugin): plugin is Plugin => plugin != null),
|
|
2200
|
-
});
|
|
2201
|
-
const codeFile = result.outputFiles?.find((f) => f.path.endsWith('.mjs'));
|
|
2202
|
-
const mapFile = result.outputFiles?.find((f) => f.path.endsWith('.mjs.map'));
|
|
2203
|
-
if (!codeFile?.text || !mapFile?.text) {
|
|
2204
|
-
return ['Workers play bundling produced incomplete output.'];
|
|
2205
|
-
}
|
|
2206
|
-
return {
|
|
2207
|
-
bundledCode: codeFile.text,
|
|
2208
|
-
sourceMapText: mapFile.text,
|
|
2209
|
-
outputExtension: 'mjs',
|
|
2210
|
-
};
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
const PLAY_ARTIFACT_TARGET_ADAPTERS: Record<
|
|
2214
|
-
PlayArtifactKind,
|
|
2215
|
-
PlayArtifactTargetAdapter
|
|
2216
|
-
> = {
|
|
2217
|
-
[PLAY_ARTIFACT_KINDS.cjsNode20]: {
|
|
2218
|
-
artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
|
|
2219
|
-
codeFormat: 'cjs_module',
|
|
2220
|
-
includeWorkersHarnessInGraphHash: false,
|
|
2221
|
-
runEsbuild: ({
|
|
2222
|
-
entryFile,
|
|
2223
|
-
customerSourceFilePaths,
|
|
2224
|
-
importedPlayDependencies,
|
|
2225
|
-
adapter,
|
|
2226
|
-
exportName,
|
|
2227
|
-
}) =>
|
|
2228
|
-
runEsbuildForCjsNode(
|
|
2229
|
-
entryFile,
|
|
2230
|
-
customerSourceFilePaths,
|
|
2231
|
-
importedPlayDependencies,
|
|
2232
|
-
adapter,
|
|
2233
|
-
exportName,
|
|
2234
|
-
),
|
|
2235
|
-
},
|
|
2236
|
-
[PLAY_ARTIFACT_KINDS.esmWorkers]: {
|
|
2237
|
-
artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
|
|
2238
|
-
codeFormat: 'esm_module',
|
|
2239
|
-
includeWorkersHarnessInGraphHash: true,
|
|
2240
|
-
runEsbuild: ({
|
|
2241
|
-
entryFile,
|
|
2242
|
-
customerSourceFilePaths,
|
|
2243
|
-
importedPlayDependencies,
|
|
2244
|
-
adapter,
|
|
2245
|
-
exportName,
|
|
2246
|
-
}) =>
|
|
2247
|
-
runEsbuildForEsmWorkers(
|
|
2248
|
-
entryFile,
|
|
2249
|
-
customerSourceFilePaths,
|
|
2250
|
-
importedPlayDependencies,
|
|
2251
|
-
adapter,
|
|
2252
|
-
exportName,
|
|
2253
|
-
),
|
|
2254
|
-
},
|
|
2255
|
-
};
|
|
2256
|
-
|
|
2257
|
-
function resolvePlayArtifactTargetAdapter(
|
|
2258
|
-
artifactKind: PlayArtifactKind,
|
|
2259
|
-
): PlayArtifactTargetAdapter {
|
|
2260
|
-
return PLAY_ARTIFACT_TARGET_ADAPTERS[artifactKind];
|
|
2261
|
-
}
|
|
2262
|
-
|
|
2263
1594
|
export async function bundlePlayFile(
|
|
2264
1595
|
filePath: string,
|
|
2265
1596
|
options: BundlePlayFileCoreOptions,
|
|
@@ -2267,7 +1598,6 @@ export async function bundlePlayFile(
|
|
|
2267
1598
|
const adapter = options.adapter;
|
|
2268
1599
|
const target: PlayArtifactKind =
|
|
2269
1600
|
options.target ?? PLAY_ARTIFACT_KINDS.cjsNode20;
|
|
2270
|
-
const targetAdapter = resolvePlayArtifactTargetAdapter(target);
|
|
2271
1601
|
const exportName = options.exportName?.trim() || 'default';
|
|
2272
1602
|
assertValidExportName(exportName);
|
|
2273
1603
|
const absolutePath = await normalizeLocalPath(filePath);
|
|
@@ -2279,29 +1609,9 @@ export async function bundlePlayFile(
|
|
|
2279
1609
|
adapter,
|
|
2280
1610
|
exportName,
|
|
2281
1611
|
);
|
|
2282
|
-
analysis.graphHash =
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
analysis,
|
|
2286
|
-
entryFile: absolutePath,
|
|
2287
|
-
adapter,
|
|
2288
|
-
exportName,
|
|
2289
|
-
})
|
|
2290
|
-
: sha256(`${analysis.graphHash}\nentry-export:${exportName}`);
|
|
2291
|
-
// For esm_workers builds, the harness source files (entry.ts +
|
|
2292
|
-
// peer DO/coordinator types it imports) are bundled INTO every play
|
|
2293
|
-
// artifact. So any harness edit must produce a different graphHash so
|
|
2294
|
-
// (a) the bundle cache misses, (b) the per-graphHash CF Worker name
|
|
2295
|
-
// changes and gets a fresh deploy. This is the file-watcher-equivalent
|
|
2296
|
-
// for hot-reload of the harness: editing entry.ts → next play run
|
|
2297
|
-
// re-bundles + redeploys automatically.
|
|
2298
|
-
if (targetAdapter.includeWorkersHarnessInGraphHash) {
|
|
2299
|
-
const harnessFingerprint =
|
|
2300
|
-
await computeWorkersHarnessFingerprintWithAdapter(adapter);
|
|
2301
|
-
analysis.graphHash = sha256(
|
|
2302
|
-
`${analysis.graphHash}\nworkers-harness:${harnessFingerprint}`,
|
|
2303
|
-
);
|
|
2304
|
-
}
|
|
1612
|
+
analysis.graphHash = sha256(
|
|
1613
|
+
`${analysis.graphHash}\nentry-export:${exportName}`,
|
|
1614
|
+
);
|
|
2305
1615
|
try {
|
|
2306
1616
|
validatePlaySourceFilesHaveNoInlineSecrets(analysis.sourceFiles);
|
|
2307
1617
|
} catch (error) {
|
|
@@ -2334,10 +1644,11 @@ export async function bundlePlayFile(
|
|
|
2334
1644
|
// Cache lookup happens after validation because a bundle cache hit is keyed
|
|
2335
1645
|
// by source and target, while cloud descriptor typecheck results also depend
|
|
2336
1646
|
// on generated tool metadata.
|
|
2337
|
-
const
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
1647
|
+
const cachedArtifact = await readArtifactCache(
|
|
1648
|
+
analysis.graphHash,
|
|
1649
|
+
target,
|
|
1650
|
+
adapter,
|
|
1651
|
+
);
|
|
2341
1652
|
const discoveredFiles =
|
|
2342
1653
|
await adapter.discoverPackagedLocalFiles(absolutePath);
|
|
2343
1654
|
if (cachedArtifact) {
|
|
@@ -2374,13 +1685,13 @@ export async function bundlePlayFile(
|
|
|
2374
1685
|
};
|
|
2375
1686
|
}
|
|
2376
1687
|
|
|
2377
|
-
const buildOutcome = await
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
1688
|
+
const buildOutcome = await runEsbuildForCjsNode(
|
|
1689
|
+
absolutePath,
|
|
1690
|
+
analysis.importPolicy.localFiles,
|
|
1691
|
+
analysis.importedPlayDependencies,
|
|
2381
1692
|
adapter,
|
|
2382
1693
|
exportName,
|
|
2383
|
-
|
|
1694
|
+
);
|
|
2384
1695
|
if (Array.isArray(buildOutcome)) {
|
|
2385
1696
|
return {
|
|
2386
1697
|
success: false,
|
|
@@ -2414,7 +1725,7 @@ export async function bundlePlayFile(
|
|
|
2414
1725
|
}
|
|
2415
1726
|
|
|
2416
1727
|
const artifact: PlayBundleArtifact = {
|
|
2417
|
-
codeFormat:
|
|
1728
|
+
codeFormat: 'cjs_module',
|
|
2418
1729
|
artifactKind: target,
|
|
2419
1730
|
entryFile: absolutePath,
|
|
2420
1731
|
virtualFilename,
|
|
@@ -2430,9 +1741,7 @@ export async function bundlePlayFile(
|
|
|
2430
1741
|
cacheHit: false,
|
|
2431
1742
|
};
|
|
2432
1743
|
|
|
2433
|
-
|
|
2434
|
-
await writeArtifactCache(artifact, adapter);
|
|
2435
|
-
}
|
|
1744
|
+
await writeArtifactCache(artifact, adapter);
|
|
2436
1745
|
|
|
2437
1746
|
return {
|
|
2438
1747
|
success: true,
|