deepline 0.1.240 → 0.1.242

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.
@@ -110,10 +110,13 @@ export const SDK_RELEASE = {
110
110
  // silently materializing them as unmatched results.
111
111
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
112
112
  // automatically without blocking their current command.
113
- version: '0.1.240',
114
- apiContract: '2026-06-dataset-handle-results-hard-cutover',
113
+ // 0.1.241 hard-cuts published and launched plays to immutable cjs_node20
114
+ // artifacts. Older clients can submit esm_workers artifacts that the Absurd
115
+ // runtime intentionally no longer compiles at publish or launch time.
116
+ version: '0.1.242',
117
+ apiContract: '2026-07-immutable-cjs-play-artifacts-hard-cutover',
115
118
  supportPolicy: {
116
- latest: '0.1.240',
119
+ latest: '0.1.242',
117
120
  minimumSupported: '0.1.53',
118
121
  deprecatedBelow: '0.1.219',
119
122
  commandMinimumSupported: [
@@ -42,12 +42,18 @@ export function bundledCodeHasCloudflareSchemeImport(
42
42
  export class PlayArtifactKindMismatchError extends Error {
43
43
  readonly expectedKind: PlayArtifactKind;
44
44
  readonly actualKind: PlayArtifactKind;
45
- readonly reason: 'kind_mismatch' | 'cloudflare_scheme_import';
45
+ readonly reason:
46
+ | 'kind_mismatch'
47
+ | 'code_format_mismatch'
48
+ | 'cloudflare_scheme_import';
46
49
 
47
50
  constructor(input: {
48
51
  expectedKind: PlayArtifactKind;
49
52
  actualKind: PlayArtifactKind;
50
- reason: 'kind_mismatch' | 'cloudflare_scheme_import';
53
+ reason:
54
+ | 'kind_mismatch'
55
+ | 'code_format_mismatch'
56
+ | 'cloudflare_scheme_import';
51
57
  message: string;
52
58
  }) {
53
59
  super(input.message);
@@ -96,6 +102,19 @@ export function assertNodeRunnableArtifact(input: {
96
102
  });
97
103
  }
98
104
 
105
+ if (artifact.codeFormat !== 'cjs_module') {
106
+ throw new PlayArtifactKindMismatchError({
107
+ expectedKind,
108
+ actualKind,
109
+ reason: 'code_format_mismatch',
110
+ message:
111
+ `Node runner (${context}) received a "${actualKind}" play artifact ` +
112
+ `with codeFormat "${artifact.codeFormat}" but requires "cjs_module". ` +
113
+ `The artifact metadata is inconsistent; rebuild it for the node runner ` +
114
+ `before launch.`,
115
+ });
116
+ }
117
+
99
118
  if (bundledCodeHasCloudflareSchemeImport(artifact.bundledCode)) {
100
119
  throw new PlayArtifactKindMismatchError({
101
120
  expectedKind,
@@ -440,6 +440,17 @@ function findSourceImportReferences(
440
440
  );
441
441
  }
442
442
 
443
+ /**
444
+ * Reports local runtime edges using the same parser that drives graph analysis.
445
+ * Migration code uses this to distinguish truly single-file source from stored
446
+ * graph metadata without maintaining a second import parser.
447
+ */
448
+ export function countLocalRuntimeImportReferences(sourceCode: string): number {
449
+ return findSourceImportReferences(sourceCode).filter((reference) =>
450
+ isLocalSpecifier(reference.specifier),
451
+ ).length;
452
+ }
453
+
443
454
  function findMatchingBrace(source: string, openIndex: number): number {
444
455
  const structuralSource = maskSourceForStructure(source);
445
456
  let depth = 0;
@@ -6,6 +6,10 @@ const BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
6
6
  const ASSIGNMENT_SECRET_LITERAL_PATTERN =
7
7
  /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
8
8
  const HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
9
+ const UUID_IDENTIFIER_PATTERN =
10
+ /^((?:[A-Za-z0-9]+[-_])*)?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
11
+ const SECRET_LABEL_PATTERN =
12
+ /(?:^|[-_])(?:api|auth|access|secret|token|key|password|credential|bearer|sk|pk|live)(?:[-_]|$)/i;
9
13
 
10
14
  function shannonEntropy(value: string): number {
11
15
  const counts = new Map<string, number>();
@@ -16,6 +20,13 @@ function shannonEntropy(value: string): number {
16
20
  }, 0);
17
21
  }
18
22
 
23
+ function isNonSecretUuidIdentifier(value: string): boolean {
24
+ const match = UUID_IDENTIFIER_PATTERN.exec(value);
25
+ if (!match) return false;
26
+ const label = match[1] ?? '';
27
+ return !SECRET_LABEL_PATTERN.test(label);
28
+ }
29
+
19
30
  /**
20
31
  * Returns the inline-secret findings in a string (empty if none). The throwing
21
32
  * validator below and the workflows→plays migration validator both call this so
@@ -35,6 +46,9 @@ export function collectInlineSecretFindings(sourceCode: string): string[] {
35
46
  }
36
47
  for (const match of sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
37
48
  const literal = match[1] ?? '';
49
+ // UUID-bearing resource names are structured identifiers, not opaque
50
+ // credentials. Keep secret-looking labels on the conservative path.
51
+ if (isNonSecretUuidIdentifier(literal)) continue;
38
52
  if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
39
53
  findings.push('high-entropy string literal');
40
54
  break;
@@ -0,0 +1,239 @@
1
+ import ts from 'typescript';
2
+
3
+ type SourceMetadata = {
4
+ name: string | null;
5
+ description: string | null;
6
+ };
7
+
8
+ type SourceContext = {
9
+ declarations: Map<string, ts.Expression>;
10
+ namedExports: Map<string, string>;
11
+ defaultExport: ts.Expression | null;
12
+ };
13
+
14
+ function unwrap(expression: ts.Expression | null): ts.Expression | null {
15
+ let current = expression;
16
+ while (current) {
17
+ if (
18
+ ts.isAsExpression(current) ||
19
+ ts.isSatisfiesExpression(current) ||
20
+ ts.isTypeAssertionExpression(current) ||
21
+ ts.isNonNullExpression(current) ||
22
+ ts.isParenthesizedExpression(current)
23
+ ) {
24
+ current = current.expression;
25
+ continue;
26
+ }
27
+ break;
28
+ }
29
+ return current;
30
+ }
31
+
32
+ function buildContext(sourceFile: ts.SourceFile): SourceContext {
33
+ const declarations = new Map<string, ts.Expression>();
34
+ const namedExports = new Map<string, string>();
35
+ let defaultExport: ts.Expression | null = null;
36
+
37
+ for (const statement of sourceFile.statements) {
38
+ if (ts.isVariableStatement(statement)) {
39
+ const exported = statement.modifiers?.some(
40
+ (modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword,
41
+ );
42
+ const immutable = Boolean(
43
+ statement.declarationList.flags & ts.NodeFlags.Const,
44
+ );
45
+ for (const declaration of statement.declarationList.declarations) {
46
+ if (!ts.isIdentifier(declaration.name) || !declaration.initializer)
47
+ continue;
48
+ if (immutable) {
49
+ declarations.set(declaration.name.text, declaration.initializer);
50
+ }
51
+ if (exported) {
52
+ namedExports.set(declaration.name.text, declaration.name.text);
53
+ }
54
+ }
55
+ continue;
56
+ }
57
+ if (ts.isExportAssignment(statement) && !statement.isExportEquals) {
58
+ defaultExport = statement.expression;
59
+ continue;
60
+ }
61
+ if (!ts.isExportDeclaration(statement) || !statement.exportClause) {
62
+ continue;
63
+ }
64
+ if (ts.isNamedExports(statement.exportClause)) {
65
+ for (const element of statement.exportClause.elements) {
66
+ namedExports.set(
67
+ element.name.text,
68
+ element.propertyName?.text ?? element.name.text,
69
+ );
70
+ }
71
+ }
72
+ }
73
+ return { declarations, namedExports, defaultExport };
74
+ }
75
+
76
+ function resolveExpression(
77
+ expression: ts.Expression | null,
78
+ context: SourceContext,
79
+ seen = new Set<string>(),
80
+ ): ts.Expression | null {
81
+ const unwrapped = unwrap(expression);
82
+ if (!unwrapped || !ts.isIdentifier(unwrapped)) return unwrapped;
83
+ if (seen.has(unwrapped.text)) return null;
84
+ seen.add(unwrapped.text);
85
+ return resolveExpression(
86
+ context.declarations.get(unwrapped.text) ?? null,
87
+ context,
88
+ seen,
89
+ );
90
+ }
91
+
92
+ function staticString(
93
+ expression: ts.Expression | undefined,
94
+ context: SourceContext,
95
+ seen = new Set<string>(),
96
+ trimResult = true,
97
+ ): string | null {
98
+ const resolved = unwrap(expression ?? null);
99
+ if (
100
+ resolved &&
101
+ (ts.isStringLiteral(resolved) ||
102
+ ts.isNoSubstitutionTemplateLiteral(resolved))
103
+ ) {
104
+ if (!resolved.text.trim()) return null;
105
+ return trimResult ? resolved.text.trim() : resolved.text;
106
+ }
107
+ if (
108
+ resolved &&
109
+ ts.isBinaryExpression(resolved) &&
110
+ resolved.operatorToken.kind === ts.SyntaxKind.PlusToken
111
+ ) {
112
+ const left = staticString(resolved.left, context, new Set(seen), false);
113
+ const right = staticString(resolved.right, context, new Set(seen), false);
114
+ const value = left !== null && right !== null ? `${left}${right}` : null;
115
+ if (!value?.trim()) return null;
116
+ return trimResult ? value.trim() : value;
117
+ }
118
+ if (!resolved || !ts.isIdentifier(resolved) || seen.has(resolved.text)) {
119
+ return null;
120
+ }
121
+ seen.add(resolved.text);
122
+ return staticString(
123
+ context.declarations.get(resolved.text),
124
+ context,
125
+ seen,
126
+ trimResult,
127
+ );
128
+ }
129
+
130
+ function propertyName(name: ts.PropertyName): string | null {
131
+ return ts.isIdentifier(name) ||
132
+ ts.isStringLiteral(name) ||
133
+ ts.isNumericLiteral(name)
134
+ ? name.text
135
+ : null;
136
+ }
137
+
138
+ function objectStringProperty(
139
+ expression: ts.Expression | undefined,
140
+ key: string,
141
+ context: SourceContext,
142
+ ): string | null {
143
+ const resolved = resolveExpression(expression ?? null, context);
144
+ if (!resolved || !ts.isObjectLiteralExpression(resolved)) return null;
145
+ for (const property of resolved.properties) {
146
+ if (
147
+ ts.isPropertyAssignment(property) &&
148
+ propertyName(property.name) === key
149
+ ) {
150
+ return staticString(property.initializer, context);
151
+ }
152
+ if (
153
+ ts.isShorthandPropertyAssignment(property) &&
154
+ property.name.text === key
155
+ ) {
156
+ return staticString(property.name, context);
157
+ }
158
+ }
159
+ return null;
160
+ }
161
+
162
+ function isDefinePlayCall(call: ts.CallExpression): boolean {
163
+ const callee = unwrap(call.expression);
164
+ if (callee && ts.isIdentifier(callee)) {
165
+ return callee.text === 'definePlay' || callee.text === 'defineWorkflow';
166
+ }
167
+ return Boolean(
168
+ callee &&
169
+ ts.isPropertyAccessExpression(callee) &&
170
+ (callee.name.text === 'definePlay' ||
171
+ callee.name.text === 'defineWorkflow'),
172
+ );
173
+ }
174
+
175
+ function metadataFromExpression(
176
+ expression: ts.Expression | null,
177
+ context: SourceContext,
178
+ ): SourceMetadata | null {
179
+ const resolved = resolveExpression(expression, context);
180
+ if (
181
+ !resolved ||
182
+ !ts.isCallExpression(resolved) ||
183
+ !isDefinePlayCall(resolved)
184
+ ) {
185
+ return null;
186
+ }
187
+ const [first] = resolved.arguments;
188
+ const name =
189
+ objectStringProperty(first, 'id', context) ?? staticString(first, context);
190
+ let description = objectStringProperty(first, 'description', context);
191
+ for (
192
+ let index = resolved.arguments.length - 1;
193
+ !description && index >= 2;
194
+ index -= 1
195
+ ) {
196
+ description = objectStringProperty(
197
+ resolved.arguments[index],
198
+ 'description',
199
+ context,
200
+ );
201
+ }
202
+ return name || description ? { name, description } : null;
203
+ }
204
+
205
+ function extractMetadata(sourceCode: string, exportName: string | null) {
206
+ const sourceFile = ts.createSourceFile(
207
+ 'play.ts',
208
+ sourceCode,
209
+ ts.ScriptTarget.Latest,
210
+ true,
211
+ ts.ScriptKind.TS,
212
+ );
213
+ const context = buildContext(sourceFile);
214
+ const exportedExpression = exportName
215
+ ? exportName === 'default'
216
+ ? context.defaultExport
217
+ : (context.declarations.get(
218
+ context.namedExports.get(exportName) ?? exportName,
219
+ ) ?? null)
220
+ : context.defaultExport;
221
+ const exported = metadataFromExpression(exportedExpression, context);
222
+ if (exported || exportName) return exported;
223
+ for (const expression of context.declarations.values()) {
224
+ const metadata = metadataFromExpression(expression, context);
225
+ if (metadata) return metadata;
226
+ }
227
+ return null;
228
+ }
229
+
230
+ export function extractDefinedPlayName(sourceCode: string): string | null {
231
+ return extractMetadata(sourceCode, null)?.name ?? null;
232
+ }
233
+
234
+ export function extractDefinedPlayDescriptionForExport(
235
+ sourceCode: string,
236
+ exportName: string,
237
+ ): string | null {
238
+ return extractMetadata(sourceCode, exportName)?.description ?? null;
239
+ }
package/dist/cli/index.js CHANGED
@@ -627,10 +627,13 @@ var SDK_RELEASE = {
627
627
  // silently materializing them as unmatched results.
628
628
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
629
629
  // automatically without blocking their current command.
630
- version: "0.1.240",
631
- apiContract: "2026-06-dataset-handle-results-hard-cutover",
630
+ // 0.1.241 hard-cuts published and launched plays to immutable cjs_node20
631
+ // artifacts. Older clients can submit esm_workers artifacts that the Absurd
632
+ // runtime intentionally no longer compiles at publish or launch time.
633
+ version: "0.1.242",
634
+ apiContract: "2026-07-immutable-cjs-play-artifacts-hard-cutover",
632
635
  supportPolicy: {
633
- latest: "0.1.240",
636
+ latest: "0.1.242",
634
637
  minimumSupported: "0.1.53",
635
638
  deprecatedBelow: "0.1.219",
636
639
  commandMinimumSupported: [
@@ -28040,6 +28043,8 @@ var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY----
28040
28043
  var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
28041
28044
  var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
28042
28045
  var HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
28046
+ var UUID_IDENTIFIER_PATTERN = /^((?:[A-Za-z0-9]+[-_])*)?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
28047
+ var SECRET_LABEL_PATTERN = /(?:^|[-_])(?:api|auth|access|secret|token|key|password|credential|bearer|sk|pk|live)(?:[-_]|$)/i;
28043
28048
  function shannonEntropy(value) {
28044
28049
  const counts = /* @__PURE__ */ new Map();
28045
28050
  for (const char of value) counts.set(char, (counts.get(char) ?? 0) + 1);
@@ -28048,6 +28053,12 @@ function shannonEntropy(value) {
28048
28053
  return entropy - p * Math.log2(p);
28049
28054
  }, 0);
28050
28055
  }
28056
+ function isNonSecretUuidIdentifier(value) {
28057
+ const match = UUID_IDENTIFIER_PATTERN.exec(value);
28058
+ if (!match) return false;
28059
+ const label = match[1] ?? "";
28060
+ return !SECRET_LABEL_PATTERN.test(label);
28061
+ }
28051
28062
  function collectInlineSecretFindings(sourceCode) {
28052
28063
  const findings = [];
28053
28064
  for (const match of sourceCode.matchAll(SECRET_ENV_PATTERN)) {
@@ -28061,6 +28072,7 @@ function collectInlineSecretFindings(sourceCode) {
28061
28072
  }
28062
28073
  for (const match of sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
28063
28074
  const literal = match[1] ?? "";
28075
+ if (isNonSecretUuidIdentifier(literal)) continue;
28064
28076
  if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
28065
28077
  findings.push("high-entropy string literal");
28066
28078
  break;
@@ -29038,6 +29050,22 @@ function sidecarStateDir(input2) {
29038
29050
  }
29039
29051
  return (0, import_node_path19.join)(input2.homeDir, ".local", "deepline", scope, "sdk-cli");
29040
29052
  }
29053
+ function sidecarRegistryUrl(hostUrl) {
29054
+ let url;
29055
+ try {
29056
+ url = new URL(hostUrl);
29057
+ } catch {
29058
+ throw new Error(
29059
+ "The Python-managed SDK sidecar is missing a valid Deepline host URL for its npm registry."
29060
+ );
29061
+ }
29062
+ if (url.protocol !== "https:" && url.protocol !== "http:" || !url.hostname || url.username || url.password) {
29063
+ throw new Error(
29064
+ "The Python-managed SDK sidecar has an invalid Deepline host URL for its npm registry."
29065
+ );
29066
+ }
29067
+ return new URL("/api/v2/npm/", url).toString();
29068
+ }
29041
29069
  function readOptionalText(path) {
29042
29070
  try {
29043
29071
  return (0, import_node_fs17.readFileSync)(path, "utf8").trim();
@@ -29067,8 +29095,9 @@ function resolvePythonSidecarUpdatePlan(options) {
29067
29095
  );
29068
29096
  const packageSpec = options.packageSpec || "deepline@latest";
29069
29097
  const npmCommand = "npm";
29098
+ const registryUrl = sidecarRegistryUrl(hostUrl);
29070
29099
  const versionDir = (0, import_node_path19.join)(stateDir, "versions", "<version>");
29071
- const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote6(versionDir)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote6).join(" ")} ${shellQuote6(packageSpec)}`;
29100
+ const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote6(versionDir)} --registry ${shellQuote6(registryUrl)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote6).join(" ")} ${shellQuote6(packageSpec)}`;
29072
29101
  return {
29073
29102
  kind: "python-sidecar",
29074
29103
  stateDir,
@@ -29077,6 +29106,7 @@ function resolvePythonSidecarUpdatePlan(options) {
29077
29106
  npmCommand,
29078
29107
  scope,
29079
29108
  hostUrl,
29109
+ registryUrl,
29080
29110
  packageSpec,
29081
29111
  manualCommand
29082
29112
  };
@@ -29336,6 +29366,8 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
29336
29366
  "install",
29337
29367
  "--prefix",
29338
29368
  tempDir,
29369
+ "--registry",
29370
+ plan.registryUrl,
29339
29371
  ...NPM_SDK_INSTALL_COMMON_FLAGS,
29340
29372
  plan.packageSpec
29341
29373
  ],
@@ -612,10 +612,13 @@ var SDK_RELEASE = {
612
612
  // silently materializing them as unmatched results.
613
613
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
614
614
  // automatically without blocking their current command.
615
- version: "0.1.240",
616
- apiContract: "2026-06-dataset-handle-results-hard-cutover",
615
+ // 0.1.241 hard-cuts published and launched plays to immutable cjs_node20
616
+ // artifacts. Older clients can submit esm_workers artifacts that the Absurd
617
+ // runtime intentionally no longer compiles at publish or launch time.
618
+ version: "0.1.242",
619
+ apiContract: "2026-07-immutable-cjs-play-artifacts-hard-cutover",
617
620
  supportPolicy: {
618
- latest: "0.1.240",
621
+ latest: "0.1.242",
619
622
  minimumSupported: "0.1.53",
620
623
  deprecatedBelow: "0.1.219",
621
624
  commandMinimumSupported: [
@@ -28088,6 +28091,8 @@ var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY----
28088
28091
  var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
28089
28092
  var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
28090
28093
  var HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
28094
+ var UUID_IDENTIFIER_PATTERN = /^((?:[A-Za-z0-9]+[-_])*)?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
28095
+ var SECRET_LABEL_PATTERN = /(?:^|[-_])(?:api|auth|access|secret|token|key|password|credential|bearer|sk|pk|live)(?:[-_]|$)/i;
28091
28096
  function shannonEntropy(value) {
28092
28097
  const counts = /* @__PURE__ */ new Map();
28093
28098
  for (const char of value) counts.set(char, (counts.get(char) ?? 0) + 1);
@@ -28096,6 +28101,12 @@ function shannonEntropy(value) {
28096
28101
  return entropy - p * Math.log2(p);
28097
28102
  }, 0);
28098
28103
  }
28104
+ function isNonSecretUuidIdentifier(value) {
28105
+ const match = UUID_IDENTIFIER_PATTERN.exec(value);
28106
+ if (!match) return false;
28107
+ const label = match[1] ?? "";
28108
+ return !SECRET_LABEL_PATTERN.test(label);
28109
+ }
28099
28110
  function collectInlineSecretFindings(sourceCode) {
28100
28111
  const findings = [];
28101
28112
  for (const match of sourceCode.matchAll(SECRET_ENV_PATTERN)) {
@@ -28109,6 +28120,7 @@ function collectInlineSecretFindings(sourceCode) {
28109
28120
  }
28110
28121
  for (const match of sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
28111
28122
  const literal = match[1] ?? "";
28123
+ if (isNonSecretUuidIdentifier(literal)) continue;
28112
28124
  if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
28113
28125
  findings.push("high-entropy string literal");
28114
28126
  break;
@@ -29101,6 +29113,22 @@ function sidecarStateDir(input2) {
29101
29113
  }
29102
29114
  return join14(input2.homeDir, ".local", "deepline", scope, "sdk-cli");
29103
29115
  }
29116
+ function sidecarRegistryUrl(hostUrl) {
29117
+ let url;
29118
+ try {
29119
+ url = new URL(hostUrl);
29120
+ } catch {
29121
+ throw new Error(
29122
+ "The Python-managed SDK sidecar is missing a valid Deepline host URL for its npm registry."
29123
+ );
29124
+ }
29125
+ if (url.protocol !== "https:" && url.protocol !== "http:" || !url.hostname || url.username || url.password) {
29126
+ throw new Error(
29127
+ "The Python-managed SDK sidecar has an invalid Deepline host URL for its npm registry."
29128
+ );
29129
+ }
29130
+ return new URL("/api/v2/npm/", url).toString();
29131
+ }
29104
29132
  function readOptionalText(path) {
29105
29133
  try {
29106
29134
  return readFileSync13(path, "utf8").trim();
@@ -29130,8 +29158,9 @@ function resolvePythonSidecarUpdatePlan(options) {
29130
29158
  );
29131
29159
  const packageSpec = options.packageSpec || "deepline@latest";
29132
29160
  const npmCommand = "npm";
29161
+ const registryUrl = sidecarRegistryUrl(hostUrl);
29133
29162
  const versionDir = join14(stateDir, "versions", "<version>");
29134
- const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote6(versionDir)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote6).join(" ")} ${shellQuote6(packageSpec)}`;
29163
+ const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote6(versionDir)} --registry ${shellQuote6(registryUrl)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote6).join(" ")} ${shellQuote6(packageSpec)}`;
29135
29164
  return {
29136
29165
  kind: "python-sidecar",
29137
29166
  stateDir,
@@ -29140,6 +29169,7 @@ function resolvePythonSidecarUpdatePlan(options) {
29140
29169
  npmCommand,
29141
29170
  scope,
29142
29171
  hostUrl,
29172
+ registryUrl,
29143
29173
  packageSpec,
29144
29174
  manualCommand
29145
29175
  };
@@ -29399,6 +29429,8 @@ async function runPythonSidecarUpdatePlan(plan, options = {}) {
29399
29429
  "install",
29400
29430
  "--prefix",
29401
29431
  tempDir,
29432
+ "--registry",
29433
+ plan.registryUrl,
29402
29434
  ...NPM_SDK_INSTALL_COMMON_FLAGS,
29403
29435
  plan.packageSpec
29404
29436
  ],
package/dist/index.js CHANGED
@@ -426,10 +426,13 @@ var SDK_RELEASE = {
426
426
  // silently materializing them as unmatched results.
427
427
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
428
428
  // automatically without blocking their current command.
429
- version: "0.1.240",
430
- apiContract: "2026-06-dataset-handle-results-hard-cutover",
429
+ // 0.1.241 hard-cuts published and launched plays to immutable cjs_node20
430
+ // artifacts. Older clients can submit esm_workers artifacts that the Absurd
431
+ // runtime intentionally no longer compiles at publish or launch time.
432
+ version: "0.1.242",
433
+ apiContract: "2026-07-immutable-cjs-play-artifacts-hard-cutover",
431
434
  supportPolicy: {
432
- latest: "0.1.240",
435
+ latest: "0.1.242",
433
436
  minimumSupported: "0.1.53",
434
437
  deprecatedBelow: "0.1.219",
435
438
  commandMinimumSupported: [
package/dist/index.mjs CHANGED
@@ -356,10 +356,13 @@ var SDK_RELEASE = {
356
356
  // silently materializing them as unmatched results.
357
357
  // 0.1.220 deprecates SDK CLI versions below 0.1.219 and updates them
358
358
  // automatically without blocking their current command.
359
- version: "0.1.240",
360
- apiContract: "2026-06-dataset-handle-results-hard-cutover",
359
+ // 0.1.241 hard-cuts published and launched plays to immutable cjs_node20
360
+ // artifacts. Older clients can submit esm_workers artifacts that the Absurd
361
+ // runtime intentionally no longer compiles at publish or launch time.
362
+ version: "0.1.242",
363
+ apiContract: "2026-07-immutable-cjs-play-artifacts-hard-cutover",
361
364
  supportPolicy: {
362
- latest: "0.1.240",
365
+ latest: "0.1.242",
363
366
  minimumSupported: "0.1.53",
364
367
  deprecatedBelow: "0.1.219",
365
368
  commandMinimumSupported: [
@@ -80,6 +80,8 @@ var PRIVATE_KEY_PATTERN = /-----BEGIN (?:RSA |EC |OPENSSH |PGP )?PRIVATE KEY----
80
80
  var BEARER_LITERAL_PATTERN = /\bBearer\s+[A-Za-z0-9._~+/=-]{16,}/i;
81
81
  var ASSIGNMENT_SECRET_LITERAL_PATTERN = /\b(?:api[_-]?key|token|secret|password)\b\s*[:=]\s*['"][^'"]{12,}['"]/i;
82
82
  var HIGH_ENTROPY_LITERAL_PATTERN = /['"]([A-Za-z0-9+/=_-]{32,})['"]/g;
83
+ var UUID_IDENTIFIER_PATTERN = /^((?:[A-Za-z0-9]+[-_])*)?([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
84
+ var SECRET_LABEL_PATTERN = /(?:^|[-_])(?:api|auth|access|secret|token|key|password|credential|bearer|sk|pk|live)(?:[-_]|$)/i;
83
85
  function shannonEntropy(value) {
84
86
  const counts = /* @__PURE__ */ new Map();
85
87
  for (const char of value) counts.set(char, (counts.get(char) ?? 0) + 1);
@@ -88,6 +90,12 @@ function shannonEntropy(value) {
88
90
  return entropy - p * Math.log2(p);
89
91
  }, 0);
90
92
  }
93
+ function isNonSecretUuidIdentifier(value) {
94
+ const match = UUID_IDENTIFIER_PATTERN.exec(value);
95
+ if (!match) return false;
96
+ const label = match[1] ?? "";
97
+ return !SECRET_LABEL_PATTERN.test(label);
98
+ }
91
99
  function collectInlineSecretFindings(sourceCode) {
92
100
  const findings = [];
93
101
  for (const match of sourceCode.matchAll(SECRET_ENV_PATTERN)) {
@@ -101,6 +109,7 @@ function collectInlineSecretFindings(sourceCode) {
101
109
  }
102
110
  for (const match of sourceCode.matchAll(HIGH_ENTROPY_LITERAL_PATTERN)) {
103
111
  const literal = match[1] ?? "";
112
+ if (isNonSecretUuidIdentifier(literal)) continue;
104
113
  if (literal.length >= 40 && shannonEntropy(literal) >= 4.2) {
105
114
  findings.push("high-entropy string literal");
106
115
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.1.240",
3
+ "version": "0.1.242",
4
4
  "description": "Deepline SDK + CLI — B2B data enrichment powered by durable cloud execution",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -62,6 +62,6 @@
62
62
  "typescript": "^5.9.3"
63
63
  },
64
64
  "deepline": {
65
- "apiContract": "2026-06-dataset-handle-results-hard-cutover"
65
+ "apiContract": "2026-07-immutable-cjs-play-artifacts-hard-cutover"
66
66
  }
67
67
  }