run402 4.129.1 → 4.130.1
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/lib/assets.mjs +36 -18
- package/lib/auth.mjs +48 -1
- package/lib/command-manifest.mjs +2 -1
- package/lib/deploy-v2.mjs +15 -8
- package/lib/dev.mjs +28 -7
- package/lib/init-astro.mjs +2 -2
- package/package.json +1 -1
- package/sdk/dist/errors.d.ts +8 -0
- package/sdk/dist/errors.d.ts.map +1 -1
- package/sdk/dist/errors.js +16 -0
- package/sdk/dist/errors.js.map +1 -1
- package/sdk/dist/namespaces/assets.d.ts +7 -1
- package/sdk/dist/namespaces/assets.d.ts.map +1 -1
- package/sdk/dist/namespaces/assets.js +39 -1
- package/sdk/dist/namespaces/assets.js.map +1 -1
- package/sdk/dist/namespaces/assets.types.d.ts +37 -0
- package/sdk/dist/namespaces/assets.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/assets.types.js +2 -0
- package/sdk/dist/namespaces/assets.types.js.map +1 -1
- package/sdk/dist/namespaces/auth.d.ts +20 -0
- package/sdk/dist/namespaces/auth.d.ts.map +1 -1
- package/sdk/dist/namespaces/auth.js +20 -0
- package/sdk/dist/namespaces/auth.js.map +1 -1
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +117 -18
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/node/paid-fetch.js +2 -2
- package/sdk/dist/node/paid-fetch.js.map +1 -1
- package/sdk/dist/node/vault-degraded-read.d.ts.map +1 -1
- package/sdk/dist/node/vault-degraded-read.js +4 -8
- package/sdk/dist/node/vault-degraded-read.js.map +1 -1
- package/sdk/dist/scoped.d.ts +4 -2
- package/sdk/dist/scoped.d.ts.map +1 -1
- package/sdk/dist/scoped.js +6 -0
- package/sdk/dist/scoped.js.map +1 -1
- 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,
|
|
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
|
},
|
|
@@ -1338,7 +1342,7 @@ async function preflightTierFunctionLimits(client, spec, ciCredentials) {
|
|
|
1338
1342
|
return;
|
|
1339
1343
|
if (!hasFunctionTierPreflightInputs(spec.functions))
|
|
1340
1344
|
return;
|
|
1341
|
-
const limits = await readTierFunctionLimits(client);
|
|
1345
|
+
const limits = await readTierFunctionLimits(client, spec.project_id);
|
|
1342
1346
|
if (!limits)
|
|
1343
1347
|
return;
|
|
1344
1348
|
const entries = collectFunctionPreflightEntries(spec.functions);
|
|
@@ -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
|
-
|
|
1358
|
-
memory >
|
|
1359
|
-
throw tierLimitError(`Function ${entry.name} memoryMb ${memory} exceeds the ${limits.tier} tier maximum of ${
|
|
1360
|
-
tier_max:
|
|
1361
|
-
max_function_memory_mb:
|
|
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;
|
|
@@ -1406,7 +1424,14 @@ function collectFunctionPreflightEntries(functions) {
|
|
|
1406
1424
|
}
|
|
1407
1425
|
return entries;
|
|
1408
1426
|
}
|
|
1409
|
-
|
|
1427
|
+
/**
|
|
1428
|
+
* The function caps of the tier the deploy is judged by: the tier of the
|
|
1429
|
+
* organization that owns the project. `/tiers/v1/status` describes the
|
|
1430
|
+
* wallet's own organization, so its caps count only when the project's tier
|
|
1431
|
+
* is the same; otherwise the static table for the project's tier applies.
|
|
1432
|
+
* When the project cannot be read, the wallet's own tier is used.
|
|
1433
|
+
*/
|
|
1434
|
+
async function readTierFunctionLimits(client, projectId) {
|
|
1410
1435
|
let status;
|
|
1411
1436
|
try {
|
|
1412
1437
|
status = await client.request("/tiers/v1/status", {
|
|
@@ -1416,6 +1441,10 @@ async function readTierFunctionLimits(client) {
|
|
|
1416
1441
|
catch {
|
|
1417
1442
|
return null;
|
|
1418
1443
|
}
|
|
1444
|
+
const projectTier = await readProjectTier(client, projectId);
|
|
1445
|
+
if (projectTier && projectTier.toLowerCase() !== String(status.tier ?? "").toLowerCase()) {
|
|
1446
|
+
status = { tier: projectTier };
|
|
1447
|
+
}
|
|
1419
1448
|
if (typeof status.tier !== "string" || status.tier.length === 0) {
|
|
1420
1449
|
return null;
|
|
1421
1450
|
}
|
|
@@ -1434,6 +1463,9 @@ async function readTierFunctionLimits(client) {
|
|
|
1434
1463
|
"memory_mb_max",
|
|
1435
1464
|
"function_memory_mb_max",
|
|
1436
1465
|
], fallback?.maxMemoryMb);
|
|
1466
|
+
// tier status names no SSR memory cap, so it comes from the static table.
|
|
1467
|
+
if (fallback)
|
|
1468
|
+
limits.maxSsrMemoryMb = { value: fallback.maxSsrMemoryMb, source: "local_static_fallback" };
|
|
1437
1469
|
limits.maxScheduledFunctions = tierStatusLimitOrFallback(status, [
|
|
1438
1470
|
"max_scheduled_functions",
|
|
1439
1471
|
"scheduled_functions_limit",
|
|
@@ -1454,6 +1486,18 @@ async function readTierFunctionLimits(client) {
|
|
|
1454
1486
|
]);
|
|
1455
1487
|
return hasAnyTierFunctionLimit(limits) ? limits : null;
|
|
1456
1488
|
}
|
|
1489
|
+
async function readProjectTier(client, projectId) {
|
|
1490
|
+
try {
|
|
1491
|
+
const project = await client.request(`/projects/v1/${encodeURIComponent(projectId)}`, {
|
|
1492
|
+
method: "GET",
|
|
1493
|
+
context: "checking the project's tier for deploy preflight",
|
|
1494
|
+
});
|
|
1495
|
+
return typeof project.tier === "string" && project.tier.length > 0 ? project.tier : null;
|
|
1496
|
+
}
|
|
1497
|
+
catch {
|
|
1498
|
+
return null;
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1457
1501
|
function tierStatusLimitOrFallback(status, keys, fallback) {
|
|
1458
1502
|
return tierStatusLimit(status, keys) ?? (fallback === undefined
|
|
1459
1503
|
? undefined
|
|
@@ -1895,7 +1939,7 @@ async function requestWithTransientRetry(send) {
|
|
|
1895
1939
|
function isTransientGatewayFailure(err) {
|
|
1896
1940
|
if (!isRun402Error(err))
|
|
1897
1941
|
return false;
|
|
1898
|
-
if (err
|
|
1942
|
+
if (isNoResponseError(err))
|
|
1899
1943
|
return true;
|
|
1900
1944
|
return err.status === 502 || err.status === 503 || err.status === 504;
|
|
1901
1945
|
}
|
|
@@ -4544,15 +4588,8 @@ function translateDeployError(err, phase, planId, operationId) {
|
|
|
4544
4588
|
context: err.context,
|
|
4545
4589
|
});
|
|
4546
4590
|
}
|
|
4547
|
-
if (err
|
|
4548
|
-
return
|
|
4549
|
-
code: "NETWORK_ERROR",
|
|
4550
|
-
phase,
|
|
4551
|
-
retryable: true,
|
|
4552
|
-
operationId,
|
|
4553
|
-
planId,
|
|
4554
|
-
context: phase,
|
|
4555
|
-
});
|
|
4591
|
+
if (isNoResponseError(err)) {
|
|
4592
|
+
return noResponseDeployError(err, phase, planId, operationId);
|
|
4556
4593
|
}
|
|
4557
4594
|
// Re-throw other Run402Error subclasses (PaymentRequired, Unauthorized, etc.)
|
|
4558
4595
|
// as-is — the consumer handles them at a different layer than
|
|
@@ -4579,6 +4616,68 @@ function translateDeployError(err, phase, planId, operationId) {
|
|
|
4579
4616
|
context: phase,
|
|
4580
4617
|
});
|
|
4581
4618
|
}
|
|
4619
|
+
/**
|
|
4620
|
+
* A deploy request that got no response: the connection failed or the client
|
|
4621
|
+
* gave up waiting (Node's fetch stops waiting for response headers after
|
|
4622
|
+
* 300 s). For a commit that is not a failed deploy: the gateway may still be
|
|
4623
|
+
* running the operation, and committing the plan again is safe (a plan commits
|
|
4624
|
+
* once), so the error says so and points at the operation.
|
|
4625
|
+
*/
|
|
4626
|
+
function noResponseDeployError(err, phase, planId, operationId) {
|
|
4627
|
+
const transportCode = noResponseTransportCode(err);
|
|
4628
|
+
const cause = transportCode ? ` (${transportCode})` : "";
|
|
4629
|
+
const isCommit = phase === "commit";
|
|
4630
|
+
const message = isCommit
|
|
4631
|
+
? `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.`
|
|
4632
|
+
: `The deploy request (${phase}) got no response from the API${cause}. Repeating it is safe.`;
|
|
4633
|
+
const nextActions = [];
|
|
4634
|
+
if (operationId) {
|
|
4635
|
+
nextActions.push({
|
|
4636
|
+
type: "poll",
|
|
4637
|
+
method: "GET",
|
|
4638
|
+
path: `/apply/v1/operations/${operationId}`,
|
|
4639
|
+
command: `run402 deploy status ${operationId}`,
|
|
4640
|
+
safe_to_auto_execute: true,
|
|
4641
|
+
why: "Read the operation to learn whether the deploy is still running, finished, or failed.",
|
|
4642
|
+
});
|
|
4643
|
+
}
|
|
4644
|
+
nextActions.push({
|
|
4645
|
+
type: "retry",
|
|
4646
|
+
safe_to_auto_execute: true,
|
|
4647
|
+
why: isCommit
|
|
4648
|
+
? "Committing the same plan again cannot run the deploy twice: it attaches to the running operation or returns its stored result."
|
|
4649
|
+
: "The request got no response; repeating it is safe.",
|
|
4650
|
+
});
|
|
4651
|
+
return new Run402DeployError(message, {
|
|
4652
|
+
code: "NETWORK_ERROR",
|
|
4653
|
+
phase,
|
|
4654
|
+
retryable: true,
|
|
4655
|
+
operationId,
|
|
4656
|
+
planId,
|
|
4657
|
+
context: phase,
|
|
4658
|
+
body: {
|
|
4659
|
+
code: "NETWORK_ERROR",
|
|
4660
|
+
category: "network",
|
|
4661
|
+
retryable: true,
|
|
4662
|
+
safe_to_retry: true,
|
|
4663
|
+
mutation_state: isCommit ? "unknown" : "none",
|
|
4664
|
+
details: {
|
|
4665
|
+
...(transportCode ? { transport_code: transportCode } : {}),
|
|
4666
|
+
...(operationId ? { operation_id: operationId } : {}),
|
|
4667
|
+
},
|
|
4668
|
+
next_actions: nextActions,
|
|
4669
|
+
},
|
|
4670
|
+
});
|
|
4671
|
+
}
|
|
4672
|
+
function noResponseTransportCode(err) {
|
|
4673
|
+
const details = err.details;
|
|
4674
|
+
if (details && typeof details === "object" && !Array.isArray(details)) {
|
|
4675
|
+
const code = details.transport_code;
|
|
4676
|
+
if (typeof code === "string")
|
|
4677
|
+
return code;
|
|
4678
|
+
}
|
|
4679
|
+
return null;
|
|
4680
|
+
}
|
|
4582
4681
|
function extractGatewayError(body) {
|
|
4583
4682
|
// Gateway returns the error in any of:
|
|
4584
4683
|
// { error: { code, message?, phase?, ... } } — nested
|