@varde-flyt/vfac 0.11.0 → 0.13.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 +19 -7
- package/dist/vfac.mjs +534 -39
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,14 +74,21 @@ vfac manifest init --product <productId> --name "My resource" > resource.yaml
|
|
|
74
74
|
|
|
75
75
|
```sh
|
|
76
76
|
vfac validate -f resource.yaml
|
|
77
|
-
vfac plan -f resource.yaml
|
|
77
|
+
vfac plan -f resource.yaml --secret SETTING=env:VARIABLE
|
|
78
78
|
vfac apply -f resource.yaml --secret SETTING=env:VARIABLE
|
|
79
79
|
vfac get operation <operationId>
|
|
80
80
|
vfac get product-instance <productInstanceId>
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
Secrets are supplied per apply and never belong in the manifest — a manifest is a
|
|
84
|
-
file you commit.
|
|
84
|
+
file you commit. **Plan the run that sets one with the same `--secret` inputs the
|
|
85
|
+
apply will carry**: `plan` takes the flag exactly as `apply` does, and without it
|
|
86
|
+
the plan describes a different request.
|
|
87
|
+
|
|
88
|
+
`requiredSecrets` in a plan is what the Product requires for the configuration in
|
|
89
|
+
your document — not a list of what the platform is missing. It names a credential
|
|
90
|
+
whether or not this resource already holds one, so it is not a shopping list to
|
|
91
|
+
act on. `secretsToWrite` is the field that says what this apply would write.
|
|
85
92
|
|
|
86
93
|
### `metadata.key` is the name you choose
|
|
87
94
|
|
|
@@ -176,7 +183,8 @@ spec:
|
|
|
176
183
|
`vfac manifest init` names the exact property for every dependency you have to
|
|
177
184
|
choose, and `vfac plan` prints the connections an apply would establish before
|
|
178
185
|
you approve it. The dependency key comes from the Product, not from you —
|
|
179
|
-
`vfac product show <productId>` lists
|
|
186
|
+
`vfac product show <productId>` lists every dependency with its key, its
|
|
187
|
+
capability, and whether a setting is what turns it on.
|
|
180
188
|
|
|
181
189
|
This is not the same thing as the section above, and the difference is worth
|
|
182
190
|
holding on to:
|
|
@@ -198,7 +206,8 @@ it.
|
|
|
198
206
|
|
|
199
207
|
Every command takes `--output json`, and it is the same data rather than a
|
|
200
208
|
prettier subset — the human format of `vfac product show` prints a readable
|
|
201
|
-
selection on purpose
|
|
209
|
+
selection on purpose and says so at the foot of its output, and the JSON carries
|
|
210
|
+
the whole Product contract.
|
|
202
211
|
|
|
203
212
|
```sh
|
|
204
213
|
vfac product show <productId> --output json
|
|
@@ -261,12 +270,15 @@ so this answers `UPDATE` and redeploys, even when the value is the value already
|
|
|
261
270
|
stored:
|
|
262
271
|
|
|
263
272
|
```sh
|
|
273
|
+
vfac plan -f resource.yaml --secret SETTING=env:VARIABLE
|
|
264
274
|
vfac apply -f resource.yaml --secret SETTING=env:VARIABLE
|
|
265
275
|
```
|
|
266
276
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
277
|
+
Three runs carry a secret: the apply that creates the resource, the first time a
|
|
278
|
+
setting needs a credential on a resource that already exists, and a rotation. Send
|
|
279
|
+
none on any other run — a pipeline that passes its secrets every run restarts your
|
|
280
|
+
service every time somebody pushes a README. Plan each of those three with the
|
|
281
|
+
same `--secret` inputs: with no secret to write, a rotation plans as `NO_CHANGE`.
|
|
270
282
|
|
|
271
283
|
## Where the Gate Secret goes
|
|
272
284
|
|
package/dist/vfac.mjs
CHANGED
|
@@ -7928,12 +7928,33 @@ function renderOperation(operationId, data) {
|
|
|
7928
7928
|
);
|
|
7929
7929
|
}
|
|
7930
7930
|
}
|
|
7931
|
+
const product = failure["product"];
|
|
7932
|
+
const reportedSettings = [];
|
|
7933
|
+
if (Array.isArray(product)) {
|
|
7934
|
+
for (const entry of product) {
|
|
7935
|
+
const one = asRecord(entry);
|
|
7936
|
+
if (one === null) continue;
|
|
7937
|
+
const component = one["component"];
|
|
7938
|
+
const code = one["code"];
|
|
7939
|
+
if (typeof component !== "string" || typeof code !== "string") continue;
|
|
7940
|
+
if (component === "" || code === "") continue;
|
|
7941
|
+
const setting = one["setting"];
|
|
7942
|
+
if (typeof setting === "string" && setting !== "") {
|
|
7943
|
+
reportedSettings.push(setting);
|
|
7944
|
+
lines.push(` ${component} refused to start: ${code} (setting: ${setting})`);
|
|
7945
|
+
} else {
|
|
7946
|
+
lines.push(` ${component} refused to start: ${code}`);
|
|
7947
|
+
}
|
|
7948
|
+
}
|
|
7949
|
+
}
|
|
7931
7950
|
const retryable = failure["retryable"];
|
|
7932
7951
|
if (typeof retryable === "boolean") {
|
|
7933
7952
|
const again = data["type"] === "PRODUCT_INSTANCE_UPGRADE" ? "`vfac lifecycle upgrade <pri_\u2026>`" : "`vfac lifecycle reconcile <pri_\u2026>`";
|
|
7934
7953
|
const changeIt = data["type"] === "PRODUCT_INSTANCE_UPGRADE" ? "" : ", or `vfac apply` a corrected manifest";
|
|
7954
|
+
const cause2 = failure["cause"];
|
|
7955
|
+
const named = reportedSettings[0];
|
|
7935
7956
|
lines.push(
|
|
7936
|
-
retryable ? ` Another attempt can succeed: ${again}.` : ` Repeating this unchanged fails again \u2014 fix what the lines above name, then ${again}${changeIt}.`
|
|
7957
|
+
retryable ? ` Another attempt can succeed: ${again}.` : named !== void 0 ? ` Correct \`${named}\` in your manifest, then \`vfac apply\` it${data["type"] === "PRODUCT_INSTANCE_UPGRADE" ? ` and ${again}` : ""}. Repeating it unchanged fails the same way.` : cause2 === "unknown" ? ` The platform could not classify this, so there is nothing here to correct. Read the whole record with \`vfac get operation ${operationId} --output json\`, and quote that id if you ask for help. Repeating it unchanged fails the same way.` : ` Repeating this unchanged fails again \u2014 fix what the lines above name, then ${again}${changeIt}.`
|
|
7937
7958
|
);
|
|
7938
7959
|
}
|
|
7939
7960
|
}
|
|
@@ -12244,6 +12265,29 @@ var ValueConditionSchema = external_exports.object({
|
|
|
12244
12265
|
anyOf: external_exports.array(external_exports.string().min(1).max(200)).min(1).max(20),
|
|
12245
12266
|
anyRow: external_exports.boolean().optional()
|
|
12246
12267
|
}).strict();
|
|
12268
|
+
var ValueReferenceSchema = external_exports.object({
|
|
12269
|
+
/**
|
|
12270
|
+
* The setting whose VALUES form the allowed set — a canonical declaration
|
|
12271
|
+
* path, or a bare root key, which is the same string at depth 1.
|
|
12272
|
+
*/
|
|
12273
|
+
path: external_exports.string().min(1).max(400)
|
|
12274
|
+
}).strict();
|
|
12275
|
+
var RowCardinalitySchema = external_exports.object({
|
|
12276
|
+
/** A setting declared DIRECTLY on the row. */
|
|
12277
|
+
property: PropertyNameSchema,
|
|
12278
|
+
/** The answers that count toward the limit. Non-empty. */
|
|
12279
|
+
anyOf: external_exports.array(external_exports.string().min(1).max(200)).min(1).max(20),
|
|
12280
|
+
/**
|
|
12281
|
+
* How many rows may answer that way. Zero is meaningful and allowed — "no
|
|
12282
|
+
* row may, under this release" is a thing an upgrade needs to be able to
|
|
12283
|
+
* say.
|
|
12284
|
+
*/
|
|
12285
|
+
max: external_exports.number().int().min(0).max(99)
|
|
12286
|
+
}).strict();
|
|
12287
|
+
var RowRulesSchema = external_exports.object({
|
|
12288
|
+
unique: external_exports.array(PropertyNameSchema).min(1).max(MAX_CONFIGURATION_CHILDREN).optional(),
|
|
12289
|
+
atMost: external_exports.array(RowCardinalitySchema).min(1).max(10).optional()
|
|
12290
|
+
}).strict();
|
|
12247
12291
|
var TitleSchema = external_exports.string().min(2).max(80).describe("Customer-facing field label.");
|
|
12248
12292
|
var V1_LEAF_BOUNDS = {
|
|
12249
12293
|
help: 400,
|
|
@@ -12317,7 +12361,16 @@ function leafShapes(bounds) {
|
|
|
12317
12361
|
* what `requiredSecrets` reports, which is one answer with one reader.
|
|
12318
12362
|
* Opening it wider is a separate decision with its own blast radius.
|
|
12319
12363
|
*/
|
|
12320
|
-
"x-required-when": ValueConditionSchema.optional()
|
|
12364
|
+
"x-required-when": ValueConditionSchema.optional(),
|
|
12365
|
+
/**
|
|
12366
|
+
* The values this one must be chosen from — see {@link ValueReferenceSchema}.
|
|
12367
|
+
*
|
|
12368
|
+
* ON A STRING ONLY, and not on a secret: the platform never reads a
|
|
12369
|
+
* secret's value, so a membership test on one could never be evaluated.
|
|
12370
|
+
* The publish rules say so rather than leaving it to be discovered, the
|
|
12371
|
+
* same way they already do for a condition pointed at a secret.
|
|
12372
|
+
*/
|
|
12373
|
+
"x-value-in": ValueReferenceSchema.optional()
|
|
12321
12374
|
}).strict();
|
|
12322
12375
|
withJsonSchemaAnnex(string, SECRET_COUPLING_ANNEX);
|
|
12323
12376
|
const number = external_exports.object({
|
|
@@ -12328,14 +12381,23 @@ function leafShapes(bounds) {
|
|
|
12328
12381
|
/** Both bounds required — "numeric limits" in the guide is not optional. */
|
|
12329
12382
|
minimum: external_exports.number(),
|
|
12330
12383
|
maximum: external_exports.number(),
|
|
12331
|
-
default: external_exports.number().optional()
|
|
12384
|
+
default: external_exports.number().optional(),
|
|
12385
|
+
/**
|
|
12386
|
+
* WIDENED FROM SECRETS TO EVERY ROOT SETTING, which this shape's own
|
|
12387
|
+
* comment on the string leaf used to record as a known gap: "a
|
|
12388
|
+
* value-conditioned requirement for an ORDINARY setting is a real gap
|
|
12389
|
+
* too". It is the same keyword, the same evaluator and the same publish
|
|
12390
|
+
* rules; what changes is which settings may carry it.
|
|
12391
|
+
*/
|
|
12392
|
+
"x-required-when": ValueConditionSchema.optional()
|
|
12332
12393
|
}).strict();
|
|
12333
12394
|
const boolean = external_exports.object({
|
|
12334
12395
|
type: external_exports.literal("boolean"),
|
|
12335
12396
|
title: TitleSchema,
|
|
12336
12397
|
description: help.optional(),
|
|
12337
12398
|
group: ConfigurationGroupSchema,
|
|
12338
|
-
default: external_exports.boolean().optional()
|
|
12399
|
+
default: external_exports.boolean().optional(),
|
|
12400
|
+
"x-required-when": ValueConditionSchema.optional()
|
|
12339
12401
|
}).strict();
|
|
12340
12402
|
const items = external_exports.object({
|
|
12341
12403
|
type: external_exports.literal("string"),
|
|
@@ -12352,7 +12414,8 @@ function leafShapes(bounds) {
|
|
|
12352
12414
|
/** Required: an unbounded list is an unbounded write. */
|
|
12353
12415
|
maxItems: external_exports.number().int().min(1).max(100),
|
|
12354
12416
|
uniqueItems: external_exports.boolean().optional(),
|
|
12355
|
-
default: external_exports.array(external_exports.string().max(200)).max(100).optional()
|
|
12417
|
+
default: external_exports.array(external_exports.string().max(200)).max(100).optional(),
|
|
12418
|
+
"x-required-when": ValueConditionSchema.optional()
|
|
12356
12419
|
}).strict();
|
|
12357
12420
|
return { string, number, boolean, items, array };
|
|
12358
12421
|
}
|
|
@@ -12372,9 +12435,9 @@ var ConfigurationPropertySchema = external_exports.discriminatedUnion("type", [
|
|
|
12372
12435
|
var NestedStringPropertySchema = V2_LEAVES.string.omit({ "x-secret": true, writeOnly: true, "x-required-when": true }).extend({ group: ConfigurationGroupSchema.optional() });
|
|
12373
12436
|
var V2_NESTED_LEAVES = {
|
|
12374
12437
|
string: NestedStringPropertySchema,
|
|
12375
|
-
number: V2_LEAVES.number.extend({ group: ConfigurationGroupSchema.optional() }),
|
|
12376
|
-
boolean: V2_LEAVES.boolean.extend({ group: ConfigurationGroupSchema.optional() }),
|
|
12377
|
-
array: V2_LEAVES.array.extend({ group: ConfigurationGroupSchema.optional() }),
|
|
12438
|
+
number: V2_LEAVES.number.omit({ "x-required-when": true }).extend({ group: ConfigurationGroupSchema.optional() }),
|
|
12439
|
+
boolean: V2_LEAVES.boolean.omit({ "x-required-when": true }).extend({ group: ConfigurationGroupSchema.optional() }),
|
|
12440
|
+
array: V2_LEAVES.array.omit({ "x-required-when": true }).extend({ group: ConfigurationGroupSchema.optional() }),
|
|
12378
12441
|
items: V2_LEAVES.items
|
|
12379
12442
|
};
|
|
12380
12443
|
function childBagShape(child) {
|
|
@@ -12418,7 +12481,23 @@ function propertyUnion(levelsBelow, leafSet) {
|
|
|
12418
12481
|
// discriminator, which is also what keeps a v1 document's
|
|
12419
12482
|
// `items: {type: 'string'}` reading exactly as it always did.
|
|
12420
12483
|
leafSet.array.extend({
|
|
12421
|
-
items: external_exports.discriminatedUnion("type", [V2_LEAVES.items, groupItems])
|
|
12484
|
+
items: external_exports.discriminatedUnion("type", [V2_LEAVES.items, groupItems]),
|
|
12485
|
+
/**
|
|
12486
|
+
* Rules over the ROWS of this list — see {@link RowRulesSchema}.
|
|
12487
|
+
*
|
|
12488
|
+
* HERE RATHER THAN ON THE LEAF SHAPE, and that placement is the whole
|
|
12489
|
+
* enforcement. `leafShapes().array` is also a v1 list and a last-level
|
|
12490
|
+
* list, both of which hold STRINGS: a rule naming a field of a row would
|
|
12491
|
+
* name nothing there, and `uniqueItems` is already the right keyword for
|
|
12492
|
+
* comparing whole scalar entries. This branch is the only one in the chain
|
|
12493
|
+
* where a list can hold groups, so declaring the keyword here makes "rows
|
|
12494
|
+
* have fields" a property of the shape rather than a rule to remember.
|
|
12495
|
+
*
|
|
12496
|
+
* The refinement still has to refuse a rule on a list of STRINGS, because
|
|
12497
|
+
* `items` is a discriminated union INSIDE this branch — the shape narrows
|
|
12498
|
+
* where a row can exist, not whether this particular list has one.
|
|
12499
|
+
*/
|
|
12500
|
+
"x-row-rules": RowRulesSchema.optional()
|
|
12422
12501
|
}),
|
|
12423
12502
|
/**
|
|
12424
12503
|
* A group of related settings.
|
|
@@ -13121,6 +13200,9 @@ function canonicalJson(value) {
|
|
|
13121
13200
|
}
|
|
13122
13201
|
|
|
13123
13202
|
// ../product-configuration/dist/configuration-tree.js
|
|
13203
|
+
function immediateContainer(node) {
|
|
13204
|
+
return node.containers[node.containers.length - 1] ?? null;
|
|
13205
|
+
}
|
|
13124
13206
|
function underList(node) {
|
|
13125
13207
|
return node.containers.some((container) => container.kind === "array");
|
|
13126
13208
|
}
|
|
@@ -13182,6 +13264,11 @@ function walkDeclarations(properties, ancestors, base, onLeaf, onContainer = ()
|
|
|
13182
13264
|
walkDeclarations(children.properties, [...ancestors, container], segments, onLeaf, onContainer);
|
|
13183
13265
|
}
|
|
13184
13266
|
}
|
|
13267
|
+
function declaredDefault(property) {
|
|
13268
|
+
if (property.type === "object")
|
|
13269
|
+
return void 0;
|
|
13270
|
+
return property.default;
|
|
13271
|
+
}
|
|
13185
13272
|
function leafAt(schema, path) {
|
|
13186
13273
|
const declaration = declarationPathOf(path);
|
|
13187
13274
|
return configurationLeaves(schema).find((leaf) => leaf.path === declaration) ?? null;
|
|
@@ -13194,6 +13281,29 @@ function declaresPath(schema, path) {
|
|
|
13194
13281
|
function isPlainObject(value) {
|
|
13195
13282
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13196
13283
|
}
|
|
13284
|
+
function expandDeclarationPath(configuration, declaration) {
|
|
13285
|
+
const out = [];
|
|
13286
|
+
const walk = (cursor, remaining, soFar) => {
|
|
13287
|
+
if (remaining.length === 0) {
|
|
13288
|
+
const path = configurationPath(...soFar);
|
|
13289
|
+
if (path !== null)
|
|
13290
|
+
out.push(path);
|
|
13291
|
+
return;
|
|
13292
|
+
}
|
|
13293
|
+
if (Array.isArray(cursor)) {
|
|
13294
|
+
cursor.forEach((element, index) => walk(element, remaining, [...soFar, index]));
|
|
13295
|
+
return;
|
|
13296
|
+
}
|
|
13297
|
+
if (!isPlainObject(cursor))
|
|
13298
|
+
return;
|
|
13299
|
+
const [head, ...rest] = remaining;
|
|
13300
|
+
if (head === void 0)
|
|
13301
|
+
return;
|
|
13302
|
+
walk(cursor[String(head)], rest, [...soFar, head]);
|
|
13303
|
+
};
|
|
13304
|
+
walk(configuration, segmentsOf(declaration), []);
|
|
13305
|
+
return out;
|
|
13306
|
+
}
|
|
13197
13307
|
function valueAt(configuration, path) {
|
|
13198
13308
|
let cursor = configuration;
|
|
13199
13309
|
for (const segment of segmentsOf(path)) {
|
|
@@ -13255,6 +13365,7 @@ function conditionHolds(condition, configuration) {
|
|
|
13255
13365
|
// ../product-configuration/dist/customer-configuration-input.js
|
|
13256
13366
|
var ABSOLUTE_MAX_STRING = MAX_DECLARABLE_STRING_LENGTH;
|
|
13257
13367
|
var MAX_REPORTED_UNDECLARED_KEYS = 10;
|
|
13368
|
+
var UNDECLARED_SETTING_MESSAGE = "This Product does not declare a setting with that name.";
|
|
13258
13369
|
function isPlainObject2(value) {
|
|
13259
13370
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13260
13371
|
}
|
|
@@ -13288,6 +13399,7 @@ function validateSubmittedConfiguration(schema, submitted, presence = {}) {
|
|
|
13288
13399
|
const secrets = {};
|
|
13289
13400
|
const configuration = validateObject({ properties: schema.properties, required: schema.required }, input, null, walk, { secrets, supplied });
|
|
13290
13401
|
drain(walk, crossFieldIssues(schema, supplied, presence, configuration));
|
|
13402
|
+
drain(walk, rowAndReferenceIssues(schema, presence, configuration));
|
|
13291
13403
|
if (walk.suppressed > 0) {
|
|
13292
13404
|
walk.issues.push({
|
|
13293
13405
|
field: "",
|
|
@@ -13338,7 +13450,7 @@ function validateObject(declaration, input, container, walk, root) {
|
|
|
13338
13450
|
};
|
|
13339
13451
|
const undeclared = Object.keys(input).filter((name) => !Object.hasOwn(declaration.properties, name));
|
|
13340
13452
|
for (const name of undeclared.slice(0, MAX_REPORTED_UNDECLARED_KEYS)) {
|
|
13341
|
-
report(walk, fieldFor(name),
|
|
13453
|
+
report(walk, fieldFor(name), UNDECLARED_SETTING_MESSAGE);
|
|
13342
13454
|
}
|
|
13343
13455
|
if (undeclared.length > MAX_REPORTED_UNDECLARED_KEYS) {
|
|
13344
13456
|
report(walk, container === null ? "" : container, `${undeclared.length - MAX_REPORTED_UNDECLARED_KEYS} further settings are not declared by this Product.`);
|
|
@@ -13531,6 +13643,106 @@ function crossFieldIssues(schema, supplied, presence, configuration = {}) {
|
|
|
13531
13643
|
}
|
|
13532
13644
|
return issues;
|
|
13533
13645
|
}
|
|
13646
|
+
function referenceOf(property) {
|
|
13647
|
+
return property?.["x-value-in"];
|
|
13648
|
+
}
|
|
13649
|
+
function rowRulesOf(property) {
|
|
13650
|
+
return property?.["x-row-rules"];
|
|
13651
|
+
}
|
|
13652
|
+
function comparableValue(value) {
|
|
13653
|
+
if (value === void 0 || value === null)
|
|
13654
|
+
return null;
|
|
13655
|
+
if (typeof value === "string")
|
|
13656
|
+
return value === "" ? null : JSON.stringify(value);
|
|
13657
|
+
if (typeof value === "number" || typeof value === "boolean")
|
|
13658
|
+
return JSON.stringify(value);
|
|
13659
|
+
return null;
|
|
13660
|
+
}
|
|
13661
|
+
function rowAndReferenceIssues(schema, presence, configuration) {
|
|
13662
|
+
const issues = [];
|
|
13663
|
+
const referenced = new Set(presence.referenced ?? []);
|
|
13664
|
+
for (const leaf of configurationLeaves(schema)) {
|
|
13665
|
+
const reference = referenceOf(leaf.property);
|
|
13666
|
+
if (reference === void 0)
|
|
13667
|
+
continue;
|
|
13668
|
+
const targetPath = parseConfigurationPath(reference.path);
|
|
13669
|
+
if (targetPath === null)
|
|
13670
|
+
continue;
|
|
13671
|
+
const allowed = new Set(valuesAt(configuration, targetPath).filter((value) => typeof value === "string"));
|
|
13672
|
+
for (const valuePath of expandDeclarationPath(configuration, leaf.path)) {
|
|
13673
|
+
if (referenced.has(valuePath))
|
|
13674
|
+
continue;
|
|
13675
|
+
const held = valueAt(configuration, valuePath);
|
|
13676
|
+
if (typeof held !== "string" || held === "")
|
|
13677
|
+
continue;
|
|
13678
|
+
if (allowed.has(held))
|
|
13679
|
+
continue;
|
|
13680
|
+
issues.push({
|
|
13681
|
+
field: valuePath,
|
|
13682
|
+
message: `This must be one of the values configured under ${labelOfPath(schema, targetPath)}. ` + (allowed.size === 0 ? "Nothing is configured there yet." : "No entry there currently holds this one.")
|
|
13683
|
+
});
|
|
13684
|
+
}
|
|
13685
|
+
}
|
|
13686
|
+
for (const container of configurationContainers(schema)) {
|
|
13687
|
+
if (container.kind !== "array")
|
|
13688
|
+
continue;
|
|
13689
|
+
const rules = rowRulesOf(container.property);
|
|
13690
|
+
if (rules === void 0)
|
|
13691
|
+
continue;
|
|
13692
|
+
for (const listPath of expandDeclarationPath(configuration, container.path)) {
|
|
13693
|
+
const rows = valueAt(configuration, listPath);
|
|
13694
|
+
if (!Array.isArray(rows))
|
|
13695
|
+
continue;
|
|
13696
|
+
const fieldOf = (index, name) => configurationPath(...pathSegments(listPath), index, name) ?? listPath;
|
|
13697
|
+
for (const name of rules.unique ?? []) {
|
|
13698
|
+
const firstAt = /* @__PURE__ */ new Map();
|
|
13699
|
+
rows.forEach((row, index) => {
|
|
13700
|
+
const held = comparableValue(isPlainObject2(row) ? row[name] : void 0);
|
|
13701
|
+
if (held === null)
|
|
13702
|
+
return;
|
|
13703
|
+
const earlier = firstAt.get(held);
|
|
13704
|
+
if (earlier === void 0) {
|
|
13705
|
+
firstAt.set(held, index);
|
|
13706
|
+
return;
|
|
13707
|
+
}
|
|
13708
|
+
issues.push({
|
|
13709
|
+
field: fieldOf(index, name),
|
|
13710
|
+
message: `${labelOfChild(container, name)} must be different in every entry; entry ${earlier + 1} already uses this one.`
|
|
13711
|
+
});
|
|
13712
|
+
});
|
|
13713
|
+
}
|
|
13714
|
+
for (const rule of rules.atMost ?? []) {
|
|
13715
|
+
let counted = 0;
|
|
13716
|
+
rows.forEach((row, index) => {
|
|
13717
|
+
const held = isPlainObject2(row) ? row[rule.property] : void 0;
|
|
13718
|
+
if (typeof held !== "string" || !rule.anyOf.includes(held))
|
|
13719
|
+
return;
|
|
13720
|
+
counted += 1;
|
|
13721
|
+
if (counted <= rule.max)
|
|
13722
|
+
return;
|
|
13723
|
+
issues.push({
|
|
13724
|
+
field: fieldOf(index, rule.property),
|
|
13725
|
+
message: rule.max === 0 ? `No entry may be set to this.` : `At most ${rule.max} ${rule.max === 1 ? "entry" : "entries"} may be set to this, and ${counted - 1} already ${counted - 1 === 1 ? "is" : "are"}.`
|
|
13726
|
+
});
|
|
13727
|
+
});
|
|
13728
|
+
}
|
|
13729
|
+
}
|
|
13730
|
+
}
|
|
13731
|
+
return issues;
|
|
13732
|
+
}
|
|
13733
|
+
function labelOfPath(schema, path) {
|
|
13734
|
+
const leaf = leafAt(schema, path);
|
|
13735
|
+
const titleOf = (node) => node?.property.title;
|
|
13736
|
+
const field = titleOf(leaf) ?? printableConfigurationPath(path);
|
|
13737
|
+
const container = leaf?.containers[0];
|
|
13738
|
+
const outer = container === void 0 ? void 0 : titleOf(container);
|
|
13739
|
+
return outer === void 0 ? `"${field}"` : `"${field}" in "${outer}"`;
|
|
13740
|
+
}
|
|
13741
|
+
function labelOfChild(container, name) {
|
|
13742
|
+
const items = container.property.items;
|
|
13743
|
+
const title = items?.properties?.[name]?.title;
|
|
13744
|
+
return title === void 0 ? `"${name}"` : `"${title}"`;
|
|
13745
|
+
}
|
|
13534
13746
|
function conditionOf(property) {
|
|
13535
13747
|
return property?.["x-required-when"];
|
|
13536
13748
|
}
|
|
@@ -13539,19 +13751,45 @@ function labelOf(schema, name) {
|
|
|
13539
13751
|
return property?.title === void 0 ? `"${name}"` : `"${property.title}"`;
|
|
13540
13752
|
}
|
|
13541
13753
|
function withoutCrossFieldRules(schema) {
|
|
13542
|
-
const
|
|
13543
|
-
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
}));
|
|
13548
|
-
return withoutCrossFieldRules({ ...schema, properties });
|
|
13549
|
-
}
|
|
13550
|
-
if (schema.dependentRequired === void 0)
|
|
13551
|
-
return schema;
|
|
13552
|
-
const { dependentRequired: _removed, ...rest } = schema;
|
|
13754
|
+
const properties = withoutPropertyRules(schema.properties);
|
|
13755
|
+
const stripped = properties === null ? schema : { ...schema, properties };
|
|
13756
|
+
if (stripped.dependentRequired === void 0)
|
|
13757
|
+
return stripped;
|
|
13758
|
+
const { dependentRequired: _removed, ...rest } = stripped;
|
|
13553
13759
|
return rest;
|
|
13554
13760
|
}
|
|
13761
|
+
var PROPERTY_RULE_KEYWORDS = ["x-required-when", "x-value-in", "x-row-rules"];
|
|
13762
|
+
function withoutPropertyRules(properties) {
|
|
13763
|
+
let out = null;
|
|
13764
|
+
const edit = (name) => {
|
|
13765
|
+
out ??= { ...properties };
|
|
13766
|
+
const copy = { ...out[name] };
|
|
13767
|
+
out[name] = copy;
|
|
13768
|
+
return copy;
|
|
13769
|
+
};
|
|
13770
|
+
for (const [name, property] of Object.entries(properties)) {
|
|
13771
|
+
if (!isPlainObject2(property))
|
|
13772
|
+
continue;
|
|
13773
|
+
for (const keyword of PROPERTY_RULE_KEYWORDS) {
|
|
13774
|
+
if (property[keyword] === void 0)
|
|
13775
|
+
continue;
|
|
13776
|
+
delete edit(name)[keyword];
|
|
13777
|
+
}
|
|
13778
|
+
const children = out?.[name] ?? property;
|
|
13779
|
+
if (isPlainObject2(children["properties"])) {
|
|
13780
|
+
const bare = withoutPropertyRules(children["properties"]);
|
|
13781
|
+
if (bare !== null)
|
|
13782
|
+
edit(name)["properties"] = bare;
|
|
13783
|
+
}
|
|
13784
|
+
const items = children["items"];
|
|
13785
|
+
if (isPlainObject2(items) && isPlainObject2(items["properties"])) {
|
|
13786
|
+
const bare = withoutPropertyRules(items["properties"]);
|
|
13787
|
+
if (bare !== null)
|
|
13788
|
+
edit(name)["items"] = { ...items, properties: bare };
|
|
13789
|
+
}
|
|
13790
|
+
}
|
|
13791
|
+
return out;
|
|
13792
|
+
}
|
|
13555
13793
|
function defaultOf(property) {
|
|
13556
13794
|
switch (property.type) {
|
|
13557
13795
|
case "string":
|
|
@@ -13604,7 +13842,11 @@ function checkString(field, property, value, issues) {
|
|
|
13604
13842
|
return void 0;
|
|
13605
13843
|
}
|
|
13606
13844
|
if (property.pattern !== void 0 && !matches(property.pattern, value)) {
|
|
13607
|
-
|
|
13845
|
+
const expectation = property.description;
|
|
13846
|
+
issues.push({
|
|
13847
|
+
field,
|
|
13848
|
+
message: expectation === void 0 ? "Value is not in the required format." : `Value is not in the required format. ${expectation.replace(/\s+$/, "")}`
|
|
13849
|
+
});
|
|
13608
13850
|
return void 0;
|
|
13609
13851
|
}
|
|
13610
13852
|
return value;
|
|
@@ -14754,11 +14996,19 @@ function checkProductDefinition(definition, ctx) {
|
|
|
14754
14996
|
if (condition === void 0)
|
|
14755
14997
|
continue;
|
|
14756
14998
|
const at = ["configuration", "properties", name, "x-required-when"];
|
|
14757
|
-
if (
|
|
14999
|
+
if ((definition.configuration.required ?? []).includes(name)) {
|
|
15000
|
+
ctx.addIssue({
|
|
15001
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15002
|
+
path: [...at],
|
|
15003
|
+
message: `"${name}" is already required, so "x-required-when" can only narrow a rule that is already unconditional. Drop one: \`required\` is always, \`x-required-when\` is the condition.`
|
|
15004
|
+
});
|
|
15005
|
+
continue;
|
|
15006
|
+
}
|
|
15007
|
+
if (declaredDefault(property) !== void 0) {
|
|
14758
15008
|
ctx.addIssue({
|
|
14759
15009
|
code: external_exports.ZodIssueCode.custom,
|
|
14760
15010
|
path: [...at],
|
|
14761
|
-
message: `"${name}"
|
|
15011
|
+
message: `"${name}" declares a default, so it is never absent and this condition could never make it required. Remove the default, or the condition.`
|
|
14762
15012
|
});
|
|
14763
15013
|
continue;
|
|
14764
15014
|
}
|
|
@@ -14834,6 +15084,8 @@ function checkProductDefinition(definition, ctx) {
|
|
|
14834
15084
|
});
|
|
14835
15085
|
}
|
|
14836
15086
|
}
|
|
15087
|
+
checkValueReferences(definition.configuration, ctx);
|
|
15088
|
+
checkRowRules(definition.configuration, ctx);
|
|
14837
15089
|
const provides = definition.serviceInterfaces?.provides ?? [];
|
|
14838
15090
|
const provideKeys = provides.map((provide) => provide.key);
|
|
14839
15091
|
const duplicateProvideKeys = provideKeys.filter((key, i) => provideKeys.indexOf(key) !== i);
|
|
@@ -14945,6 +15197,203 @@ function checkProductDefinition(definition, ctx) {
|
|
|
14945
15197
|
});
|
|
14946
15198
|
}
|
|
14947
15199
|
}
|
|
15200
|
+
function declarationIssuePath(node) {
|
|
15201
|
+
const out = ["configuration"];
|
|
15202
|
+
for (const container of node.containers) {
|
|
15203
|
+
out.push("properties", container.name);
|
|
15204
|
+
if (container.kind === "array")
|
|
15205
|
+
out.push("items");
|
|
15206
|
+
}
|
|
15207
|
+
out.push("properties", node.name);
|
|
15208
|
+
return out;
|
|
15209
|
+
}
|
|
15210
|
+
function directChildren(leaves, container) {
|
|
15211
|
+
return leaves.filter((leaf) => immediateContainer(leaf)?.path === container.path);
|
|
15212
|
+
}
|
|
15213
|
+
function valuesOutsideSpace(configuration, leaf, values) {
|
|
15214
|
+
const single = withoutCrossFieldRules({
|
|
15215
|
+
...configuration,
|
|
15216
|
+
properties: { [leaf.name]: leaf.property },
|
|
15217
|
+
required: [leaf.name]
|
|
15218
|
+
});
|
|
15219
|
+
return values.filter((value) => !validateSubmittedConfiguration(single, { [leaf.name]: value }).ok);
|
|
15220
|
+
}
|
|
15221
|
+
function checkValueReferences(configuration, ctx) {
|
|
15222
|
+
const leaves = configurationLeaves(configuration);
|
|
15223
|
+
for (const leaf of leaves) {
|
|
15224
|
+
const reference = leaf.property["x-value-in"];
|
|
15225
|
+
if (reference === void 0)
|
|
15226
|
+
continue;
|
|
15227
|
+
const at = [...declarationIssuePath(leaf), "x-value-in"];
|
|
15228
|
+
const here = printableConfigurationPath(leaf.path);
|
|
15229
|
+
if (isSecretProperty(leaf.property)) {
|
|
15230
|
+
ctx.addIssue({
|
|
15231
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15232
|
+
path: at,
|
|
15233
|
+
message: `"${here}" is a secret. The platform never reads a secret's value, so it could never check one against a set of values.`
|
|
15234
|
+
});
|
|
15235
|
+
continue;
|
|
15236
|
+
}
|
|
15237
|
+
if (leaf.property.enum !== void 0) {
|
|
15238
|
+
ctx.addIssue({
|
|
15239
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15240
|
+
path: at,
|
|
15241
|
+
message: `"${here}" already fixes its values with "enum". A setting takes its values from the contract or from another setting, not from both.`
|
|
15242
|
+
});
|
|
15243
|
+
continue;
|
|
15244
|
+
}
|
|
15245
|
+
if (declaredDefault(leaf.property) !== void 0) {
|
|
15246
|
+
ctx.addIssue({
|
|
15247
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15248
|
+
path: at,
|
|
15249
|
+
message: `"${here}" declares a default, which would be written into every row and then refused until the setting it points at happens to hold the same value. Remove the default.`
|
|
15250
|
+
});
|
|
15251
|
+
continue;
|
|
15252
|
+
}
|
|
15253
|
+
const parsed = parseConfigurationPath(reference.path);
|
|
15254
|
+
const target = parsed === null ? null : leafAt(configuration, parsed);
|
|
15255
|
+
if (target === null) {
|
|
15256
|
+
const isGroup = parsed !== null && declaresPath(configuration, parsed);
|
|
15257
|
+
ctx.addIssue({
|
|
15258
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15259
|
+
path: [...at, "path"],
|
|
15260
|
+
message: isGroup ? `"${reference.path}" is a group of settings, which holds no value to choose from. Name one setting inside it.` : `"${reference.path}" is not a declared customer configuration property.`
|
|
15261
|
+
});
|
|
15262
|
+
continue;
|
|
15263
|
+
}
|
|
15264
|
+
if (target.path === leaf.path) {
|
|
15265
|
+
ctx.addIssue({
|
|
15266
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15267
|
+
path: [...at, "path"],
|
|
15268
|
+
message: `"${here}" cannot take its values from itself.`
|
|
15269
|
+
});
|
|
15270
|
+
continue;
|
|
15271
|
+
}
|
|
15272
|
+
if (target.property.type !== "string") {
|
|
15273
|
+
ctx.addIssue({
|
|
15274
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15275
|
+
path: [...at, "path"],
|
|
15276
|
+
message: `"${reference.path}" is a ${target.property.type} setting; a reference compares string values.`
|
|
15277
|
+
});
|
|
15278
|
+
continue;
|
|
15279
|
+
}
|
|
15280
|
+
if (isSecretProperty(target.property)) {
|
|
15281
|
+
ctx.addIssue({
|
|
15282
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15283
|
+
path: [...at, "path"],
|
|
15284
|
+
message: `"${reference.path}" is a secret. The platform never reads a secret's value, so it could never be the set a reference is checked against.`
|
|
15285
|
+
});
|
|
15286
|
+
continue;
|
|
15287
|
+
}
|
|
15288
|
+
}
|
|
15289
|
+
}
|
|
15290
|
+
function checkRowRules(configuration, ctx) {
|
|
15291
|
+
const leaves = configurationLeaves(configuration);
|
|
15292
|
+
for (const leaf of leaves) {
|
|
15293
|
+
if (leaf.property["x-row-rules"] === void 0)
|
|
15294
|
+
continue;
|
|
15295
|
+
ctx.addIssue({
|
|
15296
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15297
|
+
path: [...declarationIssuePath(leaf), "x-row-rules"],
|
|
15298
|
+
message: `"${printableConfigurationPath(leaf.path)}" is a list of text entries, whose rows have no fields to name. Use "uniqueItems" to compare whole entries, or declare "items" as a group.`
|
|
15299
|
+
});
|
|
15300
|
+
}
|
|
15301
|
+
for (const container of configurationContainers(configuration)) {
|
|
15302
|
+
const rules = container.property["x-row-rules"];
|
|
15303
|
+
if (rules === void 0)
|
|
15304
|
+
continue;
|
|
15305
|
+
const at = [...declarationIssuePath(container), "x-row-rules"];
|
|
15306
|
+
const here = printableConfigurationPath(container.path);
|
|
15307
|
+
if (rules.unique === void 0 && rules.atMost === void 0) {
|
|
15308
|
+
ctx.addIssue({
|
|
15309
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15310
|
+
path: at,
|
|
15311
|
+
message: `"${here}" declares "x-row-rules" with no rule in it. Declare "unique", "atMost", or both.`
|
|
15312
|
+
});
|
|
15313
|
+
continue;
|
|
15314
|
+
}
|
|
15315
|
+
const children = directChildren(leaves, container);
|
|
15316
|
+
const childAt = (name) => children.find((child) => child.name === name);
|
|
15317
|
+
const maxItems = container.property.maxItems;
|
|
15318
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15319
|
+
(rules.unique ?? []).forEach((name, index) => {
|
|
15320
|
+
if (seen.has(name)) {
|
|
15321
|
+
ctx.addIssue({
|
|
15322
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15323
|
+
path: [...at, "unique", index],
|
|
15324
|
+
message: `"${name}" is named twice.`
|
|
15325
|
+
});
|
|
15326
|
+
return;
|
|
15327
|
+
}
|
|
15328
|
+
seen.add(name);
|
|
15329
|
+
const child = childAt(name);
|
|
15330
|
+
if (child === void 0) {
|
|
15331
|
+
ctx.addIssue({
|
|
15332
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15333
|
+
path: [...at, "unique", index],
|
|
15334
|
+
message: `"${name}" is not a setting declared on a row of "${here}".`
|
|
15335
|
+
});
|
|
15336
|
+
return;
|
|
15337
|
+
}
|
|
15338
|
+
if (child.property.type === "array") {
|
|
15339
|
+
ctx.addIssue({
|
|
15340
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15341
|
+
path: [...at, "unique", index],
|
|
15342
|
+
message: `"${name}" is a list, which holds no single value to compare across rows.`
|
|
15343
|
+
});
|
|
15344
|
+
}
|
|
15345
|
+
if (child.property.type === "boolean") {
|
|
15346
|
+
ctx.addIssue({
|
|
15347
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15348
|
+
path: [...at, "unique", index],
|
|
15349
|
+
message: `"${name}" is a true/false setting, so requiring it to be unique would cap "${here}" at two rows rather than make anything distinct. Use "atMost" to limit how many rows may answer one way.`
|
|
15350
|
+
});
|
|
15351
|
+
}
|
|
15352
|
+
});
|
|
15353
|
+
(rules.atMost ?? []).forEach((rule, index) => {
|
|
15354
|
+
const ruleAt = [...at, "atMost", index];
|
|
15355
|
+
const child = childAt(rule.property);
|
|
15356
|
+
if (child === void 0) {
|
|
15357
|
+
ctx.addIssue({
|
|
15358
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15359
|
+
path: [...ruleAt, "property"],
|
|
15360
|
+
message: `"${rule.property}" is not a setting declared on a row of "${here}".`
|
|
15361
|
+
});
|
|
15362
|
+
return;
|
|
15363
|
+
}
|
|
15364
|
+
if (child.property.type !== "string") {
|
|
15365
|
+
ctx.addIssue({
|
|
15366
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15367
|
+
path: [...ruleAt, "property"],
|
|
15368
|
+
message: `"${rule.property}" is a ${child.property.type} setting; a row rule compares string values.`
|
|
15369
|
+
});
|
|
15370
|
+
return;
|
|
15371
|
+
}
|
|
15372
|
+
if (new Set(rule.anyOf).size !== rule.anyOf.length) {
|
|
15373
|
+
ctx.addIssue({
|
|
15374
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15375
|
+
path: [...ruleAt, "anyOf"],
|
|
15376
|
+
message: "Repeated values in `anyOf`."
|
|
15377
|
+
});
|
|
15378
|
+
}
|
|
15379
|
+
if (maxItems !== void 0 && rule.max >= maxItems) {
|
|
15380
|
+
ctx.addIssue({
|
|
15381
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15382
|
+
path: [...ruleAt, "max"],
|
|
15383
|
+
message: `"${here}" holds at most ${maxItems} rows, so a limit of ${rule.max} could never be exceeded. Lower it, or remove the rule.`
|
|
15384
|
+
});
|
|
15385
|
+
}
|
|
15386
|
+
const outside = valuesOutsideSpace(configuration, child, rule.anyOf);
|
|
15387
|
+
if (outside.length > 0) {
|
|
15388
|
+
ctx.addIssue({
|
|
15389
|
+
code: external_exports.ZodIssueCode.custom,
|
|
15390
|
+
path: [...ruleAt, "anyOf"],
|
|
15391
|
+
message: `"${rule.property}" never accepts ${outside.map((value) => `"${value}"`).join(", ")}, so this rule could never count a row.`
|
|
15392
|
+
});
|
|
15393
|
+
}
|
|
15394
|
+
});
|
|
15395
|
+
}
|
|
15396
|
+
}
|
|
14948
15397
|
|
|
14949
15398
|
// ../product-contracts/dist/announcements.js
|
|
14950
15399
|
var ANNOUNCED_PRODUCTS = Object.freeze([
|
|
@@ -16801,8 +17250,16 @@ var MANIFEST_ACTIONS = [
|
|
|
16801
17250
|
"ADOPT",
|
|
16802
17251
|
/** The key names a resource and something in the document differs. */
|
|
16803
17252
|
"UPDATE",
|
|
16804
|
-
/** The key names a resource and
|
|
16805
|
-
*
|
|
17253
|
+
/** The key names a resource and this REQUEST asks for nothing: no field
|
|
17254
|
+
* differs and no secret would be written.
|
|
17255
|
+
*
|
|
17256
|
+
* NOT "the document matches it", which is how it read and is a stronger claim
|
|
17257
|
+
* than the planner makes. What a document OMITS is left alone rather than
|
|
17258
|
+
* compared — a manifest naming no connections answers this beside a resource
|
|
17259
|
+
* that holds several — so this never means the file mirrors stored state.
|
|
17260
|
+
*
|
|
17261
|
+
* A pipeline that runs on every push and changes nothing reports it, and it
|
|
17262
|
+
* is SUCCESS. */
|
|
16806
17263
|
"NO_CHANGE",
|
|
16807
17264
|
/** `adopt` points at a resource that was DELETED. Its own verb, because both
|
|
16808
17265
|
* alternatives are wrong: `NO_CHANGE` would call a missing resource fine, and
|
|
@@ -17089,7 +17546,9 @@ function secretWriteConsequence(plan) {
|
|
|
17089
17546
|
const lines = ["the value you send REPLACES the stored one, and the resource redeploys."];
|
|
17090
17547
|
if (plan.action === "UPDATE" && (plan.changes ?? []).length === 0) {
|
|
17091
17548
|
lines.push("Nothing else changed \u2014 sending a secret is itself the change.");
|
|
17092
|
-
lines.push(
|
|
17549
|
+
lines.push(
|
|
17550
|
+
"Omit --secret on a run that is not setting or changing one; that is what answers NO_CHANGE."
|
|
17551
|
+
);
|
|
17093
17552
|
}
|
|
17094
17553
|
return lines;
|
|
17095
17554
|
}
|
|
@@ -17893,9 +18352,9 @@ async function runGet(parsed) {
|
|
|
17893
18352
|
lines.push("", " Outputs");
|
|
17894
18353
|
const width = Math.max(...names.map((name) => name.length));
|
|
17895
18354
|
for (const name of names) {
|
|
17896
|
-
|
|
17897
|
-
|
|
17898
|
-
);
|
|
18355
|
+
const value = outputs[name];
|
|
18356
|
+
const shown = isSecret2(name) ? "[secret]" : value === void 0 || value === null ? "[not available]" : String(value);
|
|
18357
|
+
lines.push(` ${name.padEnd(width)} ${shown}`);
|
|
17899
18358
|
const meaning = declared.find((entry) => entry["key"] === name);
|
|
17900
18359
|
const description = meaning?.["description"];
|
|
17901
18360
|
if (typeof description === "string") {
|
|
@@ -18085,14 +18544,41 @@ function renderProduct(product) {
|
|
|
18085
18544
|
lines.push(` ${setting.label} ${setting.type ?? ""}`.trimEnd());
|
|
18086
18545
|
}
|
|
18087
18546
|
}
|
|
18088
|
-
const
|
|
18089
|
-
if (
|
|
18090
|
-
lines.push("", "
|
|
18091
|
-
for (const dependency of
|
|
18092
|
-
|
|
18547
|
+
const dependencies = product.dependencies ?? [];
|
|
18548
|
+
if (dependencies.length > 0) {
|
|
18549
|
+
lines.push("", " Connections to another resource");
|
|
18550
|
+
for (const dependency of dependencies) {
|
|
18551
|
+
const when = dependency.requiredWhen?.property;
|
|
18552
|
+
const need = dependency.required ? "required" : when === void 0 ? "optional" : `required when ${when} is ${(dependency.requiredWhen?.anyOf ?? []).join(" or ")}`;
|
|
18553
|
+
lines.push(` ${dependency.key ?? "(no key)"} ${need}`);
|
|
18554
|
+
const capability = dependency.interface?.id;
|
|
18555
|
+
if (capability !== void 0) {
|
|
18556
|
+
lines.push(
|
|
18557
|
+
` ${capability}${dependency.interface?.version ? `/${dependency.interface.version}` : ""}`
|
|
18558
|
+
);
|
|
18559
|
+
} else if (dependency.productId !== void 0) {
|
|
18560
|
+
lines.push(` ${dependency.productId}`);
|
|
18561
|
+
}
|
|
18093
18562
|
if (dependency.reason) lines.push(` ${dependency.reason}`);
|
|
18094
18563
|
}
|
|
18095
18564
|
}
|
|
18565
|
+
const outputs = product.outputs ?? [];
|
|
18566
|
+
if (outputs.length > 0) {
|
|
18567
|
+
lines.push("", " Publishes");
|
|
18568
|
+
for (const output of outputs) {
|
|
18569
|
+
lines.push(
|
|
18570
|
+
` ${output.key ?? ""} ${output.secret === true ? "secret" : output.type ?? ""}`.trimEnd()
|
|
18571
|
+
);
|
|
18572
|
+
}
|
|
18573
|
+
}
|
|
18574
|
+
const conditions = product.conditions ?? [];
|
|
18575
|
+
if (conditions.length > 0) {
|
|
18576
|
+
lines.push("", " Needs setting up outside the platform");
|
|
18577
|
+
for (const condition of conditions) {
|
|
18578
|
+
lines.push(` ${condition.key ?? ""} ${condition.displayName ?? ""}`.trimEnd());
|
|
18579
|
+
}
|
|
18580
|
+
}
|
|
18581
|
+
lines.push("", " `--output json` carries the whole declaration, this is a readable subset.");
|
|
18096
18582
|
return lines.join("\n");
|
|
18097
18583
|
}
|
|
18098
18584
|
function wrap(text, width) {
|
|
@@ -18441,6 +18927,12 @@ Run \`vfac get product-instance pri_\u2026\` to see which ones this credential m
|
|
|
18441
18927
|
`);
|
|
18442
18928
|
return 2;
|
|
18443
18929
|
}
|
|
18930
|
+
if (parsed.booleans.has("wait")) {
|
|
18931
|
+
process.stderr.write(
|
|
18932
|
+
"`--wait` belongs to `vfac apply`; `vfac lifecycle` does not support it.\nThis command answers with an operation id. Follow it with:\n vfac get operation op_\u2026\nand branch on the status it reports: SUCCEEDED, FAILED or CANCELLED. That\ncommand's exit code says whether the READ worked, never whether the operation\ndid \u2014 so a script that only checks the exit code reports a failed deploy as a\nsuccess.\n"
|
|
18933
|
+
);
|
|
18934
|
+
return 2;
|
|
18935
|
+
}
|
|
18444
18936
|
if (command === "delete" && !parsed.booleans.has("yes")) {
|
|
18445
18937
|
process.stderr.write(
|
|
18446
18938
|
`delete removes ${instanceId} and everything it is serving. This cannot be undone.
|
|
@@ -18547,7 +19039,7 @@ var USAGE = `vfac \u2014 deploy Varde Flyt resources from a manifest
|
|
|
18547
19039
|
vfac manifest init --product <productId> --name <name> [--key <key>]
|
|
18548
19040
|
[--region <region>] [--profile <profile>]
|
|
18549
19041
|
vfac validate -f resource.yaml
|
|
18550
|
-
vfac plan -f resource.yaml
|
|
19042
|
+
vfac plan -f resource.yaml [--secret NAME=env:VAR]
|
|
18551
19043
|
vfac apply -f resource.yaml [--secret NAME=env:VAR] [--adopt pri_\u2026] [--wait]
|
|
18552
19044
|
vfac get product-instances
|
|
18553
19045
|
vfac get product-instance pri_\u2026 what it is, and its outputs
|
|
@@ -18564,9 +19056,12 @@ Options
|
|
|
18564
19056
|
--project the Project to act in. Defaults to the stored context
|
|
18565
19057
|
--endpoint your organization's portal. Defaults to VFAC_ENDPOINT, then the
|
|
18566
19058
|
stored context
|
|
18567
|
-
--secret NAME=env:VARIABLE \u2014 the value is read from the
|
|
18568
|
-
|
|
18569
|
-
|
|
19059
|
+
--secret plan and apply: NAME=env:VARIABLE \u2014 the value is read from the
|
|
19060
|
+
environment. Plan a run that sets a secret with the same
|
|
19061
|
+
--secret inputs the apply will carry; without them the plan
|
|
19062
|
+
answers about a different request. A value on the command line
|
|
19063
|
+
is in your shell history and in the process table, so it is
|
|
19064
|
+
refused
|
|
18570
19065
|
--product which Product to write a starting manifest for
|
|
18571
19066
|
--name what a person will call the resource
|
|
18572
19067
|
--key its stable identity. Derived from --name when omitted
|