run402-mcp 3.5.4 → 3.5.6
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/README.md +1 -1
- package/core/dist/config.d.ts +19 -0
- package/core/dist/config.d.ts.map +1 -1
- package/core/dist/config.js +103 -4
- package/core/dist/config.js.map +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +2 -1
- package/dist/sdk.js.map +1 -1
- package/package.json +3 -3
- package/schemas/release-spec.v1.json +29 -2
- package/sdk/README.md +30 -1
- package/sdk/core-dist/config.d.ts +19 -0
- package/sdk/core-dist/config.js +103 -4
- package/sdk/dist/namespaces/deploy.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.js +281 -21
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +16 -1
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.types.js.map +1 -1
- package/sdk/dist/namespaces/projects.d.ts.map +1 -1
- package/sdk/dist/namespaces/projects.js +1 -0
- package/sdk/dist/namespaces/projects.js.map +1 -1
- package/sdk/dist/namespaces/projects.types.d.ts +7 -0
- package/sdk/dist/namespaces/projects.types.d.ts.map +1 -1
- package/sdk/dist/node/deploy-manifest.d.ts +5 -3
- package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
- package/sdk/dist/node/deploy-manifest.js +16 -2
- package/sdk/dist/node/deploy-manifest.js.map +1 -1
- package/sdk/dist/node/index.d.ts +2 -0
- package/sdk/dist/node/index.d.ts.map +1 -1
- package/sdk/dist/node/index.js +1 -0
- package/sdk/dist/node/index.js.map +1 -1
- package/sdk/dist/node/target-profile.d.ts +40 -0
- package/sdk/dist/node/target-profile.d.ts.map +1 -0
- package/sdk/dist/node/target-profile.js +98 -0
- package/sdk/dist/node/target-profile.js.map +1 -0
|
@@ -166,7 +166,7 @@ export class Deploy {
|
|
|
166
166
|
*/
|
|
167
167
|
async commit(planId, opts = {}) {
|
|
168
168
|
const emit = makeEmitter(opts.onEvent);
|
|
169
|
-
const commit = await commitInternal(this.client, planId, opts.idempotencyKey, opts.project);
|
|
169
|
+
const commit = requireCloudCommitResponse(await commitInternal(this.client, planId, opts.idempotencyKey, opts.project), "committing deploy");
|
|
170
170
|
return await pollUntilReady(this.client, commit, {}, [], emit, opts.project);
|
|
171
171
|
}
|
|
172
172
|
/**
|
|
@@ -452,9 +452,10 @@ function deriveSliceKinds(spec) {
|
|
|
452
452
|
}
|
|
453
453
|
async function applyOnce(client, spec, opts, emit) {
|
|
454
454
|
const allowWarningCodes = normalizeAllowWarningCodes(opts.allowWarningCodes);
|
|
455
|
+
const target = opts.target === "core" ? "core" : "cloud";
|
|
455
456
|
const sliceKinds = deriveSliceKinds(spec);
|
|
456
457
|
emit({ type: "plan.started" });
|
|
457
|
-
const { plan, byteReaders } = await planInternal(client, spec, opts.idempotencyKey);
|
|
458
|
+
const { plan, byteReaders } = await planInternal(client, spec, opts.idempotencyKey, false, target);
|
|
458
459
|
emit({ type: "plan.diff", diff: plan.diff });
|
|
459
460
|
emitPlanWarnings(plan, emit);
|
|
460
461
|
abortOnConfirmationWarnings(plan, opts, allowWarningCodes);
|
|
@@ -471,6 +472,21 @@ async function applyOnce(client, spec, opts, emit) {
|
|
|
471
472
|
// sandbox provider without payment auto-handling can intercept the
|
|
472
473
|
// event and resolve before we hit upload.
|
|
473
474
|
}
|
|
475
|
+
if (target === "core") {
|
|
476
|
+
await uploadCoreContent(client, spec.project, byteReaders, emit);
|
|
477
|
+
emit({
|
|
478
|
+
type: "commit.phase",
|
|
479
|
+
phase: "validate",
|
|
480
|
+
status: "started",
|
|
481
|
+
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
482
|
+
});
|
|
483
|
+
const planId = requirePlanId(plan, "applying deploy to Core");
|
|
484
|
+
const commit = await commitInternal(client, planId, opts.idempotencyKey, spec.project);
|
|
485
|
+
if (!isCoreCommitResponse(commit)) {
|
|
486
|
+
return await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project, sliceKinds);
|
|
487
|
+
}
|
|
488
|
+
return await coreDeployResult(client, commit, plan.diff, plan.warnings, emit, spec.project, sliceKinds);
|
|
489
|
+
}
|
|
474
490
|
await uploadMissing(client, spec.project, plan.missing_content, byteReaders, emit);
|
|
475
491
|
emit({
|
|
476
492
|
type: "commit.phase",
|
|
@@ -479,7 +495,7 @@ async function applyOnce(client, spec, opts, emit) {
|
|
|
479
495
|
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
480
496
|
});
|
|
481
497
|
const { planId } = requirePersistedPlan(plan, "applying deploy");
|
|
482
|
-
const commit = await commitInternal(client, planId, opts.idempotencyKey, spec.project);
|
|
498
|
+
const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project), "applying deploy");
|
|
483
499
|
const result = await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project, sliceKinds);
|
|
484
500
|
// v1.48 unified-apply: thread the plan response's `asset_entries[]` back
|
|
485
501
|
// into DeployResult.assets so callers reading `result.assets.byKey[key]`
|
|
@@ -642,12 +658,39 @@ function contentRefToWire(ref) {
|
|
|
642
658
|
...(ref.integrity ? { integrity: ref.integrity } : {}),
|
|
643
659
|
};
|
|
644
660
|
}
|
|
661
|
+
function contentRefToCoreSpec(ref) {
|
|
662
|
+
const maybeWire = ref;
|
|
663
|
+
const contentType = ref.contentType ?? maybeWire.content_type;
|
|
664
|
+
return {
|
|
665
|
+
sha256: ref.sha256,
|
|
666
|
+
size: ref.size,
|
|
667
|
+
...(contentType ? { contentType } : {}),
|
|
668
|
+
...(ref.integrity ? { integrity: ref.integrity } : {}),
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function requireContentRef(ref, resource) {
|
|
672
|
+
if (ref)
|
|
673
|
+
return ref;
|
|
674
|
+
throw new Run402DeployError(`Missing content ref for ${resource}`, {
|
|
675
|
+
code: "INTERNAL_ERROR",
|
|
676
|
+
phase: "validate",
|
|
677
|
+
resource,
|
|
678
|
+
retryable: false,
|
|
679
|
+
context: "serializing deploy spec",
|
|
680
|
+
});
|
|
681
|
+
}
|
|
645
682
|
function fileSetToWire(map) {
|
|
646
683
|
const out = {};
|
|
647
684
|
for (const [path, ref] of Object.entries(map))
|
|
648
685
|
out[path] = contentRefToWire(ref);
|
|
649
686
|
return out;
|
|
650
687
|
}
|
|
688
|
+
function fileSetToCoreSpec(map) {
|
|
689
|
+
const out = {};
|
|
690
|
+
for (const [path, ref] of Object.entries(map))
|
|
691
|
+
out[path] = contentRefToCoreSpec(ref);
|
|
692
|
+
return out;
|
|
693
|
+
}
|
|
651
694
|
function requireRoleToWire(gate) {
|
|
652
695
|
return {
|
|
653
696
|
table: gate.table,
|
|
@@ -659,6 +702,21 @@ function requireRoleToWire(gate) {
|
|
|
659
702
|
...(gate.signInPath !== undefined ? { sign_in_path: gate.signInPath } : {}),
|
|
660
703
|
};
|
|
661
704
|
}
|
|
705
|
+
function functionToCoreSpec(fn) {
|
|
706
|
+
return {
|
|
707
|
+
...(fn.runtime !== undefined ? { runtime: fn.runtime } : {}),
|
|
708
|
+
...(fn.source !== undefined ? { source: contentRefToCoreSpec(fn.source) } : {}),
|
|
709
|
+
...(fn.files !== undefined ? { files: fileSetToCoreSpec(fn.files) } : {}),
|
|
710
|
+
...(fn.entrypoint !== undefined ? { entrypoint: fn.entrypoint } : {}),
|
|
711
|
+
...(fn.config !== undefined ? { config: fn.config } : {}),
|
|
712
|
+
...(fn.deps !== undefined ? { deps: fn.deps } : {}),
|
|
713
|
+
...(fn.schedule !== undefined ? { schedule: fn.schedule } : {}),
|
|
714
|
+
...(fn.requireAuth !== undefined ? { requireAuth: fn.requireAuth } : {}),
|
|
715
|
+
...(fn.requireRole !== undefined ? { requireRole: fn.requireRole } : {}),
|
|
716
|
+
...(fn.class !== undefined ? { class: fn.class } : {}),
|
|
717
|
+
...(fn.capabilities !== undefined ? { capabilities: fn.capabilities } : {}),
|
|
718
|
+
};
|
|
719
|
+
}
|
|
662
720
|
function functionToWire(fn) {
|
|
663
721
|
return {
|
|
664
722
|
...(fn.runtime !== undefined ? { runtime: fn.runtime } : {}),
|
|
@@ -680,6 +738,7 @@ function functionToWire(fn) {
|
|
|
680
738
|
? { require_role: fn.requireRole === null ? null : requireRoleToWire(fn.requireRole) }
|
|
681
739
|
: {}),
|
|
682
740
|
...(fn.class !== undefined ? { class: fn.class } : {}),
|
|
741
|
+
...(fn.capabilities !== undefined ? { capabilities: fn.capabilities } : {}),
|
|
683
742
|
};
|
|
684
743
|
}
|
|
685
744
|
function functionMapToWire(map) {
|
|
@@ -688,6 +747,25 @@ function functionMapToWire(map) {
|
|
|
688
747
|
out[name] = functionToWire(fn);
|
|
689
748
|
return out;
|
|
690
749
|
}
|
|
750
|
+
function functionMapToCoreSpec(map) {
|
|
751
|
+
const out = {};
|
|
752
|
+
for (const [name, fn] of Object.entries(map))
|
|
753
|
+
out[name] = functionToCoreSpec(fn);
|
|
754
|
+
return out;
|
|
755
|
+
}
|
|
756
|
+
function functionsToCoreSpec(functions) {
|
|
757
|
+
return {
|
|
758
|
+
...(functions.replace !== undefined ? { replace: functionMapToCoreSpec(functions.replace) } : {}),
|
|
759
|
+
...(functions.patch !== undefined
|
|
760
|
+
? {
|
|
761
|
+
patch: {
|
|
762
|
+
...(functions.patch.set !== undefined ? { set: functionMapToCoreSpec(functions.patch.set) } : {}),
|
|
763
|
+
...(functions.patch.delete !== undefined ? { delete: functions.patch.delete } : {}),
|
|
764
|
+
},
|
|
765
|
+
}
|
|
766
|
+
: {}),
|
|
767
|
+
};
|
|
768
|
+
}
|
|
691
769
|
function databaseToWire(database) {
|
|
692
770
|
return {
|
|
693
771
|
...(database.expose !== undefined ? { expose: database.expose } : {}),
|
|
@@ -697,7 +775,27 @@ function databaseToWire(database) {
|
|
|
697
775
|
migrations: database.migrations.map((m) => ({
|
|
698
776
|
id: m.id,
|
|
699
777
|
checksum: m.checksum,
|
|
700
|
-
|
|
778
|
+
...(m.sql !== undefined
|
|
779
|
+
? { sql: m.sql }
|
|
780
|
+
: { sql_ref: contentRefToWire(requireContentRef(m.sql_ref, `database.migrations.${m.id}.sql_ref`)) }),
|
|
781
|
+
...(m.transaction !== undefined ? { transaction: m.transaction } : {}),
|
|
782
|
+
})),
|
|
783
|
+
}
|
|
784
|
+
: {}),
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function databaseToCoreSpec(database) {
|
|
788
|
+
return {
|
|
789
|
+
...(database.expose !== undefined ? { expose: database.expose } : {}),
|
|
790
|
+
...(database.zero_downtime !== undefined ? { zero_downtime: database.zero_downtime } : {}),
|
|
791
|
+
...(database.migrations !== undefined
|
|
792
|
+
? {
|
|
793
|
+
migrations: database.migrations.map((m) => ({
|
|
794
|
+
id: m.id,
|
|
795
|
+
checksum: m.checksum,
|
|
796
|
+
...(m.sql !== undefined
|
|
797
|
+
? { sql: m.sql }
|
|
798
|
+
: { sql_ref: contentRefToCoreSpec(requireContentRef(m.sql_ref, `database.migrations.${m.id}.sql_ref`)) }),
|
|
701
799
|
...(m.transaction !== undefined ? { transaction: m.transaction } : {}),
|
|
702
800
|
})),
|
|
703
801
|
}
|
|
@@ -717,6 +815,24 @@ function functionsToWire(functions) {
|
|
|
717
815
|
: {}),
|
|
718
816
|
};
|
|
719
817
|
}
|
|
818
|
+
function siteToCoreSpec(site) {
|
|
819
|
+
if ("replace" in site && site.replace) {
|
|
820
|
+
return {
|
|
821
|
+
replace: fileSetToCoreSpec(site.replace),
|
|
822
|
+
...(site.public_paths ? { public_paths: site.public_paths } : {}),
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
if ("patch" in site && site.patch) {
|
|
826
|
+
return {
|
|
827
|
+
patch: {
|
|
828
|
+
...(site.patch.put ? { put: fileSetToCoreSpec(site.patch.put) } : {}),
|
|
829
|
+
...(site.patch.delete ? { delete: site.patch.delete } : {}),
|
|
830
|
+
},
|
|
831
|
+
...(site.public_paths ? { public_paths: site.public_paths } : {}),
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
return { public_paths: site.public_paths };
|
|
835
|
+
}
|
|
720
836
|
function siteToWire(site) {
|
|
721
837
|
if ("replace" in site && site.replace) {
|
|
722
838
|
return {
|
|
@@ -743,6 +859,21 @@ function i18nToWire(i18n) {
|
|
|
743
859
|
...(i18n.unknownLocalePolicy !== undefined ? { unknown_locale_policy: i18n.unknownLocalePolicy } : {}),
|
|
744
860
|
};
|
|
745
861
|
}
|
|
862
|
+
function releaseSpecToCoreSpec(spec) {
|
|
863
|
+
return {
|
|
864
|
+
project: spec.project,
|
|
865
|
+
...(spec.base !== undefined ? { base: spec.base } : {}),
|
|
866
|
+
...(spec.database !== undefined ? { database: databaseToCoreSpec(spec.database) } : {}),
|
|
867
|
+
...(spec.secrets !== undefined ? { secrets: spec.secrets } : {}),
|
|
868
|
+
...(spec.functions !== undefined ? { functions: functionsToCoreSpec(spec.functions) } : {}),
|
|
869
|
+
...(spec.site !== undefined ? { site: siteToCoreSpec(spec.site) } : {}),
|
|
870
|
+
...(spec.subdomains !== undefined ? { subdomains: spec.subdomains } : {}),
|
|
871
|
+
...(spec.routes !== undefined ? { routes: spec.routes } : {}),
|
|
872
|
+
...(spec.checks !== undefined ? { checks: spec.checks } : {}),
|
|
873
|
+
...(spec.assets !== undefined ? { assets: spec.assets } : {}),
|
|
874
|
+
...(spec.i18n !== undefined ? { i18n: spec.i18n } : {}),
|
|
875
|
+
};
|
|
876
|
+
}
|
|
746
877
|
function releaseSpecToWire(spec) {
|
|
747
878
|
return {
|
|
748
879
|
project_id: spec.project,
|
|
@@ -758,19 +889,24 @@ function releaseSpecToWire(spec) {
|
|
|
758
889
|
...(spec.i18n !== undefined ? { i18n: spec.i18n === null ? null : i18nToWire(spec.i18n) } : {}),
|
|
759
890
|
};
|
|
760
891
|
}
|
|
761
|
-
async function planInternal(client, spec, idempotencyKey, dryRun = false) {
|
|
892
|
+
async function planInternal(client, spec, idempotencyKey, dryRun = false, target = "cloud") {
|
|
762
893
|
const ciCredentials = isCiClient(client);
|
|
763
894
|
validateSpec(spec);
|
|
764
895
|
if (ciCredentials)
|
|
765
896
|
assertCiDeployableSpec(spec);
|
|
766
|
-
const
|
|
767
|
-
await
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
//
|
|
897
|
+
const isCore = target === "core";
|
|
898
|
+
const { normalized, byteReaders } = await normalizeReleaseSpec(client, spec, {
|
|
899
|
+
inlineMigrationSql: isCore,
|
|
900
|
+
});
|
|
901
|
+
if (!isCore)
|
|
902
|
+
await preflightTierFunctionLimits(client, normalized, ciCredentials);
|
|
903
|
+
const wireSpec = isCore ? releaseSpecToCoreSpec(normalized) : releaseSpecToWire(normalized);
|
|
904
|
+
// The gateway expects { spec, manifest_ref?, idempotency_key? }. Cloud
|
|
905
|
+
// receives the legacy snake_case apply wire shape; Core receives the
|
|
906
|
+
// open ReleaseSpec shape from @run402/release. For oversized Cloud specs
|
|
907
|
+
// the SDK uploads the manifest JSON to CAS first and references it; the
|
|
908
|
+
// gateway still needs `spec` in the body (with at least the project), so
|
|
909
|
+
// we keep a minimal stub there.
|
|
774
910
|
const inlineBody = { spec: wireSpec };
|
|
775
911
|
if (idempotencyKey && !dryRun)
|
|
776
912
|
inlineBody.idempotency_key = idempotencyKey;
|
|
@@ -779,6 +915,15 @@ async function planInternal(client, spec, idempotencyKey, dryRun = false) {
|
|
|
779
915
|
if (inlineBytes <= PLAN_BODY_LIMIT_BYTES) {
|
|
780
916
|
body = inlineBody;
|
|
781
917
|
}
|
|
918
|
+
else if (isCore) {
|
|
919
|
+
throw new Run402DeployError("Core deploy planning requires an inline spec under the gateway body cap; manifest_ref is not supported by Core Developer Preview yet.", {
|
|
920
|
+
code: "DRY_RUN_REQUIRES_INLINE_SPEC",
|
|
921
|
+
phase: "validate",
|
|
922
|
+
resource: "manifest_ref",
|
|
923
|
+
retryable: false,
|
|
924
|
+
context: "planning Core deploy",
|
|
925
|
+
});
|
|
926
|
+
}
|
|
782
927
|
else {
|
|
783
928
|
if (dryRun) {
|
|
784
929
|
throw new Run402DeployError("Dry-run deploy planning requires an inline spec under the gateway body cap; the normalized deploy plan would require manifest_ref.", {
|
|
@@ -1250,6 +1395,33 @@ async function uploadMissing(client, projectId, presence, byteReaders, emit) {
|
|
|
1250
1395
|
// above; this call is the plan-level idempotency anchor.
|
|
1251
1396
|
await client.request(`/content/v1/plans/${encodeURIComponent(planRes.plan_id)}/commit`, { method: "POST", headers, body: {}, context: "committing content upload" });
|
|
1252
1397
|
}
|
|
1398
|
+
async function uploadCoreContent(client, projectId, byteReaders, emit) {
|
|
1399
|
+
const entries = [...byteReaders.entries()].sort(([a], [b]) => a.localeCompare(b));
|
|
1400
|
+
const total = entries.length;
|
|
1401
|
+
let done = 0;
|
|
1402
|
+
for (const [sha256, reader] of entries) {
|
|
1403
|
+
const bytes = await reader();
|
|
1404
|
+
await client.request(`/projects/v1/${encodeURIComponent(projectId)}/content`, {
|
|
1405
|
+
method: "POST",
|
|
1406
|
+
body: {
|
|
1407
|
+
sha256,
|
|
1408
|
+
size: bytes.byteLength,
|
|
1409
|
+
content_type: reader.contentType ?? "application/octet-stream",
|
|
1410
|
+
bytes_base64: base64FromBytes(bytes),
|
|
1411
|
+
},
|
|
1412
|
+
context: "staging Core deploy content",
|
|
1413
|
+
});
|
|
1414
|
+
done += 1;
|
|
1415
|
+
emit({
|
|
1416
|
+
type: "content.upload.progress",
|
|
1417
|
+
label: reader.label ?? sha256,
|
|
1418
|
+
sha256,
|
|
1419
|
+
done,
|
|
1420
|
+
total,
|
|
1421
|
+
...(reader.slice ? { slice_kind: reader.slice } : {}),
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1253
1425
|
async function uploadOneWithRetry(fetchFn, session, bytes) {
|
|
1254
1426
|
const MAX_ATTEMPTS = 3;
|
|
1255
1427
|
for (let attempt = 1;; attempt++) {
|
|
@@ -1555,7 +1727,7 @@ async function startInternal(client, spec, opts) {
|
|
|
1555
1727
|
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
1556
1728
|
});
|
|
1557
1729
|
const { planId } = requirePersistedPlan(plan, "starting deploy");
|
|
1558
|
-
const commit = await commitInternal(client, planId, opts.idempotencyKey, spec.project);
|
|
1730
|
+
const commit = requireCloudCommitResponse(await commitInternal(client, planId, opts.idempotencyKey, spec.project), "starting deploy");
|
|
1559
1731
|
return await pollUntilReady(client, commit, plan.diff, plan.warnings, emit, spec.project, sliceKinds);
|
|
1560
1732
|
})();
|
|
1561
1733
|
// Avoid an unhandled-rejection at construction time. Consumers must call
|
|
@@ -1693,6 +1865,7 @@ const FUNCTION_SPEC_FIELDS = new Set([
|
|
|
1693
1865
|
"requireAuth",
|
|
1694
1866
|
"requireRole",
|
|
1695
1867
|
"class",
|
|
1868
|
+
"capabilities",
|
|
1696
1869
|
]);
|
|
1697
1870
|
const FUNCTION_CONFIG_FIELDS = new Set(["timeoutSeconds", "memoryMb"]);
|
|
1698
1871
|
const SITE_SPEC_FIELDS = new Set(["replace", "patch", "public_paths"]);
|
|
@@ -2316,6 +2489,7 @@ function invalidRouteSpec(message, resource) {
|
|
|
2316
2489
|
function normalizePlanResponse(plan) {
|
|
2317
2490
|
const raw = plan;
|
|
2318
2491
|
const warnings = Array.isArray(raw.warnings) ? raw.warnings : [];
|
|
2492
|
+
const missingContent = Array.isArray(raw.missing_content) ? raw.missing_content : [];
|
|
2319
2493
|
if (raw.kind === "plan_response") {
|
|
2320
2494
|
const diff = {
|
|
2321
2495
|
is_noop: raw.is_noop,
|
|
@@ -2332,6 +2506,7 @@ function normalizePlanResponse(plan) {
|
|
|
2332
2506
|
return {
|
|
2333
2507
|
...plan,
|
|
2334
2508
|
warnings,
|
|
2509
|
+
missing_content: missingContent,
|
|
2335
2510
|
diff,
|
|
2336
2511
|
payment_required: raw.payment_required ?? null,
|
|
2337
2512
|
};
|
|
@@ -2339,6 +2514,8 @@ function normalizePlanResponse(plan) {
|
|
|
2339
2514
|
return {
|
|
2340
2515
|
...plan,
|
|
2341
2516
|
warnings,
|
|
2517
|
+
missing_content: missingContent,
|
|
2518
|
+
diff: plan.diff ?? {},
|
|
2342
2519
|
};
|
|
2343
2520
|
}
|
|
2344
2521
|
function requirePersistedPlan(plan, context) {
|
|
@@ -2353,6 +2530,77 @@ function requirePersistedPlan(plan, context) {
|
|
|
2353
2530
|
context,
|
|
2354
2531
|
});
|
|
2355
2532
|
}
|
|
2533
|
+
function requirePlanId(plan, context) {
|
|
2534
|
+
if (plan.plan_id)
|
|
2535
|
+
return plan.plan_id;
|
|
2536
|
+
throw new Run402DeployError("Plan response cannot be committed because it does not include plan_id.", {
|
|
2537
|
+
code: "DRY_RUN_PLAN_NOT_COMMITTABLE",
|
|
2538
|
+
phase: "plan",
|
|
2539
|
+
resource: "plan_id",
|
|
2540
|
+
retryable: false,
|
|
2541
|
+
context,
|
|
2542
|
+
});
|
|
2543
|
+
}
|
|
2544
|
+
function isCoreCommitResponse(commit) {
|
|
2545
|
+
return (typeof commit.plan_id === "string" &&
|
|
2546
|
+
typeof commit.project_id === "string" &&
|
|
2547
|
+
typeof commit.release_digest === "string" &&
|
|
2548
|
+
(commit.status === "committed" ||
|
|
2549
|
+
commit.status === "noop" ||
|
|
2550
|
+
commit.status === "deferred"));
|
|
2551
|
+
}
|
|
2552
|
+
function requireCloudCommitResponse(commit, context) {
|
|
2553
|
+
if (!isCoreCommitResponse(commit))
|
|
2554
|
+
return commit;
|
|
2555
|
+
throw new Run402DeployError("Core commit response reached a Cloud operation-polling path.", {
|
|
2556
|
+
code: "INTERNAL_ERROR",
|
|
2557
|
+
phase: "commit",
|
|
2558
|
+
retryable: false,
|
|
2559
|
+
context,
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
async function coreDeployResult(client, commit, diff, warnings, emit, projectId, sliceKinds = []) {
|
|
2563
|
+
if (commit.status === "deferred") {
|
|
2564
|
+
throw new Run402DeployError(commit.deferred_reason ?? "Core deploy commit deferred.", {
|
|
2565
|
+
code: "INTERNAL_ERROR",
|
|
2566
|
+
phase: commit.deferred_phase ?? "commit",
|
|
2567
|
+
retryable: true,
|
|
2568
|
+
context: "committing Core deploy",
|
|
2569
|
+
});
|
|
2570
|
+
}
|
|
2571
|
+
const urls = await coreProjectUrls(client, projectId);
|
|
2572
|
+
emit({
|
|
2573
|
+
type: "ready",
|
|
2574
|
+
releaseId: commit.release_id,
|
|
2575
|
+
urls,
|
|
2576
|
+
...(sliceKinds.length > 0 ? { slice_kinds: sliceKinds } : {}),
|
|
2577
|
+
});
|
|
2578
|
+
return {
|
|
2579
|
+
release_id: commit.release_id,
|
|
2580
|
+
operation_id: `core:${commit.plan_id}`,
|
|
2581
|
+
urls,
|
|
2582
|
+
diff,
|
|
2583
|
+
warnings,
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
async function coreProjectUrls(client, projectId) {
|
|
2587
|
+
try {
|
|
2588
|
+
const project = await client.request(`/projects/v1/${encodeURIComponent(projectId)}`, {
|
|
2589
|
+
method: "GET",
|
|
2590
|
+
context: "fetching Core project endpoints",
|
|
2591
|
+
});
|
|
2592
|
+
const staticUrl = project.endpoints?.static_base_url;
|
|
2593
|
+
return {
|
|
2594
|
+
...(staticUrl ? { site: staticUrl, static: staticUrl } : {}),
|
|
2595
|
+
...(project.endpoints?.rest_url ? { rest: project.endpoints.rest_url } : {}),
|
|
2596
|
+
...(project.endpoints?.storage_base_url ? { storage: project.endpoints.storage_base_url } : {}),
|
|
2597
|
+
};
|
|
2598
|
+
}
|
|
2599
|
+
catch {
|
|
2600
|
+
const staticUrl = `${client.apiBase.replace(/\/+$/, "")}/projects/v1/${encodeURIComponent(projectId)}/static`;
|
|
2601
|
+
return { site: staticUrl, static: staticUrl };
|
|
2602
|
+
}
|
|
2603
|
+
}
|
|
2356
2604
|
function emitPlanWarnings(plan, emit) {
|
|
2357
2605
|
if (plan.warnings.length > 0) {
|
|
2358
2606
|
emit({ type: "plan.warnings", warnings: plan.warnings });
|
|
@@ -2526,7 +2774,7 @@ function invalidSecretSpec(message, resource) {
|
|
|
2526
2774
|
context: "validating spec",
|
|
2527
2775
|
});
|
|
2528
2776
|
}
|
|
2529
|
-
async function normalizeReleaseSpec(client, spec) {
|
|
2777
|
+
async function normalizeReleaseSpec(client, spec, opts = {}) {
|
|
2530
2778
|
const byteReaders = new Map();
|
|
2531
2779
|
// Slice-tagged `remember`. Each slice category creates its own remember
|
|
2532
2780
|
// closure so the registered reader carries `reader.slice = "release" |
|
|
@@ -2585,7 +2833,7 @@ async function normalizeReleaseSpec(client, spec) {
|
|
|
2585
2833
|
db.zero_downtime = spec.database.zero_downtime;
|
|
2586
2834
|
}
|
|
2587
2835
|
if (spec.database.migrations && spec.database.migrations.length > 0) {
|
|
2588
|
-
db.migrations = await Promise.all(spec.database.migrations.map(async (m) => normalizeMigration(client, spec.project, m, rememberRelease)));
|
|
2836
|
+
db.migrations = await Promise.all(spec.database.migrations.map(async (m) => normalizeMigration(client, spec.project, m, rememberRelease, opts)));
|
|
2589
2837
|
}
|
|
2590
2838
|
normalized.database = db;
|
|
2591
2839
|
}
|
|
@@ -2667,6 +2915,8 @@ async function normalizeFunction(fn, remember) {
|
|
|
2667
2915
|
out.requireRole = fn.requireRole;
|
|
2668
2916
|
if (fn.class !== undefined)
|
|
2669
2917
|
out.class = fn.class;
|
|
2918
|
+
if (fn.capabilities !== undefined)
|
|
2919
|
+
out.capabilities = [...fn.capabilities];
|
|
2670
2920
|
if (fn.source !== undefined) {
|
|
2671
2921
|
const resolved = await resolveContent(fn.source, "function source");
|
|
2672
2922
|
out.source = remember(resolved);
|
|
@@ -2966,7 +3216,7 @@ async function normalizeAssetSlice(slice, remember) {
|
|
|
2966
3216
|
}
|
|
2967
3217
|
return out;
|
|
2968
3218
|
}
|
|
2969
|
-
async function normalizeMigration(client, projectId, m, remember) {
|
|
3219
|
+
async function normalizeMigration(client, projectId, m, remember, opts = {}) {
|
|
2970
3220
|
if (!m.id) {
|
|
2971
3221
|
throw new Run402DeployError("MigrationSpec.id is required", {
|
|
2972
3222
|
code: "INVALID_SPEC",
|
|
@@ -2978,6 +3228,7 @@ async function normalizeMigration(client, projectId, m, remember) {
|
|
|
2978
3228
|
});
|
|
2979
3229
|
}
|
|
2980
3230
|
let sql_ref;
|
|
3231
|
+
let sql;
|
|
2981
3232
|
let checksum;
|
|
2982
3233
|
if (m.sql_ref) {
|
|
2983
3234
|
sql_ref = m.sql_ref;
|
|
@@ -2986,9 +3237,14 @@ async function normalizeMigration(client, projectId, m, remember) {
|
|
|
2986
3237
|
else if (m.sql !== undefined) {
|
|
2987
3238
|
const bytes = new TextEncoder().encode(m.sql);
|
|
2988
3239
|
const sha256 = await sha256Hex(bytes);
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
3240
|
+
if (opts.inlineMigrationSql) {
|
|
3241
|
+
sql = m.sql;
|
|
3242
|
+
}
|
|
3243
|
+
else {
|
|
3244
|
+
const ref = { sha256, size: bytes.byteLength, contentType: "application/sql" };
|
|
3245
|
+
remember({ ref, reader: makeBytesReader(bytes, `migration:${m.id}`) });
|
|
3246
|
+
sql_ref = ref;
|
|
3247
|
+
}
|
|
2992
3248
|
checksum = m.checksum ?? sha256;
|
|
2993
3249
|
}
|
|
2994
3250
|
else {
|
|
@@ -3004,7 +3260,11 @@ async function normalizeMigration(client, projectId, m, remember) {
|
|
|
3004
3260
|
context: "validating spec",
|
|
3005
3261
|
});
|
|
3006
3262
|
}
|
|
3007
|
-
const out = { id: m.id, checksum
|
|
3263
|
+
const out = { id: m.id, checksum };
|
|
3264
|
+
if (sql_ref)
|
|
3265
|
+
out.sql_ref = sql_ref;
|
|
3266
|
+
if (sql !== undefined)
|
|
3267
|
+
out.sql = sql;
|
|
3008
3268
|
if (m.transaction)
|
|
3009
3269
|
out.transaction = m.transaction;
|
|
3010
3270
|
return out;
|