deepline 0.1.54 → 0.1.56
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/cli/index.js +673 -127
- package/dist/cli/index.mjs +681 -128
- package/dist/index.d.mts +220 -34
- package/dist/index.d.ts +220 -34
- package/dist/index.js +22 -4
- package/dist/index.mjs +22 -4
- package/dist/repo/apps/play-runner-workers/src/entry.ts +36 -12
- package/dist/repo/apps/play-runner-workers/src/runtime/dataset-handles.ts +35 -7
- package/dist/repo/sdk/src/client.ts +33 -2
- package/dist/repo/sdk/src/play.ts +167 -33
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +27 -18
- package/dist/repo/sdk/src/release.ts +3 -3
- package/dist/repo/sdk/src/types.ts +21 -0
- package/dist/repo/shared_libs/play-runtime/csv-rename.ts +55 -3
- package/dist/repo/shared_libs/play-runtime/profiles.ts +26 -54
- package/dist/repo/shared_libs/play-runtime/providers.ts +71 -0
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +9 -1
- package/dist/repo/shared_libs/plays/bundling/index.ts +225 -69
- package/dist/repo/shared_libs/plays/dataset.ts +25 -1
- package/package.json +1 -1
|
@@ -2,7 +2,14 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { mkdir, readFile, realpath, stat, writeFile } from 'node:fs/promises';
|
|
4
4
|
import { tmpdir } from 'node:os';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
basename,
|
|
7
|
+
dirname,
|
|
8
|
+
extname,
|
|
9
|
+
isAbsolute,
|
|
10
|
+
join,
|
|
11
|
+
resolve,
|
|
12
|
+
} from 'node:path';
|
|
6
13
|
import { builtinModules } from 'node:module';
|
|
7
14
|
import { build, type Message, type Plugin } from 'esbuild';
|
|
8
15
|
import {
|
|
@@ -37,11 +44,23 @@ const PLAY_ARTIFACT_CACHE_DIR = join(
|
|
|
37
44
|
`deepline-play-artifacts-v${PLAY_BUNDLE_CACHE_VERSION}`,
|
|
38
45
|
);
|
|
39
46
|
const PLAY_PROXY_NAMESPACE = 'deepline-play-runtime-ref';
|
|
40
|
-
const SOURCE_EXTENSIONS = [
|
|
47
|
+
const SOURCE_EXTENSIONS = [
|
|
48
|
+
'.ts',
|
|
49
|
+
'.tsx',
|
|
50
|
+
'.mts',
|
|
51
|
+
'.cts',
|
|
52
|
+
'.js',
|
|
53
|
+
'.jsx',
|
|
54
|
+
'.mjs',
|
|
55
|
+
'.cjs',
|
|
56
|
+
'.json',
|
|
57
|
+
];
|
|
41
58
|
const WORKERS_PLAY_ENTRY_VIRTUAL = 'deepline-play-entry';
|
|
42
59
|
const PLAY_SOURCE_FILE_PATTERN = /\.play\.(?:[cm]?[jt]sx?)$/i;
|
|
43
60
|
const NODE_BUILTIN_SET = new Set(
|
|
44
|
-
builtinModules.flatMap((name) =>
|
|
61
|
+
builtinModules.flatMap((name) =>
|
|
62
|
+
name.startsWith('node:') ? [name, name.slice(5)] : [name, `node:${name}`],
|
|
63
|
+
),
|
|
45
64
|
);
|
|
46
65
|
|
|
47
66
|
export type {
|
|
@@ -87,7 +106,9 @@ export type PlayBundlingAdapter = {
|
|
|
87
106
|
sdkWorkersEntryFile: string;
|
|
88
107
|
workersHarnessEntryFile: string;
|
|
89
108
|
workersHarnessFilesDir: string;
|
|
90
|
-
discoverPackagedLocalFiles(
|
|
109
|
+
discoverPackagedLocalFiles(
|
|
110
|
+
filePath: string,
|
|
111
|
+
): Promise<PlayLocalFileDiscoveryResult>;
|
|
91
112
|
typecheckPlaySource?(input: {
|
|
92
113
|
sourceCode: string;
|
|
93
114
|
sourcePath: string;
|
|
@@ -229,18 +250,25 @@ function isPlaySourceFile(filePath: string): boolean {
|
|
|
229
250
|
function stripCommentsToSpaces(source: string): string {
|
|
230
251
|
return source
|
|
231
252
|
.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, ' '))
|
|
232
|
-
.replace(
|
|
233
|
-
|
|
253
|
+
.replace(
|
|
254
|
+
/(^|[^:])\/\/.*$/gm,
|
|
255
|
+
(match, prefix: string) =>
|
|
256
|
+
prefix + ' '.repeat(Math.max(0, match.length - prefix.length)),
|
|
234
257
|
);
|
|
235
258
|
}
|
|
236
259
|
|
|
237
|
-
function lineAndColumnAt(
|
|
260
|
+
function lineAndColumnAt(
|
|
261
|
+
source: string,
|
|
262
|
+
index: number,
|
|
263
|
+
): { line: number; column: number } {
|
|
238
264
|
const prefix = source.slice(0, index);
|
|
239
265
|
const lines = prefix.split('\n');
|
|
240
266
|
return { line: lines.length, column: lines[lines.length - 1]!.length + 1 };
|
|
241
267
|
}
|
|
242
268
|
|
|
243
|
-
function findSourceImportReferences(
|
|
269
|
+
function findSourceImportReferences(
|
|
270
|
+
sourceCode: string,
|
|
271
|
+
): SourceImportReference[] {
|
|
244
272
|
const source = stripCommentsToSpaces(sourceCode);
|
|
245
273
|
const references: SourceImportReference[] = [];
|
|
246
274
|
const addReference = (
|
|
@@ -261,17 +289,29 @@ function findSourceImportReferences(sourceCode: string): SourceImportReference[]
|
|
|
261
289
|
const staticImportPattern =
|
|
262
290
|
/\b(?:import|export)\s+(?!type\b)(?:[\s\S]*?\s+from\s*)?(['"])([^'"\n]+)\1/g;
|
|
263
291
|
for (const match of source.matchAll(staticImportPattern)) {
|
|
264
|
-
addReference(
|
|
292
|
+
addReference(
|
|
293
|
+
match[2],
|
|
294
|
+
match.index! + match[0].lastIndexOf(match[1]!),
|
|
295
|
+
'static',
|
|
296
|
+
);
|
|
265
297
|
}
|
|
266
298
|
|
|
267
299
|
const dynamicImportPattern = /\bimport\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
268
300
|
for (const match of source.matchAll(dynamicImportPattern)) {
|
|
269
|
-
addReference(
|
|
301
|
+
addReference(
|
|
302
|
+
match[2],
|
|
303
|
+
match.index! + match[0].lastIndexOf(match[1]!),
|
|
304
|
+
'dynamic-import',
|
|
305
|
+
);
|
|
270
306
|
}
|
|
271
307
|
|
|
272
308
|
const requirePattern = /\brequire\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
273
309
|
for (const match of source.matchAll(requirePattern)) {
|
|
274
|
-
addReference(
|
|
310
|
+
addReference(
|
|
311
|
+
match[2],
|
|
312
|
+
match.index! + match[0].lastIndexOf(match[1]!),
|
|
313
|
+
'require',
|
|
314
|
+
);
|
|
275
315
|
}
|
|
276
316
|
|
|
277
317
|
const literalDynamicImportIndexes = new Set(
|
|
@@ -297,18 +337,27 @@ function findSourceImportReferences(sourceCode: string): SourceImportReference[]
|
|
|
297
337
|
}
|
|
298
338
|
|
|
299
339
|
return references.sort((left, right) =>
|
|
300
|
-
left.line === right.line
|
|
340
|
+
left.line === right.line
|
|
341
|
+
? left.column - right.column
|
|
342
|
+
: left.line - right.line,
|
|
301
343
|
);
|
|
302
344
|
}
|
|
303
345
|
|
|
304
346
|
function unquoteStringLiteral(literal: string): string | null {
|
|
305
347
|
const trimmed = literal.trim();
|
|
306
348
|
const quote = trimmed[0];
|
|
307
|
-
if (
|
|
349
|
+
if (
|
|
350
|
+
(quote !== '"' && quote !== "'") ||
|
|
351
|
+
trimmed[trimmed.length - 1] !== quote
|
|
352
|
+
) {
|
|
308
353
|
return null;
|
|
309
354
|
}
|
|
310
355
|
try {
|
|
311
|
-
return JSON.parse(
|
|
356
|
+
return JSON.parse(
|
|
357
|
+
quote === '"'
|
|
358
|
+
? trimmed
|
|
359
|
+
: `"${trimmed.slice(1, -1).replace(/"/g, '\\"')}"`,
|
|
360
|
+
);
|
|
312
361
|
} catch {
|
|
313
362
|
return trimmed.slice(1, -1);
|
|
314
363
|
}
|
|
@@ -345,7 +394,8 @@ function findMatchingBrace(source: string, openIndex: number): number {
|
|
|
345
394
|
|
|
346
395
|
export function extractDefinedPlayName(sourceCode: string): string | null {
|
|
347
396
|
const source = stripCommentsToSpaces(sourceCode);
|
|
348
|
-
const callPattern =
|
|
397
|
+
const callPattern =
|
|
398
|
+
/(?:\b[A-Za-z_$][\w$]*\s*\.\s*)?\b(?:definePlay|defineWorkflow)\s*\(/g;
|
|
349
399
|
for (const match of source.matchAll(callPattern)) {
|
|
350
400
|
const openParen = match.index! + match[0].length - 1;
|
|
351
401
|
const firstArgStart = openParen + 1;
|
|
@@ -354,7 +404,9 @@ export function extractDefinedPlayName(sourceCode: string): string | null {
|
|
|
354
404
|
const argIndex = firstArgStart + firstNonSpace;
|
|
355
405
|
const quote = source[argIndex];
|
|
356
406
|
if (quote === '"' || quote === "'") {
|
|
357
|
-
const literalMatch = source
|
|
407
|
+
const literalMatch = source
|
|
408
|
+
.slice(argIndex)
|
|
409
|
+
.match(/^(['"])(?:\\.|(?!\1)[\s\S])*\1/);
|
|
358
410
|
const value = literalMatch ? unquoteStringLiteral(literalMatch[0]) : null;
|
|
359
411
|
if (value?.trim()) return value.trim();
|
|
360
412
|
}
|
|
@@ -362,7 +414,9 @@ export function extractDefinedPlayName(sourceCode: string): string | null {
|
|
|
362
414
|
const closeBrace = findMatchingBrace(source, argIndex);
|
|
363
415
|
if (closeBrace < 0) continue;
|
|
364
416
|
const objectSource = source.slice(argIndex + 1, closeBrace);
|
|
365
|
-
const idMatch = objectSource.match(
|
|
417
|
+
const idMatch = objectSource.match(
|
|
418
|
+
/(?:^|[,{\s])(?:id|['"]id['"])\s*:\s*(['"])([\s\S]*?)\1/,
|
|
419
|
+
);
|
|
366
420
|
if (idMatch?.[2]?.trim()) {
|
|
367
421
|
return idMatch[2].trim();
|
|
368
422
|
}
|
|
@@ -526,7 +580,12 @@ function workersNodeBuiltinStubPlugin(): Plugin {
|
|
|
526
580
|
// These are the node builtins NOT exposed by Cloudflare's nodejs_compat.
|
|
527
581
|
// Keep this list narrow — anything supported (path, crypto, etc.) should
|
|
528
582
|
// pass through as `external: ['node:*']` in the build config.
|
|
529
|
-
const UNSUPPORTED = new Set([
|
|
583
|
+
const UNSUPPORTED = new Set([
|
|
584
|
+
'node:fs',
|
|
585
|
+
'node:fs/promises',
|
|
586
|
+
'node:os',
|
|
587
|
+
'node:child_process',
|
|
588
|
+
]);
|
|
530
589
|
return {
|
|
531
590
|
name: 'deepline-workers-node-builtin-stub',
|
|
532
591
|
setup(buildContext) {
|
|
@@ -613,7 +672,8 @@ function zodNonEnglishLocaleStubPlugin(): Plugin {
|
|
|
613
672
|
// Match any zod v4 locale module path EXCEPT en + en variants.
|
|
614
673
|
// The filter uses a coarse regex; the namespace handler then
|
|
615
674
|
// double-checks with a precise basename test before stubbing.
|
|
616
|
-
const LOCALE_PATH_FILTER =
|
|
675
|
+
const LOCALE_PATH_FILTER =
|
|
676
|
+
/[\\/]zod[\\/]v4[\\/]locales[\\/][^\\/]+\.(?:c?js|mjs)$/;
|
|
617
677
|
const NAMESPACE = 'deepline-zod-locale-stub';
|
|
618
678
|
return {
|
|
619
679
|
name: 'deepline-zod-non-english-locale-stub',
|
|
@@ -631,16 +691,13 @@ function zodNonEnglishLocaleStubPlugin(): Plugin {
|
|
|
631
691
|
// Anything else: stub with an empty default export.
|
|
632
692
|
return { path: args.path, namespace: NAMESPACE };
|
|
633
693
|
});
|
|
634
|
-
buildContext.onLoad(
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
loader: 'js',
|
|
642
|
-
}),
|
|
643
|
-
);
|
|
694
|
+
buildContext.onLoad({ filter: /.*/, namespace: NAMESPACE }, () => ({
|
|
695
|
+
// zod locales export a default object literal. Empty object is
|
|
696
|
+
// structurally compatible — accessing any locale key returns
|
|
697
|
+
// undefined and zod falls back to its built-in English.
|
|
698
|
+
contents: 'export default {};',
|
|
699
|
+
loader: 'js',
|
|
700
|
+
}));
|
|
644
701
|
},
|
|
645
702
|
};
|
|
646
703
|
}
|
|
@@ -735,7 +792,10 @@ function importedPlayProxyPlugin(
|
|
|
735
792
|
}
|
|
736
793
|
|
|
737
794
|
const dependenciesByPath = new Map(
|
|
738
|
-
importedPlayDependencies.map((dependency) => [
|
|
795
|
+
importedPlayDependencies.map((dependency) => [
|
|
796
|
+
dependency.filePath,
|
|
797
|
+
dependency,
|
|
798
|
+
]),
|
|
739
799
|
);
|
|
740
800
|
|
|
741
801
|
return {
|
|
@@ -759,19 +819,23 @@ function importedPlayProxyPlugin(
|
|
|
759
819
|
};
|
|
760
820
|
});
|
|
761
821
|
|
|
762
|
-
buildContext.onLoad(
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
822
|
+
buildContext.onLoad(
|
|
823
|
+
{ filter: /.*/, namespace: PLAY_PROXY_NAMESPACE },
|
|
824
|
+
async (args) => {
|
|
825
|
+
const dependency =
|
|
826
|
+
(args.pluginData as ImportedPlayDependency | undefined) ??
|
|
827
|
+
dependenciesByPath.get(args.path);
|
|
828
|
+
if (!dependency) {
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
768
831
|
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
832
|
+
return {
|
|
833
|
+
contents: buildImportedPlayProxyModule(dependency.playName),
|
|
834
|
+
loader: 'ts',
|
|
835
|
+
resolveDir: dirname(args.path),
|
|
836
|
+
};
|
|
837
|
+
},
|
|
838
|
+
);
|
|
775
839
|
},
|
|
776
840
|
};
|
|
777
841
|
}
|
|
@@ -785,21 +849,32 @@ async function fileExists(filePath: string): Promise<boolean> {
|
|
|
785
849
|
}
|
|
786
850
|
}
|
|
787
851
|
|
|
788
|
-
async function resolveLocalImport(
|
|
852
|
+
async function resolveLocalImport(
|
|
853
|
+
fromFile: string,
|
|
854
|
+
specifier: string,
|
|
855
|
+
): Promise<string> {
|
|
789
856
|
if (specifier.startsWith('file:')) {
|
|
790
857
|
return normalizeLocalPath(new URL(specifier).pathname);
|
|
791
858
|
}
|
|
792
859
|
|
|
793
|
-
const base = isAbsolute(specifier)
|
|
860
|
+
const base = isAbsolute(specifier)
|
|
861
|
+
? resolve(specifier)
|
|
862
|
+
: resolve(dirname(fromFile), specifier);
|
|
794
863
|
const candidates: string[] = [base];
|
|
795
864
|
const explicitExtension = extname(base).toLowerCase();
|
|
796
865
|
|
|
797
866
|
if (!explicitExtension) {
|
|
798
|
-
candidates.push(
|
|
799
|
-
|
|
867
|
+
candidates.push(
|
|
868
|
+
...SOURCE_EXTENSIONS.map((extension) => `${base}${extension}`),
|
|
869
|
+
);
|
|
870
|
+
candidates.push(
|
|
871
|
+
...SOURCE_EXTENSIONS.map((extension) => join(base, `index${extension}`)),
|
|
872
|
+
);
|
|
800
873
|
} else if (['.js', '.jsx', '.mjs', '.cjs'].includes(explicitExtension)) {
|
|
801
874
|
const stem = base.slice(0, -explicitExtension.length);
|
|
802
|
-
candidates.push(
|
|
875
|
+
candidates.push(
|
|
876
|
+
...SOURCE_EXTENSIONS.map((extension) => `${stem}${extension}`),
|
|
877
|
+
);
|
|
803
878
|
}
|
|
804
879
|
|
|
805
880
|
for (const candidate of candidates) {
|
|
@@ -808,7 +883,9 @@ async function resolveLocalImport(fromFile: string, specifier: string): Promise<
|
|
|
808
883
|
}
|
|
809
884
|
}
|
|
810
885
|
|
|
811
|
-
throw new Error(
|
|
886
|
+
throw new Error(
|
|
887
|
+
`Could not resolve local import "${specifier}" from ${fromFile}`,
|
|
888
|
+
);
|
|
812
889
|
}
|
|
813
890
|
|
|
814
891
|
function resolvePackageImport(
|
|
@@ -876,7 +953,9 @@ async function analyzeSourceGraph(
|
|
|
876
953
|
}
|
|
877
954
|
|
|
878
955
|
if (NODE_BUILTIN_SET.has(specifier)) {
|
|
879
|
-
nodeBuiltins.add(
|
|
956
|
+
nodeBuiltins.add(
|
|
957
|
+
specifier.startsWith('node:') ? specifier : `node:${specifier}`,
|
|
958
|
+
);
|
|
880
959
|
return;
|
|
881
960
|
}
|
|
882
961
|
|
|
@@ -914,7 +993,11 @@ async function analyzeSourceGraph(
|
|
|
914
993
|
);
|
|
915
994
|
}
|
|
916
995
|
|
|
917
|
-
const packageImport = resolvePackageImport(
|
|
996
|
+
const packageImport = resolvePackageImport(
|
|
997
|
+
specifier,
|
|
998
|
+
absolutePath,
|
|
999
|
+
adapter,
|
|
1000
|
+
);
|
|
918
1001
|
packages.set(packageImport.name, packageImport.version);
|
|
919
1002
|
};
|
|
920
1003
|
|
|
@@ -976,8 +1059,9 @@ async function analyzeSourceGraph(
|
|
|
976
1059
|
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
977
1060
|
},
|
|
978
1061
|
playName,
|
|
979
|
-
importedPlayDependencies: [...importedPlayDependencies.values()]
|
|
980
|
-
|
|
1062
|
+
importedPlayDependencies: [...importedPlayDependencies.values()].sort(
|
|
1063
|
+
(left, right) => left.filePath.localeCompare(right.filePath),
|
|
1064
|
+
),
|
|
981
1065
|
};
|
|
982
1066
|
}
|
|
983
1067
|
|
|
@@ -995,14 +1079,19 @@ async function computeWorkersHarnessFingerprintWithAdapter(
|
|
|
995
1079
|
adapter: PlayBundlingAdapter,
|
|
996
1080
|
): Promise<string> {
|
|
997
1081
|
const { readdir } = await import('node:fs/promises');
|
|
998
|
-
const entries = await readdir(adapter.workersHarnessFilesDir, {
|
|
1082
|
+
const entries = await readdir(adapter.workersHarnessFilesDir, {
|
|
1083
|
+
withFileTypes: true,
|
|
1084
|
+
});
|
|
999
1085
|
const tsFiles = entries
|
|
1000
1086
|
.filter((e) => e.isFile() && /\.[cm]?ts$/.test(e.name))
|
|
1001
1087
|
.map((e) => e.name)
|
|
1002
1088
|
.sort();
|
|
1003
1089
|
const parts: Array<{ name: string; hash: string }> = [];
|
|
1004
1090
|
for (const name of tsFiles) {
|
|
1005
|
-
const contents = await readFile(
|
|
1091
|
+
const contents = await readFile(
|
|
1092
|
+
join(adapter.workersHarnessFilesDir, name),
|
|
1093
|
+
'utf-8',
|
|
1094
|
+
);
|
|
1006
1095
|
parts.push({ name, hash: sha256(contents) });
|
|
1007
1096
|
}
|
|
1008
1097
|
return sha256(JSON.stringify(parts));
|
|
@@ -1137,6 +1226,18 @@ type EsbuildBundleOutput = {
|
|
|
1137
1226
|
outputExtension: 'cjs' | 'mjs';
|
|
1138
1227
|
};
|
|
1139
1228
|
|
|
1229
|
+
type PlayArtifactTargetAdapter = {
|
|
1230
|
+
artifactKind: PlayArtifactKind;
|
|
1231
|
+
codeFormat: PlayBundleArtifact['codeFormat'];
|
|
1232
|
+
includeWorkersHarnessInGraphHash: boolean;
|
|
1233
|
+
runEsbuild(input: {
|
|
1234
|
+
entryFile: string;
|
|
1235
|
+
importedPlayDependencies: ImportedPlayDependency[];
|
|
1236
|
+
adapter: PlayBundlingAdapter;
|
|
1237
|
+
exportName: string;
|
|
1238
|
+
}): Promise<EsbuildBundleOutput | string[]>;
|
|
1239
|
+
};
|
|
1240
|
+
|
|
1140
1241
|
async function runEsbuildForCjsNode(
|
|
1141
1242
|
entryFile: string,
|
|
1142
1243
|
importedPlayDependencies: ImportedPlayDependency[],
|
|
@@ -1268,12 +1369,60 @@ async function runEsbuildForEsmWorkers(
|
|
|
1268
1369
|
};
|
|
1269
1370
|
}
|
|
1270
1371
|
|
|
1372
|
+
const PLAY_ARTIFACT_TARGET_ADAPTERS: Record<
|
|
1373
|
+
PlayArtifactKind,
|
|
1374
|
+
PlayArtifactTargetAdapter
|
|
1375
|
+
> = {
|
|
1376
|
+
[PLAY_ARTIFACT_KINDS.cjsNode20]: {
|
|
1377
|
+
artifactKind: PLAY_ARTIFACT_KINDS.cjsNode20,
|
|
1378
|
+
codeFormat: 'cjs_module',
|
|
1379
|
+
includeWorkersHarnessInGraphHash: false,
|
|
1380
|
+
runEsbuild: ({
|
|
1381
|
+
entryFile,
|
|
1382
|
+
importedPlayDependencies,
|
|
1383
|
+
adapter,
|
|
1384
|
+
exportName,
|
|
1385
|
+
}) =>
|
|
1386
|
+
runEsbuildForCjsNode(
|
|
1387
|
+
entryFile,
|
|
1388
|
+
importedPlayDependencies,
|
|
1389
|
+
adapter,
|
|
1390
|
+
exportName,
|
|
1391
|
+
),
|
|
1392
|
+
},
|
|
1393
|
+
[PLAY_ARTIFACT_KINDS.esmWorkers]: {
|
|
1394
|
+
artifactKind: PLAY_ARTIFACT_KINDS.esmWorkers,
|
|
1395
|
+
codeFormat: 'esm_module',
|
|
1396
|
+
includeWorkersHarnessInGraphHash: true,
|
|
1397
|
+
runEsbuild: ({
|
|
1398
|
+
entryFile,
|
|
1399
|
+
importedPlayDependencies,
|
|
1400
|
+
adapter,
|
|
1401
|
+
exportName,
|
|
1402
|
+
}) =>
|
|
1403
|
+
runEsbuildForEsmWorkers(
|
|
1404
|
+
entryFile,
|
|
1405
|
+
importedPlayDependencies,
|
|
1406
|
+
adapter,
|
|
1407
|
+
exportName,
|
|
1408
|
+
),
|
|
1409
|
+
},
|
|
1410
|
+
};
|
|
1411
|
+
|
|
1412
|
+
function resolvePlayArtifactTargetAdapter(
|
|
1413
|
+
artifactKind: PlayArtifactKind,
|
|
1414
|
+
): PlayArtifactTargetAdapter {
|
|
1415
|
+
return PLAY_ARTIFACT_TARGET_ADAPTERS[artifactKind];
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1271
1418
|
export async function bundlePlayFile(
|
|
1272
1419
|
filePath: string,
|
|
1273
1420
|
options: BundlePlayFileCoreOptions,
|
|
1274
1421
|
): Promise<BundledPlayFileResult> {
|
|
1275
1422
|
const adapter = options.adapter;
|
|
1276
|
-
const target: PlayArtifactKind =
|
|
1423
|
+
const target: PlayArtifactKind =
|
|
1424
|
+
options.target ?? PLAY_ARTIFACT_KINDS.cjsNode20;
|
|
1425
|
+
const targetAdapter = resolvePlayArtifactTargetAdapter(target);
|
|
1277
1426
|
const exportName = options.exportName?.trim() || 'default';
|
|
1278
1427
|
assertValidExportName(exportName);
|
|
1279
1428
|
const absolutePath = await normalizeLocalPath(filePath);
|
|
@@ -1291,8 +1440,9 @@ export async function bundlePlayFile(
|
|
|
1291
1440
|
// changes and gets a fresh deploy. This is the file-watcher-equivalent
|
|
1292
1441
|
// for hot-reload of the harness: editing entry.ts → next play run
|
|
1293
1442
|
// re-bundles + redeploys automatically.
|
|
1294
|
-
if (
|
|
1295
|
-
const harnessFingerprint =
|
|
1443
|
+
if (targetAdapter.includeWorkersHarnessInGraphHash) {
|
|
1444
|
+
const harnessFingerprint =
|
|
1445
|
+
await computeWorkersHarnessFingerprintWithAdapter(adapter);
|
|
1296
1446
|
analysis.graphHash = sha256(
|
|
1297
1447
|
`${analysis.graphHash}\nworkers-harness:${harnessFingerprint}`,
|
|
1298
1448
|
);
|
|
@@ -1303,7 +1453,9 @@ export async function bundlePlayFile(
|
|
|
1303
1453
|
sourcePath: absolutePath,
|
|
1304
1454
|
importedFilePaths: [
|
|
1305
1455
|
...analysis.importPolicy.localFiles,
|
|
1306
|
-
...analysis.importedPlayDependencies.map(
|
|
1456
|
+
...analysis.importedPlayDependencies.map(
|
|
1457
|
+
(dependency) => dependency.filePath,
|
|
1458
|
+
),
|
|
1307
1459
|
],
|
|
1308
1460
|
})) ?? []),
|
|
1309
1461
|
];
|
|
@@ -1318,8 +1470,13 @@ export async function bundlePlayFile(
|
|
|
1318
1470
|
// Cache lookup happens after validation because a bundle cache hit is keyed
|
|
1319
1471
|
// by source and target, while cloud descriptor typecheck results also depend
|
|
1320
1472
|
// on generated tool metadata.
|
|
1321
|
-
const cachedArtifact = await readArtifactCache(
|
|
1322
|
-
|
|
1473
|
+
const cachedArtifact = await readArtifactCache(
|
|
1474
|
+
analysis.graphHash,
|
|
1475
|
+
target,
|
|
1476
|
+
adapter,
|
|
1477
|
+
);
|
|
1478
|
+
const discoveredFiles =
|
|
1479
|
+
await adapter.discoverPackagedLocalFiles(absolutePath);
|
|
1323
1480
|
if (cachedArtifact) {
|
|
1324
1481
|
const cachedArtifactSizeError = getBundleSizeError(
|
|
1325
1482
|
absolutePath,
|
|
@@ -1347,10 +1504,12 @@ export async function bundlePlayFile(
|
|
|
1347
1504
|
};
|
|
1348
1505
|
}
|
|
1349
1506
|
|
|
1350
|
-
const buildOutcome =
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1507
|
+
const buildOutcome = await targetAdapter.runEsbuild({
|
|
1508
|
+
entryFile: absolutePath,
|
|
1509
|
+
importedPlayDependencies: analysis.importedPlayDependencies,
|
|
1510
|
+
adapter,
|
|
1511
|
+
exportName,
|
|
1512
|
+
});
|
|
1354
1513
|
if (Array.isArray(buildOutcome)) {
|
|
1355
1514
|
return {
|
|
1356
1515
|
success: false,
|
|
@@ -1380,11 +1539,8 @@ export async function bundlePlayFile(
|
|
|
1380
1539
|
};
|
|
1381
1540
|
}
|
|
1382
1541
|
|
|
1383
|
-
const codeFormat: PlayBundleArtifact['codeFormat'] =
|
|
1384
|
-
target === PLAY_ARTIFACT_KINDS.esmWorkers ? 'esm_module' : 'cjs_module';
|
|
1385
|
-
|
|
1386
1542
|
const artifact: PlayBundleArtifact = {
|
|
1387
|
-
codeFormat,
|
|
1543
|
+
codeFormat: targetAdapter.codeFormat,
|
|
1388
1544
|
artifactKind: target,
|
|
1389
1545
|
entryFile: absolutePath,
|
|
1390
1546
|
virtualFilename,
|
|
@@ -1416,7 +1572,7 @@ export async function bundlePlayFile(
|
|
|
1416
1572
|
} catch (error) {
|
|
1417
1573
|
if (error && typeof error === 'object' && 'errors' in error) {
|
|
1418
1574
|
const errors = Array.isArray((error as { errors?: Message[] }).errors)
|
|
1419
|
-
? (
|
|
1575
|
+
? (error as { errors: Message[] }).errors.map(formatEsbuildMessage)
|
|
1420
1576
|
: ['Play bundling failed.'];
|
|
1421
1577
|
return {
|
|
1422
1578
|
success: false,
|
|
@@ -55,14 +55,34 @@ export type PlayDatasetInput<T> =
|
|
|
55
55
|
| AsyncIterable<T>
|
|
56
56
|
| PlayDataset<T>;
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Durable handle for rows produced by `ctx.csv(...)` or `ctx.map(...).run()`.
|
|
60
|
+
*
|
|
61
|
+
* A `PlayDataset` is not a normal in-memory array. It points at runtime-managed
|
|
62
|
+
* rows, usually backed by persisted sheet storage, and carries metadata such as
|
|
63
|
+
* dataset kind, dataset id, table namespace, count, and preview rows.
|
|
64
|
+
*
|
|
65
|
+
* Pass dataset handles directly into later `ctx.map(...)` stages by default so
|
|
66
|
+
* Deepline keeps row progress, retries, memory use, and table output under
|
|
67
|
+
* runtime control. Use `count()` and `peek()` for bounded inspection. Use
|
|
68
|
+
* `materialize(limit)` or async iteration only when the dataset is intentionally
|
|
69
|
+
* small and bounded.
|
|
70
|
+
*/
|
|
58
71
|
export interface PlayDataset<T> extends AsyncIterable<T> {
|
|
59
72
|
readonly [PLAY_DATASET_BRAND]: true;
|
|
73
|
+
/** Dataset kind. */
|
|
60
74
|
readonly datasetKind: PlayDatasetKind;
|
|
75
|
+
/** Dataset id. */
|
|
61
76
|
readonly datasetId: string;
|
|
77
|
+
/** Backing store info. */
|
|
62
78
|
readonly backing?: PlayDatasetBacking;
|
|
79
|
+
/** Display label. */
|
|
63
80
|
readonly sourceLabel?: string | null;
|
|
81
|
+
/** Runtime table name. */
|
|
64
82
|
readonly tableNamespace?: string | null;
|
|
83
|
+
/** Row count. */
|
|
65
84
|
count(): Promise<number>;
|
|
85
|
+
/** Preview rows. */
|
|
66
86
|
peek(limit?: number): Promise<T[]>;
|
|
67
87
|
/**
|
|
68
88
|
* Explicit escape hatch for bounded result sets.
|
|
@@ -310,7 +330,11 @@ export async function materializePlayDatasetInput<T>(
|
|
|
310
330
|
input: PlayDatasetInput<T>,
|
|
311
331
|
): Promise<T[]> {
|
|
312
332
|
if (isPlayDataset(input)) {
|
|
313
|
-
|
|
333
|
+
const rows: T[] = [];
|
|
334
|
+
for await (const row of input) {
|
|
335
|
+
rows.push(row);
|
|
336
|
+
}
|
|
337
|
+
return rows;
|
|
314
338
|
}
|
|
315
339
|
|
|
316
340
|
if (Array.isArray(input)) {
|