run402 4.129.1 → 4.130.0

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.
Files changed (35) hide show
  1. package/lib/assets.mjs +36 -18
  2. package/lib/auth.mjs +48 -1
  3. package/lib/command-manifest.mjs +2 -1
  4. package/lib/deploy-v2.mjs +15 -8
  5. package/lib/dev.mjs +28 -7
  6. package/package.json +1 -1
  7. package/sdk/dist/errors.d.ts +8 -0
  8. package/sdk/dist/errors.d.ts.map +1 -1
  9. package/sdk/dist/errors.js +16 -0
  10. package/sdk/dist/errors.js.map +1 -1
  11. package/sdk/dist/namespaces/assets.d.ts +7 -1
  12. package/sdk/dist/namespaces/assets.d.ts.map +1 -1
  13. package/sdk/dist/namespaces/assets.js +39 -1
  14. package/sdk/dist/namespaces/assets.js.map +1 -1
  15. package/sdk/dist/namespaces/assets.types.d.ts +37 -0
  16. package/sdk/dist/namespaces/assets.types.d.ts.map +1 -1
  17. package/sdk/dist/namespaces/assets.types.js +2 -0
  18. package/sdk/dist/namespaces/assets.types.js.map +1 -1
  19. package/sdk/dist/namespaces/auth.d.ts +20 -0
  20. package/sdk/dist/namespaces/auth.d.ts.map +1 -1
  21. package/sdk/dist/namespaces/auth.js +20 -0
  22. package/sdk/dist/namespaces/auth.js.map +1 -1
  23. package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
  24. package/sdk/dist/namespaces/deploy.js +92 -16
  25. package/sdk/dist/namespaces/deploy.js.map +1 -1
  26. package/sdk/dist/node/paid-fetch.js +2 -2
  27. package/sdk/dist/node/paid-fetch.js.map +1 -1
  28. package/sdk/dist/node/vault-degraded-read.d.ts.map +1 -1
  29. package/sdk/dist/node/vault-degraded-read.js +4 -8
  30. package/sdk/dist/node/vault-degraded-read.js.map +1 -1
  31. package/sdk/dist/scoped.d.ts +4 -2
  32. package/sdk/dist/scoped.d.ts.map +1 -1
  33. package/sdk/dist/scoped.js +6 -0
  34. package/sdk/dist/scoped.js.map +1 -1
  35. package/vault-surface.json +1 -1
@@ -24,7 +24,7 @@ import { isGrantKeyCredentials } from "../grant-key-credentials.js";
24
24
  import { isKnownBinaryContent, isUtf8StringSource } from "../validation.js";
25
25
  import { assertCiDeployableSpec } from "./ci.js";
26
26
  import { ROUTE_PRICING_NETWORKS, ROUTE_HTTP_METHODS, isModernPlanMigrationDiff, normalizeDeployResolveRequest, } from "./deploy.types.js";
27
- import { ApiError, LocalError, NetworkError, PaymentRequired, Run402DeployError, Unauthorized, isRun402Error, isTransferFreezeError, } from "../errors.js";
27
+ import { ApiError, LocalError, PaymentRequired, Run402DeployError, Unauthorized, isNoResponseError, isRun402Error, isTransferFreezeError, } from "../errors.js";
28
28
  import { assertAssetMetadata, assertExifPolicy, } from "./assets-validation.js";
29
29
  import { withSiteRemovalSummaries } from "./site-removal-summary.js";
30
30
  // ─── Constants ───────────────────────────────────────────────────────────────
