deepline 0.2.49 → 0.2.50
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/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/plays/bundling/index.ts +35 -7
- package/dist/bundling-sources/shared_libs/plays/enrich-compat-adapter.ts +21 -0
- package/dist/bundling-sources/shared_libs/plays/enrich-play-compiler.ts +1555 -0
- package/dist/bundling-sources/shared_libs/plays/user-code-safety.ts +61 -0
- package/dist/cli/index.js +7 -5
- package/dist/cli/index.mjs +10 -6
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/dist/install-integrity.json +3 -0
- package/dist/plays/bundle-play-file.d.mts +2 -0
- package/dist/plays/bundle-play-file.d.ts +2 -0
- package/dist/plays/bundle-play-file.mjs +31 -6
- package/package.json +1 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Compile-time safety gate for user-authored play code (enrich `extract_js`,
|
|
2
|
+
// `run_if_js`, and `run_javascript` step `code`).
|
|
3
|
+
//
|
|
4
|
+
// Plays replay deterministically under Worker Loader, and the step code runs
|
|
5
|
+
// with provider data in scope. So user code may NOT be non-deterministic
|
|
6
|
+
// (Math.random, Date.now, ...) — replay would diverge — and may NOT reach out
|
|
7
|
+
// of the sandbox (fetch, require, process, ...). We reject those at compile
|
|
8
|
+
// time with a clear, named error (fail loud, per the repo non-negotiables).
|
|
9
|
+
//
|
|
10
|
+
// This is a fast static scan, not a security boundary on its own: the play
|
|
11
|
+
// runtime is the real boundary (it executes step code in an isolate that does
|
|
12
|
+
// not expose these globals). The scan exists to fail authoring early with a
|
|
13
|
+
// readable message instead of producing a play that silently misbehaves at run
|
|
14
|
+
// time. The `(?<!\.)` guards keep it from flagging harmless property access on
|
|
15
|
+
// user objects (e.g. `row.process_date`, `data.fetch`).
|
|
16
|
+
|
|
17
|
+
type ForbiddenRule = { readonly pattern: RegExp; readonly reason: string };
|
|
18
|
+
|
|
19
|
+
const FORBIDDEN: readonly ForbiddenRule[] = [
|
|
20
|
+
// Non-deterministic — breaks replay.
|
|
21
|
+
{ pattern: /\bMath\s*\.\s*random\b/, reason: 'Math.random()' },
|
|
22
|
+
{ pattern: /\bDate\s*\.\s*now\b/, reason: 'Date.now()' },
|
|
23
|
+
{ pattern: /\bnew\s+Date\s*\(\s*\)/, reason: 'new Date() with no argument' },
|
|
24
|
+
{ pattern: /\bperformance\s*\.\s*now\b/, reason: 'performance.now()' },
|
|
25
|
+
{
|
|
26
|
+
pattern: /\bcrypto\s*\.\s*(?:randomUUID|getRandomValues)\b/,
|
|
27
|
+
reason: 'crypto random',
|
|
28
|
+
},
|
|
29
|
+
// Sandbox escape / I/O.
|
|
30
|
+
{ pattern: /(?<!\.)\bfetch\s*\(/, reason: 'fetch()' },
|
|
31
|
+
{ pattern: /(?<!\.)\bimport\s*\(/, reason: 'dynamic import()' },
|
|
32
|
+
{ pattern: /(?<!\.)\brequire\s*\(/, reason: 'require()' },
|
|
33
|
+
{ pattern: /(?<!\.)\beval\s*\(/, reason: 'eval()' },
|
|
34
|
+
{
|
|
35
|
+
pattern: /(?<!\.)\bnew\s+Function\b|(?<!\.)\bFunction\s*\(/,
|
|
36
|
+
reason: 'the Function constructor',
|
|
37
|
+
},
|
|
38
|
+
{ pattern: /(?<!\.)\bprocess\b/, reason: 'process' },
|
|
39
|
+
{ pattern: /(?<!\.)\bglobalThis\b/, reason: 'globalThis' },
|
|
40
|
+
{ pattern: /(?<!\.)\b(?:window|self)\b/, reason: 'window/self' },
|
|
41
|
+
{ pattern: /(?<!\.)\bXMLHttpRequest\b/, reason: 'XMLHttpRequest' },
|
|
42
|
+
{ pattern: /(?<!\.)\bWebAssembly\b/, reason: 'WebAssembly' },
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Throw if `code` references a forbidden (non-deterministic or sandbox-escaping)
|
|
47
|
+
* construct. `label` describes where the code came from for the error message,
|
|
48
|
+
* e.g. `extract_js for "email"` or `run_javascript step "enrich"`.
|
|
49
|
+
*/
|
|
50
|
+
export function assertUserCodeIsSafe(code: string, label: string): void {
|
|
51
|
+
if (typeof code !== 'string' || !code.trim()) return;
|
|
52
|
+
for (const { pattern, reason } of FORBIDDEN) {
|
|
53
|
+
if (pattern.test(code)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`${label} uses ${reason}, which is not allowed in play code: it ` +
|
|
56
|
+
`breaks deterministic replay or escapes the sandbox. Remove it and ` +
|
|
57
|
+
`compute the value from the row/result instead.`,
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -1044,7 +1044,7 @@ var SDK_RELEASE = {
|
|
|
1044
1044
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1045
1045
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1046
1046
|
// release keeps lazy paging semantics independent of row residency.
|
|
1047
|
-
version: "0.2.
|
|
1047
|
+
version: "0.2.50",
|
|
1048
1048
|
contracts: {
|
|
1049
1049
|
api: {
|
|
1050
1050
|
name: "sdk-http-api",
|
|
@@ -24663,7 +24663,7 @@ function getterFromLegacyExtractJs(extractJs, fallbackAlias) {
|
|
|
24663
24663
|
return null;
|
|
24664
24664
|
}
|
|
24665
24665
|
|
|
24666
|
-
//
|
|
24666
|
+
// ../shared_libs/plays/enrich-compat-adapter.ts
|
|
24667
24667
|
var ENRICH_COMPAT_DEFAULT_PLAY_NAME = "deepline-enrich-v1-compat";
|
|
24668
24668
|
var ENRICH_COMPAT_DEFAULT_MAP_NAME = "deepline_enrich_rows";
|
|
24669
24669
|
function buildEnrichCompatibilityPlan(options = {}) {
|
|
@@ -24673,7 +24673,7 @@ function buildEnrichCompatibilityPlan(options = {}) {
|
|
|
24673
24673
|
};
|
|
24674
24674
|
}
|
|
24675
24675
|
|
|
24676
|
-
//
|
|
24676
|
+
// ../shared_libs/plays/user-code-safety.ts
|
|
24677
24677
|
var FORBIDDEN = [
|
|
24678
24678
|
// Non-deterministic — breaks replay.
|
|
24679
24679
|
{ pattern: /\bMath\s*\.\s*random\b/, reason: "Math.random()" },
|
|
@@ -24710,7 +24710,7 @@ function assertUserCodeIsSafe(code, label) {
|
|
|
24710
24710
|
}
|
|
24711
24711
|
}
|
|
24712
24712
|
|
|
24713
|
-
//
|
|
24713
|
+
// ../shared_libs/plays/enrich-play-compiler.ts
|
|
24714
24714
|
function isWaterfall(command) {
|
|
24715
24715
|
return "with_waterfall" in command;
|
|
24716
24716
|
}
|
|
@@ -25141,7 +25141,9 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
|
|
|
25141
25141
|
const generatedAliases = collectGeneratedAliases(config.commands);
|
|
25142
25142
|
const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
|
|
25143
25143
|
const playOptionsSource = [
|
|
25144
|
-
`description: ${stringLiteral(
|
|
25144
|
+
`description: ${stringLiteral(
|
|
25145
|
+
"Read a CSV file, run the configured Deepline enrich commands, and return enriched rows."
|
|
25146
|
+
)}`,
|
|
25145
25147
|
...options.maxCreditsPerRun === void 0 ? [] : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]
|
|
25146
25148
|
].join(", ");
|
|
25147
25149
|
const body = [
|
package/dist/cli/index.mjs
CHANGED
|
@@ -1030,7 +1030,7 @@ var SDK_RELEASE = {
|
|
|
1030
1030
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
1031
1031
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
1032
1032
|
// release keeps lazy paging semantics independent of row residency.
|
|
1033
|
-
version: "0.2.
|
|
1033
|
+
version: "0.2.50",
|
|
1034
1034
|
contracts: {
|
|
1035
1035
|
api: {
|
|
1036
1036
|
name: "sdk-http-api",
|
|
@@ -12313,7 +12313,9 @@ import {
|
|
|
12313
12313
|
extname,
|
|
12314
12314
|
isAbsolute as isAbsolute3,
|
|
12315
12315
|
join as join7,
|
|
12316
|
-
|
|
12316
|
+
relative as relative2,
|
|
12317
|
+
resolve as resolve8,
|
|
12318
|
+
sep
|
|
12317
12319
|
} from "path";
|
|
12318
12320
|
import { builtinModules } from "module";
|
|
12319
12321
|
import { Parser } from "acorn";
|
|
@@ -24707,7 +24709,7 @@ function getterFromLegacyExtractJs(extractJs, fallbackAlias) {
|
|
|
24707
24709
|
return null;
|
|
24708
24710
|
}
|
|
24709
24711
|
|
|
24710
|
-
//
|
|
24712
|
+
// ../shared_libs/plays/enrich-compat-adapter.ts
|
|
24711
24713
|
var ENRICH_COMPAT_DEFAULT_PLAY_NAME = "deepline-enrich-v1-compat";
|
|
24712
24714
|
var ENRICH_COMPAT_DEFAULT_MAP_NAME = "deepline_enrich_rows";
|
|
24713
24715
|
function buildEnrichCompatibilityPlan(options = {}) {
|
|
@@ -24717,7 +24719,7 @@ function buildEnrichCompatibilityPlan(options = {}) {
|
|
|
24717
24719
|
};
|
|
24718
24720
|
}
|
|
24719
24721
|
|
|
24720
|
-
//
|
|
24722
|
+
// ../shared_libs/plays/user-code-safety.ts
|
|
24721
24723
|
var FORBIDDEN = [
|
|
24722
24724
|
// Non-deterministic — breaks replay.
|
|
24723
24725
|
{ pattern: /\bMath\s*\.\s*random\b/, reason: "Math.random()" },
|
|
@@ -24754,7 +24756,7 @@ function assertUserCodeIsSafe(code, label) {
|
|
|
24754
24756
|
}
|
|
24755
24757
|
}
|
|
24756
24758
|
|
|
24757
|
-
//
|
|
24759
|
+
// ../shared_libs/plays/enrich-play-compiler.ts
|
|
24758
24760
|
function isWaterfall(command) {
|
|
24759
24761
|
return "with_waterfall" in command;
|
|
24760
24762
|
}
|
|
@@ -25185,7 +25187,9 @@ function compileEnrichConfigToPlaySource(config, options = {}) {
|
|
|
25185
25187
|
const generatedAliases = collectGeneratedAliases(config.commands);
|
|
25186
25188
|
const runOptionsSource = options.failFast ? `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart), onRowError: 'fail' as const }` : `{ key: (row, index) => __dlEnrichRowKey(row, index + rowStart) }`;
|
|
25187
25189
|
const playOptionsSource = [
|
|
25188
|
-
`description: ${stringLiteral(
|
|
25190
|
+
`description: ${stringLiteral(
|
|
25191
|
+
"Read a CSV file, run the configured Deepline enrich commands, and return enriched rows."
|
|
25192
|
+
)}`,
|
|
25189
25193
|
...options.maxCreditsPerRun === void 0 ? [] : [`billing: { maxCreditsPerRun: ${String(options.maxCreditsPerRun)} }`]
|
|
25190
25194
|
].join(", ");
|
|
25191
25195
|
const body = [
|
package/dist/index.js
CHANGED
|
@@ -763,7 +763,7 @@ var SDK_RELEASE = {
|
|
|
763
763
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
764
764
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
765
765
|
// release keeps lazy paging semantics independent of row residency.
|
|
766
|
-
version: "0.2.
|
|
766
|
+
version: "0.2.50",
|
|
767
767
|
contracts: {
|
|
768
768
|
api: {
|
|
769
769
|
name: "sdk-http-api",
|
package/dist/index.mjs
CHANGED
|
@@ -689,7 +689,7 @@ var SDK_RELEASE = {
|
|
|
689
689
|
// 0.2.0 makes Dataset Handles uniformly async-only after 0.1.320 briefly
|
|
690
690
|
// exposed storage-dependent synchronous access. This deliberate minor
|
|
691
691
|
// release keeps lazy paging semantics independent of row residency.
|
|
692
|
-
version: "0.2.
|
|
692
|
+
version: "0.2.50",
|
|
693
693
|
contracts: {
|
|
694
694
|
api: {
|
|
695
695
|
name: "sdk-http-api",
|
|
@@ -191,6 +191,8 @@
|
|
|
191
191
|
"dist/bundling-sources/shared_libs/plays/dataset-summary.ts",
|
|
192
192
|
"dist/bundling-sources/shared_libs/plays/dataset.ts",
|
|
193
193
|
"dist/bundling-sources/shared_libs/plays/definition.ts",
|
|
194
|
+
"dist/bundling-sources/shared_libs/plays/enrich-compat-adapter.ts",
|
|
195
|
+
"dist/bundling-sources/shared_libs/plays/enrich-play-compiler.ts",
|
|
194
196
|
"dist/bundling-sources/shared_libs/plays/file-refs.ts",
|
|
195
197
|
"dist/bundling-sources/shared_libs/plays/input-contract-definition.ts",
|
|
196
198
|
"dist/bundling-sources/shared_libs/plays/input-contract.ts",
|
|
@@ -202,6 +204,7 @@
|
|
|
202
204
|
"dist/bundling-sources/shared_libs/plays/static-pipeline.ts",
|
|
203
205
|
"dist/bundling-sources/shared_libs/plays/tool-category-descriptions.ts",
|
|
204
206
|
"dist/bundling-sources/shared_libs/plays/tool-codegen.ts",
|
|
207
|
+
"dist/bundling-sources/shared_libs/plays/user-code-safety.ts",
|
|
205
208
|
"dist/bundling-sources/shared_libs/product-notifications/contract.ts",
|
|
206
209
|
"dist/bundling-sources/shared_libs/runtime-env.ts",
|
|
207
210
|
"dist/bundling-sources/shared_libs/security/outbound-url-policy.ts",
|
|
@@ -65,6 +65,8 @@ type PlayLocalFileDiscoveryResult = {
|
|
|
65
65
|
};
|
|
66
66
|
type PlayBundlingAdapter = {
|
|
67
67
|
projectRoot: string;
|
|
68
|
+
/** Optional root used only to make source-graph identity independent of temporary absolute paths. */
|
|
69
|
+
sourceIdentityRoot?: string;
|
|
68
70
|
nodeModulesDir: string;
|
|
69
71
|
cacheDir?: string;
|
|
70
72
|
sdkSourceRoot: string;
|
|
@@ -65,6 +65,8 @@ type PlayLocalFileDiscoveryResult = {
|
|
|
65
65
|
};
|
|
66
66
|
type PlayBundlingAdapter = {
|
|
67
67
|
projectRoot: string;
|
|
68
|
+
/** Optional root used only to make source-graph identity independent of temporary absolute paths. */
|
|
69
|
+
sourceIdentityRoot?: string;
|
|
68
70
|
nodeModulesDir: string;
|
|
69
71
|
cacheDir?: string;
|
|
70
72
|
sdkSourceRoot: string;
|
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
extname,
|
|
22
22
|
isAbsolute,
|
|
23
23
|
join,
|
|
24
|
-
|
|
24
|
+
relative,
|
|
25
|
+
resolve,
|
|
26
|
+
sep
|
|
25
27
|
} from "path";
|
|
26
28
|
import { builtinModules } from "module";
|
|
27
29
|
import { Parser } from "acorn";
|
|
@@ -4060,6 +4062,15 @@ function assertValidExportName(exportName) {
|
|
|
4060
4062
|
function sha256(value) {
|
|
4061
4063
|
return createHash("sha256").update(value).digest("hex");
|
|
4062
4064
|
}
|
|
4065
|
+
function sourceIdentityPath(filePath, adapter) {
|
|
4066
|
+
if (!adapter.sourceIdentityRoot) return filePath;
|
|
4067
|
+
const identityRoot = resolve(adapter.sourceIdentityRoot);
|
|
4068
|
+
const logicalPath = relative(identityRoot, resolve(filePath));
|
|
4069
|
+
if (!logicalPath || logicalPath === ".." || logicalPath.startsWith(`..${sep}`) || isAbsolute(logicalPath)) {
|
|
4070
|
+
return filePath;
|
|
4071
|
+
}
|
|
4072
|
+
return logicalPath.split(/[\\/]+/).join("/");
|
|
4073
|
+
}
|
|
4063
4074
|
function formatEsbuildMessage(message) {
|
|
4064
4075
|
const location = message.location ? `${message.location.file}:${message.location.line}:${message.location.column}` : null;
|
|
4065
4076
|
return location ? `${location} ${message.text}` : message.text;
|
|
@@ -4980,12 +4991,15 @@ async function analyzeSourceGraph(entryFile, adapter, exportName) {
|
|
|
4980
4991
|
const sourceHash = sha256(sourceCode);
|
|
4981
4992
|
const graphHash = sha256(
|
|
4982
4993
|
JSON.stringify({
|
|
4983
|
-
entryFile: absoluteEntryFile,
|
|
4984
|
-
localFiles: [...localFiles.entries()].map(([filePath, contents]) => ({
|
|
4994
|
+
entryFile: sourceIdentityPath(absoluteEntryFile, adapter),
|
|
4995
|
+
localFiles: [...localFiles.entries()].map(([filePath, contents]) => ({
|
|
4996
|
+
filePath: sourceIdentityPath(filePath, adapter),
|
|
4997
|
+
hash: sha256(contents)
|
|
4998
|
+
})).sort((left, right) => left.filePath.localeCompare(right.filePath)),
|
|
4985
4999
|
nodeBuiltins: [...nodeBuiltins].sort(),
|
|
4986
5000
|
packages: [...packages.entries()].map(([name, version]) => ({ name, version })).sort((left, right) => left.name.localeCompare(right.name)),
|
|
4987
5001
|
importedPlayDependencies: [...importedPlayDependencies.values()].map((dependency) => ({
|
|
4988
|
-
filePath: dependency.filePath,
|
|
5002
|
+
filePath: sourceIdentityPath(dependency.filePath, adapter),
|
|
4989
5003
|
playName: dependency.playName
|
|
4990
5004
|
})).sort((left, right) => left.filePath.localeCompare(right.filePath))
|
|
4991
5005
|
})
|
|
@@ -5024,6 +5038,7 @@ async function analyzeSourceGraph(entryFile, adapter, exportName) {
|
|
|
5024
5038
|
}
|
|
5025
5039
|
function artifactCachePath(graphHash, artifactKind, adapter) {
|
|
5026
5040
|
return join(
|
|
5041
|
+
/* turbopackIgnore: true */
|
|
5027
5042
|
adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR,
|
|
5028
5043
|
`${graphHash}.${artifactKind}.json`
|
|
5029
5044
|
);
|
|
@@ -5031,7 +5046,12 @@ function artifactCachePath(graphHash, artifactKind, adapter) {
|
|
|
5031
5046
|
async function readArtifactCache(graphHash, artifactKind, adapter) {
|
|
5032
5047
|
try {
|
|
5033
5048
|
const serialized = await readFile(
|
|
5034
|
-
|
|
5049
|
+
/* turbopackIgnore: true */
|
|
5050
|
+
artifactCachePath(
|
|
5051
|
+
graphHash,
|
|
5052
|
+
artifactKind,
|
|
5053
|
+
adapter
|
|
5054
|
+
),
|
|
5035
5055
|
"utf-8"
|
|
5036
5056
|
);
|
|
5037
5057
|
return JSON.parse(serialized);
|
|
@@ -5041,8 +5061,13 @@ async function readArtifactCache(graphHash, artifactKind, adapter) {
|
|
|
5041
5061
|
}
|
|
5042
5062
|
async function writeArtifactCache(artifact, adapter) {
|
|
5043
5063
|
const cacheDir = adapter.cacheDir ?? PLAY_ARTIFACT_CACHE_DIR;
|
|
5044
|
-
await mkdir(
|
|
5064
|
+
await mkdir(
|
|
5065
|
+
/* turbopackIgnore: true */
|
|
5066
|
+
cacheDir,
|
|
5067
|
+
{ recursive: true }
|
|
5068
|
+
);
|
|
5045
5069
|
await writeFile(
|
|
5070
|
+
/* turbopackIgnore: true */
|
|
5046
5071
|
artifactCachePath(
|
|
5047
5072
|
artifact.graphHash,
|
|
5048
5073
|
artifact.artifactKind ?? PLAY_ARTIFACT_KINDS.cjsNode20,
|