deepline 0.1.12 → 0.1.20
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 +14 -6
- package/dist/cli/index.js +1346 -717
- package/dist/cli/index.mjs +1342 -713
- package/dist/index.d.mts +199 -23
- package/dist/index.d.ts +199 -23
- package/dist/index.js +221 -14
- package/dist/index.mjs +221 -14
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +214 -77
- package/dist/repo/apps/play-runner-workers/src/dedup-do.ts +85 -60
- package/dist/repo/apps/play-runner-workers/src/entry.ts +385 -66
- package/dist/repo/sdk/src/client.ts +237 -0
- package/dist/repo/sdk/src/config.ts +125 -8
- package/dist/repo/sdk/src/http.ts +29 -5
- package/dist/repo/sdk/src/play.ts +19 -36
- package/dist/repo/sdk/src/plays/bundle-play-file.ts +22 -8
- package/dist/repo/sdk/src/plays/local-file-discovery.ts +207 -160
- package/dist/repo/sdk/src/types.ts +25 -0
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/tool-result.ts +237 -145
- package/dist/repo/shared_libs/plays/bundling/index.ts +206 -229
- package/dist/repo/shared_libs/plays/dataset.ts +28 -0
- package/dist/repo/shared_libs/plays/row-identity.ts +59 -4
- package/package.json +5 -4
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/index.mjs.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/repo/apps/play-runner-workers/src/runtime/README.md +0 -21
- package/dist/repo/apps/play-runner-workers/src/runtime/batching.ts +0 -177
- package/dist/repo/apps/play-runner-workers/src/runtime/execution-plan.ts +0 -52
- package/dist/repo/apps/play-runner-workers/src/runtime/tool-batch.ts +0 -100
- package/dist/repo/sdk/src/cli/commands/auth.ts +0 -500
- package/dist/repo/sdk/src/cli/commands/billing.ts +0 -188
- package/dist/repo/sdk/src/cli/commands/csv.ts +0 -123
- package/dist/repo/sdk/src/cli/commands/db.ts +0 -119
- package/dist/repo/sdk/src/cli/commands/feedback.ts +0 -40
- package/dist/repo/sdk/src/cli/commands/org.ts +0 -117
- package/dist/repo/sdk/src/cli/commands/play.ts +0 -3441
- package/dist/repo/sdk/src/cli/commands/tools.ts +0 -687
- package/dist/repo/sdk/src/cli/dataset-stats.ts +0 -415
- package/dist/repo/sdk/src/cli/index.ts +0 -148
- package/dist/repo/sdk/src/cli/progress.ts +0 -149
- package/dist/repo/sdk/src/cli/skills-sync.ts +0 -141
- package/dist/repo/sdk/src/cli/trace.ts +0 -61
- package/dist/repo/sdk/src/cli/utils.ts +0 -145
- package/dist/repo/sdk/src/compat.ts +0 -77
- package/dist/repo/shared_libs/observability/node-tracing.ts +0 -129
- package/dist/repo/shared_libs/observability/tracing.ts +0 -98
- package/dist/repo/shared_libs/play-runtime/context.ts +0 -4242
- package/dist/repo/shared_libs/play-runtime/ctx-contract.ts +0 -250
- package/dist/repo/shared_libs/play-runtime/ctx-types.ts +0 -725
- package/dist/repo/shared_libs/play-runtime/dataset-id.ts +0 -10
- package/dist/repo/shared_libs/play-runtime/db-session-crypto.ts +0 -304
- package/dist/repo/shared_libs/play-runtime/db-session.ts +0 -462
- package/dist/repo/shared_libs/play-runtime/live-events.ts +0 -214
- package/dist/repo/shared_libs/play-runtime/live-state-contract.ts +0 -50
- package/dist/repo/shared_libs/play-runtime/map-execution-frame.ts +0 -114
- package/dist/repo/shared_libs/play-runtime/map-row-identity.ts +0 -158
- package/dist/repo/shared_libs/play-runtime/progress-emitter.ts +0 -172
- package/dist/repo/shared_libs/play-runtime/protocol.ts +0 -121
- package/dist/repo/shared_libs/play-runtime/public-play-contract.ts +0 -42
- package/dist/repo/shared_libs/play-runtime/result-normalization.ts +0 -33
- package/dist/repo/shared_libs/play-runtime/runtime-api.ts +0 -1873
- package/dist/repo/shared_libs/play-runtime/runtime-constraints.ts +0 -2
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-neon-serverless.ts +0 -201
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver-pg.ts +0 -48
- package/dist/repo/shared_libs/play-runtime/runtime-pg-driver.ts +0 -84
- package/dist/repo/shared_libs/play-runtime/static-pipeline-types.ts +0 -147
- package/dist/repo/shared_libs/play-runtime/suspension.ts +0 -68
- package/dist/repo/shared_libs/play-runtime/tracing.ts +0 -31
- package/dist/repo/shared_libs/play-runtime/waterfall-replay.ts +0 -75
- package/dist/repo/shared_libs/play-runtime/worker-api-types.ts +0 -140
- package/dist/repo/shared_libs/plays/artifact-transport.ts +0 -14
- package/dist/repo/shared_libs/plays/artifact-types.ts +0 -49
- package/dist/repo/shared_libs/plays/compiler-manifest.ts +0 -186
- package/dist/repo/shared_libs/plays/definition.ts +0 -264
- package/dist/repo/shared_libs/plays/file-refs.ts +0 -11
- package/dist/repo/shared_libs/plays/rate-limit-scheduler.ts +0 -206
- package/dist/repo/shared_libs/plays/resolve-static-pipeline.ts +0 -164
- package/dist/repo/shared_libs/plays/runtime-validation.ts +0 -395
- package/dist/repo/shared_libs/temporal/constants.ts +0 -39
- package/dist/repo/shared_libs/temporal/preview-config.ts +0 -153
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { existsSync } from 'node:fs';
|
|
3
2
|
import { mkdir, readFile, realpath, stat, writeFile } from 'node:fs/promises';
|
|
4
3
|
import { tmpdir } from 'node:os';
|
|
5
4
|
import { basename, dirname, extname, isAbsolute, join, resolve } from 'node:path';
|
|
6
5
|
import { builtinModules, createRequire } from 'node:module';
|
|
7
6
|
import { build, type Message, type Plugin } from 'esbuild';
|
|
8
|
-
import ts from 'typescript';
|
|
9
7
|
import {
|
|
10
8
|
PLAY_ARTIFACT_KINDS,
|
|
11
9
|
type PlayArtifactKind,
|
|
@@ -90,7 +88,6 @@ export type PlayBundlingAdapter = {
|
|
|
90
88
|
workersHarnessEntryFile: string;
|
|
91
89
|
workersHarnessFilesDir: string;
|
|
92
90
|
discoverPackagedLocalFiles(filePath: string): Promise<PlayLocalFileDiscoveryResult>;
|
|
93
|
-
typecheckSdkTypes?: boolean;
|
|
94
91
|
typecheckPlaySource?(input: {
|
|
95
92
|
sourceCode: string;
|
|
96
93
|
sourcePath: string;
|
|
@@ -112,6 +109,7 @@ export type BundledPlayFileSuccess = {
|
|
|
112
109
|
success: true;
|
|
113
110
|
artifact: PlayBundleArtifact;
|
|
114
111
|
sourceCode: string;
|
|
112
|
+
sourceFiles: Record<string, string>;
|
|
115
113
|
filePath: string;
|
|
116
114
|
playName: string | null;
|
|
117
115
|
compilerManifest?: PlayCompilerManifest;
|
|
@@ -137,6 +135,7 @@ type PackageResolution = {
|
|
|
137
135
|
|
|
138
136
|
type SourceGraphAnalysis = {
|
|
139
137
|
sourceCode: string;
|
|
138
|
+
sourceFiles: Record<string, string>;
|
|
140
139
|
sourceHash: string;
|
|
141
140
|
graphHash: string;
|
|
142
141
|
importPolicy: PlayImportPolicy;
|
|
@@ -149,6 +148,13 @@ type PlayWorkspace = {
|
|
|
149
148
|
rootDir: string;
|
|
150
149
|
};
|
|
151
150
|
|
|
151
|
+
type SourceImportReference = {
|
|
152
|
+
specifier: string;
|
|
153
|
+
line: number;
|
|
154
|
+
column: number;
|
|
155
|
+
kind: 'static' | 'require' | 'dynamic-import';
|
|
156
|
+
};
|
|
157
|
+
|
|
152
158
|
function sha256(value: string): string {
|
|
153
159
|
return createHash('sha256').update(value).digest('hex');
|
|
154
160
|
}
|
|
@@ -160,67 +166,6 @@ function formatEsbuildMessage(message: Message): string {
|
|
|
160
166
|
return location ? `${location} ${message.text}` : message.text;
|
|
161
167
|
}
|
|
162
168
|
|
|
163
|
-
function formatTypeScriptDiagnostic(diagnostic: ts.Diagnostic): string | null {
|
|
164
|
-
if (!diagnostic.file) {
|
|
165
|
-
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n').trim();
|
|
166
|
-
return message || null;
|
|
167
|
-
}
|
|
168
|
-
const start = diagnostic.start ?? 0;
|
|
169
|
-
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(start);
|
|
170
|
-
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n').trim();
|
|
171
|
-
if (!message) {
|
|
172
|
-
return null;
|
|
173
|
-
}
|
|
174
|
-
return `${diagnostic.file.fileName}:${line + 1}:${character + 1} ${message}`;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
function resolveBundledTypeRoots(): string[] {
|
|
178
|
-
try {
|
|
179
|
-
return [dirname(dirname(playArtifactRequire.resolve('@types/node/package.json')))];
|
|
180
|
-
} catch {
|
|
181
|
-
return [];
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
function typecheckPlaySource(
|
|
186
|
-
input: SourceGraphAnalysis,
|
|
187
|
-
adapter: PlayBundlingAdapter,
|
|
188
|
-
): string[] {
|
|
189
|
-
const rootNames = Array.from(
|
|
190
|
-
new Set([
|
|
191
|
-
...input.importPolicy.localFiles,
|
|
192
|
-
...input.importedPlayDependencies.map((dependency) => dependency.filePath),
|
|
193
|
-
]),
|
|
194
|
-
);
|
|
195
|
-
// Resolve `deepline` to SDK source, not ignored dist artifacts. The source
|
|
196
|
-
// package surface is the canonical local play authoring contract.
|
|
197
|
-
const sdkTypesPath = adapter.sdkTypesEntryFile ?? adapter.sdkEntryFile;
|
|
198
|
-
const program = ts.createProgram(rootNames, {
|
|
199
|
-
target: ts.ScriptTarget.ES2023,
|
|
200
|
-
// SDK source uses fetch/RequestInit/URL and node-aware config helpers.
|
|
201
|
-
// The play runtime import policy below still bans Node modules from play
|
|
202
|
-
// source for workers_edge bundles.
|
|
203
|
-
lib: ['lib.es2023.d.ts', 'lib.dom.d.ts'],
|
|
204
|
-
module: ts.ModuleKind.ESNext,
|
|
205
|
-
moduleResolution: ts.ModuleResolutionKind.Bundler,
|
|
206
|
-
paths: { deepline: [sdkTypesPath] },
|
|
207
|
-
strict: true,
|
|
208
|
-
skipLibCheck: true,
|
|
209
|
-
noEmit: true,
|
|
210
|
-
esModuleInterop: true,
|
|
211
|
-
allowSyntheticDefaultImports: true,
|
|
212
|
-
allowImportingTsExtensions: true,
|
|
213
|
-
allowJs: true,
|
|
214
|
-
resolveJsonModule: true,
|
|
215
|
-
types: ['node'],
|
|
216
|
-
typeRoots: resolveBundledTypeRoots(),
|
|
217
|
-
});
|
|
218
|
-
return ts
|
|
219
|
-
.getPreEmitDiagnostics(program)
|
|
220
|
-
.map(formatTypeScriptDiagnostic)
|
|
221
|
-
.filter((message): message is string => Boolean(message));
|
|
222
|
-
}
|
|
223
|
-
|
|
224
169
|
function isLocalSpecifier(specifier: string): boolean {
|
|
225
170
|
return (
|
|
226
171
|
specifier.startsWith('./') ||
|
|
@@ -254,18 +199,15 @@ function assertWithinPlayWorkspace(input: {
|
|
|
254
199
|
specifier: string;
|
|
255
200
|
resolvedPath: string;
|
|
256
201
|
workspace: PlayWorkspace;
|
|
257
|
-
|
|
258
|
-
|
|
202
|
+
line: number;
|
|
203
|
+
column: number;
|
|
259
204
|
}): void {
|
|
260
205
|
if (isPathInsideDirectory(input.resolvedPath, input.workspace.rootDir)) {
|
|
261
206
|
return;
|
|
262
207
|
}
|
|
263
208
|
|
|
264
|
-
const position = input.sourceFile.getLineAndCharacterOfPosition(
|
|
265
|
-
input.node.getStart(input.sourceFile),
|
|
266
|
-
);
|
|
267
209
|
throw new Error(
|
|
268
|
-
`${input.importer}:${
|
|
210
|
+
`${input.importer}:${input.line}:${input.column} ` +
|
|
269
211
|
`Local play imports must stay inside the play workspace (${input.workspace.rootDir}). ` +
|
|
270
212
|
`Import "${input.specifier}" resolved to ${input.resolvedPath}, which crosses into app/backend code. ` +
|
|
271
213
|
'Use the public SDK/API surface or move shared helpers into the play workspace.',
|
|
@@ -280,95 +222,156 @@ function getPackageName(specifier: string): string {
|
|
|
280
222
|
return specifier.split('/')[0] ?? specifier;
|
|
281
223
|
}
|
|
282
224
|
|
|
283
|
-
function
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
225
|
+
function isPlaySourceFile(filePath: string): boolean {
|
|
226
|
+
return PLAY_SOURCE_FILE_PATTERN.test(filePath);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function stripCommentsToSpaces(source: string): string {
|
|
230
|
+
return source
|
|
231
|
+
.replace(/\/\*[\s\S]*?\*\//g, (match) => match.replace(/[^\n]/g, ' '))
|
|
232
|
+
.replace(/(^|[^:])\/\/.*$/gm, (match, prefix: string) =>
|
|
233
|
+
prefix + ' '.repeat(Math.max(0, match.length - prefix.length)),
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function lineAndColumnAt(source: string, index: number): { line: number; column: number } {
|
|
238
|
+
const prefix = source.slice(0, index);
|
|
239
|
+
const lines = prefix.split('\n');
|
|
240
|
+
return { line: lines.length, column: lines[lines.length - 1]!.length + 1 };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function findSourceImportReferences(sourceCode: string): SourceImportReference[] {
|
|
244
|
+
const source = stripCommentsToSpaces(sourceCode);
|
|
245
|
+
const references: SourceImportReference[] = [];
|
|
246
|
+
const addReference = (
|
|
247
|
+
specifier: string | undefined,
|
|
248
|
+
specifierIndex: number,
|
|
249
|
+
kind: SourceImportReference['kind'],
|
|
250
|
+
) => {
|
|
251
|
+
if (!specifier) return;
|
|
252
|
+
const position = lineAndColumnAt(sourceCode, specifierIndex);
|
|
253
|
+
references.push({
|
|
254
|
+
specifier,
|
|
255
|
+
line: position.line,
|
|
256
|
+
column: position.column,
|
|
257
|
+
kind,
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const staticImportPattern =
|
|
262
|
+
/\b(?:import|export)\s+(?!type\b)(?:[\s\S]*?\s+from\s*)?(['"])([^'"\n]+)\1/g;
|
|
263
|
+
for (const match of source.matchAll(staticImportPattern)) {
|
|
264
|
+
addReference(match[2], match.index! + match[0].lastIndexOf(match[1]!), 'static');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const dynamicImportPattern = /\bimport\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
268
|
+
for (const match of source.matchAll(dynamicImportPattern)) {
|
|
269
|
+
addReference(match[2], match.index! + match[0].lastIndexOf(match[1]!), 'dynamic-import');
|
|
298
270
|
}
|
|
271
|
+
|
|
272
|
+
const requirePattern = /\brequire\s*\(\s*(['"])([^'"\n]+)\1/g;
|
|
273
|
+
for (const match of source.matchAll(requirePattern)) {
|
|
274
|
+
addReference(match[2], match.index! + match[0].lastIndexOf(match[1]!), 'require');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const literalDynamicImportIndexes = new Set(
|
|
278
|
+
[...source.matchAll(dynamicImportPattern)].map((match) => match.index!),
|
|
279
|
+
);
|
|
280
|
+
for (const match of source.matchAll(/\bimport\s*\(/g)) {
|
|
281
|
+
if (literalDynamicImportIndexes.has(match.index!)) continue;
|
|
282
|
+
const position = lineAndColumnAt(sourceCode, match.index!);
|
|
283
|
+
throw new Error(
|
|
284
|
+
`:${position.line}:${position.column} Dynamic import() is not allowed in plays. Use static imports instead.`,
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
const literalRequireIndexes = new Set(
|
|
289
|
+
[...source.matchAll(requirePattern)].map((match) => match.index!),
|
|
290
|
+
);
|
|
291
|
+
for (const match of source.matchAll(/\brequire\s*\(/g)) {
|
|
292
|
+
if (literalRequireIndexes.has(match.index!)) continue;
|
|
293
|
+
const position = lineAndColumnAt(sourceCode, match.index!);
|
|
294
|
+
throw new Error(
|
|
295
|
+
`:${position.line}:${position.column} Dynamic require() is not allowed in plays. Use static imports or require("literal") only.`,
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return references.sort((left, right) =>
|
|
300
|
+
left.line === right.line ? left.column - right.column : left.line - right.line,
|
|
301
|
+
);
|
|
299
302
|
}
|
|
300
303
|
|
|
301
|
-
function
|
|
302
|
-
|
|
304
|
+
function unquoteStringLiteral(literal: string): string | null {
|
|
305
|
+
const trimmed = literal.trim();
|
|
306
|
+
const quote = trimmed[0];
|
|
307
|
+
if ((quote !== '"' && quote !== "'") || trimmed[trimmed.length - 1] !== quote) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
return JSON.parse(quote === '"' ? trimmed : `"${trimmed.slice(1, -1).replace(/"/g, '\\"')}"`);
|
|
312
|
+
} catch {
|
|
313
|
+
return trimmed.slice(1, -1);
|
|
314
|
+
}
|
|
303
315
|
}
|
|
304
316
|
|
|
305
|
-
function
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
for (
|
|
310
|
-
|
|
317
|
+
function findMatchingBrace(source: string, openIndex: number): number {
|
|
318
|
+
let depth = 0;
|
|
319
|
+
let quote: string | null = null;
|
|
320
|
+
let escaped = false;
|
|
321
|
+
for (let index = openIndex; index < source.length; index += 1) {
|
|
322
|
+
const char = source[index]!;
|
|
323
|
+
if (quote) {
|
|
324
|
+
if (escaped) {
|
|
325
|
+
escaped = false;
|
|
326
|
+
} else if (char === '\\') {
|
|
327
|
+
escaped = true;
|
|
328
|
+
} else if (char === quote) {
|
|
329
|
+
quote = null;
|
|
330
|
+
}
|
|
311
331
|
continue;
|
|
312
332
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
(ts.isIdentifier(name) && name.text === propertyName) ||
|
|
316
|
-
(ts.isStringLiteralLike(name) && name.text === propertyName);
|
|
317
|
-
if (!matches) {
|
|
333
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
334
|
+
quote = char;
|
|
318
335
|
continue;
|
|
319
336
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
337
|
+
if (char === '{') depth += 1;
|
|
338
|
+
if (char === '}') {
|
|
339
|
+
depth -= 1;
|
|
340
|
+
if (depth === 0) return index;
|
|
341
|
+
}
|
|
323
342
|
}
|
|
324
|
-
|
|
325
|
-
return null;
|
|
343
|
+
return -1;
|
|
326
344
|
}
|
|
327
345
|
|
|
328
346
|
export function extractDefinedPlayName(
|
|
329
347
|
sourceCode: string,
|
|
330
|
-
|
|
348
|
+
_filePath: string,
|
|
331
349
|
): string | null {
|
|
332
|
-
const
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
350
|
+
const source = stripCommentsToSpaces(sourceCode);
|
|
351
|
+
const callPattern = /(?:\b[A-Za-z_$][\w$]*\s*\.\s*)?\b(?:definePlay|defineWorkflow)\s*\(/g;
|
|
352
|
+
for (const match of source.matchAll(callPattern)) {
|
|
353
|
+
const openParen = match.index! + match[0].length - 1;
|
|
354
|
+
const firstArgStart = openParen + 1;
|
|
355
|
+
const firstNonSpace = source.slice(firstArgStart).search(/\S/);
|
|
356
|
+
if (firstNonSpace < 0) continue;
|
|
357
|
+
const argIndex = firstArgStart + firstNonSpace;
|
|
358
|
+
const quote = source[argIndex];
|
|
359
|
+
if (quote === '"' || quote === "'") {
|
|
360
|
+
const literalMatch = source.slice(argIndex).match(/^(['"])(?:\\.|(?!\1)[\s\S])*\1/);
|
|
361
|
+
const value = literalMatch ? unquoteStringLiteral(literalMatch[0]) : null;
|
|
362
|
+
if (value?.trim()) return value.trim();
|
|
344
363
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
(expression.name.text === 'definePlay' ||
|
|
353
|
-
expression.name.text === 'defineWorkflow'));
|
|
354
|
-
if (isDefinePlayCall) {
|
|
355
|
-
const firstArgument = node.arguments[0];
|
|
356
|
-
if (firstArgument && ts.isStringLiteralLike(firstArgument)) {
|
|
357
|
-
detectedPlayName = firstArgument.text.trim() || null;
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
if (firstArgument && ts.isObjectLiteralExpression(firstArgument)) {
|
|
361
|
-
detectedPlayName = extractStringLiteralProperty(firstArgument, 'id');
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
+
if (quote === '{') {
|
|
365
|
+
const closeBrace = findMatchingBrace(source, argIndex);
|
|
366
|
+
if (closeBrace < 0) continue;
|
|
367
|
+
const objectSource = source.slice(argIndex + 1, closeBrace);
|
|
368
|
+
const idMatch = objectSource.match(/(?:^|[,{\s])(?:id|['"]id['"])\s*:\s*(['"])([\s\S]*?)\1/);
|
|
369
|
+
if (idMatch?.[2]?.trim()) {
|
|
370
|
+
return idMatch[2].trim();
|
|
364
371
|
}
|
|
365
372
|
}
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
};
|
|
369
|
-
|
|
370
|
-
visit(sourceFile);
|
|
371
|
-
return detectedPlayName;
|
|
373
|
+
}
|
|
374
|
+
return null;
|
|
372
375
|
}
|
|
373
376
|
|
|
374
377
|
function getPackageRequireCandidates(fromFile: string) {
|
|
@@ -821,23 +824,15 @@ async function analyzeSourceGraph(
|
|
|
821
824
|
return;
|
|
822
825
|
}
|
|
823
826
|
|
|
824
|
-
const sourceFile = ts.createSourceFile(
|
|
825
|
-
absolutePath,
|
|
826
|
-
sourceCode,
|
|
827
|
-
ts.ScriptTarget.Latest,
|
|
828
|
-
true,
|
|
829
|
-
scriptKindForFile(absolutePath),
|
|
830
|
-
);
|
|
831
|
-
|
|
832
827
|
const handleSpecifier = async (
|
|
833
828
|
specifier: string,
|
|
834
|
-
|
|
829
|
+
line: number,
|
|
830
|
+
column: number,
|
|
835
831
|
kind: 'static' | 'require' | 'dynamic-import',
|
|
836
832
|
) => {
|
|
837
833
|
if (kind === 'dynamic-import') {
|
|
838
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
839
834
|
throw new Error(
|
|
840
|
-
`${absolutePath}:${
|
|
835
|
+
`${absolutePath}:${line}:${column} Dynamic import() is not allowed in plays. Use static imports instead.`,
|
|
841
836
|
);
|
|
842
837
|
}
|
|
843
838
|
|
|
@@ -853,16 +848,15 @@ async function analyzeSourceGraph(
|
|
|
853
848
|
specifier,
|
|
854
849
|
resolvedPath: resolved,
|
|
855
850
|
workspace,
|
|
856
|
-
|
|
857
|
-
|
|
851
|
+
line,
|
|
852
|
+
column,
|
|
858
853
|
});
|
|
859
854
|
if (resolved !== absoluteEntryFile && isPlaySourceFile(resolved)) {
|
|
860
855
|
const importedSource = await readFile(resolved, 'utf-8');
|
|
861
856
|
const importedPlayName = extractDefinedPlayName(importedSource, resolved);
|
|
862
857
|
if (!importedPlayName) {
|
|
863
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
864
858
|
throw new Error(
|
|
865
|
-
`${absolutePath}:${
|
|
859
|
+
`${absolutePath}:${line}:${column} Imported play file "${specifier}" must export definePlay(...) so it can be runtime-composed.`,
|
|
866
860
|
);
|
|
867
861
|
}
|
|
868
862
|
importedPlayDependencies.set(resolved, {
|
|
@@ -876,9 +870,8 @@ async function analyzeSourceGraph(
|
|
|
876
870
|
}
|
|
877
871
|
|
|
878
872
|
if (specifier.includes(':')) {
|
|
879
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
880
873
|
throw new Error(
|
|
881
|
-
`${absolutePath}:${
|
|
874
|
+
`${absolutePath}:${line}:${column} Unsupported import specifier "${specifier}". Allowed imports are relative files, Node builtins, and installed packages.`,
|
|
882
875
|
);
|
|
883
876
|
}
|
|
884
877
|
|
|
@@ -886,48 +879,21 @@ async function analyzeSourceGraph(
|
|
|
886
879
|
packages.set(packageImport.name, packageImport.version);
|
|
887
880
|
};
|
|
888
881
|
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
)
|
|
897
|
-
ts.isStringLiteralLike(node.moduleSpecifier)
|
|
898
|
-
) {
|
|
899
|
-
await handleSpecifier(node.moduleSpecifier.text, node, 'static');
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
if (ts.isCallExpression(node)) {
|
|
903
|
-
if (node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
904
|
-
if (node.arguments.length !== 1 || !ts.isStringLiteralLike(node.arguments[0]!)) {
|
|
905
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
906
|
-
throw new Error(
|
|
907
|
-
`${absolutePath}:${position.line + 1}:${position.character + 1} Dynamic import() is not allowed in plays. Use static imports instead.`,
|
|
908
|
-
);
|
|
909
|
-
}
|
|
910
|
-
await handleSpecifier(node.arguments[0]!.text, node, 'dynamic-import');
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
if (ts.isIdentifier(node.expression) && node.expression.text === 'require') {
|
|
914
|
-
const firstArgument = node.arguments[0];
|
|
915
|
-
if (node.arguments.length !== 1 || !firstArgument || !ts.isStringLiteralLike(firstArgument)) {
|
|
916
|
-
const position = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
917
|
-
throw new Error(
|
|
918
|
-
`${absolutePath}:${position.line + 1}:${position.character + 1} Dynamic require() is not allowed in plays. Use static imports or require(\"literal\") only.`,
|
|
919
|
-
);
|
|
920
|
-
}
|
|
921
|
-
await handleSpecifier(firstArgument.text, node, 'require');
|
|
922
|
-
}
|
|
882
|
+
try {
|
|
883
|
+
for (const reference of findSourceImportReferences(sourceCode)) {
|
|
884
|
+
await handleSpecifier(
|
|
885
|
+
reference.specifier,
|
|
886
|
+
reference.line,
|
|
887
|
+
reference.column,
|
|
888
|
+
reference.kind,
|
|
889
|
+
);
|
|
923
890
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
891
|
+
} catch (error) {
|
|
892
|
+
if (error instanceof Error && error.message.startsWith(':')) {
|
|
893
|
+
throw new Error(`${absolutePath}${error.message}`);
|
|
927
894
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
await walk(sourceFile);
|
|
895
|
+
throw error;
|
|
896
|
+
}
|
|
931
897
|
};
|
|
932
898
|
|
|
933
899
|
await visitFile(absoluteEntryFile);
|
|
@@ -956,6 +922,11 @@ async function analyzeSourceGraph(
|
|
|
956
922
|
|
|
957
923
|
return {
|
|
958
924
|
sourceCode,
|
|
925
|
+
sourceFiles: Object.fromEntries(
|
|
926
|
+
[...localFiles.entries()].sort((left, right) =>
|
|
927
|
+
left[0].localeCompare(right[0]),
|
|
928
|
+
),
|
|
929
|
+
),
|
|
959
930
|
sourceHash,
|
|
960
931
|
graphHash,
|
|
961
932
|
importPolicy: {
|
|
@@ -1067,12 +1038,11 @@ function normalizeSourceMapForRuntime(sourceMapText: string): string {
|
|
|
1067
1038
|
return JSON.stringify(parsed);
|
|
1068
1039
|
}
|
|
1069
1040
|
|
|
1070
|
-
function
|
|
1041
|
+
export function getBundleSizeErrorForBytes(
|
|
1071
1042
|
filePath: string,
|
|
1072
|
-
|
|
1043
|
+
bundleBytes: number,
|
|
1073
1044
|
artifactKind: PlayArtifactKind,
|
|
1074
1045
|
): string | null {
|
|
1075
|
-
const bundleBytes = Buffer.byteLength(bundledCode, 'utf8');
|
|
1076
1046
|
if (bundleBytes > MAX_PLAY_BUNDLE_BYTES) {
|
|
1077
1047
|
return `${filePath} Play bundle exceeds the 30 MiB limit (${bundleBytes} bytes > ${MAX_PLAY_BUNDLE_BYTES} bytes).`;
|
|
1078
1048
|
}
|
|
@@ -1093,6 +1063,18 @@ function getBundleSizeError(
|
|
|
1093
1063
|
return null;
|
|
1094
1064
|
}
|
|
1095
1065
|
|
|
1066
|
+
function getBundleSizeError(
|
|
1067
|
+
filePath: string,
|
|
1068
|
+
bundledCode: string,
|
|
1069
|
+
artifactKind: PlayArtifactKind,
|
|
1070
|
+
): string | null {
|
|
1071
|
+
return getBundleSizeErrorForBytes(
|
|
1072
|
+
filePath,
|
|
1073
|
+
Buffer.byteLength(bundledCode, 'utf8'),
|
|
1074
|
+
artifactKind,
|
|
1075
|
+
);
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1096
1078
|
export type BundlePlayFileOptions = {
|
|
1097
1079
|
/**
|
|
1098
1080
|
* Which artifact to produce. Defaults to `cjs_node20` (Daytona / local-process
|
|
@@ -1276,14 +1258,27 @@ export async function bundlePlayFile(
|
|
|
1276
1258
|
`${analysis.graphHash}\nworkers-harness:${harnessFingerprint}`,
|
|
1277
1259
|
);
|
|
1278
1260
|
}
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1261
|
+
const typecheckErrors = [
|
|
1262
|
+
...((await adapter.typecheckPlaySource?.({
|
|
1263
|
+
sourceCode: analysis.sourceCode,
|
|
1264
|
+
sourcePath: absolutePath,
|
|
1265
|
+
importedFilePaths: [
|
|
1266
|
+
...analysis.importPolicy.localFiles,
|
|
1267
|
+
...analysis.importedPlayDependencies.map((dependency) => dependency.filePath),
|
|
1268
|
+
],
|
|
1269
|
+
})) ?? []),
|
|
1270
|
+
];
|
|
1271
|
+
if (typecheckErrors.length > 0) {
|
|
1272
|
+
return {
|
|
1273
|
+
success: false,
|
|
1274
|
+
filePath: absolutePath,
|
|
1275
|
+
errors: typecheckErrors,
|
|
1276
|
+
};
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
// Cache lookup happens after validation because a bundle cache hit is keyed
|
|
1280
|
+
// by source and target, while cloud descriptor typecheck results also depend
|
|
1281
|
+
// on generated tool metadata.
|
|
1287
1282
|
const cachedArtifact = await readArtifactCache(analysis.graphHash, target, adapter);
|
|
1288
1283
|
const discoveredFiles = await adapter.discoverPackagedLocalFiles(absolutePath);
|
|
1289
1284
|
if (cachedArtifact) {
|
|
@@ -1304,6 +1299,7 @@ export async function bundlePlayFile(
|
|
|
1304
1299
|
success: true,
|
|
1305
1300
|
artifact: { ...cachedArtifact, cacheHit: true },
|
|
1306
1301
|
sourceCode: analysis.sourceCode,
|
|
1302
|
+
sourceFiles: analysis.sourceFiles,
|
|
1307
1303
|
filePath: absolutePath,
|
|
1308
1304
|
playName: analysis.playName,
|
|
1309
1305
|
packagedFiles: discoveredFiles.files,
|
|
@@ -1312,26 +1308,6 @@ export async function bundlePlayFile(
|
|
|
1312
1308
|
};
|
|
1313
1309
|
}
|
|
1314
1310
|
|
|
1315
|
-
const typecheckErrors = [
|
|
1316
|
-
...(adapter.typecheckSdkTypes === false
|
|
1317
|
-
? []
|
|
1318
|
-
: typecheckPlaySource(analysis, adapter)),
|
|
1319
|
-
...((await adapter.typecheckPlaySource?.({
|
|
1320
|
-
sourceCode: analysis.sourceCode,
|
|
1321
|
-
sourcePath: absolutePath,
|
|
1322
|
-
importedFilePaths: [
|
|
1323
|
-
...analysis.importPolicy.localFiles,
|
|
1324
|
-
...analysis.importedPlayDependencies.map((dependency) => dependency.filePath),
|
|
1325
|
-
],
|
|
1326
|
-
})) ?? []),
|
|
1327
|
-
];
|
|
1328
|
-
if (typecheckErrors.length > 0) {
|
|
1329
|
-
return {
|
|
1330
|
-
success: false,
|
|
1331
|
-
filePath: absolutePath,
|
|
1332
|
-
errors: typecheckErrors,
|
|
1333
|
-
};
|
|
1334
|
-
}
|
|
1335
1311
|
const buildOutcome =
|
|
1336
1312
|
target === PLAY_ARTIFACT_KINDS.esmWorkers
|
|
1337
1313
|
? await runEsbuildForEsmWorkers(absolutePath, analysis.importedPlayDependencies, adapter, exportName)
|
|
@@ -1391,6 +1367,7 @@ export async function bundlePlayFile(
|
|
|
1391
1367
|
success: true,
|
|
1392
1368
|
artifact,
|
|
1393
1369
|
sourceCode: analysis.sourceCode,
|
|
1370
|
+
sourceFiles: analysis.sourceFiles,
|
|
1394
1371
|
filePath: absolutePath,
|
|
1395
1372
|
playName: analysis.playName,
|
|
1396
1373
|
packagedFiles: discoveredFiles.files,
|
|
@@ -19,6 +19,21 @@ export type PlayDatasetBacking =
|
|
|
19
19
|
file: PlayExecutionFileRef;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
export type PlayDatasetWorkProgressSummary = {
|
|
23
|
+
total: number;
|
|
24
|
+
executed: number;
|
|
25
|
+
reused: number;
|
|
26
|
+
skipped: number;
|
|
27
|
+
pending: number;
|
|
28
|
+
failed: number;
|
|
29
|
+
degraded?: boolean;
|
|
30
|
+
duplicates?: {
|
|
31
|
+
exact?: number;
|
|
32
|
+
semantic?: number;
|
|
33
|
+
rejected?: number;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
22
37
|
export interface SerializedPlayDataset<T> {
|
|
23
38
|
kind: 'dataset';
|
|
24
39
|
datasetKind: PlayDatasetKind;
|
|
@@ -28,6 +43,9 @@ export interface SerializedPlayDataset<T> {
|
|
|
28
43
|
sourceLabel?: string | null;
|
|
29
44
|
tableNamespace?: string | null;
|
|
30
45
|
columns?: string[];
|
|
46
|
+
_metadata?: {
|
|
47
|
+
workProgress?: PlayDatasetWorkProgressSummary;
|
|
48
|
+
};
|
|
31
49
|
preview: T[];
|
|
32
50
|
}
|
|
33
51
|
|
|
@@ -61,6 +79,9 @@ export interface PlayDataset<T> extends AsyncIterable<T> {
|
|
|
61
79
|
sourceLabel?: string | null;
|
|
62
80
|
tableNamespace?: string | null;
|
|
63
81
|
columns?: string[];
|
|
82
|
+
_metadata?: {
|
|
83
|
+
workProgress?: PlayDatasetWorkProgressSummary;
|
|
84
|
+
};
|
|
64
85
|
preview: T[];
|
|
65
86
|
};
|
|
66
87
|
}
|
|
@@ -136,6 +157,7 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
136
157
|
readonly tableNamespace?: string | null;
|
|
137
158
|
private readonly previewRows: readonly T[];
|
|
138
159
|
private readonly previewColumns?: string[];
|
|
160
|
+
private readonly workProgress?: PlayDatasetWorkProgressSummary;
|
|
139
161
|
private cachedCount: number;
|
|
140
162
|
private readonly resolvers: PlayDatasetResolvers<T>;
|
|
141
163
|
|
|
@@ -147,6 +169,7 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
147
169
|
previewRows: readonly T[];
|
|
148
170
|
sourceLabel?: string | null;
|
|
149
171
|
tableNamespace?: string | null;
|
|
172
|
+
workProgress?: PlayDatasetWorkProgressSummary;
|
|
150
173
|
resolvers: PlayDatasetResolvers<T>;
|
|
151
174
|
}) {
|
|
152
175
|
this.datasetKind = input.datasetKind;
|
|
@@ -157,6 +180,7 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
157
180
|
this.previewColumns = inferPreviewColumns(this.previewRows);
|
|
158
181
|
this.sourceLabel = input.sourceLabel ?? null;
|
|
159
182
|
this.tableNamespace = input.tableNamespace ?? null;
|
|
183
|
+
this.workProgress = input.workProgress;
|
|
160
184
|
this.resolvers = input.resolvers;
|
|
161
185
|
}
|
|
162
186
|
|
|
@@ -212,6 +236,9 @@ class DeferredPlayDataset<T> implements PlayDataset<T> {
|
|
|
212
236
|
...(this.sourceLabel ? { sourceLabel: this.sourceLabel } : {}),
|
|
213
237
|
...(this.tableNamespace ? { tableNamespace: this.tableNamespace } : {}),
|
|
214
238
|
...(this.previewColumns ? { columns: this.previewColumns } : {}),
|
|
239
|
+
...(this.workProgress
|
|
240
|
+
? { _metadata: { workProgress: this.workProgress } }
|
|
241
|
+
: {}),
|
|
215
242
|
preview: [...this.previewRows],
|
|
216
243
|
};
|
|
217
244
|
}
|
|
@@ -229,6 +256,7 @@ export function createDeferredPlayDataset<T>(input: {
|
|
|
229
256
|
previewRows?: readonly T[];
|
|
230
257
|
sourceLabel?: string | null;
|
|
231
258
|
tableNamespace?: string | null;
|
|
259
|
+
workProgress?: PlayDatasetWorkProgressSummary;
|
|
232
260
|
resolvers: PlayDatasetResolvers<T>;
|
|
233
261
|
}): PlayDataset<T> {
|
|
234
262
|
return new DeferredPlayDataset({
|