@@ -85,18 +85,22 @@ const STATIC_FUNCTION_LIMITS_BY_TIER = {
85
85
  prototype: {
86
86
  maxTimeoutSeconds: 10,
87
87
  maxMemoryMb: 128,
88
+ maxSsrMemoryMb: 128,
88
89
  maxScheduledFunctions: 1,
89
90
  minCronIntervalMinutes: 15,
90
91
  },
91
92
  hobby: {
92
93
  maxTimeoutSeconds: 30,
93
94
  maxMemoryMb: 256,
95
+ maxSsrMemoryMb: 256,
94
96
  maxScheduledFunctions: 3,
95
97
  minCronIntervalMinutes: 5,
96
98
  },
97
99
  team: {
98
100
  maxTimeoutSeconds: 60,
99
101
  maxMemoryMb: 512,
102
+ // An SSR-class function (the Astro `ssr` function) may use one vCPU.
103
+ maxSsrMemoryMb: 1769,
100
104
  maxScheduledFunctions: 10,
101
105
  minCronIntervalMinutes: 1,
102
106
  },
@@ -1353,12 +1357,19 @@ async function preflightTierFunctionLimits(client, spec, ciCredentials) {
1353
1357
  });
1354
1358
  }
1355
1359
  const memory = entry.fn.config?.memoryMb;
