@varde-flyt/vfac 0.7.0 → 0.8.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.
- package/README.md +29 -5
- package/dist/vfac.mjs +1257 -373
- package/package.json +1 -1
package/dist/vfac.mjs
CHANGED
|
@@ -7424,22 +7424,46 @@ function parseArgs(argv) {
|
|
|
7424
7424
|
}
|
|
7425
7425
|
|
|
7426
7426
|
// src/config.ts
|
|
7427
|
-
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7427
|
+
import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
7428
7428
|
import { homedir } from "node:os";
|
|
7429
7429
|
import { dirname, join } from "node:path";
|
|
7430
|
+
var salvaged = null;
|
|
7431
|
+
function salvagedConfigPath() {
|
|
7432
|
+
return salvaged;
|
|
7433
|
+
}
|
|
7430
7434
|
function configPath() {
|
|
7431
7435
|
const base = process.env["VFAC_CONFIG_HOME"] ?? join(homedir(), ".config", "vfac");
|
|
7432
7436
|
return join(base, "config.json");
|
|
7433
7437
|
}
|
|
7434
7438
|
function readStored(path = configPath()) {
|
|
7439
|
+
let raw;
|
|
7440
|
+
try {
|
|
7441
|
+
raw = readFileSync(path, "utf8");
|
|
7442
|
+
} catch {
|
|
7443
|
+
return {};
|
|
7444
|
+
}
|
|
7435
7445
|
try {
|
|
7436
|
-
const parsed = JSON.parse(
|
|
7437
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
7446
|
+
const parsed = JSON.parse(raw);
|
|
7447
|
+
if (typeof parsed !== "object" || parsed === null) throw new Error("not an object");
|
|
7438
7448
|
return parsed;
|
|
7439
7449
|
} catch {
|
|
7450
|
+
salvage(path);
|
|
7440
7451
|
return {};
|
|
7441
7452
|
}
|
|
7442
7453
|
}
|
|
7454
|
+
function salvage(path) {
|
|
7455
|
+
const kept = `${path}.corrupt`;
|
|
7456
|
+
try {
|
|
7457
|
+
readFileSync(kept, "utf8");
|
|
7458
|
+
return;
|
|
7459
|
+
} catch {
|
|
7460
|
+
}
|
|
7461
|
+
try {
|
|
7462
|
+
renameSync(path, kept);
|
|
7463
|
+
salvaged = kept;
|
|
7464
|
+
} catch {
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7443
7467
|
function writeStored(next, path = configPath()) {
|
|
7444
7468
|
const directory = dirname(path);
|
|
7445
7469
|
mkdirSync(directory, { recursive: true, mode: 448 });
|
|
@@ -11964,6 +11988,14 @@ var coerce = {
|
|
|
11964
11988
|
};
|
|
11965
11989
|
var NEVER = INVALID;
|
|
11966
11990
|
|
|
11991
|
+
// ../product-configuration/dist/configuration-bounds.js
|
|
11992
|
+
var MAX_CONFIGURATION_DEPTH = 2;
|
|
11993
|
+
var MAX_CONFIGURATION_LEAVES = 40;
|
|
11994
|
+
var MAX_CONFIGURATION_NODES = 60;
|
|
11995
|
+
var MAX_CONFIGURATION_VALUE_LEAVES = 1e3;
|
|
11996
|
+
var MAX_CONFIGURATION_ISSUES = 50;
|
|
11997
|
+
var MAX_CONFIGURATION_VALUE_BYTES = 16384;
|
|
11998
|
+
|
|
11967
11999
|
// ../product-configuration/dist/json-schema-annex.js
|
|
11968
12000
|
var ANNEXES = /* @__PURE__ */ new WeakMap();
|
|
11969
12001
|
function withJsonSchemaAnnex(schema, annex) {
|
|
@@ -12263,12 +12295,49 @@ var ArrayPropertySchema = external_exports.object({
|
|
|
12263
12295
|
uniqueItems: external_exports.boolean().optional(),
|
|
12264
12296
|
default: external_exports.array(external_exports.string().max(200)).max(100).optional()
|
|
12265
12297
|
}).strict();
|
|
12298
|
+
var MAX_CONFIGURATION_PROPERTIES = 40;
|
|
12266
12299
|
var ConfigurationPropertySchema = external_exports.discriminatedUnion("type", [
|
|
12267
12300
|
StringPropertySchema,
|
|
12268
12301
|
NumberPropertySchema,
|
|
12269
12302
|
BooleanPropertySchema,
|
|
12270
12303
|
ArrayPropertySchema
|
|
12271
12304
|
]);
|
|
12305
|
+
var NestedStringPropertySchema = StringPropertySchema.omit({
|
|
12306
|
+
"x-secret": true,
|
|
12307
|
+
writeOnly: true
|
|
12308
|
+
});
|
|
12309
|
+
var NestedConfigurationPropertySchema = external_exports.discriminatedUnion("type", [
|
|
12310
|
+
NestedStringPropertySchema,
|
|
12311
|
+
NumberPropertySchema,
|
|
12312
|
+
BooleanPropertySchema,
|
|
12313
|
+
ArrayPropertySchema
|
|
12314
|
+
]);
|
|
12315
|
+
var nestedPropertiesShape = {
|
|
12316
|
+
properties: external_exports.record(PropertyNameSchema, NestedConfigurationPropertySchema),
|
|
12317
|
+
required: external_exports.array(PropertyNameSchema).max(MAX_CONFIGURATION_PROPERTIES).optional(),
|
|
12318
|
+
additionalProperties: external_exports.literal(false)
|
|
12319
|
+
};
|
|
12320
|
+
var ObjectPropertySchema = external_exports.object({
|
|
12321
|
+
type: external_exports.literal("object"),
|
|
12322
|
+
title: TitleSchema,
|
|
12323
|
+
description: HelpTextSchema.optional(),
|
|
12324
|
+
group: ConfigurationGroupSchema,
|
|
12325
|
+
...nestedPropertiesShape
|
|
12326
|
+
}).strict();
|
|
12327
|
+
var ObjectArrayItemsSchema = external_exports.object({
|
|
12328
|
+
type: external_exports.literal("object"),
|
|
12329
|
+
...nestedPropertiesShape
|
|
12330
|
+
}).strict();
|
|
12331
|
+
var ArrayPropertyV2Schema = ArrayPropertySchema.extend({
|
|
12332
|
+
items: external_exports.discriminatedUnion("type", [ArrayItemsSchema, ObjectArrayItemsSchema])
|
|
12333
|
+
});
|
|
12334
|
+
var RootConfigurationPropertySchema = external_exports.discriminatedUnion("type", [
|
|
12335
|
+
StringPropertySchema,
|
|
12336
|
+
NumberPropertySchema,
|
|
12337
|
+
BooleanPropertySchema,
|
|
12338
|
+
ArrayPropertyV2Schema,
|
|
12339
|
+
ObjectPropertySchema
|
|
12340
|
+
]);
|
|
12272
12341
|
var CustomerConfigurationObjectSchema = external_exports.object({
|
|
12273
12342
|
type: external_exports.literal("object"),
|
|
12274
12343
|
properties: external_exports.record(PropertyNameSchema, ConfigurationPropertySchema).describe("Customer-editable settings, keyed by camelCase property name."),
|
|
@@ -12302,7 +12371,6 @@ var CustomerConfigurationObjectSchema = external_exports.object({
|
|
|
12302
12371
|
*/
|
|
12303
12372
|
additionalProperties: external_exports.literal(false)
|
|
12304
12373
|
}).strict();
|
|
12305
|
-
var MAX_CONFIGURATION_PROPERTIES = 40;
|
|
12306
12374
|
var CustomerConfigurationSchema = CustomerConfigurationObjectSchema.superRefine((config, ctx) => {
|
|
12307
12375
|
const names = Object.keys(config.properties);
|
|
12308
12376
|
if (names.length > MAX_CONFIGURATION_PROPERTIES) {
|
|
@@ -12314,182 +12382,192 @@ var CustomerConfigurationSchema = CustomerConfigurationObjectSchema.superRefine(
|
|
|
12314
12382
|
}
|
|
12315
12383
|
for (const name of names) {
|
|
12316
12384
|
const property = config.properties[name];
|
|
12317
|
-
|
|
12318
|
-
|
|
12319
|
-
|
|
12385
|
+
checkDeclaredProperty(name, property, ["properties", name], ctx, true);
|
|
12386
|
+
}
|
|
12387
|
+
for (const name of config.required ?? []) {
|
|
12388
|
+
if (!Object.hasOwn(config.properties, name)) {
|
|
12320
12389
|
ctx.addIssue({
|
|
12321
12390
|
code: external_exports.ZodIssueCode.custom,
|
|
12322
|
-
path,
|
|
12323
|
-
message:
|
|
12391
|
+
path: ["required"],
|
|
12392
|
+
message: `"${name}" is listed as required but is not a declared property.`
|
|
12324
12393
|
});
|
|
12325
12394
|
}
|
|
12395
|
+
}
|
|
12396
|
+
const duplicates = (config.required ?? []).filter((name, index, all) => all.indexOf(name) !== index);
|
|
12397
|
+
if (duplicates.length > 0) {
|
|
12398
|
+
ctx.addIssue({
|
|
12399
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12400
|
+
path: ["required"],
|
|
12401
|
+
message: `Duplicate required entries: ${[...new Set(duplicates)].join(", ")}.`
|
|
12402
|
+
});
|
|
12403
|
+
}
|
|
12404
|
+
checkDependentRequired(config, ctx);
|
|
12405
|
+
});
|
|
12406
|
+
function checkDeclaredProperty(name, property, path, ctx, atRoot) {
|
|
12407
|
+
const infrastructure = infrastructureVocabularyViolation(name);
|
|
12408
|
+
if (infrastructure) {
|
|
12409
|
+
ctx.addIssue({
|
|
12410
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12411
|
+
path,
|
|
12412
|
+
message: `${infrastructure}. Customer settings describe outcomes, not infrastructure.`
|
|
12413
|
+
});
|
|
12414
|
+
}
|
|
12415
|
+
if (atRoot) {
|
|
12326
12416
|
const platformOwned = platformOwnedFieldViolation(name);
|
|
12327
12417
|
if (platformOwned) {
|
|
12328
12418
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path, message: `${platformOwned}.` });
|
|
12329
12419
|
}
|
|
12330
|
-
|
|
12331
|
-
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12336
|
-
path: [...path, label],
|
|
12337
|
-
message: `${violation}. Customer settings offer outcomes, not infrastructure sizes.`
|
|
12338
|
-
});
|
|
12339
|
-
}
|
|
12340
|
-
}
|
|
12341
|
-
}
|
|
12342
|
-
if (property.type === "string") {
|
|
12343
|
-
const secret = property["x-secret"] === true;
|
|
12344
|
-
const credential = credentialNameViolation(name);
|
|
12345
|
-
if (credential && !secret) {
|
|
12346
|
-
ctx.addIssue({
|
|
12347
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12348
|
-
path,
|
|
12349
|
-
message: `${credential} and must be declared "x-secret": true with "writeOnly": true, or renamed if it is not one.`
|
|
12350
|
-
});
|
|
12351
|
-
}
|
|
12352
|
-
if (secret && property.writeOnly !== true) {
|
|
12353
|
-
ctx.addIssue({
|
|
12354
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12355
|
-
path,
|
|
12356
|
-
message: `"${name}" is marked x-secret but not writeOnly \u2014 a read API could echo the value.`
|
|
12357
|
-
});
|
|
12358
|
-
}
|
|
12359
|
-
if (property.writeOnly === true && !secret) {
|
|
12360
|
-
ctx.addIssue({
|
|
12361
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12362
|
-
path,
|
|
12363
|
-
message: `"${name}" is marked writeOnly but not x-secret \u2014 the value would not be routed to the secret flow.`
|
|
12364
|
-
});
|
|
12365
|
-
}
|
|
12366
|
-
if (secret && property.default !== void 0) {
|
|
12367
|
-
ctx.addIssue({
|
|
12368
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12369
|
-
path: [...path, "default"],
|
|
12370
|
-
message: `"${name}" is a secret and must not declare a default value.`
|
|
12371
|
-
});
|
|
12372
|
-
}
|
|
12373
|
-
if (secret && property.enum !== void 0) {
|
|
12374
|
-
ctx.addIssue({
|
|
12375
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12376
|
-
path: [...path, "enum"],
|
|
12377
|
-
message: `"${name}" is a secret; an enum would enumerate candidate secret values.`
|
|
12378
|
-
});
|
|
12379
|
-
}
|
|
12380
|
-
if (property.enum === void 0 && property.maxLength === void 0) {
|
|
12381
|
-
ctx.addIssue({
|
|
12382
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12383
|
-
path,
|
|
12384
|
-
message: `"${name}" must declare either an enum or a maxLength.`
|
|
12385
|
-
});
|
|
12386
|
-
}
|
|
12387
|
-
if (property.enum !== void 0 && property.default !== void 0 && !property.enum.includes(property.default)) {
|
|
12388
|
-
ctx.addIssue({
|
|
12389
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12390
|
-
path: [...path, "default"],
|
|
12391
|
-
message: `"${name}" declares a default outside its enum.`
|
|
12392
|
-
});
|
|
12393
|
-
}
|
|
12394
|
-
if (property.minLength !== void 0 && property.maxLength !== void 0 && property.minLength > property.maxLength) {
|
|
12395
|
-
ctx.addIssue({
|
|
12396
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12397
|
-
path,
|
|
12398
|
-
message: `"${name}" has minLength greater than maxLength.`
|
|
12399
|
-
});
|
|
12400
|
-
}
|
|
12401
|
-
if (property.default !== void 0 && property.maxLength !== void 0 && property.default.length > property.maxLength) {
|
|
12402
|
-
ctx.addIssue({
|
|
12403
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12404
|
-
path: [...path, "default"],
|
|
12405
|
-
message: `"${name}" declares a default longer than its own maxLength.`
|
|
12406
|
-
});
|
|
12407
|
-
}
|
|
12408
|
-
if (property.pattern !== void 0 && !isSafeRegex(property.pattern)) {
|
|
12420
|
+
}
|
|
12421
|
+
for (const [label, values] of enumerableValues(property)) {
|
|
12422
|
+
for (const value of values) {
|
|
12423
|
+
const violation = infrastructureValueViolation(value);
|
|
12424
|
+
if (violation) {
|
|
12409
12425
|
ctx.addIssue({
|
|
12410
12426
|
code: external_exports.ZodIssueCode.custom,
|
|
12411
|
-
path: [...path,
|
|
12412
|
-
message:
|
|
12427
|
+
path: [...path, label],
|
|
12428
|
+
message: `${violation}. Customer settings offer outcomes, not infrastructure sizes.`
|
|
12413
12429
|
});
|
|
12414
12430
|
}
|
|
12415
12431
|
}
|
|
12416
|
-
|
|
12417
|
-
|
|
12418
|
-
|
|
12419
|
-
|
|
12420
|
-
|
|
12421
|
-
|
|
12422
|
-
|
|
12423
|
-
|
|
12424
|
-
|
|
12432
|
+
}
|
|
12433
|
+
if (property.type === "string") {
|
|
12434
|
+
const secret = property["x-secret"] === true;
|
|
12435
|
+
const credential = credentialNameViolation(name);
|
|
12436
|
+
if (credential && !secret) {
|
|
12437
|
+
ctx.addIssue({
|
|
12438
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12439
|
+
path,
|
|
12440
|
+
// THE REMEDIATION HAS TO BE ONE THE CONTRACT ALLOWS. At the root, the
|
|
12441
|
+
// answer is to declare the two markers. Below it, that answer is
|
|
12442
|
+
// IMPOSSIBLE — the nested shape omits both keys and `.strict()` refuses
|
|
12443
|
+
// them — so telling a publisher to add them sends them to write a
|
|
12444
|
+
// second invalid document, and an agent following the validator loops.
|
|
12445
|
+
// A validator's errors are part of the agent-facing contract.
|
|
12446
|
+
message: atRoot ? `${credential} and must be declared "x-secret": true with "writeOnly": true, or renamed if it is not one.` : `${credential}, and a credential must be a TOP-LEVEL setting in this contract format \u2014 move it out of the group and declare it "x-secret": true with "writeOnly": true, or rename it if it is not one.`
|
|
12447
|
+
});
|
|
12448
|
+
}
|
|
12449
|
+
if (secret && property.writeOnly !== true) {
|
|
12450
|
+
ctx.addIssue({
|
|
12451
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12452
|
+
path,
|
|
12453
|
+
message: `"${name}" is marked x-secret but not writeOnly \u2014 a read API could echo the value.`
|
|
12454
|
+
});
|
|
12455
|
+
}
|
|
12456
|
+
if (property.writeOnly === true && !secret) {
|
|
12457
|
+
ctx.addIssue({
|
|
12458
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12459
|
+
path,
|
|
12460
|
+
message: `"${name}" is marked writeOnly but not x-secret \u2014 the value would not be routed to the secret flow.`
|
|
12461
|
+
});
|
|
12462
|
+
}
|
|
12463
|
+
if (secret && property.default !== void 0) {
|
|
12464
|
+
ctx.addIssue({
|
|
12465
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12466
|
+
path: [...path, "default"],
|
|
12467
|
+
message: `"${name}" is a secret and must not declare a default value.`
|
|
12468
|
+
});
|
|
12469
|
+
}
|
|
12470
|
+
if (secret && property.enum !== void 0) {
|
|
12471
|
+
ctx.addIssue({
|
|
12472
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12473
|
+
path: [...path, "enum"],
|
|
12474
|
+
message: `"${name}" is a secret; an enum would enumerate candidate secret values.`
|
|
12475
|
+
});
|
|
12476
|
+
}
|
|
12477
|
+
if (property.enum === void 0 && property.maxLength === void 0) {
|
|
12478
|
+
ctx.addIssue({
|
|
12479
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12480
|
+
path,
|
|
12481
|
+
message: `"${name}" must declare either an enum or a maxLength.`
|
|
12482
|
+
});
|
|
12483
|
+
}
|
|
12484
|
+
if (property.enum !== void 0 && property.default !== void 0 && !property.enum.includes(property.default)) {
|
|
12485
|
+
ctx.addIssue({
|
|
12486
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12487
|
+
path: [...path, "default"],
|
|
12488
|
+
message: `"${name}" declares a default outside its enum.`
|
|
12489
|
+
});
|
|
12490
|
+
}
|
|
12491
|
+
if (property.minLength !== void 0 && property.maxLength !== void 0 && property.minLength > property.maxLength) {
|
|
12492
|
+
ctx.addIssue({
|
|
12493
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12494
|
+
path,
|
|
12495
|
+
message: `"${name}" has minLength greater than maxLength.`
|
|
12496
|
+
});
|
|
12497
|
+
}
|
|
12498
|
+
if (property.default !== void 0 && property.maxLength !== void 0 && property.default.length > property.maxLength) {
|
|
12499
|
+
ctx.addIssue({
|
|
12500
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12501
|
+
path: [...path, "default"],
|
|
12502
|
+
message: `"${name}" declares a default longer than its own maxLength.`
|
|
12503
|
+
});
|
|
12504
|
+
}
|
|
12505
|
+
if (property.pattern !== void 0 && !isSafeRegex(property.pattern)) {
|
|
12506
|
+
ctx.addIssue({
|
|
12507
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12508
|
+
path: [...path, "pattern"],
|
|
12509
|
+
message: `"${name}" declares a pattern that is not a valid regular expression.`
|
|
12510
|
+
});
|
|
12511
|
+
}
|
|
12512
|
+
}
|
|
12513
|
+
if (property.type === "integer" || property.type === "number") {
|
|
12514
|
+
if (property.minimum > property.maximum) {
|
|
12515
|
+
ctx.addIssue({
|
|
12516
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12517
|
+
path,
|
|
12518
|
+
message: `"${name}" has minimum greater than maximum.`
|
|
12519
|
+
});
|
|
12520
|
+
}
|
|
12521
|
+
if (property.default !== void 0 && (property.default < property.minimum || property.default > property.maximum)) {
|
|
12522
|
+
ctx.addIssue({
|
|
12523
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12524
|
+
path: [...path, "default"],
|
|
12525
|
+
message: `"${name}" declares a default outside its minimum/maximum range.`
|
|
12526
|
+
});
|
|
12527
|
+
}
|
|
12528
|
+
if (property.type === "integer" && !Number.isInteger(property.default ?? 0)) {
|
|
12529
|
+
ctx.addIssue({
|
|
12530
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12531
|
+
path: [...path, "default"],
|
|
12532
|
+
message: `"${name}" is an integer but declares a fractional default.`
|
|
12533
|
+
});
|
|
12534
|
+
}
|
|
12535
|
+
}
|
|
12536
|
+
if (property.type === "array") {
|
|
12537
|
+
const allowed = property.items.enum;
|
|
12538
|
+
if (allowed === void 0 && property.items.maxLength === void 0) {
|
|
12539
|
+
ctx.addIssue({
|
|
12540
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12541
|
+
path: [...path, "items"],
|
|
12542
|
+
message: `"${name}" items must declare either an enum or a maxLength.`
|
|
12543
|
+
});
|
|
12544
|
+
}
|
|
12545
|
+
if (property.minItems !== void 0 && property.minItems > property.maxItems) {
|
|
12546
|
+
ctx.addIssue({
|
|
12547
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12548
|
+
path,
|
|
12549
|
+
message: `"${name}" has minItems greater than maxItems.`
|
|
12550
|
+
});
|
|
12551
|
+
}
|
|
12552
|
+
if (property.default !== void 0) {
|
|
12553
|
+
if (property.default.length > property.maxItems) {
|
|
12425
12554
|
ctx.addIssue({
|
|
12426
12555
|
code: external_exports.ZodIssueCode.custom,
|
|
12427
12556
|
path: [...path, "default"],
|
|
12428
|
-
message: `"${name}" declares a default
|
|
12557
|
+
message: `"${name}" declares a default longer than maxItems.`
|
|
12429
12558
|
});
|
|
12430
12559
|
}
|
|
12431
|
-
|
|
12560
|
+
const outside = allowed ? property.default.filter((value) => !allowed.includes(value)) : [];
|
|
12561
|
+
if (outside.length > 0) {
|
|
12432
12562
|
ctx.addIssue({
|
|
12433
12563
|
code: external_exports.ZodIssueCode.custom,
|
|
12434
12564
|
path: [...path, "default"],
|
|
12435
|
-
message: `"${name}"
|
|
12436
|
-
});
|
|
12437
|
-
}
|
|
12438
|
-
}
|
|
12439
|
-
if (property.type === "array") {
|
|
12440
|
-
const allowed = property.items.enum;
|
|
12441
|
-
if (allowed === void 0 && property.items.maxLength === void 0) {
|
|
12442
|
-
ctx.addIssue({
|
|
12443
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12444
|
-
path: [...path, "items"],
|
|
12445
|
-
message: `"${name}" items must declare either an enum or a maxLength.`
|
|
12446
|
-
});
|
|
12447
|
-
}
|
|
12448
|
-
if (property.minItems !== void 0 && property.minItems > property.maxItems) {
|
|
12449
|
-
ctx.addIssue({
|
|
12450
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12451
|
-
path,
|
|
12452
|
-
message: `"${name}" has minItems greater than maxItems.`
|
|
12565
|
+
message: `"${name}" declares default values outside its items enum: ${outside.join(", ")}.`
|
|
12453
12566
|
});
|
|
12454
12567
|
}
|
|
12455
|
-
if (property.default !== void 0) {
|
|
12456
|
-
if (property.default.length > property.maxItems) {
|
|
12457
|
-
ctx.addIssue({
|
|
12458
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12459
|
-
path: [...path, "default"],
|
|
12460
|
-
message: `"${name}" declares a default longer than maxItems.`
|
|
12461
|
-
});
|
|
12462
|
-
}
|
|
12463
|
-
const outside = allowed ? property.default.filter((value) => !allowed.includes(value)) : [];
|
|
12464
|
-
if (outside.length > 0) {
|
|
12465
|
-
ctx.addIssue({
|
|
12466
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12467
|
-
path: [...path, "default"],
|
|
12468
|
-
message: `"${name}" declares default values outside its items enum: ${outside.join(", ")}.`
|
|
12469
|
-
});
|
|
12470
|
-
}
|
|
12471
|
-
}
|
|
12472
12568
|
}
|
|
12473
12569
|
}
|
|
12474
|
-
|
|
12475
|
-
if (!Object.hasOwn(config.properties, name)) {
|
|
12476
|
-
ctx.addIssue({
|
|
12477
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12478
|
-
path: ["required"],
|
|
12479
|
-
message: `"${name}" is listed as required but is not a declared property.`
|
|
12480
|
-
});
|
|
12481
|
-
}
|
|
12482
|
-
}
|
|
12483
|
-
const duplicates = (config.required ?? []).filter((name, index, all) => all.indexOf(name) !== index);
|
|
12484
|
-
if (duplicates.length > 0) {
|
|
12485
|
-
ctx.addIssue({
|
|
12486
|
-
code: external_exports.ZodIssueCode.custom,
|
|
12487
|
-
path: ["required"],
|
|
12488
|
-
message: `Duplicate required entries: ${[...new Set(duplicates)].join(", ")}.`
|
|
12489
|
-
});
|
|
12490
|
-
}
|
|
12491
|
-
checkDependentRequired(config, ctx);
|
|
12492
|
-
});
|
|
12570
|
+
}
|
|
12493
12571
|
function checkDependentRequired(config, ctx) {
|
|
12494
12572
|
const clauses = Object.entries(config.dependentRequired ?? {});
|
|
12495
12573
|
if (clauses.length === 0)
|
|
@@ -12611,29 +12689,400 @@ function checkOneSecretPerGroup(config, ctx) {
|
|
|
12611
12689
|
});
|
|
12612
12690
|
}
|
|
12613
12691
|
}
|
|
12614
|
-
|
|
12615
|
-
|
|
12616
|
-
|
|
12617
|
-
|
|
12618
|
-
|
|
12619
|
-
|
|
12620
|
-
|
|
12692
|
+
var CustomerConfigurationV2ObjectSchema = external_exports.object({
|
|
12693
|
+
type: external_exports.literal("object"),
|
|
12694
|
+
properties: external_exports.record(PropertyNameSchema, RootConfigurationPropertySchema).describe("Customer-editable settings, keyed by camelCase property name."),
|
|
12695
|
+
required: external_exports.array(PropertyNameSchema).max(MAX_CONFIGURATION_PROPERTIES).optional(),
|
|
12696
|
+
/**
|
|
12697
|
+
* ROOT PROPERTIES ONLY, in v2.0.
|
|
12698
|
+
*
|
|
12699
|
+
* The published key promises that "a publisher running an off-the-shelf
|
|
12700
|
+
* validator over that file must get the answer the platform gives", and
|
|
12701
|
+
* JSON Schema 2020-12 `dependentRequired` is scoped to the object that
|
|
12702
|
+
* carries it. A clause naming a nested leaf would be a rule no standard
|
|
12703
|
+
* validator applies, which is the one thing this key may not become. A
|
|
12704
|
+
* nested object may not carry its own clause either — that is expressible
|
|
12705
|
+
* and honest, and it is deliberately left for when something needs it.
|
|
12706
|
+
*/
|
|
12707
|
+
dependentRequired: external_exports.record(PropertyNameSchema, external_exports.array(PropertyNameSchema).min(1).max(MAX_CONFIGURATION_PROPERTIES)).optional().describe("Settings that must be supplied together, keyed by the triggering property."),
|
|
12708
|
+
additionalProperties: external_exports.literal(false)
|
|
12709
|
+
}).strict();
|
|
12710
|
+
function countNodes(property) {
|
|
12711
|
+
if (property.type === "object") {
|
|
12712
|
+
const children = Object.keys(property.properties).length;
|
|
12713
|
+
return { leaves: children, nodes: children + 1, instantiated: children };
|
|
12621
12714
|
}
|
|
12622
|
-
if (property.type === "array") {
|
|
12623
|
-
|
|
12624
|
-
|
|
12625
|
-
|
|
12626
|
-
|
|
12715
|
+
if (property.type === "array" && property.items.type === "object") {
|
|
12716
|
+
const children = Object.keys(property.items.properties).length;
|
|
12717
|
+
return {
|
|
12718
|
+
leaves: children,
|
|
12719
|
+
nodes: children + 1,
|
|
12720
|
+
instantiated: children * property.maxItems
|
|
12721
|
+
};
|
|
12627
12722
|
}
|
|
12628
|
-
return
|
|
12723
|
+
return { leaves: 1, nodes: 1, instantiated: 1 };
|
|
12629
12724
|
}
|
|
12630
|
-
function
|
|
12631
|
-
|
|
12632
|
-
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12725
|
+
function childrenOf(property) {
|
|
12726
|
+
if (property.type === "object")
|
|
12727
|
+
return property;
|
|
12728
|
+
if (property.type === "array" && property.items.type === "object")
|
|
12729
|
+
return property.items;
|
|
12730
|
+
return null;
|
|
12731
|
+
}
|
|
12732
|
+
function minimumConfigurationBytes(config) {
|
|
12733
|
+
const rootRequired = new Set(config.required ?? []);
|
|
12734
|
+
let total = 2;
|
|
12735
|
+
for (const [name, property] of Object.entries(config.properties)) {
|
|
12736
|
+
const children = childrenOf(property);
|
|
12737
|
+
if (children === null) {
|
|
12738
|
+
if (!rootRequired.has(name) && declaredLeafDefault(property) === void 0)
|
|
12739
|
+
continue;
|
|
12740
|
+
total += name.length + 3 + minimumLeafBytes(property);
|
|
12741
|
+
continue;
|
|
12742
|
+
}
|
|
12743
|
+
if (!rootRequired.has(name))
|
|
12744
|
+
continue;
|
|
12745
|
+
const inner = minimumGroupBytes(children.properties, children.required ?? []);
|
|
12746
|
+
total += name.length + 3 + (property.type === "array" ? 2 + (property.minItems ?? 0) * inner : inner);
|
|
12747
|
+
}
|
|
12748
|
+
return total;
|
|
12749
|
+
}
|
|
12750
|
+
function minimumGroupBytes(properties, required) {
|
|
12751
|
+
const names = new Set(required);
|
|
12752
|
+
let total = 2;
|
|
12753
|
+
for (const [name, property] of Object.entries(properties)) {
|
|
12754
|
+
if (!names.has(name) && declaredLeafDefault(property) === void 0)
|
|
12755
|
+
continue;
|
|
12756
|
+
total += name.length + 3 + minimumLeafBytes(property);
|
|
12757
|
+
}
|
|
12758
|
+
return total;
|
|
12759
|
+
}
|
|
12760
|
+
function minimumLeafBytes(property) {
|
|
12761
|
+
switch (property.type) {
|
|
12762
|
+
case "string": {
|
|
12763
|
+
const shortestEnum = property.enum?.reduce((a, b) => a.length <= b.length ? a : b);
|
|
12764
|
+
const shortest = shortestEnum?.length ?? Math.max(property.minLength ?? 0, 1);
|
|
12765
|
+
return shortest + 2;
|
|
12766
|
+
}
|
|
12767
|
+
case "integer":
|
|
12768
|
+
case "number":
|
|
12769
|
+
return 1;
|
|
12770
|
+
case "boolean":
|
|
12771
|
+
return 4;
|
|
12772
|
+
case "array":
|
|
12773
|
+
return 2 + (property.minItems ?? 0) * 3;
|
|
12774
|
+
case "object":
|
|
12775
|
+
return 2;
|
|
12776
|
+
}
|
|
12777
|
+
}
|
|
12778
|
+
function declaredLeafDefault(property) {
|
|
12779
|
+
return property.type === "object" ? void 0 : property.default;
|
|
12780
|
+
}
|
|
12781
|
+
var CustomerConfigurationV2Schema = CustomerConfigurationV2ObjectSchema.superRefine((config, ctx) => {
|
|
12782
|
+
const names = Object.keys(config.properties);
|
|
12783
|
+
if (names.length > MAX_CONFIGURATION_PROPERTIES) {
|
|
12784
|
+
ctx.addIssue({
|
|
12785
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12786
|
+
path: ["properties"],
|
|
12787
|
+
message: `A Product may declare at most ${MAX_CONFIGURATION_PROPERTIES} customer settings; found ${names.length}.`
|
|
12788
|
+
});
|
|
12789
|
+
}
|
|
12790
|
+
let leaves = 0;
|
|
12791
|
+
let nodes = 0;
|
|
12792
|
+
let instantiated = 0;
|
|
12793
|
+
for (const name of names) {
|
|
12794
|
+
const property = config.properties[name];
|
|
12795
|
+
const path = ["properties", name];
|
|
12796
|
+
const counted = countNodes(property);
|
|
12797
|
+
leaves += counted.leaves;
|
|
12798
|
+
nodes += counted.nodes;
|
|
12799
|
+
instantiated += counted.instantiated;
|
|
12800
|
+
const children = childrenOf(property);
|
|
12801
|
+
if (children === null) {
|
|
12802
|
+
checkDeclaredProperty(name, property, path, ctx, true);
|
|
12803
|
+
continue;
|
|
12804
|
+
}
|
|
12805
|
+
const infrastructure = infrastructureVocabularyViolation(name);
|
|
12806
|
+
if (infrastructure) {
|
|
12807
|
+
ctx.addIssue({
|
|
12808
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12809
|
+
path,
|
|
12810
|
+
message: `${infrastructure}. Customer settings describe outcomes, not infrastructure.`
|
|
12811
|
+
});
|
|
12812
|
+
}
|
|
12813
|
+
const platformOwned = platformOwnedFieldViolation(name);
|
|
12814
|
+
if (platformOwned) {
|
|
12815
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path, message: `${platformOwned}.` });
|
|
12816
|
+
}
|
|
12817
|
+
const childNames = Object.keys(children.properties);
|
|
12818
|
+
if (childNames.length === 0) {
|
|
12819
|
+
ctx.addIssue({
|
|
12820
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12821
|
+
path: [...path, "properties"],
|
|
12822
|
+
message: `"${name}" declares no settings. A group with nothing in it renders as an empty section.`
|
|
12823
|
+
});
|
|
12824
|
+
}
|
|
12825
|
+
if (childNames.length > MAX_CONFIGURATION_PROPERTIES) {
|
|
12826
|
+
ctx.addIssue({
|
|
12827
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12828
|
+
path: [...path, "properties"],
|
|
12829
|
+
message: `"${name}" may declare at most ${MAX_CONFIGURATION_PROPERTIES} settings; found ${childNames.length}.`
|
|
12830
|
+
});
|
|
12831
|
+
}
|
|
12832
|
+
if (property.type === "array" && property.default !== void 0) {
|
|
12833
|
+
ctx.addIssue({
|
|
12834
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12835
|
+
path: [...path, "default"],
|
|
12836
|
+
message: `"${name}" is a list of groups and cannot declare a default. Declare defaults on the settings inside it.`
|
|
12837
|
+
});
|
|
12838
|
+
}
|
|
12839
|
+
if (property.type === "array" && property.minItems !== void 0 && property.minItems > property.maxItems) {
|
|
12840
|
+
ctx.addIssue({
|
|
12841
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12842
|
+
path,
|
|
12843
|
+
message: `"${name}" has minItems greater than maxItems.`
|
|
12844
|
+
});
|
|
12845
|
+
}
|
|
12846
|
+
for (const childName of childNames) {
|
|
12847
|
+
checkDeclaredProperty(childName, children.properties[childName], [...path, "properties", childName], ctx, false);
|
|
12848
|
+
}
|
|
12849
|
+
for (const required of children.required ?? []) {
|
|
12850
|
+
if (!Object.hasOwn(children.properties, required)) {
|
|
12851
|
+
ctx.addIssue({
|
|
12852
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12853
|
+
path: [...path, "required"],
|
|
12854
|
+
message: `"${required}" is listed as required in "${name}" but is not one of its settings.`
|
|
12855
|
+
});
|
|
12856
|
+
}
|
|
12857
|
+
}
|
|
12858
|
+
}
|
|
12859
|
+
if (leaves > MAX_CONFIGURATION_LEAVES) {
|
|
12860
|
+
ctx.addIssue({
|
|
12861
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12862
|
+
path: ["properties"],
|
|
12863
|
+
message: `A Product may declare at most ${MAX_CONFIGURATION_LEAVES} customer settings in total; found ${leaves}.`
|
|
12864
|
+
});
|
|
12865
|
+
}
|
|
12866
|
+
if (nodes > MAX_CONFIGURATION_NODES) {
|
|
12867
|
+
ctx.addIssue({
|
|
12868
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12869
|
+
path: ["properties"],
|
|
12870
|
+
message: `A Product may declare at most ${MAX_CONFIGURATION_NODES} configuration nodes; found ${nodes}.`
|
|
12871
|
+
});
|
|
12872
|
+
}
|
|
12873
|
+
if (instantiated > MAX_CONFIGURATION_VALUE_LEAVES) {
|
|
12874
|
+
ctx.addIssue({
|
|
12875
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12876
|
+
path: ["properties"],
|
|
12877
|
+
message: `This Product's settings could expand to ${instantiated} values \u2014 a list of groups instantiates its settings once per item. At most ${MAX_CONFIGURATION_VALUE_LEAVES} are allowed; reduce maxItems, or the number of settings inside the list.`
|
|
12878
|
+
});
|
|
12879
|
+
}
|
|
12880
|
+
for (const name of config.required ?? []) {
|
|
12881
|
+
if (!Object.hasOwn(config.properties, name)) {
|
|
12882
|
+
ctx.addIssue({
|
|
12883
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12884
|
+
path: ["required"],
|
|
12885
|
+
message: `"${name}" is listed as required but is not a declared property.`
|
|
12886
|
+
});
|
|
12887
|
+
}
|
|
12888
|
+
}
|
|
12889
|
+
const floor = minimumConfigurationBytes(config);
|
|
12890
|
+
if (floor > MAX_CONFIGURATION_VALUE_BYTES) {
|
|
12891
|
+
ctx.addIssue({
|
|
12892
|
+
code: external_exports.ZodIssueCode.custom,
|
|
12893
|
+
path: ["properties"],
|
|
12894
|
+
message: `The smallest configuration that could satisfy this Product is at least ${floor} bytes, and the limit is ${MAX_CONFIGURATION_VALUE_BYTES}. No customer could deploy it \u2014 reduce the required settings, their minimum lengths, or a list's minItems.`
|
|
12895
|
+
});
|
|
12896
|
+
}
|
|
12897
|
+
checkDependentRequired(config, ctx);
|
|
12898
|
+
checkOneSecretPerGroup(config, ctx);
|
|
12899
|
+
});
|
|
12900
|
+
function enumerableValues(property) {
|
|
12901
|
+
const out = [];
|
|
12902
|
+
if (property.type === "string") {
|
|
12903
|
+
if (property.enum)
|
|
12904
|
+
out.push(["enum", property.enum]);
|
|
12905
|
+
if (property.default !== void 0)
|
|
12906
|
+
out.push(["default", [property.default]]);
|
|
12907
|
+
}
|
|
12908
|
+
if (property.type === "array") {
|
|
12909
|
+
if (property.items.enum)
|
|
12910
|
+
out.push(["items", property.items.enum]);
|
|
12911
|
+
if (property.default)
|
|
12912
|
+
out.push(["default", property.default]);
|
|
12913
|
+
}
|
|
12914
|
+
return out;
|
|
12915
|
+
}
|
|
12916
|
+
function isSafeRegex(pattern) {
|
|
12917
|
+
try {
|
|
12918
|
+
new RegExp(pattern);
|
|
12919
|
+
return true;
|
|
12920
|
+
} catch {
|
|
12921
|
+
return false;
|
|
12922
|
+
}
|
|
12923
|
+
}
|
|
12924
|
+
function isSecretProperty(property) {
|
|
12925
|
+
return property.type === "string" && property["x-secret"] === true;
|
|
12926
|
+
}
|
|
12927
|
+
|
|
12928
|
+
// ../product-configuration/dist/configuration-path.js
|
|
12929
|
+
var MAX_CONFIGURATION_PATH_SEGMENTS = MAX_CONFIGURATION_DEPTH + 1;
|
|
12930
|
+
function isIndexSegment(raw) {
|
|
12931
|
+
return /^\d+$/.test(raw) && String(Number(raw)) === raw;
|
|
12932
|
+
}
|
|
12933
|
+
function isPathSegment(segment) {
|
|
12934
|
+
if (typeof segment === "number")
|
|
12935
|
+
return Number.isInteger(segment) && segment >= 0;
|
|
12936
|
+
return CONFIGURATION_PROPERTY_NAME_REGEX.test(segment) || isIndexSegment(segment);
|
|
12937
|
+
}
|
|
12938
|
+
function configurationPath(...segments) {
|
|
12939
|
+
if (segments.length === 0 || segments.length > MAX_CONFIGURATION_PATH_SEGMENTS)
|
|
12940
|
+
return null;
|
|
12941
|
+
if (!segments.every(isPathSegment))
|
|
12942
|
+
return null;
|
|
12943
|
+
if (typeof segments[0] === "number" || isIndexSegment(String(segments[0])))
|
|
12944
|
+
return null;
|
|
12945
|
+
if (segments.length === 1)
|
|
12946
|
+
return String(segments[0]);
|
|
12947
|
+
return `/${segments.map(String).join("/")}`;
|
|
12948
|
+
}
|
|
12949
|
+
function parseConfigurationPath(raw) {
|
|
12950
|
+
if (typeof raw !== "string" || raw.length === 0)
|
|
12951
|
+
return null;
|
|
12952
|
+
if (!raw.startsWith("/"))
|
|
12953
|
+
return configurationPath(raw);
|
|
12954
|
+
const segments = raw.slice(1).split("/");
|
|
12955
|
+
if (segments.length < 2)
|
|
12956
|
+
return null;
|
|
12957
|
+
return configurationPath(...segments);
|
|
12958
|
+
}
|
|
12959
|
+
function pathSegments(path) {
|
|
12960
|
+
const raw = path.startsWith("/") ? path.slice(1).split("/") : [path];
|
|
12961
|
+
return raw.map((segment) => isIndexSegment(segment) ? Number(segment) : segment);
|
|
12962
|
+
}
|
|
12963
|
+
function declarationPathOf(path) {
|
|
12964
|
+
const segments = pathSegments(path).filter((segment) => typeof segment !== "number");
|
|
12965
|
+
return configurationPath(...segments) ?? path;
|
|
12966
|
+
}
|
|
12967
|
+
function printableConfigurationPath(path) {
|
|
12968
|
+
return pathSegments(path).join(".");
|
|
12969
|
+
}
|
|
12970
|
+
|
|
12971
|
+
// ../product-configuration/dist/canonical-json.js
|
|
12972
|
+
function canonicalise(value, path) {
|
|
12973
|
+
if (value === null)
|
|
12974
|
+
return "null";
|
|
12975
|
+
if (typeof value === "string")
|
|
12976
|
+
return JSON.stringify(value);
|
|
12977
|
+
if (typeof value === "boolean")
|
|
12978
|
+
return value ? "true" : "false";
|
|
12979
|
+
if (typeof value === "number") {
|
|
12980
|
+
if (!Number.isFinite(value)) {
|
|
12981
|
+
throw new Error(`canonicalJson: non-finite number at ${path}`);
|
|
12982
|
+
}
|
|
12983
|
+
return JSON.stringify(value === 0 ? 0 : value);
|
|
12984
|
+
}
|
|
12985
|
+
if (typeof value !== "object") {
|
|
12986
|
+
throw new Error(`canonicalJson: ${typeof value} is not JSON at ${path}`);
|
|
12987
|
+
}
|
|
12988
|
+
if (Array.isArray(value)) {
|
|
12989
|
+
return `[${value.map((item, i) => canonicalise(item, `${path}[${i}]`)).join(",")}]`;
|
|
12990
|
+
}
|
|
12991
|
+
const entries = Object.entries(value);
|
|
12992
|
+
for (const [key, item] of entries) {
|
|
12993
|
+
if (item === void 0) {
|
|
12994
|
+
throw new Error(`canonicalJson: undefined property at ${path}.${key}`);
|
|
12995
|
+
}
|
|
12996
|
+
}
|
|
12997
|
+
const sorted = entries.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
|
|
12998
|
+
const body = sorted.map(([key, item]) => `${JSON.stringify(key)}:${canonicalise(item, `${path}.${key}`)}`).join(",");
|
|
12999
|
+
return `{${body}}`;
|
|
13000
|
+
}
|
|
13001
|
+
function canonicalJson(value) {
|
|
13002
|
+
return canonicalise(value, "$");
|
|
13003
|
+
}
|
|
13004
|
+
|
|
13005
|
+
// ../product-configuration/dist/configuration-tree.js
|
|
13006
|
+
function containerChildren(property) {
|
|
13007
|
+
if (property.type === "object" && property.properties !== void 0) {
|
|
13008
|
+
return {
|
|
13009
|
+
kind: "object",
|
|
13010
|
+
properties: property.properties,
|
|
13011
|
+
required: property.required ?? []
|
|
13012
|
+
};
|
|
13013
|
+
}
|
|
13014
|
+
if (property.type === "array" && property.items !== void 0) {
|
|
13015
|
+
const items = property.items;
|
|
13016
|
+
if (items.type !== "object" || items.properties === void 0)
|
|
13017
|
+
return null;
|
|
13018
|
+
return {
|
|
13019
|
+
kind: "array",
|
|
13020
|
+
properties: items.properties,
|
|
13021
|
+
required: items.required ?? []
|
|
13022
|
+
};
|
|
13023
|
+
}
|
|
13024
|
+
return null;
|
|
13025
|
+
}
|
|
13026
|
+
function isConfigurationContainer(property) {
|
|
13027
|
+
return containerChildren(property) !== null;
|
|
13028
|
+
}
|
|
13029
|
+
function configurationLeaves(schema) {
|
|
13030
|
+
const out = [];
|
|
13031
|
+
for (const [name, property] of Object.entries(schema.properties)) {
|
|
13032
|
+
const children = containerChildren(property);
|
|
13033
|
+
if (children === null) {
|
|
13034
|
+
const path = configurationPath(name);
|
|
13035
|
+
if (path !== null) {
|
|
13036
|
+
out.push({ path, name, property, container: null });
|
|
13037
|
+
}
|
|
13038
|
+
continue;
|
|
13039
|
+
}
|
|
13040
|
+
const containerPath = configurationPath(name);
|
|
13041
|
+
if (containerPath === null)
|
|
13042
|
+
continue;
|
|
13043
|
+
const container = {
|
|
13044
|
+
path: containerPath,
|
|
13045
|
+
name,
|
|
13046
|
+
kind: children.kind,
|
|
13047
|
+
property,
|
|
13048
|
+
required: children.required
|
|
13049
|
+
};
|
|
13050
|
+
for (const [childName, child] of Object.entries(children.properties)) {
|
|
13051
|
+
const path = configurationPath(name, childName);
|
|
13052
|
+
if (path === null)
|
|
13053
|
+
continue;
|
|
13054
|
+
out.push({ path, name: childName, property: child, container });
|
|
13055
|
+
}
|
|
13056
|
+
}
|
|
13057
|
+
return out;
|
|
13058
|
+
}
|
|
13059
|
+
function configurationContainers(schema) {
|
|
13060
|
+
const out = [];
|
|
13061
|
+
for (const [name, property] of Object.entries(schema.properties)) {
|
|
13062
|
+
const children = containerChildren(property);
|
|
13063
|
+
if (children === null)
|
|
13064
|
+
continue;
|
|
13065
|
+
const path = configurationPath(name);
|
|
13066
|
+
if (path === null)
|
|
13067
|
+
continue;
|
|
13068
|
+
out.push({
|
|
13069
|
+
path,
|
|
13070
|
+
name,
|
|
13071
|
+
kind: children.kind,
|
|
13072
|
+
property,
|
|
13073
|
+
required: children.required
|
|
13074
|
+
});
|
|
13075
|
+
}
|
|
13076
|
+
return out;
|
|
13077
|
+
}
|
|
13078
|
+
function leafAt(schema, path) {
|
|
13079
|
+
const declaration = declarationPathOf(path);
|
|
13080
|
+
return configurationLeaves(schema).find((leaf) => leaf.path === declaration) ?? null;
|
|
13081
|
+
}
|
|
13082
|
+
function declaresPath(schema, path) {
|
|
13083
|
+
if (leafAt(schema, path) !== null)
|
|
13084
|
+
return true;
|
|
13085
|
+
return configurationContainers(schema).some((container) => container.path === declarationPathOf(path));
|
|
12637
13086
|
}
|
|
12638
13087
|
|
|
12639
13088
|
// ../product-configuration/dist/customer-configuration-input.js
|
|
@@ -12642,11 +13091,24 @@ var MAX_REPORTED_UNDECLARED_KEYS = 10;
|
|
|
12642
13091
|
function isPlainObject(value) {
|
|
12643
13092
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12644
13093
|
}
|
|
12645
|
-
function
|
|
12646
|
-
|
|
13094
|
+
function report(walk, field, message) {
|
|
13095
|
+
if (walk.issues.length >= MAX_CONFIGURATION_ISSUES) {
|
|
13096
|
+
walk.suppressed += 1;
|
|
13097
|
+
return;
|
|
13098
|
+
}
|
|
13099
|
+
walk.issues.push({ field, message });
|
|
13100
|
+
}
|
|
13101
|
+
function drain(walk, collected) {
|
|
13102
|
+
for (const issue of collected)
|
|
13103
|
+
report(walk, issue.field, issue.message);
|
|
12647
13104
|
}
|
|
12648
13105
|
function validateSubmittedConfiguration(schema, submitted, presence = {}) {
|
|
12649
|
-
const
|
|
13106
|
+
const walk = {
|
|
13107
|
+
issues: [],
|
|
13108
|
+
suppressed: 0,
|
|
13109
|
+
leaves: 0,
|
|
13110
|
+
referenced: new Set(presence.referenced ?? [])
|
|
13111
|
+
};
|
|
12650
13112
|
const supplied = /* @__PURE__ */ new Set();
|
|
12651
13113
|
if (submitted !== void 0 && submitted !== null && !isPlainObject(submitted)) {
|
|
12652
13114
|
return {
|
|
@@ -12656,64 +13118,195 @@ function validateSubmittedConfiguration(schema, submitted, presence = {}) {
|
|
|
12656
13118
|
};
|
|
12657
13119
|
}
|
|
12658
13120
|
const input = isPlainObject(submitted) ? submitted : {};
|
|
12659
|
-
const
|
|
12660
|
-
|
|
12661
|
-
|
|
12662
|
-
|
|
12663
|
-
|
|
12664
|
-
});
|
|
12665
|
-
}
|
|
12666
|
-
if (undeclared.length > MAX_REPORTED_UNDECLARED_KEYS) {
|
|
12667
|
-
issues.push({
|
|
13121
|
+
const secrets = {};
|
|
13122
|
+
const configuration = validateObject({ properties: schema.properties, required: schema.required }, input, null, walk, { secrets, supplied });
|
|
13123
|
+
drain(walk, crossFieldIssues(schema, supplied, presence));
|
|
13124
|
+
if (walk.suppressed > 0) {
|
|
13125
|
+
walk.issues.push({
|
|
12668
13126
|
field: "",
|
|
12669
|
-
|
|
12670
|
-
// cannot carry anything the caller chose.
|
|
12671
|
-
message: `${undeclared.length - MAX_REPORTED_UNDECLARED_KEYS} further settings are not declared by this Product.`
|
|
13127
|
+
message: `${walk.suppressed} further problems were found and are not listed.`
|
|
12672
13128
|
});
|
|
12673
13129
|
}
|
|
12674
|
-
|
|
12675
|
-
|
|
12676
|
-
|
|
12677
|
-
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
13130
|
+
if (declaresContainer(schema)) {
|
|
13131
|
+
const size = utf8ByteLength(JSON.stringify(configuration));
|
|
13132
|
+
if (size > MAX_CONFIGURATION_VALUE_BYTES) {
|
|
13133
|
+
report(walk, "", `This configuration is ${size} bytes once defaults are applied, and the limit is ${MAX_CONFIGURATION_VALUE_BYTES}. Remove some items.`);
|
|
13134
|
+
}
|
|
13135
|
+
}
|
|
13136
|
+
if (walk.issues.length > 0)
|
|
13137
|
+
return { ok: false, issues: walk.issues, partial: configuration };
|
|
13138
|
+
return { ok: true, configuration, secrets };
|
|
13139
|
+
}
|
|
13140
|
+
function utf8ByteLength(value) {
|
|
13141
|
+
return new TextEncoder().encode(value).length;
|
|
13142
|
+
}
|
|
13143
|
+
function declaresContainer(schema) {
|
|
13144
|
+
return Object.values(schema.properties).some((property) => isConfigurationContainer(property));
|
|
13145
|
+
}
|
|
13146
|
+
function containsReferenced(walk, container) {
|
|
13147
|
+
if (walk.referenced.size === 0)
|
|
13148
|
+
return false;
|
|
13149
|
+
const parsedOuter = parseConfigurationPath(container);
|
|
13150
|
+
if (parsedOuter === null)
|
|
13151
|
+
return false;
|
|
13152
|
+
const outer = pathSegments(parsedOuter);
|
|
13153
|
+
for (const candidate of walk.referenced) {
|
|
13154
|
+
const parsed = parseConfigurationPath(candidate);
|
|
13155
|
+
if (parsed === null)
|
|
13156
|
+
continue;
|
|
13157
|
+
const inner = pathSegments(parsed);
|
|
13158
|
+
if (inner.length <= outer.length)
|
|
13159
|
+
continue;
|
|
13160
|
+
if (outer.every((segment, index) => inner[index] === segment))
|
|
13161
|
+
return true;
|
|
13162
|
+
}
|
|
13163
|
+
return false;
|
|
13164
|
+
}
|
|
13165
|
+
function validateObject(declaration, input, container, walk, root) {
|
|
13166
|
+
const required = new Set(declaration.required ?? []);
|
|
13167
|
+
const out = {};
|
|
13168
|
+
const fieldFor = (name) => {
|
|
13169
|
+
const path = container === null ? configurationPath(name) : configurationPath(...pathSegments(container), name);
|
|
13170
|
+
return path ?? "";
|
|
13171
|
+
};
|
|
13172
|
+
const undeclared = Object.keys(input).filter((name) => !Object.hasOwn(declaration.properties, name));
|
|
13173
|
+
for (const name of undeclared.slice(0, MAX_REPORTED_UNDECLARED_KEYS)) {
|
|
13174
|
+
report(walk, fieldFor(name), "This Product does not declare a setting with that name.");
|
|
13175
|
+
}
|
|
13176
|
+
if (undeclared.length > MAX_REPORTED_UNDECLARED_KEYS) {
|
|
13177
|
+
report(walk, container === null ? "" : container, `${undeclared.length - MAX_REPORTED_UNDECLARED_KEYS} further settings are not declared by this Product.`);
|
|
13178
|
+
}
|
|
13179
|
+
for (const [name, property] of Object.entries(declaration.properties)) {
|
|
13180
|
+
const field = fieldFor(name);
|
|
13181
|
+
const children = containerDeclaration(property);
|
|
13182
|
+
if (children !== null) {
|
|
13183
|
+
const value = input[name];
|
|
13184
|
+
const filled = validateContainer(name, property, children, value, field, walk);
|
|
13185
|
+
if (filled !== void 0)
|
|
13186
|
+
out[name] = filled;
|
|
13187
|
+
else if (required.has(name) && !containsReferenced(walk, field))
|
|
13188
|
+
report(walk, field, "This setting is required.");
|
|
13189
|
+
continue;
|
|
13190
|
+
}
|
|
13191
|
+
const leaf = property;
|
|
13192
|
+
if (walk.referenced.has(field)) {
|
|
13193
|
+
const sent = input[name];
|
|
13194
|
+
if (Object.hasOwn(input, name) && sent !== void 0) {
|
|
13195
|
+
report(walk, field, "This setting is answered by another Resource, so it cannot also be set here.");
|
|
13196
|
+
}
|
|
13197
|
+
continue;
|
|
13198
|
+
}
|
|
13199
|
+
const raw = input[name];
|
|
13200
|
+
const blank = typeof raw === "string" && raw.trim().length === 0;
|
|
13201
|
+
const present = Object.hasOwn(input, name) && raw !== void 0 && !blank;
|
|
13202
|
+
const secret = root !== null && isSecretProperty(leaf);
|
|
13203
|
+
if (present && root !== null && container === null)
|
|
13204
|
+
root.supplied.add(name);
|
|
12683
13205
|
if (!present) {
|
|
12684
|
-
const fallback = secret ? void 0 : defaultOf(
|
|
13206
|
+
const fallback = secret ? void 0 : defaultOf(leaf);
|
|
12685
13207
|
if (fallback !== void 0) {
|
|
12686
|
-
|
|
13208
|
+
walk.leaves += 1;
|
|
13209
|
+
out[name] = fallback;
|
|
12687
13210
|
} else if (required.has(name)) {
|
|
12688
|
-
|
|
13211
|
+
report(walk, field, "This setting is required.");
|
|
12689
13212
|
}
|
|
12690
13213
|
continue;
|
|
12691
13214
|
}
|
|
12692
|
-
|
|
12693
|
-
const
|
|
12694
|
-
const checked = checkProperty(
|
|
12695
|
-
if (
|
|
13215
|
+
walk.leaves += 1;
|
|
13216
|
+
const collected = [];
|
|
13217
|
+
const checked = checkProperty(field, leaf, raw, collected);
|
|
13218
|
+
if (collected.length > 0 || checked === void 0) {
|
|
13219
|
+
drain(walk, collected);
|
|
12696
13220
|
continue;
|
|
13221
|
+
}
|
|
12697
13222
|
if (secret) {
|
|
12698
13223
|
if (typeof checked === "string" && checked.length > 0)
|
|
12699
|
-
secrets[name] = checked;
|
|
12700
|
-
else if (required.has(name))
|
|
12701
|
-
|
|
12702
|
-
}
|
|
13224
|
+
root.secrets[name] = checked;
|
|
13225
|
+
else if (required.has(name))
|
|
13226
|
+
report(walk, field, "This setting is required.");
|
|
12703
13227
|
continue;
|
|
12704
13228
|
}
|
|
12705
|
-
|
|
13229
|
+
out[name] = checked;
|
|
12706
13230
|
}
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12710
|
-
|
|
13231
|
+
return out;
|
|
13232
|
+
}
|
|
13233
|
+
function containerDeclaration(property) {
|
|
13234
|
+
if (property.type === "object" && property.properties !== void 0) {
|
|
13235
|
+
return {
|
|
13236
|
+
kind: "object",
|
|
13237
|
+
properties: property.properties,
|
|
13238
|
+
required: property.required,
|
|
13239
|
+
maxItems: 1
|
|
13240
|
+
};
|
|
13241
|
+
}
|
|
13242
|
+
if (property.type === "array" && property.items !== void 0) {
|
|
13243
|
+
const items = property.items;
|
|
13244
|
+
if (items.type !== "object" || items.properties === void 0)
|
|
13245
|
+
return null;
|
|
13246
|
+
return {
|
|
13247
|
+
kind: "array",
|
|
13248
|
+
properties: items.properties,
|
|
13249
|
+
required: items.required,
|
|
13250
|
+
maxItems: property.maxItems ?? 0,
|
|
13251
|
+
minItems: property.minItems,
|
|
13252
|
+
uniqueItems: property.uniqueItems === true
|
|
13253
|
+
};
|
|
13254
|
+
}
|
|
13255
|
+
return null;
|
|
13256
|
+
}
|
|
13257
|
+
function validateContainer(name, property, children, value, field, walk) {
|
|
13258
|
+
const path = parseConfigurationPath(field);
|
|
13259
|
+
if (children.kind === "object") {
|
|
13260
|
+
if (value === void 0)
|
|
13261
|
+
return void 0;
|
|
13262
|
+
if (!isPlainObject(value)) {
|
|
13263
|
+
report(walk, field, "Expected a group of settings.");
|
|
13264
|
+
return void 0;
|
|
13265
|
+
}
|
|
13266
|
+
const filled = validateObject(children, value, path, walk, null);
|
|
13267
|
+
return Object.keys(filled).length === 0 ? void 0 : filled;
|
|
13268
|
+
}
|
|
13269
|
+
if (value === void 0)
|
|
13270
|
+
return void 0;
|
|
13271
|
+
if (!Array.isArray(value)) {
|
|
13272
|
+
report(walk, field, "Expected a list.");
|
|
13273
|
+
return void 0;
|
|
13274
|
+
}
|
|
13275
|
+
if (value.length > children.maxItems) {
|
|
13276
|
+
report(walk, field, `At most ${children.maxItems} items are allowed.`);
|
|
13277
|
+
return void 0;
|
|
13278
|
+
}
|
|
13279
|
+
if (children.minItems !== void 0 && value.length < children.minItems) {
|
|
13280
|
+
report(walk, field, `At least ${children.minItems} items are required.`);
|
|
13281
|
+
return void 0;
|
|
13282
|
+
}
|
|
13283
|
+
const out = [];
|
|
13284
|
+
for (const [index, element] of value.entries()) {
|
|
13285
|
+
if (walk.leaves >= MAX_CONFIGURATION_VALUE_LEAVES) {
|
|
13286
|
+
report(walk, field, "This configuration has too many values.");
|
|
13287
|
+
break;
|
|
13288
|
+
}
|
|
13289
|
+
if (!isPlainObject(element)) {
|
|
13290
|
+
report(walk, `${field}`, `Item ${index + 1} is not a group of settings.`);
|
|
13291
|
+
continue;
|
|
13292
|
+
}
|
|
13293
|
+
const elementPath = path === null ? null : configurationPath(...pathSegments(path), index);
|
|
13294
|
+
out.push(validateObject(children, element, elementPath, walk, null));
|
|
13295
|
+
}
|
|
13296
|
+
if (children.uniqueItems === true) {
|
|
13297
|
+
const seen = new Set(out.map((entry) => canonicalJson(entry)));
|
|
13298
|
+
if (seen.size !== out.length) {
|
|
13299
|
+
report(walk, field, "Items must be unique.");
|
|
13300
|
+
return void 0;
|
|
13301
|
+
}
|
|
13302
|
+
}
|
|
13303
|
+
return out;
|
|
12711
13304
|
}
|
|
12712
13305
|
function crossFieldIssues(schema, supplied, presence) {
|
|
12713
13306
|
const clauses = Object.entries(schema.dependentRequired ?? {});
|
|
12714
13307
|
if (clauses.length === 0)
|
|
12715
13308
|
return [];
|
|
12716
|
-
const alsoPresent = new Set(presence.present ?? []);
|
|
13309
|
+
const alsoPresent = /* @__PURE__ */ new Set([...presence.present ?? [], ...presence.referenced ?? []]);
|
|
12717
13310
|
const unknown = new Set(presence.unknown ?? []);
|
|
12718
13311
|
const known = (name) => !unknown.has(name);
|
|
12719
13312
|
const held = (name) => supplied.has(name) || alsoPresent.has(name);
|
|
@@ -12875,12 +13468,17 @@ function matches(pattern, value) {
|
|
|
12875
13468
|
var RESOURCE_API_VERSION = "resources.vardeflyt.no/v1";
|
|
12876
13469
|
var PRODUCT_INSTANCE_KIND = "ProductInstance";
|
|
12877
13470
|
|
|
13471
|
+
// ../product-configuration/dist/resource-key.js
|
|
13472
|
+
var RESOURCE_KEY_PATTERN = /^[a-z][a-z0-9-]{1,61}[a-z0-9]$/;
|
|
13473
|
+
var RESOURCE_KEY_RULE = "A resource key is 3\u201363 characters of lowercase letters, digits and hyphens, starting with a letter and ending with a letter or digit.";
|
|
13474
|
+
var ResourceKeySchema = external_exports.string().regex(RESOURCE_KEY_PATTERN, RESOURCE_KEY_RULE).describe(RESOURCE_KEY_RULE);
|
|
13475
|
+
|
|
12878
13476
|
// ../product-configuration/dist/product-instance-example.js
|
|
12879
|
-
function resolveExampleChoice(options, selected,
|
|
13477
|
+
function resolveExampleChoice(options, selected, declaredDefault2) {
|
|
12880
13478
|
if (selected !== void 0)
|
|
12881
13479
|
return options.includes(selected) ? { value: selected, issue: null } : { value: null, issue: "invalid" };
|
|
12882
|
-
if (
|
|
12883
|
-
return { value:
|
|
13480
|
+
if (declaredDefault2 !== void 0 && options.includes(declaredDefault2))
|
|
13481
|
+
return { value: declaredDefault2, issue: null };
|
|
12884
13482
|
if (options.length === 1)
|
|
12885
13483
|
return { value: options[0], issue: null };
|
|
12886
13484
|
return { value: null, issue: options.length === 0 ? "unavailable" : "required" };
|
|
@@ -12908,17 +13506,84 @@ function seedConfiguration(configuration) {
|
|
|
12908
13506
|
requiredSecrets.push(name);
|
|
12909
13507
|
continue;
|
|
12910
13508
|
}
|
|
13509
|
+
const children = containerChildren2(declaration);
|
|
13510
|
+
if (children !== null) {
|
|
13511
|
+
if (!required.has(name))
|
|
13512
|
+
continue;
|
|
13513
|
+
if (children.kind === "object") {
|
|
13514
|
+
values[name] = seedGroup(children, name, open);
|
|
13515
|
+
continue;
|
|
13516
|
+
}
|
|
13517
|
+
const count = children.minItems ?? 0;
|
|
13518
|
+
values[name] = Array.from({ length: count }, () => seedGroup(children, name, open));
|
|
13519
|
+
if (count > 1)
|
|
13520
|
+
dedupeOpen(open);
|
|
13521
|
+
continue;
|
|
13522
|
+
}
|
|
12911
13523
|
if (declaration.default !== void 0) {
|
|
12912
13524
|
values[name] = declaration.default;
|
|
12913
13525
|
continue;
|
|
12914
13526
|
}
|
|
12915
13527
|
if (required.has(name)) {
|
|
12916
13528
|
values[name] = "";
|
|
12917
|
-
open.push({ name, type: declaration.type ?? null });
|
|
13529
|
+
open.push({ name, label: name, type: declaration.type ?? null });
|
|
12918
13530
|
}
|
|
12919
13531
|
}
|
|
12920
13532
|
return { values, open, requiredSecrets, groups };
|
|
12921
13533
|
}
|
|
13534
|
+
function containerChildren2(declaration) {
|
|
13535
|
+
const node = declaration;
|
|
13536
|
+
if (node.type === "object" && node.properties !== void 0) {
|
|
13537
|
+
return {
|
|
13538
|
+
kind: "object",
|
|
13539
|
+
properties: node.properties,
|
|
13540
|
+
required: node.required ?? []
|
|
13541
|
+
};
|
|
13542
|
+
}
|
|
13543
|
+
if (node.type === "array" && node.items !== void 0) {
|
|
13544
|
+
const items = node.items;
|
|
13545
|
+
if (items.type !== "object" || items.properties === void 0)
|
|
13546
|
+
return null;
|
|
13547
|
+
return {
|
|
13548
|
+
kind: "array",
|
|
13549
|
+
properties: items.properties,
|
|
13550
|
+
required: items.required ?? [],
|
|
13551
|
+
...typeof node.minItems === "number" ? { minItems: node.minItems } : {}
|
|
13552
|
+
};
|
|
13553
|
+
}
|
|
13554
|
+
return null;
|
|
13555
|
+
}
|
|
13556
|
+
function dedupeOpen(open) {
|
|
13557
|
+
const seen = /* @__PURE__ */ new Set();
|
|
13558
|
+
const unique = open.filter((entry) => {
|
|
13559
|
+
if (seen.has(entry.name))
|
|
13560
|
+
return false;
|
|
13561
|
+
seen.add(entry.name);
|
|
13562
|
+
return true;
|
|
13563
|
+
});
|
|
13564
|
+
open.length = 0;
|
|
13565
|
+
open.push(...unique);
|
|
13566
|
+
}
|
|
13567
|
+
function seedGroup(children, container, open) {
|
|
13568
|
+
const required = new Set(children.required);
|
|
13569
|
+
const values = {};
|
|
13570
|
+
for (const [name, declaration] of Object.entries(children.properties)) {
|
|
13571
|
+
if (declaration.default !== void 0) {
|
|
13572
|
+
values[name] = declaration.default;
|
|
13573
|
+
continue;
|
|
13574
|
+
}
|
|
13575
|
+
if (required.has(name)) {
|
|
13576
|
+
values[name] = "";
|
|
13577
|
+
const path = configurationPath(container, name);
|
|
13578
|
+
open.push({
|
|
13579
|
+
name: path ?? name,
|
|
13580
|
+
label: path === null ? name : printableConfigurationPath(path),
|
|
13581
|
+
type: declaration.type ?? null
|
|
13582
|
+
});
|
|
13583
|
+
}
|
|
13584
|
+
}
|
|
13585
|
+
return values;
|
|
13586
|
+
}
|
|
12922
13587
|
function productInstanceExample(input) {
|
|
12923
13588
|
return {
|
|
12924
13589
|
apiVersion: RESOURCE_API_VERSION,
|
|
@@ -12937,7 +13602,7 @@ function productInstanceExample(input) {
|
|
|
12937
13602
|
}
|
|
12938
13603
|
function exampleResourceKey(name) {
|
|
12939
13604
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^[^a-z]+/, "").replace(/-+$/, "").slice(0, 63);
|
|
12940
|
-
return
|
|
13605
|
+
return RESOURCE_KEY_PATTERN.test(slug) ? slug : "";
|
|
12941
13606
|
}
|
|
12942
13607
|
|
|
12943
13608
|
// ../platform-schemas/dist/index.js
|
|
@@ -13030,13 +13695,32 @@ var OperationStatusSchema = external_exports.enum([
|
|
|
13030
13695
|
|
|
13031
13696
|
// ../product-contracts/dist/api-version.js
|
|
13032
13697
|
var PRODUCT_API_VERSION = "products.vardeflyt.no/v1";
|
|
13698
|
+
var PRODUCT_API_VERSION_V2 = "products.vardeflyt.no/v2";
|
|
13699
|
+
var PARSEABLE_PRODUCT_API_VERSIONS = /* @__PURE__ */ new Set([
|
|
13700
|
+
PRODUCT_API_VERSION,
|
|
13701
|
+
PRODUCT_API_VERSION_V2
|
|
13702
|
+
]);
|
|
13703
|
+
function supportedList() {
|
|
13704
|
+
return [...PARSEABLE_PRODUCT_API_VERSIONS].map((value) => `"${value}"`).join(" or ");
|
|
13705
|
+
}
|
|
13706
|
+
function unsupportedProductApiVersionMessage() {
|
|
13707
|
+
return `apiVersion must be ${supportedList()}. An unrecognized contract format is refused rather than ignored.`;
|
|
13708
|
+
}
|
|
13033
13709
|
var PRODUCT_DEFINITION_KIND = "ProductDefinition";
|
|
13034
13710
|
var DEPLOYMENT_BLUEPRINT_KIND = "DeploymentBlueprint";
|
|
13035
13711
|
var ProductApiVersionSchema = external_exports.literal(PRODUCT_API_VERSION, {
|
|
13036
13712
|
errorMap: () => ({
|
|
13037
|
-
message: `apiVersion must be
|
|
13713
|
+
message: `apiVersion must be ${supportedList()}. An unrecognized contract format is refused rather than ignored.`
|
|
13038
13714
|
})
|
|
13039
13715
|
});
|
|
13716
|
+
var ProductApiVersionV2Schema = external_exports.literal(PRODUCT_API_VERSION_V2, {
|
|
13717
|
+
errorMap: () => ({
|
|
13718
|
+
message: `apiVersion must be ${supportedList()}. An unrecognized contract format is refused rather than ignored.`
|
|
13719
|
+
})
|
|
13720
|
+
});
|
|
13721
|
+
var ProductApiVersionAnySchema = external_exports.union([ProductApiVersionSchema, ProductApiVersionV2Schema], {
|
|
13722
|
+
errorMap: () => ({ message: unsupportedProductApiVersionMessage() })
|
|
13723
|
+
}).describe("The Product contract format this document is written against.");
|
|
13040
13724
|
var ResourceApiVersionSchema = external_exports.literal(RESOURCE_API_VERSION, {
|
|
13041
13725
|
errorMap: () => ({
|
|
13042
13726
|
message: `apiVersion must be "${RESOURCE_API_VERSION}". An unrecognized contract format is refused rather than ignored.`
|
|
@@ -13413,6 +14097,18 @@ var ProductConditionSchema = external_exports.object({
|
|
|
13413
14097
|
*/
|
|
13414
14098
|
description: external_exports.string().min(10).max(300)
|
|
13415
14099
|
}).strict();
|
|
14100
|
+
var RequiredWhenSchema = external_exports.object({
|
|
14101
|
+
/** A declared, non-secret customer-configuration property. */
|
|
14102
|
+
property: external_exports.string().regex(CONFIGURATION_PROPERTY_NAME_REGEX, "Must name a declared customer-configuration property."),
|
|
14103
|
+
/** The values that make this dependency required. Non-empty. */
|
|
14104
|
+
anyOf: external_exports.array(external_exports.string().min(1).max(80)).min(1).max(40)
|
|
14105
|
+
}).strict();
|
|
14106
|
+
var RequiredWhenV2Schema = external_exports.object({
|
|
14107
|
+
path: external_exports.string().refine((raw) => parseConfigurationPath(raw) !== null, {
|
|
14108
|
+
message: 'A configuration path is a root property name, or an RFC 6901 pointer such as "/assistant/model".'
|
|
14109
|
+
}),
|
|
14110
|
+
anyOf: external_exports.array(external_exports.string().min(1).max(80)).min(1).max(40)
|
|
14111
|
+
}).strict();
|
|
13416
14112
|
var ProductDependencySchema = external_exports.object({
|
|
13417
14113
|
/**
|
|
13418
14114
|
* OPTIONAL ONLY WHEN `interface` IS PRESENT, enforced below.
|
|
@@ -13527,13 +14223,11 @@ var ProductDependencySchema = external_exports.object({
|
|
|
13527
14223
|
* `.optional()`, never `.default()` — see the Blueprint's banner on
|
|
13528
14224
|
* `runtime`. Every dependency published to date carries none.
|
|
13529
14225
|
*/
|
|
13530
|
-
requiredWhen:
|
|
13531
|
-
/** A declared, non-secret customer-configuration property. */
|
|
13532
|
-
property: external_exports.string().regex(CONFIGURATION_PROPERTY_NAME_REGEX, "Must name a declared customer-configuration property."),
|
|
13533
|
-
/** The values that make this dependency required. Non-empty. */
|
|
13534
|
-
anyOf: external_exports.array(external_exports.string().min(1).max(80)).min(1).max(40)
|
|
13535
|
-
}).strict().optional()
|
|
14226
|
+
requiredWhen: RequiredWhenSchema.optional()
|
|
13536
14227
|
}).strict();
|
|
14228
|
+
var ProductDependencyV2Schema = ProductDependencySchema.extend({
|
|
14229
|
+
requiredWhen: RequiredWhenV2Schema.optional()
|
|
14230
|
+
});
|
|
13537
14231
|
var ServiceInterfaceProvideSchema = external_exports.object({
|
|
13538
14232
|
key: ServiceBindingKeySchema,
|
|
13539
14233
|
interfaceId: ServiceInterfaceIdSchema,
|
|
@@ -13670,7 +14364,14 @@ var ProductDefinitionObjectSchema = external_exports.object({
|
|
|
13670
14364
|
*/
|
|
13671
14365
|
blueprint: external_exports.object({ version: ContractVersionSchema }).strict()
|
|
13672
14366
|
}).strict();
|
|
13673
|
-
var ProductDefinitionSchema = ProductDefinitionObjectSchema.superRefine(
|
|
14367
|
+
var ProductDefinitionSchema = ProductDefinitionObjectSchema.superRefine(checkProductDefinition);
|
|
14368
|
+
var ProductDefinitionV2ObjectSchema = ProductDefinitionObjectSchema.extend({
|
|
14369
|
+
apiVersion: ProductApiVersionV2Schema,
|
|
14370
|
+
configuration: CustomerConfigurationV2Schema,
|
|
14371
|
+
dependencies: external_exports.array(ProductDependencyV2Schema).max(8)
|
|
14372
|
+
});
|
|
14373
|
+
var ProductDefinitionV2Schema = ProductDefinitionV2ObjectSchema.superRefine(checkProductDefinition);
|
|
14374
|
+
function checkProductDefinition(definition, ctx) {
|
|
13674
14375
|
const profileIds = definition.profiles.map((profile) => profile.id);
|
|
13675
14376
|
const duplicateProfiles = profileIds.filter((id, i) => profileIds.indexOf(id) !== i);
|
|
13676
14377
|
if (duplicateProfiles.length > 0) {
|
|
@@ -13792,42 +14493,55 @@ var ProductDefinitionSchema = ProductDefinitionObjectSchema.superRefine((definit
|
|
|
13792
14493
|
message: "Repeated values in `anyOf`."
|
|
13793
14494
|
});
|
|
13794
14495
|
}
|
|
13795
|
-
const
|
|
13796
|
-
|
|
14496
|
+
const named = "path" in condition ? condition.path : condition.property;
|
|
14497
|
+
const member = "path" in condition ? "path" : "property";
|
|
14498
|
+
const parsed = parseConfigurationPath(named);
|
|
14499
|
+
const leaf = parsed === null ? null : leafAt(definition.configuration, parsed);
|
|
14500
|
+
if (leaf === null) {
|
|
14501
|
+
const isGroup = parsed !== null && declaresPath(definition.configuration, parsed);
|
|
14502
|
+
ctx.addIssue({
|
|
14503
|
+
code: external_exports.ZodIssueCode.custom,
|
|
14504
|
+
path: [...at, member],
|
|
14505
|
+
message: isGroup ? `"${named}" is a group of settings, which holds no single value to compare. Name one setting inside it.` : `"${named}" is not a declared customer configuration property.`
|
|
14506
|
+
});
|
|
14507
|
+
return;
|
|
14508
|
+
}
|
|
14509
|
+
if (leaf.container?.kind === "array") {
|
|
13797
14510
|
ctx.addIssue({
|
|
13798
14511
|
code: external_exports.ZodIssueCode.custom,
|
|
13799
|
-
path: [...at,
|
|
13800
|
-
message: `"${
|
|
14512
|
+
path: [...at, member],
|
|
14513
|
+
message: `"${named}" is inside a list, so it names one value per item rather than one value. A condition must name a setting the instance holds exactly once.`
|
|
13801
14514
|
});
|
|
13802
14515
|
return;
|
|
13803
14516
|
}
|
|
14517
|
+
const property = leaf.property;
|
|
13804
14518
|
if (property.type !== "string") {
|
|
13805
14519
|
ctx.addIssue({
|
|
13806
14520
|
code: external_exports.ZodIssueCode.custom,
|
|
13807
|
-
path: [...at,
|
|
13808
|
-
message: `"${
|
|
14521
|
+
path: [...at, member],
|
|
14522
|
+
message: `"${named}" is a ${property.type} setting; a condition compares string values.`
|
|
13809
14523
|
});
|
|
13810
14524
|
return;
|
|
13811
14525
|
}
|
|
13812
|
-
if (property
|
|
14526
|
+
if (isSecretProperty(property)) {
|
|
13813
14527
|
ctx.addIssue({
|
|
13814
14528
|
code: external_exports.ZodIssueCode.custom,
|
|
13815
|
-
path: [...at,
|
|
13816
|
-
message: `"${
|
|
14529
|
+
path: [...at, member],
|
|
14530
|
+
message: `"${named}" is a secret. The platform never reads a secret's value, so a condition on one could never be evaluated.`
|
|
13817
14531
|
});
|
|
13818
14532
|
return;
|
|
13819
14533
|
}
|
|
13820
14534
|
const single = withoutCrossFieldRules({
|
|
13821
14535
|
...definition.configuration,
|
|
13822
|
-
properties: { [
|
|
13823
|
-
required: [
|
|
14536
|
+
properties: { [leaf.name]: property },
|
|
14537
|
+
required: [leaf.name]
|
|
13824
14538
|
});
|
|
13825
|
-
const outside = condition.anyOf.filter((value) => !validateSubmittedConfiguration(single, { [
|
|
14539
|
+
const outside = condition.anyOf.filter((value) => !validateSubmittedConfiguration(single, { [leaf.name]: value }).ok);
|
|
13826
14540
|
if (outside.length > 0) {
|
|
13827
14541
|
ctx.addIssue({
|
|
13828
14542
|
code: external_exports.ZodIssueCode.custom,
|
|
13829
14543
|
path: [...at, "anyOf"],
|
|
13830
|
-
message: `"${
|
|
14544
|
+
message: `"${named}" never accepts ${outside.map((v) => `"${v}"`).join(", ")}, so this condition could never make the dependency required.`
|
|
13831
14545
|
});
|
|
13832
14546
|
}
|
|
13833
14547
|
});
|
|
@@ -13941,7 +14655,7 @@ var ProductDefinitionSchema = ProductDefinitionObjectSchema.superRefine((definit
|
|
|
13941
14655
|
message: 'dataResidency "global" contradicts externalProcessing false \u2014 data cannot be global without leaving the tenant boundary.'
|
|
13942
14656
|
});
|
|
13943
14657
|
}
|
|
13944
|
-
}
|
|
14658
|
+
}
|
|
13945
14659
|
|
|
13946
14660
|
// ../product-contracts/dist/announcements.js
|
|
13947
14661
|
var ANNOUNCED_PRODUCTS = Object.freeze([
|
|
@@ -14131,108 +14845,166 @@ var ComponentIngressSchema = external_exports.discriminatedUnion("exposure", [
|
|
|
14131
14845
|
authentication: external_exports.enum(["signed-request", "mtls"])
|
|
14132
14846
|
}).strict()
|
|
14133
14847
|
]);
|
|
14848
|
+
var LiteralEnvBindingSchema = external_exports.object({
|
|
14849
|
+
source: external_exports.literal("literal"),
|
|
14850
|
+
name: EnvVarNameSchema,
|
|
14851
|
+
value: external_exports.string().max(512)
|
|
14852
|
+
}).strict();
|
|
14853
|
+
var InstanceEnvBindingSchema = external_exports.object({
|
|
14854
|
+
source: external_exports.literal("instance"),
|
|
14855
|
+
name: EnvVarNameSchema,
|
|
14856
|
+
/** Closed set: the Control Plane knows these without Product knowledge. */
|
|
14857
|
+
field: external_exports.enum([
|
|
14858
|
+
"tenantKey",
|
|
14859
|
+
"tenantId",
|
|
14860
|
+
"projectId",
|
|
14861
|
+
"productInstanceId",
|
|
14862
|
+
"instanceKey",
|
|
14863
|
+
"productId",
|
|
14864
|
+
"productVersion",
|
|
14865
|
+
"profile",
|
|
14866
|
+
"region",
|
|
14867
|
+
"environment"
|
|
14868
|
+
])
|
|
14869
|
+
}).strict();
|
|
14870
|
+
var PlatformEnvBindingSchema = external_exports.object({
|
|
14871
|
+
source: external_exports.literal("platform"),
|
|
14872
|
+
name: EnvVarNameSchema,
|
|
14873
|
+
key: external_exports.enum(["controlPlaneUrl", "observabilityEndpoint", "logLevel", "serviceVersion"])
|
|
14874
|
+
}).strict();
|
|
14875
|
+
var ComponentEndpointEnvBindingSchema = external_exports.object({
|
|
14876
|
+
source: external_exports.literal("component-endpoint"),
|
|
14877
|
+
name: EnvVarNameSchema,
|
|
14878
|
+
/** Resolved to the sibling component's private URL at reconcile time. */
|
|
14879
|
+
componentId: ComponentIdSchema
|
|
14880
|
+
}).strict();
|
|
14881
|
+
var ComponentPublicUrlEnvBindingSchema = external_exports.object({
|
|
14882
|
+
/**
|
|
14883
|
+
* The CUSTOMER-FACING address of a PUBLIC component — the URL a browser
|
|
14884
|
+
* opens, not the in-network one a sibling calls.
|
|
14885
|
+
*
|
|
14886
|
+
* WHY THE PLATFORM HAS TO SUPPLY IT. The address is assigned during
|
|
14887
|
+
* deployment, so nobody knows it earlier: not the publisher, who writes
|
|
14888
|
+
* the contract months before, and not the customer, who would otherwise
|
|
14889
|
+
* be asked to type an address that does not exist yet. A console that
|
|
14890
|
+
* needs its own address — to build an OAuth redirect URI, to put an
|
|
14891
|
+
* absolute link in an email — had no way to learn it, and asking the
|
|
14892
|
+
* customer produced exactly the failure you would expect: an empty
|
|
14893
|
+
* setting and a console nobody can sign in to.
|
|
14894
|
+
*
|
|
14895
|
+
* It is deliberately NOT derivable from the request. A server behind a
|
|
14896
|
+
* proxy infers its bind address, which looks right in development and is
|
|
14897
|
+
* wrong in production; a forwarded Host header is attacker-controlled.
|
|
14898
|
+
* The platform knows the answer, so the platform states it.
|
|
14899
|
+
*
|
|
14900
|
+
* `componentId` may name this component or another, but it must be a
|
|
14901
|
+
* PUBLIC one: `validateProductContracts` refuses a private target, the
|
|
14902
|
+
* same rule `outputs` already carries, because a private endpoint is not
|
|
14903
|
+
* an address to hand out.
|
|
14904
|
+
*/
|
|
14905
|
+
source: external_exports.literal("component-public-url"),
|
|
14906
|
+
name: EnvVarNameSchema,
|
|
14907
|
+
componentId: ComponentIdSchema
|
|
14908
|
+
}).strict();
|
|
14909
|
+
var ServiceBindingAttributeEnvBindingSchema = external_exports.object({
|
|
14910
|
+
/**
|
|
14911
|
+
* A NON-SECRET value from a service binding to ANOTHER Product.
|
|
14912
|
+
*
|
|
14913
|
+
* THE ONLY SOURCE THAT LEAVES THIS PRODUCT INSTANCE. Every other member of
|
|
14914
|
+
* this union resolves inside one deployment: a literal, a fact about this
|
|
14915
|
+
* instance, a sibling component's address, a setting this customer typed.
|
|
14916
|
+
* This one is answered by a different Product Instance, possibly in a
|
|
14917
|
+
* different logical Project, which is why it is the only source whose
|
|
14918
|
+
* value can be absent for a reason that is nobody's mistake.
|
|
14919
|
+
*
|
|
14920
|
+
* ABSENT WHILE THE BINDING IS PENDING, and absent rather than empty. The
|
|
14921
|
+
* variable is left out of the container entirely until the provider
|
|
14922
|
+
* completes the binding, so a Product can tell "not yet" from "set to
|
|
14923
|
+
* nothing" — the same rule `configuration` already follows. Read
|
|
14924
|
+
* `VFAC_SERVICE_BINDING_<KEY>_STATUS`, which the platform injects for
|
|
14925
|
+
* every declared binding, rather than inferring readiness from absence.
|
|
14926
|
+
*
|
|
14927
|
+
* CREDENTIALS DO NOT COME THIS WAY. `field` must name a field the
|
|
14928
|
+
* interface classifies as an attribute; a secret field bound here is
|
|
14929
|
+
* refused by `validateProductContracts()`, and the credential-shaped-name
|
|
14930
|
+
* rule below refuses the variable name independently.
|
|
14931
|
+
*/
|
|
14932
|
+
source: external_exports.literal("service-binding-attribute"),
|
|
14933
|
+
name: EnvVarNameSchema,
|
|
14934
|
+
/** The `serviceBindings[].key` this value comes from. */
|
|
14935
|
+
binding: ServiceBindingKeySchema,
|
|
14936
|
+
/** The interface field, e.g. `issuerUrl`. Checked against the registry. */
|
|
14937
|
+
field: external_exports.string().regex(/^[a-z][a-zA-Z0-9]{1,47}$/)
|
|
14938
|
+
}).strict();
|
|
14939
|
+
var ConfigurationEnvBindingSchema = external_exports.object({
|
|
14940
|
+
source: external_exports.literal("configuration"),
|
|
14941
|
+
name: EnvVarNameSchema,
|
|
14942
|
+
/**
|
|
14943
|
+
* A NON-SECRET customer setting from the Product Definition.
|
|
14944
|
+
* `validateProductContracts()` rejects a reference to an `x-secret`
|
|
14945
|
+
* property — those travel through `secrets[]` and Secret Manager, never
|
|
14946
|
+
* through plain environment wiring.
|
|
14947
|
+
*/
|
|
14948
|
+
property: external_exports.string().regex(/^[a-z][a-zA-Z0-9]{1,47}$/)
|
|
14949
|
+
}).strict();
|
|
14134
14950
|
var EnvBindingSchema = external_exports.discriminatedUnion("source", [
|
|
14951
|
+
LiteralEnvBindingSchema,
|
|
14952
|
+
InstanceEnvBindingSchema,
|
|
14953
|
+
PlatformEnvBindingSchema,
|
|
14954
|
+
ComponentEndpointEnvBindingSchema,
|
|
14955
|
+
ComponentPublicUrlEnvBindingSchema,
|
|
14956
|
+
ServiceBindingAttributeEnvBindingSchema,
|
|
14957
|
+
ConfigurationEnvBindingSchema
|
|
14958
|
+
]);
|
|
14959
|
+
var ConfigurationBindingPathSchema = external_exports.string().refine((raw) => parseConfigurationPath(raw) !== null, {
|
|
14960
|
+
message: 'A configuration path is a root property name, or an RFC 6901 pointer such as "/assistant/model".'
|
|
14961
|
+
}).refine((raw) => !/\/\d+(\/|$)/.test(raw), {
|
|
14962
|
+
message: 'A Blueprint binds a DECLARED setting, so a path may not carry a list index. Bind the list with "configuration-json".'
|
|
14963
|
+
});
|
|
14964
|
+
var EnvBindingV2Schema = external_exports.discriminatedUnion("source", [
|
|
14965
|
+
LiteralEnvBindingSchema,
|
|
14966
|
+
InstanceEnvBindingSchema,
|
|
14967
|
+
PlatformEnvBindingSchema,
|
|
14968
|
+
ComponentEndpointEnvBindingSchema,
|
|
14969
|
+
ComponentPublicUrlEnvBindingSchema,
|
|
14970
|
+
ServiceBindingAttributeEnvBindingSchema,
|
|
14135
14971
|
external_exports.object({
|
|
14136
|
-
source: external_exports.literal("
|
|
14137
|
-
name: EnvVarNameSchema,
|
|
14138
|
-
value: external_exports.string().max(512)
|
|
14139
|
-
}).strict(),
|
|
14140
|
-
external_exports.object({
|
|
14141
|
-
source: external_exports.literal("instance"),
|
|
14142
|
-
name: EnvVarNameSchema,
|
|
14143
|
-
/** Closed set: the Control Plane knows these without Product knowledge. */
|
|
14144
|
-
field: external_exports.enum([
|
|
14145
|
-
"tenantKey",
|
|
14146
|
-
"tenantId",
|
|
14147
|
-
"projectId",
|
|
14148
|
-
"productInstanceId",
|
|
14149
|
-
"instanceKey",
|
|
14150
|
-
"productId",
|
|
14151
|
-
"productVersion",
|
|
14152
|
-
"profile",
|
|
14153
|
-
"region",
|
|
14154
|
-
"environment"
|
|
14155
|
-
])
|
|
14156
|
-
}).strict(),
|
|
14157
|
-
external_exports.object({
|
|
14158
|
-
source: external_exports.literal("platform"),
|
|
14159
|
-
name: EnvVarNameSchema,
|
|
14160
|
-
key: external_exports.enum(["controlPlaneUrl", "observabilityEndpoint", "logLevel", "serviceVersion"])
|
|
14161
|
-
}).strict(),
|
|
14162
|
-
external_exports.object({
|
|
14163
|
-
source: external_exports.literal("component-endpoint"),
|
|
14972
|
+
source: external_exports.literal("configuration"),
|
|
14164
14973
|
name: EnvVarNameSchema,
|
|
14165
|
-
/** Resolved to the sibling component's private URL at reconcile time. */
|
|
14166
|
-
componentId: ComponentIdSchema
|
|
14167
|
-
}).strict(),
|
|
14168
|
-
external_exports.object({
|
|
14169
14974
|
/**
|
|
14170
|
-
*
|
|
14171
|
-
* opens, not the in-network one a sibling calls.
|
|
14975
|
+
* A NON-SECRET customer setting, named by its canonical path.
|
|
14172
14976
|
*
|
|
14173
|
-
*
|
|
14174
|
-
*
|
|
14175
|
-
*
|
|
14176
|
-
*
|
|
14177
|
-
*
|
|
14178
|
-
* absolute link in an email — had no way to learn it, and asking the
|
|
14179
|
-
* customer produced exactly the failure you would expect: an empty
|
|
14180
|
-
* setting and a console nobody can sign in to.
|
|
14181
|
-
*
|
|
14182
|
-
* It is deliberately NOT derivable from the request. A server behind a
|
|
14183
|
-
* proxy infers its bind address, which looks right in development and is
|
|
14184
|
-
* wrong in production; a forwarded Host header is attacker-controlled.
|
|
14185
|
-
* The platform knows the answer, so the platform states it.
|
|
14186
|
-
*
|
|
14187
|
-
* `componentId` may name this component or another, but it must be a
|
|
14188
|
-
* PUBLIC one: `validateProductContracts` refuses a private target, the
|
|
14189
|
-
* same rule `outputs` already carries, because a private endpoint is not
|
|
14190
|
-
* an address to hand out.
|
|
14977
|
+
* `validateProductContracts` refuses a path that names no leaf, a path
|
|
14978
|
+
* that names a GROUP — a group has no scalar rendering, and
|
|
14979
|
+
* `configuration-json` is how one is carried — and any `x-secret`
|
|
14980
|
+
* property, which travels through `secrets[]` and never through plain
|
|
14981
|
+
* environment wiring.
|
|
14191
14982
|
*/
|
|
14192
|
-
|
|
14193
|
-
name: EnvVarNameSchema,
|
|
14194
|
-
componentId: ComponentIdSchema
|
|
14983
|
+
path: ConfigurationBindingPathSchema
|
|
14195
14984
|
}).strict(),
|
|
14196
14985
|
external_exports.object({
|
|
14986
|
+
source: external_exports.literal("configuration-json"),
|
|
14987
|
+
name: EnvVarNameSchema,
|
|
14197
14988
|
/**
|
|
14198
|
-
*
|
|
14989
|
+
* THE WHOLE VALIDATED CONFIGURATION, OR ONE SUBTREE OF IT, AS JSON.
|
|
14199
14990
|
*
|
|
14200
|
-
*
|
|
14201
|
-
*
|
|
14202
|
-
*
|
|
14203
|
-
*
|
|
14204
|
-
*
|
|
14205
|
-
*
|
|
14991
|
+
* WHY THIS EXISTS. A component may carry at most forty environment
|
|
14992
|
+
* bindings, and a nested Product spends one per leaf — so the format that
|
|
14993
|
+
* lets a Product have structure would immediately run out of room to
|
|
14994
|
+
* deliver it. This binds a whole document instead, and the Product's own
|
|
14995
|
+
* runtime translates it into whatever shape it wants. The Control Plane
|
|
14996
|
+
* learns nothing about that shape, which is the point.
|
|
14206
14997
|
*
|
|
14207
|
-
*
|
|
14208
|
-
*
|
|
14209
|
-
*
|
|
14210
|
-
*
|
|
14211
|
-
*
|
|
14212
|
-
*
|
|
14998
|
+
* WHAT IT CARRIES: validated, non-secret configuration with resolved
|
|
14999
|
+
* ORDINARY resource references materialised in place. Never a secret
|
|
15000
|
+
* value — secrets are root-only and travel through `secrets[]`, and a
|
|
15001
|
+
* subtree cannot contain one. Serialised with `canonicalJson`, so the same
|
|
15002
|
+
* logical configuration is the same bytes and the environment fingerprint
|
|
15003
|
+
* does not move on key order alone.
|
|
14213
15004
|
*
|
|
14214
|
-
*
|
|
14215
|
-
* interface classifies as an attribute; a secret field bound here is
|
|
14216
|
-
* refused by `validateProductContracts()`, and the credential-shaped-name
|
|
14217
|
-
* rule below refuses the variable name independently.
|
|
15005
|
+
* Absent `path` means the whole document.
|
|
14218
15006
|
*/
|
|
14219
|
-
|
|
14220
|
-
name: EnvVarNameSchema,
|
|
14221
|
-
/** The `serviceBindings[].key` this value comes from. */
|
|
14222
|
-
binding: ServiceBindingKeySchema,
|
|
14223
|
-
/** The interface field, e.g. `issuerUrl`. Checked against the registry. */
|
|
14224
|
-
field: external_exports.string().regex(/^[a-z][a-zA-Z0-9]{1,47}$/)
|
|
14225
|
-
}).strict(),
|
|
14226
|
-
external_exports.object({
|
|
14227
|
-
source: external_exports.literal("configuration"),
|
|
14228
|
-
name: EnvVarNameSchema,
|
|
14229
|
-
/**
|
|
14230
|
-
* A NON-SECRET customer setting from the Product Definition.
|
|
14231
|
-
* `validateProductContracts()` rejects a reference to an `x-secret`
|
|
14232
|
-
* property — those travel through `secrets[]` and Secret Manager, never
|
|
14233
|
-
* through plain environment wiring.
|
|
14234
|
-
*/
|
|
14235
|
-
property: external_exports.string().regex(/^[a-z][a-zA-Z0-9]{1,47}$/)
|
|
15007
|
+
path: ConfigurationBindingPathSchema.optional()
|
|
14236
15008
|
}).strict()
|
|
14237
15009
|
]);
|
|
14238
15010
|
var MAX_BOOTSTRAP_SCRIPT_LENGTH = 32768;
|
|
@@ -14444,11 +15216,12 @@ var ComponentDependencySchema = external_exports.object({
|
|
|
14444
15216
|
minVersion: ContractVersionSchema.optional(),
|
|
14445
15217
|
maxVersion: ContractVersionSchema.optional()
|
|
14446
15218
|
}).strict();
|
|
15219
|
+
var MAX_COMPONENT_ENV_BINDINGS = 40;
|
|
14447
15220
|
var componentCommonShape = {
|
|
14448
15221
|
id: ComponentIdSchema.describe("Scoped by its Product; does not repeat the Product ID (\xA78)."),
|
|
14449
15222
|
kind: ComponentKindSchema,
|
|
14450
15223
|
description: external_exports.string().min(10).max(300),
|
|
14451
|
-
env: external_exports.array(EnvBindingSchema).max(
|
|
15224
|
+
env: external_exports.array(EnvBindingSchema).max(MAX_COMPONENT_ENV_BINDINGS),
|
|
14452
15225
|
dependsOn: external_exports.array(ComponentDependencySchema).max(8)
|
|
14453
15226
|
};
|
|
14454
15227
|
var ServerlessContainerComponentSchema = external_exports.object({
|
|
@@ -14500,6 +15273,16 @@ var RuntimeComponentSchema = external_exports.discriminatedUnion("runtime", [
|
|
|
14500
15273
|
ServerlessContainerComponentSchema,
|
|
14501
15274
|
VirtualMachineComponentSchema
|
|
14502
15275
|
]);
|
|
15276
|
+
var ServerlessContainerComponentV2Schema = ServerlessContainerComponentSchema.extend({
|
|
15277
|
+
env: external_exports.array(EnvBindingV2Schema).max(MAX_COMPONENT_ENV_BINDINGS)
|
|
15278
|
+
});
|
|
15279
|
+
var VirtualMachineComponentV2Schema = VirtualMachineComponentSchema.extend({
|
|
15280
|
+
env: external_exports.array(EnvBindingV2Schema).max(MAX_COMPONENT_ENV_BINDINGS)
|
|
15281
|
+
});
|
|
15282
|
+
var RuntimeComponentV2Schema = external_exports.discriminatedUnion("runtime", [
|
|
15283
|
+
ServerlessContainerComponentV2Schema,
|
|
15284
|
+
VirtualMachineComponentV2Schema
|
|
15285
|
+
]);
|
|
14503
15286
|
function isVirtualMachineComponent(component) {
|
|
14504
15287
|
return component.runtime === "virtual-machine";
|
|
14505
15288
|
}
|
|
@@ -14748,7 +15531,47 @@ var BlueprintLifecycleSchema = external_exports.object({
|
|
|
14748
15531
|
* the service-interface surface is unchanged. Nothing published to date
|
|
14749
15532
|
* regresses, and a release cannot strand an instance by forgetting it.
|
|
14750
15533
|
*/
|
|
14751
|
-
directFromVersions: external_exports.array(ContractVersionSchema).max(20).optional()
|
|
15534
|
+
directFromVersions: external_exports.array(ContractVersionSchema).max(20).optional(),
|
|
15535
|
+
/**
|
|
15536
|
+
* How a stored configuration is carried across a release that MOVED a
|
|
15537
|
+
* setting.
|
|
15538
|
+
*
|
|
15539
|
+
* THE CASE THIS EXISTS FOR is a flat Product taking on structure:
|
|
15540
|
+
* `assistantName` becomes `/assistant/name`. Nothing else on this
|
|
15541
|
+
* platform can express that. Without it the target release simply does
|
|
15542
|
+
* not declare `assistantName`, so the upgrade drops the customer's value
|
|
15543
|
+
* and then refuses the deploy for a missing required setting — and the
|
|
15544
|
+
* customer's answer is gone either way.
|
|
15545
|
+
*
|
|
15546
|
+
* `move` AND NOTHING ELSE. A migration the platform cannot fully
|
|
15547
|
+
* evaluate is one it cannot apply safely, and every other operation a
|
|
15548
|
+
* publisher might want — rename a value, split one setting into two,
|
|
15549
|
+
* compute a default — needs the Product's own knowledge of what those
|
|
15550
|
+
* values MEAN. Moving a value is the one thing the platform can do
|
|
15551
|
+
* correctly without knowing anything about it.
|
|
15552
|
+
*
|
|
15553
|
+
* APPLIED AT CUTOVER, in the transaction that writes the new
|
|
15554
|
+
* configuration, and to the REFERENCE ROWS as well as the stored
|
|
15555
|
+
* document — a Resource Reference is identified by the path it answers,
|
|
15556
|
+
* so a setting that moved takes its edge with it or the edge points at
|
|
15557
|
+
* nothing.
|
|
15558
|
+
*
|
|
15559
|
+
* AN ABSENT SOURCE IS A NO-OP, deliberately. A customer who never
|
|
15560
|
+
* answered an optional setting has nothing to carry, and inventing an
|
|
15561
|
+
* empty value for them would turn "not configured" into "configured
|
|
15562
|
+
* blank" — two states this platform keeps apart everywhere else.
|
|
15563
|
+
*
|
|
15564
|
+
* `.optional()`, never `.default([])`, for the reason
|
|
15565
|
+
* `directFromVersions` states one field above: a materialised key makes
|
|
15566
|
+
* a byte-identical republish `RELEASED_CONTRACT_MUTATED`.
|
|
15567
|
+
*/
|
|
15568
|
+
configurationMigrations: external_exports.array(external_exports.object({
|
|
15569
|
+
op: external_exports.literal("move"),
|
|
15570
|
+
/** Where the value is today, in the release being left. */
|
|
15571
|
+
from: ConfigurationBindingPathSchema,
|
|
15572
|
+
/** Where this release declares it. */
|
|
15573
|
+
to: ConfigurationBindingPathSchema
|
|
15574
|
+
}).strict()).max(40).optional()
|
|
14752
15575
|
}).strict(),
|
|
14753
15576
|
rollback: external_exports.object({
|
|
14754
15577
|
supported: external_exports.boolean(),
|
|
@@ -14874,7 +15697,14 @@ function isOidcClientServiceBinding(binding) {
|
|
|
14874
15697
|
}
|
|
14875
15698
|
var DeploymentBlueprintObjectSchema = external_exports.object({
|
|
14876
15699
|
/** The CONTRACT FORMAT version — not the Blueprint's. See api-version.ts. */
|
|
14877
|
-
|
|
15700
|
+
/**
|
|
15701
|
+
* The SHARED base carries either literal; each format pins its own below.
|
|
15702
|
+
*
|
|
15703
|
+
* Nothing parses this object schema directly — `DeploymentBlueprintV1Schema`
|
|
15704
|
+
* and `…V2Schema` extend it — so the permissive literal here is never what a
|
|
15705
|
+
* document is held to, and never what an artifact publishes.
|
|
15706
|
+
*/
|
|
15707
|
+
apiVersion: ProductApiVersionAnySchema,
|
|
14878
15708
|
kind: kindSchema(DEPLOYMENT_BLUEPRINT_KIND),
|
|
14879
15709
|
productId: ProductIdSchema,
|
|
14880
15710
|
/** This Blueprint's own version. The Definition pins it exactly. */
|
|
@@ -14942,7 +15772,17 @@ var DeploymentBlueprintObjectSchema = external_exports.object({
|
|
|
14942
15772
|
outputs: external_exports.array(BlueprintOutputSchema).min(1).max(12),
|
|
14943
15773
|
lifecycle: BlueprintLifecycleSchema
|
|
14944
15774
|
}).strict();
|
|
14945
|
-
var
|
|
15775
|
+
var DeploymentBlueprintV1ObjectSchema = DeploymentBlueprintObjectSchema.extend({
|
|
15776
|
+
apiVersion: ProductApiVersionSchema
|
|
15777
|
+
});
|
|
15778
|
+
var DeploymentBlueprintV2ObjectSchema = DeploymentBlueprintObjectSchema.extend({
|
|
15779
|
+
apiVersion: ProductApiVersionV2Schema,
|
|
15780
|
+
components: external_exports.array(RuntimeComponentV2Schema).min(1).max(MAX_RUNTIME_COMPONENTS)
|
|
15781
|
+
});
|
|
15782
|
+
var DeploymentBlueprintV1Schema = DeploymentBlueprintV1ObjectSchema.superRefine(checkDeploymentBlueprint);
|
|
15783
|
+
var DeploymentBlueprintV2Schema = DeploymentBlueprintV2ObjectSchema.superRefine(checkDeploymentBlueprint);
|
|
15784
|
+
var DeploymentBlueprintSchema = DeploymentBlueprintV1Schema;
|
|
15785
|
+
function checkDeploymentBlueprint(blueprint, ctx) {
|
|
14946
15786
|
const componentIds = blueprint.components.map((component) => component.id);
|
|
14947
15787
|
const knownComponents = new Set(componentIds);
|
|
14948
15788
|
const publicComponents = new Set(blueprint.components.filter((component) => component.ingress.exposure === "public").map((component) => component.id));
|
|
@@ -15043,13 +15883,7 @@ var DeploymentBlueprintSchema = DeploymentBlueprintObjectSchema.superRefine((blu
|
|
|
15043
15883
|
});
|
|
15044
15884
|
const handoff = resource.bootstrap.productHandoff;
|
|
15045
15885
|
if (handoff !== void 0) {
|
|
15046
|
-
const handoffPath = [
|
|
15047
|
-
"dynamicResources",
|
|
15048
|
-
index,
|
|
15049
|
-
"bootstrap",
|
|
15050
|
-
"productHandoff",
|
|
15051
|
-
"componentId"
|
|
15052
|
-
];
|
|
15886
|
+
const handoffPath = ["dynamicResources", index, "bootstrap", "productHandoff", "componentId"];
|
|
15053
15887
|
const target = blueprint.components.find((component) => component.id === handoff.componentId);
|
|
15054
15888
|
if (target === void 0) {
|
|
15055
15889
|
ctx.addIssue({
|
|
@@ -15660,7 +16494,7 @@ var DeploymentBlueprintSchema = DeploymentBlueprintObjectSchema.superRefine((blu
|
|
|
15660
16494
|
});
|
|
15661
16495
|
}
|
|
15662
16496
|
}
|
|
15663
|
-
}
|
|
16497
|
+
}
|
|
15664
16498
|
|
|
15665
16499
|
// ../product-contracts/dist/deployability.js
|
|
15666
16500
|
var VIRTUAL_MACHINE_PROFILE_INTERFACE = {
|
|
@@ -15701,17 +16535,15 @@ function isTerminalAction(action) {
|
|
|
15701
16535
|
}
|
|
15702
16536
|
var ManifestActionSchema = external_exports.enum(MANIFEST_ACTIONS);
|
|
15703
16537
|
|
|
15704
|
-
// ../product-contracts/dist/resource-key.js
|
|
15705
|
-
var ResourceKeySchema = external_exports.string().regex(/^[a-z][a-z0-9-]{1,61}[a-z0-9]$/, "A resource key is 3\u201363 characters of lowercase letters, digits and hyphens, starting with a letter and ending with a letter or digit.");
|
|
15706
|
-
|
|
15707
16538
|
// ../product-contracts/dist/resource-output-reference.js
|
|
16539
|
+
var OUTPUT_KEY_RULE = "Output keys are camelCase.";
|
|
15708
16540
|
var ResourceOutputReferenceSchema = external_exports.object({
|
|
15709
16541
|
valueFrom: external_exports.object({
|
|
15710
16542
|
resourceOutput: external_exports.object({
|
|
15711
16543
|
/** The producing Resource's `metadata.key`, in the same Project. */
|
|
15712
16544
|
resourceKey: ResourceKeySchema,
|
|
15713
16545
|
/** The key of an output that Resource's Product declares. */
|
|
15714
|
-
output: external_exports.string().regex(/^[a-z][a-zA-Z0-9]{1,47}$/,
|
|
16546
|
+
output: external_exports.string().regex(/^[a-z][a-zA-Z0-9]{1,47}$/, OUTPUT_KEY_RULE)
|
|
15715
16547
|
}).strict()
|
|
15716
16548
|
}).strict()
|
|
15717
16549
|
}).strict();
|
|
@@ -15869,7 +16701,33 @@ var ProductSubmissionObjectSchema = external_exports.object({
|
|
|
15869
16701
|
definition: ProductDefinitionSchema,
|
|
15870
16702
|
blueprint: DeploymentBlueprintSchema
|
|
15871
16703
|
}).strict();
|
|
15872
|
-
var
|
|
16704
|
+
var submissionShape = {
|
|
16705
|
+
kind: kindSchema(PRODUCT_SUBMISSION_KIND),
|
|
16706
|
+
submission: SubmissionEnvelopeSchema
|
|
16707
|
+
};
|
|
16708
|
+
var ProductSubmissionV1ObjectSchema = external_exports.object({
|
|
16709
|
+
apiVersion: ProductApiVersionSchema,
|
|
16710
|
+
...submissionShape,
|
|
16711
|
+
definition: ProductDefinitionSchema,
|
|
16712
|
+
blueprint: DeploymentBlueprintV1Schema
|
|
16713
|
+
}).strict();
|
|
16714
|
+
var ProductSubmissionV2ObjectSchema = external_exports.object({
|
|
16715
|
+
apiVersion: ProductApiVersionV2Schema,
|
|
16716
|
+
...submissionShape,
|
|
16717
|
+
definition: ProductDefinitionV2Schema,
|
|
16718
|
+
blueprint: DeploymentBlueprintV2Schema
|
|
16719
|
+
}).strict();
|
|
16720
|
+
var ProductSubmissionV1Schema = ProductSubmissionV1ObjectSchema.superRefine(checkProductSubmission);
|
|
16721
|
+
var ProductSubmissionV2Schema = ProductSubmissionV2ObjectSchema.superRefine(checkProductSubmission);
|
|
16722
|
+
var ProductSubmissionSchema = ProductSubmissionV1Schema;
|
|
16723
|
+
function checkProductSubmission(submission, ctx) {
|
|
16724
|
+
if (submission.definition.apiVersion !== submission.apiVersion) {
|
|
16725
|
+
ctx.addIssue({
|
|
16726
|
+
code: external_exports.ZodIssueCode.custom,
|
|
16727
|
+
path: ["definition", "apiVersion"],
|
|
16728
|
+
message: `This submission is written against "${submission.apiVersion}" but its Product Definition declares "${submission.definition.apiVersion}". One submission is one contract format.`
|
|
16729
|
+
});
|
|
16730
|
+
}
|
|
15873
16731
|
if (submission.definition.id !== submission.submission.productId) {
|
|
15874
16732
|
ctx.addIssue({
|
|
15875
16733
|
code: external_exports.ZodIssueCode.custom,
|
|
@@ -15891,7 +16749,7 @@ var ProductSubmissionSchema = ProductSubmissionObjectSchema.superRefine((submiss
|
|
|
15891
16749
|
message: `The Product Definition is version "${submission.definition.version}" but the submission claims "${submission.submission.version}". They must be the same version.`
|
|
15892
16750
|
});
|
|
15893
16751
|
}
|
|
15894
|
-
}
|
|
16752
|
+
}
|
|
15895
16753
|
var PUBLISH_RULE_ANNEX = {
|
|
15896
16754
|
allOf: [
|
|
15897
16755
|
{
|
|
@@ -16327,6 +17185,16 @@ async function runDoctor(parsed) {
|
|
|
16327
17185
|
const json = parsed.flags["output"] === "json";
|
|
16328
17186
|
const checks = [{ name: "CLI", ok: true, detail: `vfac ${cliVersion()}` }];
|
|
16329
17187
|
const stored = readStored();
|
|
17188
|
+
const salvaged2 = salvagedConfigPath();
|
|
17189
|
+
if (salvaged2 !== null) {
|
|
17190
|
+
checks.push({
|
|
17191
|
+
name: "Config",
|
|
17192
|
+
ok: true,
|
|
17193
|
+
note: true,
|
|
17194
|
+
detail: `the previous config could not be read and was kept at ${salvaged2}. What this command reports below is a fresh one \u2014 the endpoint and Project it held are gone until you set them again. Delete the kept file once you have; it may hold a stale session.`,
|
|
17195
|
+
facts: { salvagedConfigPath: salvaged2 }
|
|
17196
|
+
});
|
|
17197
|
+
}
|
|
16330
17198
|
const resolved = resolveEndpoint(parsed.flags["endpoint"], stored);
|
|
16331
17199
|
if (!resolved) {
|
|
16332
17200
|
checks.push({
|
|
@@ -16334,32 +17202,41 @@ async function runDoctor(parsed) {
|
|
|
16334
17202
|
ok: false,
|
|
16335
17203
|
detail: "not set. Run `vfac context set --endpoint https://your-organization.cloud.vardeflyt.no`, or set VFAC_ENDPOINT."
|
|
16336
17204
|
});
|
|
16337
|
-
return
|
|
17205
|
+
return report2(checks, json);
|
|
16338
17206
|
}
|
|
16339
17207
|
const checked = validateEndpoint(resolved.value, resolved.source);
|
|
16340
17208
|
if (!checked.ok) {
|
|
16341
17209
|
checks.push({ name: "Endpoint", ok: false, detail: checked.message });
|
|
16342
|
-
return
|
|
17210
|
+
return report2(checks, json);
|
|
16343
17211
|
}
|
|
16344
17212
|
const endpoint = checked.endpoint;
|
|
16345
17213
|
checks.push({
|
|
16346
17214
|
name: "Endpoint",
|
|
16347
17215
|
ok: true,
|
|
16348
|
-
detail: `${endpoint} (from ${resolved.source})
|
|
17216
|
+
detail: `${endpoint} (from ${resolved.source})`,
|
|
17217
|
+
facts: { endpoint, source: resolved.source }
|
|
17218
|
+
});
|
|
17219
|
+
const selected = stored.context?.projectId ?? null;
|
|
17220
|
+
checks.push({
|
|
17221
|
+
name: "Project",
|
|
17222
|
+
ok: true,
|
|
17223
|
+
note: selected === null,
|
|
17224
|
+
detail: selected === null ? "none selected. Commands need `--project prj_\u2026`, or run `vfac context set --project prj_\u2026` once. This is not a fault \u2014 it is what a pipeline that names the Project per command looks like \u2014 but it is NOT the same thing as which Projects your credential reaches." : `${selected} (selected in this context; which Projects the credential reaches is a separate question)`,
|
|
17225
|
+
facts: { selectedProjectId: selected }
|
|
16349
17226
|
});
|
|
16350
17227
|
const probe = await probeMachineApi({ endpoint });
|
|
16351
17228
|
if (!probe.ok) {
|
|
16352
17229
|
checks.push({ name: "Machine API", ok: false, detail: probe.message });
|
|
16353
|
-
return
|
|
17230
|
+
return report2(checks, json);
|
|
16354
17231
|
}
|
|
16355
17232
|
checks.push({ name: "Machine API", ok: true, detail: probe.apiVersion });
|
|
16356
17233
|
const compatible = compatibility(cliVersion(), probe.minimumCliVersion);
|
|
16357
17234
|
checks.push(compatible);
|
|
16358
|
-
if (!compatible.ok) return
|
|
17235
|
+
if (!compatible.ok) return report2(checks, json);
|
|
16359
17236
|
const signedIn = await signIn({ endpoint });
|
|
16360
17237
|
if (!signedIn.ok) {
|
|
16361
17238
|
checks.push({ name: "Context Gate", ok: false, detail: signedIn.message });
|
|
16362
|
-
return
|
|
17239
|
+
return report2(checks, json);
|
|
16363
17240
|
}
|
|
16364
17241
|
checks.push({
|
|
16365
17242
|
name: "Context Gate",
|
|
@@ -16380,7 +17257,7 @@ async function runDoctor(parsed) {
|
|
|
16380
17257
|
ok: false,
|
|
16381
17258
|
detail: who.error.status === 404 ? "this Tenant Portal does not serve /api/v1/whoami yet \u2014 it is running an older build." : who.error.message
|
|
16382
17259
|
});
|
|
16383
|
-
return
|
|
17260
|
+
return report2(checks, json);
|
|
16384
17261
|
}
|
|
16385
17262
|
const access = who.data.access;
|
|
16386
17263
|
const projects = access.projects.map((project) => project.projectId);
|
|
@@ -16391,7 +17268,8 @@ async function runDoctor(parsed) {
|
|
|
16391
17268
|
access.tenantWide ? {
|
|
16392
17269
|
name: "Access",
|
|
16393
17270
|
ok: true,
|
|
16394
|
-
detail: `the whole organization \u2014 ${access.tenantPermissions.join(", ")}
|
|
17271
|
+
detail: `the whole organization \u2014 ${access.tenantPermissions.join(", ")}`,
|
|
17272
|
+
facts: { scope: "organization", grantedProjectIds: null }
|
|
16395
17273
|
} : projects.length === 0 ? {
|
|
16396
17274
|
// A FAILURE, NOT A NOTE. This credential authenticates and can do
|
|
16397
17275
|
// nothing at all — and the check said so in words while `report`
|
|
@@ -16421,6 +17299,14 @@ async function runDoctor(parsed) {
|
|
|
16421
17299
|
// believes it can deploy and is then refused reports a platform
|
|
16422
17300
|
// defect, which is precisely the outcome the guide now tells it not
|
|
16423
17301
|
// to reach for. Scope and role are two questions; this answers both.
|
|
17302
|
+
facts: {
|
|
17303
|
+
scope: "projects",
|
|
17304
|
+
// THE GRANT, and the name says which of the two questions it
|
|
17305
|
+
// answers. A reader gating on `doctor --output json` had no way
|
|
17306
|
+
// to tell this list from the selected Project; now the field
|
|
17307
|
+
// names are the difference.
|
|
17308
|
+
grantedProjectIds: projects.join(",")
|
|
17309
|
+
},
|
|
16424
17310
|
detail: `${projects.join(", ")} \u2014 and nothing organization-wide. ` + (mutating.length > 0 ? "You can deploy in those Projects, read their catalogue, and list them. " : "Read-only there: catalogue, manifests, resources and operations. An apply or a lifecycle command is refused, and that is what was granted rather than a fault. ") + "Anything ACROSS the organization \u2014 a Project you hold nothing in, or its members \u2014 is refused."
|
|
16425
17311
|
}
|
|
16426
17312
|
);
|
|
@@ -16431,7 +17317,7 @@ async function runDoctor(parsed) {
|
|
|
16431
17317
|
detail: "run `vfac guide` for the platform's own instructions, written for a machine"
|
|
16432
17318
|
});
|
|
16433
17319
|
checks.push(await updateAvailable(cliVersion()));
|
|
16434
|
-
return
|
|
17320
|
+
return report2(checks, json);
|
|
16435
17321
|
}
|
|
16436
17322
|
function compatibility(local, declared) {
|
|
16437
17323
|
const name = "Compatibility";
|
|
@@ -16511,7 +17397,7 @@ async function updateAvailable(local) {
|
|
|
16511
17397
|
facts
|
|
16512
17398
|
};
|
|
16513
17399
|
}
|
|
16514
|
-
function
|
|
17400
|
+
function report2(checks, json) {
|
|
16515
17401
|
const failed = checks.filter((check) => !check.ok);
|
|
16516
17402
|
if (json) {
|
|
16517
17403
|
process.stdout.write(`${JSON.stringify({ ok: failed.length === 0, checks })}
|
|
@@ -16887,16 +17773,14 @@ function renderProduct(product) {
|
|
|
16887
17773
|
(profile) => `${profile.id}${profile.default ? " (default)" : ""}`
|
|
16888
17774
|
);
|
|
16889
17775
|
lines.push(` profile ${profiles.join(", ") || "(none declared)"}`);
|
|
16890
|
-
const
|
|
16891
|
-
|
|
16892
|
-
if (required.length > 0) {
|
|
17776
|
+
const seed = seedConfiguration(product.configuration);
|
|
17777
|
+
if (seed.open.length > 0 || seed.requiredSecrets.length > 0) {
|
|
16893
17778
|
lines.push("", " Required configuration");
|
|
16894
|
-
for (const name of
|
|
16895
|
-
|
|
16896
|
-
|
|
16897
|
-
|
|
16898
|
-
|
|
16899
|
-
);
|
|
17779
|
+
for (const name of seed.requiredSecrets) {
|
|
17780
|
+
lines.push(` ${name} (secret \u2014 pass --secret ${name}=env:VAR)`);
|
|
17781
|
+
}
|
|
17782
|
+
for (const setting of seed.open) {
|
|
17783
|
+
lines.push(` ${setting.label} ${setting.type ?? ""}`.trimEnd());
|
|
16900
17784
|
}
|
|
16901
17785
|
}
|
|
16902
17786
|
const needed = (product.dependencies ?? []).filter((dependency) => dependency.required);
|
|
@@ -17129,9 +18013,7 @@ async function runManifestInit(parsed) {
|
|
|
17129
18013
|
const notes = [];
|
|
17130
18014
|
const key = parsed.flags["key"] ?? exampleResourceKey(name);
|
|
17131
18015
|
if (!key) {
|
|
17132
|
-
notes.push(
|
|
17133
|
-
"metadata.key \u2014 a stable identity, 3 to 63 characters, lower case. Required before apply"
|
|
17134
|
-
);
|
|
18016
|
+
notes.push(`metadata.key \u2014 a stable identity, required before apply. ${RESOURCE_KEY_RULE}`);
|
|
17135
18017
|
}
|
|
17136
18018
|
const chooseable = (product.dependencies ?? []).filter(
|
|
17137
18019
|
(dependency) => dependency.interface?.cardinality === "tenant-multiple"
|
|
@@ -17171,7 +18053,7 @@ async function runManifestInit(parsed) {
|
|
|
17171
18053
|
}
|
|
17172
18054
|
for (const setting of seed.open) {
|
|
17173
18055
|
notes.push(
|
|
17174
|
-
`spec.configuration.${setting.
|
|
18056
|
+
`spec.configuration.${setting.label} \u2014 required${setting.type ? ` (${setting.type})` : ""}`
|
|
17175
18057
|
);
|
|
17176
18058
|
}
|
|
17177
18059
|
for (const group of seed.groups) {
|
|
@@ -17260,6 +18142,8 @@ Run \`vfac get product-instance pri_\u2026\` to see which ones this credential m
|
|
|
17260
18142
|
if (command === "delete" && !parsed.booleans.has("yes")) {
|
|
17261
18143
|
process.stderr.write(
|
|
17262
18144
|
`delete removes ${instanceId} and everything it is serving. This cannot be undone.
|
|
18145
|
+
If it was deployed from a manifest, its \`metadata.key\` stays claimed: a replacement
|
|
18146
|
+
needs a different key, and re-applying the same file will answer GONE.
|
|
17263
18147
|
Re-run with --yes to confirm: vfac lifecycle delete ${instanceId} --yes
|
|
17264
18148
|
Or suspend it instead, which stops it and keeps it: \`vfac lifecycle suspend\`.
|
|
17265
18149
|
`
|