run402-mcp 4.0.0 → 4.0.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/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/deploy.d.ts +62 -10
- package/dist/tools/deploy.d.ts.map +1 -1
- package/dist/tools/deploy.js +12 -2
- package/dist/tools/deploy.js.map +1 -1
- package/package.json +1 -1
- package/schemas/release-spec.v1.json +14 -3
- package/schemas/run402-app.v1.schema.json +56 -1
- package/sdk/dist/config.d.ts +22 -5
- package/sdk/dist/config.d.ts.map +1 -1
- package/sdk/dist/config.js +6 -1
- package/sdk/dist/config.js.map +1 -1
- package/sdk/dist/namespaces/deploy.js +57 -8
- package/sdk/dist/namespaces/deploy.js.map +1 -1
- package/sdk/dist/namespaces/deploy.types.d.ts +19 -5
- package/sdk/dist/namespaces/deploy.types.d.ts.map +1 -1
- package/sdk/dist/namespaces/deploy.types.js.map +1 -1
- package/sdk/dist/node/deploy-manifest.d.ts +14 -2
- package/sdk/dist/node/deploy-manifest.d.ts.map +1 -1
- package/sdk/dist/node/deploy-manifest.js +45 -8
- package/sdk/dist/node/deploy-manifest.js.map +1 -1
package/sdk/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAwHA,MAAM,UAAU,YAAY,CAA+C,MAAS;IAClF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,IAAY,EAAE,UAAkC,EAAE;IACpE,OAAO;QACL,QAAQ,EAAE,WAAW;QACrB,IAAI;QACJ,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxE,GAAG,CAAC,OAAO,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClG,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY,EAAE,UAAmC,EAAE;IACtE,OAAO;QACL,QAAQ,EAAE,SAAS;QACnB,IAAI;QACJ,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS;YACnC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE;YACtC,CAAC,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS;gBAClC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,YAAY,EAAE;gBACvC,CAAC,CAAC,EAAE,CAAC;QACT,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,IAAY,EACZ,UAAsC,EAAE;IAExC,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3D,MAAM,IAAI,SAAS,CAAC,uDAAuD,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO;QACL,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS;YAC5B,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE;YACxB,CAAC,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,QAAQ,EAAE,IAAI;QACd,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnD,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,UAA2C,EAAE;IAE7C,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ;QACpC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAyB;QAC1C,GAAG,CAAC,OAAO,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClE,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5G,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,OAAO,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChE,GAAG,CAAC,OAAO,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1F,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,GAAG,CAAC,OAAO,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,EAAU,EACV,IAAY,EACZ,OAAqC;IAErC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO;QACL,EAAE;QACF,IAAI,EAAE,UAAU;QAChB,IAAI;QACJ,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzE,GAAG,CAAC,OAAO,CAAC,aAAa,KAAK,SAAS;YACrC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,aAAa,EAAE;YAC3C,CAAC,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS;gBACpC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE;gBAC5C,CAAC,CAAC,EAAE,CAAC;QACT,GAAG,CAAC,OAAO,CAAC,aAAa,KAAK,SAAS;YACrC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,aAAa,EAAE;YAC3C,CAAC,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS;gBACpC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,cAAc,EAAE;gBAC5C,CAAC,CAAC,EAAE,CAAC;QACT,GAAG,EAAE;YACH,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;YAClC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9E,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,SAAS;gBACjD,CAAC,CAAC,EAAE,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE;gBAC9D,CAAC,CAAC,EAAE,CAAC;SACR;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,EAAU,EACV,OAAe,EACf,OAAkC;IAElC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO;QACL,EAAE;QACF,IAAI,EAAE,OAAO;QACb,OAAO;QACP,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;QAC3B,GAAG,EAAE;YACH,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;YAClC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9E,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,KAAK,SAAS;gBACjD,CAAC,CAAC,EAAE,qBAAqB,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE;gBAC9D,CAAC,CAAC,EAAE,CAAC;SACR;KACF,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY;IACrC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC;IACxE,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC;AAC9C,CAAC"}
|
|
@@ -1960,7 +1960,7 @@ const DEPLOYABLE_SPEC_FIELDS = [
|
|
|
1960
1960
|
];
|
|
1961
1961
|
const BASE_SPEC_FIELDS = new Set(["release", "release_id"]);
|
|
1962
1962
|
const DATABASE_SPEC_FIELDS = new Set(["migrations", "expose", "zero_downtime"]);
|
|
1963
|
-
const MIGRATION_SPEC_FIELDS = new Set(["id", "checksum", "sql", "sql_ref", "transaction"]);
|
|
1963
|
+
const MIGRATION_SPEC_FIELDS = new Set(["id", "name", "checksum", "sql", "sql_ref", "transaction"]);
|
|
1964
1964
|
const FUNCTIONS_SPEC_FIELDS = new Set(["replace", "patch"]);
|
|
1965
1965
|
const FUNCTIONS_PATCH_FIELDS = new Set(["set", "delete"]);
|
|
1966
1966
|
const FUNCTION_SPEC_FIELDS = new Set([
|
|
@@ -1995,6 +1995,7 @@ const I18N_LOCALE_TAG_REGEX = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
|
1995
1995
|
const I18N_COOKIE_NAME_REGEX = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
1996
1996
|
const I18N_MAX_LOCALES = 50;
|
|
1997
1997
|
const I18N_MAX_DETECT_SOURCES = 10;
|
|
1998
|
+
const MIGRATION_NAME_RE = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
|
|
1998
1999
|
function validateSpec(spec) {
|
|
1999
2000
|
if (!spec || typeof spec !== "object") {
|
|
2000
2001
|
throw new Run402DeployError("ReleaseSpec must be an object", {
|
|
@@ -2072,15 +2073,38 @@ function validateDatabaseSpec(database) {
|
|
|
2072
2073
|
if (!Array.isArray(obj.migrations)) {
|
|
2073
2074
|
throw invalidSpec("ReleaseSpec.database.migrations must be an array", "database.migrations");
|
|
2074
2075
|
}
|
|
2076
|
+
const seenNames = new Map();
|
|
2075
2077
|
for (const [index, migration] of obj.migrations.entries()) {
|
|
2076
2078
|
const m = requireObject(migration, `database.migrations.${index}`);
|
|
2077
2079
|
validateKnownFields(m, `database.migrations.${index}`, MIGRATION_SPEC_FIELDS);
|
|
2080
|
+
validateMigrationIdentity(m, index, seenNames);
|
|
2078
2081
|
}
|
|
2079
2082
|
}
|
|
2080
2083
|
if (obj.expose !== undefined) {
|
|
2081
2084
|
requireObject(obj.expose, "database.expose");
|
|
2082
2085
|
}
|
|
2083
2086
|
}
|
|
2087
|
+
function validateMigrationIdentity(migration, index, seenNames) {
|
|
2088
|
+
const resource = `database.migrations.${index}`;
|
|
2089
|
+
const hasId = hasOwn(migration, "id") && migration.id !== undefined;
|
|
2090
|
+
const hasName = hasOwn(migration, "name") && migration.name !== undefined;
|
|
2091
|
+
if (hasId && hasName) {
|
|
2092
|
+
throw invalidSpec(`ReleaseSpec.${resource} declares both id and name; use exactly one`, resource);
|
|
2093
|
+
}
|
|
2094
|
+
if (!hasId && !hasName) {
|
|
2095
|
+
throw invalidSpec(`ReleaseSpec.${resource} must declare exactly one of id or name`, resource);
|
|
2096
|
+
}
|
|
2097
|
+
if (hasName) {
|
|
2098
|
+
if (typeof migration.name !== "string" || !MIGRATION_NAME_RE.test(migration.name)) {
|
|
2099
|
+
throw invalidSpec(`ReleaseSpec.${resource}.name must match /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/`, `${resource}.name`);
|
|
2100
|
+
}
|
|
2101
|
+
const firstIndex = seenNames.get(migration.name);
|
|
2102
|
+
if (firstIndex !== undefined) {
|
|
2103
|
+
throw invalidSpec(`ReleaseSpec.${resource}.name duplicates database.migrations.${firstIndex}.name ${JSON.stringify(migration.name)}`, `${resource}.name`);
|
|
2104
|
+
}
|
|
2105
|
+
seenNames.set(migration.name, index);
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2084
2108
|
function validateFunctionsSpec(functions) {
|
|
2085
2109
|
if (functions === undefined)
|
|
2086
2110
|
return;
|
|
@@ -3021,6 +3045,7 @@ async function normalizeReleaseSpec(client, spec, opts = {}) {
|
|
|
3021
3045
|
}
|
|
3022
3046
|
if (spec.database.migrations && spec.database.migrations.length > 0) {
|
|
3023
3047
|
db.migrations = await Promise.all(spec.database.migrations.map(async (m) => normalizeMigration(client, spec.project, m, rememberRelease, opts)));
|
|
3048
|
+
assertUniqueMigrationIds(db.migrations);
|
|
3024
3049
|
}
|
|
3025
3050
|
normalized.database = db;
|
|
3026
3051
|
}
|
|
@@ -3438,8 +3463,10 @@ async function normalizeAssetSlice(slice, remember) {
|
|
|
3438
3463
|
return out;
|
|
3439
3464
|
}
|
|
3440
3465
|
async function normalizeMigration(client, projectId, m, remember, opts = {}) {
|
|
3441
|
-
|
|
3442
|
-
|
|
3466
|
+
const originalId = "id" in m ? m.id : undefined;
|
|
3467
|
+
const name = "name" in m ? m.name : undefined;
|
|
3468
|
+
if (!originalId && !name) {
|
|
3469
|
+
throw new Run402DeployError("MigrationSpec.id or MigrationSpec.name is required", {
|
|
3443
3470
|
code: "INVALID_SPEC",
|
|
3444
3471
|
phase: "validate",
|
|
3445
3472
|
resource: "database.migrations",
|
|
@@ -3451,37 +3478,42 @@ async function normalizeMigration(client, projectId, m, remember, opts = {}) {
|
|
|
3451
3478
|
let sql_ref;
|
|
3452
3479
|
let sql;
|
|
3453
3480
|
let checksum;
|
|
3481
|
+
let contentHash;
|
|
3482
|
+
const identityLabel = originalId ?? name ?? "<unknown>";
|
|
3454
3483
|
if (m.sql_ref) {
|
|
3455
3484
|
sql_ref = m.sql_ref;
|
|
3485
|
+
contentHash = m.sql_ref.sha256;
|
|
3456
3486
|
checksum = m.checksum ?? m.sql_ref.sha256;
|
|
3457
3487
|
}
|
|
3458
3488
|
else if (m.sql !== undefined) {
|
|
3459
3489
|
const bytes = new TextEncoder().encode(m.sql);
|
|
3460
3490
|
const sha256 = await sha256Hex(bytes);
|
|
3491
|
+
contentHash = sha256;
|
|
3461
3492
|
if (opts.inlineMigrationSql) {
|
|
3462
3493
|
sql = m.sql;
|
|
3463
3494
|
}
|
|
3464
3495
|
else {
|
|
3465
3496
|
const ref = { sha256, size: bytes.byteLength, contentType: "application/sql" };
|
|
3466
|
-
remember({ ref, reader: makeBytesReader(bytes, `migration:${
|
|
3497
|
+
remember({ ref, reader: makeBytesReader(bytes, `migration:${identityLabel}`) });
|
|
3467
3498
|
sql_ref = ref;
|
|
3468
3499
|
}
|
|
3469
3500
|
checksum = m.checksum ?? sha256;
|
|
3470
3501
|
}
|
|
3471
3502
|
else {
|
|
3472
|
-
throw new Run402DeployError(`MigrationSpec ${
|
|
3503
|
+
throw new Run402DeployError(`MigrationSpec ${identityLabel} must include sql or sql_ref`, {
|
|
3473
3504
|
code: "INVALID_SPEC",
|
|
3474
3505
|
phase: "validate",
|
|
3475
|
-
resource: `database.migrations.${
|
|
3506
|
+
resource: `database.migrations.${identityLabel}`,
|
|
3476
3507
|
retryable: false,
|
|
3477
3508
|
fix: {
|
|
3478
3509
|
action: "set_field",
|
|
3479
|
-
path: `database.migrations.${
|
|
3510
|
+
path: `database.migrations.${identityLabel}.sql`,
|
|
3480
3511
|
},
|
|
3481
3512
|
context: "validating spec",
|
|
3482
3513
|
});
|
|
3483
3514
|
}
|
|
3484
|
-
const
|
|
3515
|
+
const id = originalId ?? `${name}_${contentHash.slice(0, 16)}`;
|
|
3516
|
+
const out = { id, checksum };
|
|
3485
3517
|
if (sql_ref)
|
|
3486
3518
|
out.sql_ref = sql_ref;
|
|
3487
3519
|
if (sql !== undefined)
|
|
@@ -3493,6 +3525,23 @@ async function normalizeMigration(client, projectId, m, remember, opts = {}) {
|
|
|
3493
3525
|
void client;
|
|
3494
3526
|
void projectId;
|
|
3495
3527
|
}
|
|
3528
|
+
function assertUniqueMigrationIds(migrations) {
|
|
3529
|
+
const seen = new Map();
|
|
3530
|
+
for (const [index, migration] of migrations.entries()) {
|
|
3531
|
+
const firstIndex = seen.get(migration.id);
|
|
3532
|
+
if (firstIndex !== undefined) {
|
|
3533
|
+
throw new Run402DeployError(`ReleaseSpec.database.migrations.${index}.id duplicates database.migrations.${firstIndex}.id ${JSON.stringify(migration.id)}`, {
|
|
3534
|
+
code: "INVALID_SPEC",
|
|
3535
|
+
phase: "validate",
|
|
3536
|
+
resource: `database.migrations.${index}.id`,
|
|
3537
|
+
retryable: false,
|
|
3538
|
+
fix: { action: "set_field", path: `database.migrations.${index}.id` },
|
|
3539
|
+
context: "validating spec",
|
|
3540
|
+
});
|
|
3541
|
+
}
|
|
3542
|
+
seen.set(migration.id, index);
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3496
3545
|
// ─── Content source resolution ───────────────────────────────────────────────
|
|
3497
3546
|
async function resolveContent(source, label) {
|
|
3498
3547
|
// Pre-resolved ContentRef — pass through, no reader needed (caller is
|