1360
+ // An SSR-class function has its own cap. With no class declared the
1361
+ // function keeps its stored one, which only the gateway knows.
1362
+ const memoryLimit = entry.fn.class === "ssr"
1363
+ ? limits.maxSsrMemoryMb ?? limits.maxMemoryMb
1364
+ : entry.fn.class === undefined
1365
+ ? largerLimit(limits.maxMemoryMb, limits.maxSsrMemoryMb)
1366
+ : limits.maxMemoryMb;
1356
1367
  if (memory !== undefined &&
1357
- limits.maxMemoryMb &&
1358
- memory > limits.maxMemoryMb.value) {
1359
- throw tierLimitError(`Function ${entry.name} memoryMb ${memory} exceeds the ${limits.tier} tier maximum of ${limits.maxMemoryMb.value}.`, `${entry.fieldPrefix}.config.memoryMb`, memory, limits, limits.maxMemoryMb, {
1360
- tier_max: limits.maxMemoryMb.value,
1361
- max_function_memory_mb: limits.maxMemoryMb.value,
1368
+ memoryLimit &&
1369
+ memory > memoryLimit.value) {
1370
+ throw tierLimitError(`Function ${entry.name} memoryMb ${memory} exceeds the ${limits.tier} tier maximum of ${memoryLimit.value}.`, `${entry.fieldPrefix}.config.memoryMb`, memory, limits, memoryLimit, {
1371
+ tier_max: memoryLimit.value,
1372
+ max_function_memory_mb: memoryLimit.value,
1362
1373
  });
1363
1374
  }
1364
1375
  for (const trigger of scheduleTriggersForFunction(entry.fn)) {
@@ -1387,6 +1398,13 @@ async function preflightTierFunctionLimits(client, spec, ciCredentials) {
1387
1398
  }
1388
1399
  }
1389
1400
  }
1401
+ function largerLimit(a, b) {
1402
+ if (!a)
1403
+ return b;
1404
+ if (!b)
1405
+ return a;
1406
+ return b.value > a.value ? b : a;
1407
+ }
1390
1408
  function hasFunctionTierPreflightInputs(functions) {
1391
1409
  if (!functions)
1392
1410
  return false;
@@ -1434,6 +1452,9 @@ async function readTierFunctionLimits(client) {
1434
1452
  "memory_mb_max",
1435
1453
  "function_memory_mb_max",
1436
1454
  ], fallback?.maxMemoryMb);
1455
+ // tier status names no SSR memory cap, so it comes from the static table.
1456
+ if (fallback)
1457
+ limits.maxSsrMemoryMb = { value: fallback.maxSsrMemoryMb, source: "local_static_fallback" };
1437
1458
  limits.maxScheduledFunctions = tierStatusLimitOrFallback(status, [
1438
1459
  "max_scheduled_functions",
1439
1460
  "scheduled_functions_limit",
@@ -1895,7 +1916,7 @@ async function requestWithTransientRetry(send) {
1895
1916
  function isTransientGatewayFailure(err) {
1896
1917
  if (!isRun402Error(err))
1897
1918
  return false;
1898
- if (err.kind === "network_error")
1919
+ if (isNoResponseError(err))
1899
1920
  return true;
1900
1921
  return err.status === 502 || err.status === 503 || err.status === 504;
1901
1922
  }
@@ -4544,15 +4565,8 @@ function translateDeployError(err, phase, planId, operationId) {
4544
4565
  context: err.context,
4545
4566
  });
4546
4567
  }
4547
- if (err instanceof NetworkError) {
4548
- return new Run402DeployError(err.message, {
4549
- code: "NETWORK_ERROR",
4550
- phase,
4551
- retryable: true,
4552
- operationId,
4553
- planId,
4554
- context: phase,
4555
- });
4568
+ if (isNoResponseError(err)) {
4569
+ return noResponseDeployError(err, phase, planId, operationId);
4556
4570
  }
4557
4571
  // Re-throw other Run402Error subclasses (PaymentRequired, Unauthorized, etc.)
4558
4572
  // as-is — the consumer handles them at a different layer than
@@ -4579,6 +4593,68 @@ function translateDeployError(err, phase, planId, operationId) {
4579
4593
  context: phase,
4580
4594
  });
4581
4595
  }
4596
+ /**
4597
+ * A deploy request that got no response: the connection failed or the client
4598
+ * gave up waiting (Node's fetch stops waiting for response headers after
4599
+ * 300 s). For a commit that is not a failed deploy: the gateway may still be
4600
+ * running the operation, and committing the plan again is safe (a plan commits
4601
+ * once), so the error says so and points at the operation.
4602
+ */
4603
+ function noResponseDeployError(err, phase, planId, operationId) {
4604
+ const transportCode = noResponseTransportCode(err);
4605
+ const cause = transportCode ? ` (${transportCode})` : "";
4606
+ const isCommit = phase === "commit";
4607
+ const message = isCommit
4608
+ ? `The deploy commit got no response from the API${cause}. The deploy may still be running on the gateway${operationId ? ` as operation ${operationId}` : ""}; nothing failed that is known. Check the operation, or commit the same plan again: a plan commits once, so a repeat follows the running deploy.`
4609
+ : `The deploy request (${phase}) got no response from the API${cause}. Repeating it is safe.`;
4610
+ const nextActions = [];
4611
+ if (operationId) {
4612
+ nextActions.push({
4613
+ type: "poll",
4614
+ method: "GET",
4615
+ path: `/apply/v1/operations/${operationId}`,
4616
+ command: `run402 deploy status ${operationId}`,
4617
+ safe_to_auto_execute: true,
4618
+ why: "Read the operation to learn whether the deploy is still running, finished, or failed.",
4619
+ });
4620
+ }
4621
+ nextActions.push({
4622
+ type: "retry",
4623
+ safe_to_auto_execute: true,
4624
+ why: isCommit
4625
+ ? "Committing the same plan again cannot run the deploy twice: it attaches to the running operation or returns its stored result."
4626
+ : "The request got no response; repeating it is safe.",
4627
+ });
4628
+ return new Run402DeployError(message, {
4629
+ code: "NETWORK_ERROR",
4630
+ phase,
4631
+ retryable: true,
4632
+ operationId,
4633
+ planId,
4634
+ context: phase,
4635
+ body: {
4636
+ code: "NETWORK_ERROR",
4637
+ category: "network",
4638
+ retryable: true,
4639
+ safe_to_retry: true,
4640
+ mutation_state: isCommit ? "unknown" : "none",
4641
+ details: {
4642
+ ...(transportCode ? { transport_code: transportCode } : {}),
4643
+ ...(operationId ? { operation_id: operationId } : {}),
4644
+ },
4645
+ next_actions: nextActions,
4646
+ },
4647
+ });
4648
+ }
4649
+ function noResponseTransportCode(err) {
4650
+ const details = err.details;
4651
+ if (details && typeof details === "object" && !Array.isArray(details)) {
4652
+ const code = details.transport_code;
4653
+ if (typeof code === "string")
4654
+ return code;
4655
+ }
4656
+ return null;
4657
+ }
4582
4658
  function extractGatewayError(body) {
4583
4659
  // Gateway returns the error in any of:
4584
4660
  // { error: { code, message?, phase?, ... } } — nested