deepline 0.3.31 → 0.3.32

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.
@@ -192,7 +192,7 @@ export const SDK_RELEASE = {
192
192
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
193
193
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
194
194
  // getters keep their established compatibility behavior.
195
- version: '0.3.31',
195
+ version: '0.3.32',
196
196
  updateSummary:
197
197
  'New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.',
198
198
  contracts: {
@@ -49,7 +49,10 @@ import {
49
49
  PLAY_RUNTIME_TEST_FAULT_HEADER,
50
50
  recognizedRuntimeTestFaultCount,
51
51
  } from '@shared_libs/play-runtime/test-runtime-seams';
52
- import { vercelProtectionBypassHeaders } from '@shared_libs/play-runtime/vercel-protection';
52
+ import {
53
+ isVercelSecurityCheckpointResponse,
54
+ vercelProtectionBypassHeaders,
55
+ } from '@shared_libs/play-runtime/vercel-protection';
53
56
  import type { RuntimeReceiptAction } from '@shared_libs/play-runtime/runtime-actions';
54
57
  import { RUNTIME_CAPACITY_POLICY } from '@shared_libs/play-runtime/runtime-capacity-policy';
55
58
  import { RUNTIME_RELIABILITY_POLICY } from '@shared_libs/play-runtime/runtime-reliability-policy';
@@ -478,10 +481,20 @@ function isRetryableAppRuntimeResponse(input: {
478
481
  action: RuntimeApiRequest['action'];
479
482
  status: number;
480
483
  body: string;
484
+ contentType: string | null;
481
485
  }): boolean {
482
486
  if (!isRetryableAppRuntimeAction(input.action)) {
483
487
  return false;
484
488
  }
489
+ // A WAF checkpoint is not a statement from the app about the idempotent
490
+ // projection. Do not make every 403 retryable: only this exact Vercel HTML
491
+ // response on a replay-safe action is an intermediary failure.
492
+ if (
493
+ input.action === 'append_run_events' &&
494
+ isVercelSecurityCheckpointResponse(input)
495
+ ) {
496
+ return true;
497
+ }
485
498
  // The app runtime may explicitly classify an otherwise-client-error status
486
499
  // as transient. Keep the structured delivery contract authoritative rather
487
500
  // than reducing every 4xx to permanent at the worker boundary.
@@ -1273,6 +1286,7 @@ async function postAppRuntimeApi<TResponse>(
1273
1286
  action: body.action,
1274
1287
  status: response.status,
1275
1288
  body: responseText,
1289
+ contentType: response.headers.get('content-type'),
1276
1290
  })
1277
1291
  ) {
1278
1292
  const retryDelayMs = Math.max(
@@ -1299,6 +1313,7 @@ async function postAppRuntimeApi<TResponse>(
1299
1313
  action: body.action,
1300
1314
  status: response.status,
1301
1315
  body: responseText,
1316
+ contentType: response.headers.get('content-type'),
1302
1317
  })
1303
1318
  ? 'retryable_http'
1304
1319
  : 'http_error',
@@ -1328,6 +1343,7 @@ async function postAppRuntimeApi<TResponse>(
1328
1343
  action: body.action,
1329
1344
  status: response.status,
1330
1345
  body: responseText,
1346
+ contentType: response.headers.get('content-type'),
1331
1347
  }),
1332
1348
  detail: summarizeAppRuntimeErrorBody(responseText),
1333
1349
  boundaryLabel,
@@ -1,6 +1,7 @@
1
1
  type FetchLike = typeof fetch;
2
2
 
3
3
  const vercelProtectionCookieCache = new Map<string, Promise<string | null>>();
4
+ const VERCEL_PROTECTION_COOKIE_PREFLIGHT_TIMEOUT_MS = 5_000;
4
5
 
5
6
  async function awaitWithSignal<T>(
6
7
  promise: Promise<T>,
@@ -45,6 +46,25 @@ export function vercelProtectionBypassHeader(
45
46
  return normalized ? { 'x-vercel-protection-bypass': normalized } : {};
46
47
  }
47
48
 
49
+ /**
50
+ * A Vercel Firewall checkpoint is a transport/intermediary response, not an
51
+ * application authorization decision. Keep this deliberately narrow: callers
52
+ * still decide which replay-safe internal action may retry it.
53
+ */
54
+ export function isVercelSecurityCheckpointResponse(input: {
55
+ status: number;
56
+ contentType: string | null | undefined;
57
+ body: string;
58
+ }): boolean {
59
+ if (input.status !== 403) return false;
60
+ if (!/^text\/html(?:\s*;|$)/i.test(input.contentType?.trim() ?? '')) {
61
+ return false;
62
+ }
63
+ return /<title\b[^>]*>\s*Vercel Security Checkpoint\s*<\/title>/i.test(
64
+ input.body,
65
+ );
66
+ }
67
+
48
68
  function setCookieHeaders(headers: Headers): string[] {
49
69
  const getter = (headers as Headers & { getSetCookie?: () => string[] })
50
70
  .getSetCookie;
@@ -75,14 +95,27 @@ export async function resolveVercelProtectionBypassCookie(input: {
75
95
 
76
96
  const cacheKey = `${baseUrl}\n${token}`;
77
97
  const cached = vercelProtectionCookieCache.get(cacheKey);
78
- if (cached) return await awaitWithSignal(cached, input.signal);
98
+ if (cached) {
99
+ try {
100
+ return await awaitWithSignal(cached, input.signal);
101
+ } catch (error) {
102
+ if (input.signal?.aborted) throw input.signal.reason ?? error;
103
+ // A concurrent caller must retain the same header-only fallback as the
104
+ // caller that created the shared preflight promise.
105
+ return null;
106
+ }
107
+ }
79
108
 
80
109
  const promise = (async () => {
81
110
  const url = new URL(`${baseUrl}/api/v2/health`);
82
111
  addVercelProtectionBypassSearchParams(url, token);
112
+ // Keep the cache independent from an individual outbox lease. A caller
113
+ // may stop waiting, but the shared bootstrap is always bounded and either
114
+ // supplies a reusable cookie or evicts itself for a later retry.
83
115
  const response = await (input.fetchImpl ?? fetch)(url.toString(), {
84
116
  headers: { 'x-vercel-protection-bypass': token },
85
- }).catch(() => null);
117
+ signal: AbortSignal.timeout(VERCEL_PROTECTION_COOKIE_PREFLIGHT_TIMEOUT_MS),
118
+ });
86
119
  return response ? cookieHeaderFromSetCookie(response.headers) : null;
87
120
  })();
88
121
  vercelProtectionCookieCache.set(cacheKey, promise);
@@ -91,7 +124,15 @@ export async function resolveVercelProtectionBypassCookie(input: {
91
124
  vercelProtectionCookieCache.delete(cacheKey);
92
125
  }
93
126
  });
94
- return await awaitWithSignal(promise, input.signal);
127
+ try {
128
+ return await awaitWithSignal(promise, input.signal);
129
+ } catch (error) {
130
+ if (input.signal?.aborted) throw input.signal.reason ?? error;
131
+ // The header-only bypass remains useful when cookie bootstrap is briefly
132
+ // unavailable; do not turn a bounded preflight failure into a permanent
133
+ // delivery failure. The rejection handler above evicts this cache entry.
134
+ return null;
135
+ }
95
136
  }
96
137
 
97
138
  export async function vercelProtectionBypassHeaders(input: {
package/dist/cli/index.js CHANGED
@@ -1042,7 +1042,7 @@ var SDK_RELEASE = {
1042
1042
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
1043
1043
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1044
1044
  // getters keep their established compatibility behavior.
1045
- version: "0.3.31",
1045
+ version: "0.3.32",
1046
1046
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
1047
1047
  contracts: {
1048
1048
  api: {
@@ -34243,9 +34243,10 @@ Notes:
34243
34243
  for a patch-style change.
34244
34244
  Repeating the exact saved definition resumes an incomplete deploy cleanup:
34245
34245
  Deepline keeps the replacement, removes only the stored previous binding after
34246
- provider confirmation, and never creates or charges another monitor. Deepline
34247
- also retries eligible incomplete deploy cleanups automatically in bounded
34248
- background passes; no separate repair command is required.
34246
+ provider confirmation, and never creates or charges another monitor. There is
34247
+ no separate repair command or retry queue: rerun the same deploy/update.
34248
+ Scheduled reconciliation can also finish that exact saved cleanup; it never
34249
+ creates another monitor.
34249
34250
  For a bounded urgent Deepline Native preview, set
34250
34251
  controls.execution_type="priority". Deepline injects the provider custom
34251
34252
  field and enforces a ten-slot per-org cap; do not use it for regular or bulk
@@ -1028,7 +1028,7 @@ var SDK_RELEASE = {
1028
1028
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
1029
1029
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
1030
1030
  // getters keep their established compatibility behavior.
1031
- version: "0.3.31",
1031
+ version: "0.3.32",
1032
1032
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
1033
1033
  contracts: {
1034
1034
  api: {
@@ -34313,9 +34313,10 @@ Notes:
34313
34313
  for a patch-style change.
34314
34314
  Repeating the exact saved definition resumes an incomplete deploy cleanup:
34315
34315
  Deepline keeps the replacement, removes only the stored previous binding after
34316
- provider confirmation, and never creates or charges another monitor. Deepline
34317
- also retries eligible incomplete deploy cleanups automatically in bounded
34318
- background passes; no separate repair command is required.
34316
+ provider confirmation, and never creates or charges another monitor. There is
34317
+ no separate repair command or retry queue: rerun the same deploy/update.
34318
+ Scheduled reconciliation can also finish that exact saved cleanup; it never
34319
+ creates another monitor.
34319
34320
  For a bounded urgent Deepline Native preview, set
34320
34321
  controls.execution_type="priority". Deepline injects the provider custom
34321
34322
  field and enforces a ten-slot per-org cap; do not use it for regular or bulk
package/dist/index.js CHANGED
@@ -778,7 +778,7 @@ var SDK_RELEASE = {
778
778
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
779
779
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
780
780
  // getters keep their established compatibility behavior.
781
- version: "0.3.31",
781
+ version: "0.3.32",
782
782
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
783
783
  contracts: {
784
784
  api: {
package/dist/index.mjs CHANGED
@@ -701,7 +701,7 @@ var SDK_RELEASE = {
701
701
  // 0.3.0 introduces raw-v2: complete scrubbed provider responses are
702
702
  // available at toolResponse.rawV2 while toolResponse.raw and all declared
703
703
  // getters keep their established compatibility behavior.
704
- version: "0.3.31",
704
+ version: "0.3.32",
705
705
  updateSummary: "New raw-v2 tool responses preserve complete scrubbed provider envelopes at toolResponse.rawV2, including JSON:API included resources, links, cursors, and totals. Existing toolResponse.raw and declared getters keep working unchanged.",
706
706
  contracts: {
707
707
  api: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepline",
3
- "version": "0.3.31",
3
+ "version": "0.3.32",
4
4
  "description": "GTM data CLI and TypeScript SDK for coding agents",
5
5
  "license": "MIT",
6
6
  "homepage": "https://code.deepline.com",