@varde-flyt/vfac 0.15.0 → 0.15.2
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 +23 -13
- package/dist/vfac.mjs +245 -29
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -26,10 +26,10 @@ vfac guide
|
|
|
26
26
|
vfac whoami
|
|
27
27
|
```
|
|
28
28
|
|
|
29
|
-
`doctor` checks the endpoint, which Project this terminal has selected
|
|
30
|
-
|
|
31
|
-
terminal is signed in and what that credential
|
|
32
|
-
the first thing that is actually wrong. Both ways of signing in count: a Context
|
|
29
|
+
`doctor` checks the endpoint, which Project this terminal has selected and which
|
|
30
|
+
one this command will act in, the API, whether this client is new enough for the
|
|
31
|
+
platform it is pointed at, how this terminal is signed in and what that credential
|
|
32
|
+
reaches, in that order, and reports the first thing that is actually wrong. Both ways of signing in count: a Context
|
|
33
33
|
Gate exchanged from `VFAC_CREDENTIAL_ID` and `VFAC_CREDENTIAL_SECRET`, or a
|
|
34
34
|
sign-in from `vfac login` that is still valid. A platform declares the oldest client it supports;
|
|
35
35
|
below that, `doctor` fails and says so before sending your credential anywhere.
|
|
@@ -37,7 +37,10 @@ below that, `doctor` fails and says so before sending your credential anywhere.
|
|
|
37
37
|
The selected Project and the Projects your credential reaches are two different
|
|
38
38
|
lines, and reading the second as the first is the mistake worth naming: a command
|
|
39
39
|
with no `--project` uses the SELECTED one, and having access to a Project is not
|
|
40
|
-
the same as being in it. `
|
|
40
|
+
the same as being in it. `--project` overrides the selection for one command and
|
|
41
|
+
writes nothing, so `vfac doctor --project prj_…` reports the Project it would act
|
|
42
|
+
in, says the flag is where that came from, and still names what your context has
|
|
43
|
+
selected. `doctor` also says so when it has just started a fresh
|
|
41
44
|
config because the old one could not be read — the endpoint and Project you had
|
|
42
45
|
set are gone in that case, and the unreadable file is kept beside it rather than
|
|
43
46
|
discarded.
|
|
@@ -68,7 +71,7 @@ vfac context set --project <projectId>
|
|
|
68
71
|
|
|
69
72
|
```sh
|
|
70
73
|
vfac product list
|
|
71
|
-
vfac product show <productId>
|
|
74
|
+
vfac product show <productId> # every setting, and when you must answer it
|
|
72
75
|
vfac manifest init --product <productId> --name "My resource" > resource.yaml
|
|
73
76
|
```
|
|
74
77
|
|
|
@@ -97,9 +100,12 @@ the plan describes a different request.
|
|
|
97
100
|
|
|
98
101
|
`--secret` names a root setting by its name, and a setting inside a group by its
|
|
99
102
|
path — `--secret /upstreamAuth/clientSecret=env:UPSTREAM_CLIENT_SECRET` for the
|
|
100
|
-
`clientSecret` under `upstreamAuth`. `vfac product show`
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
`clientSecret` under `upstreamAuth`. `vfac product show` prints that form beside
|
|
104
|
+
EVERY credential the Product declares, with a line saying whether it is required
|
|
105
|
+
of everyone, required when another setting holds a particular value, or required
|
|
106
|
+
because another setting was answered — `dependentRequired` is directional, and
|
|
107
|
+
the line says which way it runs; `vfac manifest init` names the ones required
|
|
108
|
+
outright. A path never names an item of a list: no secret is declared there.
|
|
103
109
|
|
|
104
110
|
`requiredSecrets` in a plan is what the Product requires for the configuration in
|
|
105
111
|
your document — not a list of what the platform is missing. It names a credential
|
|
@@ -109,7 +115,9 @@ act on. `secretsToWrite` is the field that says what this apply would write.
|
|
|
109
115
|
A credential the Product requires for your document — outright, or because of
|
|
110
116
|
what a setting is set to — that the run neither supplies nor the resource already
|
|
111
117
|
holds is refused by `plan` and `apply` alike, before anything is written: the
|
|
112
|
-
error names every one, by the path `--secret` takes, and the command exits 1.
|
|
118
|
+
error names every one, by the path `--secret` takes, and the command exits 1. So
|
|
119
|
+
is a credential the run DOES supply whose value the Product's own declaration
|
|
120
|
+
refuses: the error names the setting and the bound it missed, never the value.
|
|
113
121
|
`vfac validate` carries no secrets and refuses none; it lists them.
|
|
114
122
|
|
|
115
123
|
### `metadata.key` is the name you choose
|
|
@@ -229,9 +237,11 @@ it.
|
|
|
229
237
|
## For an agent or a pipeline
|
|
230
238
|
|
|
231
239
|
Every command takes `--output json`, and it is the same data rather than a
|
|
232
|
-
prettier subset
|
|
233
|
-
|
|
234
|
-
the
|
|
240
|
+
prettier subset. The human format of `vfac product show` lists every setting the
|
|
241
|
+
Product declares and says when each must be answered; what it leaves to the JSON
|
|
242
|
+
form is the prose and the value constraints — descriptions, patterns, bounds —
|
|
243
|
+
and it says so at the foot of its output. The JSON carries the whole Product
|
|
244
|
+
contract.
|
|
235
245
|
|
|
236
246
|
```sh
|
|
237
247
|
vfac product show <productId> --output json
|
package/dist/vfac.mjs
CHANGED
|
@@ -13207,6 +13207,14 @@ function canonicalJson(value) {
|
|
|
13207
13207
|
function immediateContainer(node) {
|
|
13208
13208
|
return node.containers[node.containers.length - 1] ?? null;
|
|
13209
13209
|
}
|
|
13210
|
+
function resolvedGroup(node) {
|
|
13211
|
+
for (const container of node.containers) {
|
|
13212
|
+
const declared = container.property.group;
|
|
13213
|
+
if (declared !== void 0)
|
|
13214
|
+
return declared;
|
|
13215
|
+
}
|
|
13216
|
+
return node.property.group;
|
|
13217
|
+
}
|
|
13210
13218
|
function underList(node) {
|
|
13211
13219
|
return node.containers.some((container) => container.kind === "array");
|
|
13212
13220
|
}
|
|
@@ -14210,6 +14218,116 @@ function exampleResourceKey(name) {
|
|
|
14210
14218
|
}
|
|
14211
14219
|
var DEPLOYMENT_EXAMPLE_GUARANTEE = "Product-owned configuration is complete and E2E-proven; tenant-specific secrets and Resource/provider selections are supplied by the tenant.";
|
|
14212
14220
|
|
|
14221
|
+
// ../product-configuration/dist/configuration-requirements.js
|
|
14222
|
+
function configurationRequirements(configuration) {
|
|
14223
|
+
if (configuration === void 0 || configuration === null)
|
|
14224
|
+
return [];
|
|
14225
|
+
const schema = configuration;
|
|
14226
|
+
const rootRequired = new Set(schema.required ?? []);
|
|
14227
|
+
const carriers = new Map(conditionCarriers(schema).map((carrier) => [carrier.path, carrier]));
|
|
14228
|
+
const secretPaths = new Set(configurationLeaves(schema).filter((leaf) => isSecretProperty(leaf.property)).map((leaf) => String(leaf.path)));
|
|
14229
|
+
return configurationLeaves(schema).map((leaf) => {
|
|
14230
|
+
const parent = immediateContainer(leaf);
|
|
14231
|
+
const immediatelyRequired = parent === null ? rootRequired.has(leaf.name) : parent.required.includes(leaf.name);
|
|
14232
|
+
const chainRequired = containersRequiredToRoot(schema, leaf);
|
|
14233
|
+
const always = requiredToRoot(schema, leaf);
|
|
14234
|
+
const secret = isSecretProperty(leaf.property);
|
|
14235
|
+
const condition = conditionFor(schema, leaf.path, leaf.containers, carriers);
|
|
14236
|
+
const clause = clauseEdges(schema, leaf, secretPaths);
|
|
14237
|
+
const requiredness = always ? "always" : condition !== null && condition.carrier === "setting" ? "when-value" : immediatelyRequired && !chainRequired ? "when-group" : clause.requiredBy.length > 0 ? "with-siblings" : "optional";
|
|
14238
|
+
const containers = leaf.containers.map((container, index) => settingContainer(container, index === 0 ? rootRequired : new Set(leaf.containers[index - 1]?.required ?? [])));
|
|
14239
|
+
const list = [...containers].reverse().find((container) => container.kind === "array") ?? null;
|
|
14240
|
+
return {
|
|
14241
|
+
path: leaf.path,
|
|
14242
|
+
printablePath: printableConfigurationPath(leaf.path),
|
|
14243
|
+
title: leaf.property.title,
|
|
14244
|
+
description: leaf.property.description,
|
|
14245
|
+
type: leaf.property.type,
|
|
14246
|
+
secret,
|
|
14247
|
+
requiredness,
|
|
14248
|
+
// NEVER A SECRET'S, even though the declaration rules already refuse one.
|
|
14249
|
+
// Being wrong in that direction prints a credential, which is the same
|
|
14250
|
+
// paranoia `product-instance-example.ts` documents for its own reader.
|
|
14251
|
+
defaultValue: secret ? void 0 : declaredDefault(leaf.property),
|
|
14252
|
+
allowed: secret ? [] : allowedValues(leaf.property),
|
|
14253
|
+
condition,
|
|
14254
|
+
requires: clause.requires,
|
|
14255
|
+
requiredBy: clause.requiredBy,
|
|
14256
|
+
containers,
|
|
14257
|
+
perRow: underList(leaf),
|
|
14258
|
+
list,
|
|
14259
|
+
group: resolvedGroup(leaf)
|
|
14260
|
+
};
|
|
14261
|
+
});
|
|
14262
|
+
}
|
|
14263
|
+
function allowedValues(property) {
|
|
14264
|
+
const leaf = property;
|
|
14265
|
+
return [...leaf.enum ?? leaf.items?.enum ?? []];
|
|
14266
|
+
}
|
|
14267
|
+
function conditionFor(schema, path, containers, carriers) {
|
|
14268
|
+
const own = carriers.get(path);
|
|
14269
|
+
const ancestor = [...containers].reverse().map((container) => carriers.get(container.path)).find((carrier2) => carrier2 !== void 0 && carrier2.kind === "container");
|
|
14270
|
+
const carrier = own?.kind === "leaf" ? own : ancestor;
|
|
14271
|
+
if (carrier === void 0)
|
|
14272
|
+
return null;
|
|
14273
|
+
const setting = parseConfigurationPath(conditionSetting(carrier.condition));
|
|
14274
|
+
if (setting === null)
|
|
14275
|
+
return null;
|
|
14276
|
+
return {
|
|
14277
|
+
carrier: carrier.kind === "leaf" ? "setting" : "container",
|
|
14278
|
+
carrierPath: carrier.path,
|
|
14279
|
+
setting,
|
|
14280
|
+
printableSetting: printableConfigurationPath(setting),
|
|
14281
|
+
settingLabel: labelOfPath(schema, setting),
|
|
14282
|
+
anyOf: [...carrier.condition.anyOf],
|
|
14283
|
+
anyRow: "path" in carrier.condition && carrier.condition.anyRow === true
|
|
14284
|
+
};
|
|
14285
|
+
}
|
|
14286
|
+
function clauseEdges(schema, leaf, secretPaths) {
|
|
14287
|
+
const parent = immediateContainer(leaf);
|
|
14288
|
+
const scope = parent === null ? schema : parent.kind === "array" ? parent.property.items ?? parent.property : parent.property;
|
|
14289
|
+
const requires = /* @__PURE__ */ new Set();
|
|
14290
|
+
const requiredBy = /* @__PURE__ */ new Set();
|
|
14291
|
+
for (const [trigger, dependents] of Object.entries(scope.dependentRequired ?? {})) {
|
|
14292
|
+
if (trigger === leaf.name)
|
|
14293
|
+
for (const dependent of dependents)
|
|
14294
|
+
requires.add(dependent);
|
|
14295
|
+
else if (dependents.includes(leaf.name))
|
|
14296
|
+
requiredBy.add(trigger);
|
|
14297
|
+
}
|
|
14298
|
+
const order = Object.keys(scope.properties ?? {});
|
|
14299
|
+
const members = (names) => [...names].sort((a, b) => order.indexOf(a) - order.indexOf(b)).flatMap((name) => {
|
|
14300
|
+
const path = memberPath(leaf, name);
|
|
14301
|
+
return path === null ? [] : [
|
|
14302
|
+
{
|
|
14303
|
+
path,
|
|
14304
|
+
printablePath: printableConfigurationPath(path),
|
|
14305
|
+
secret: secretPaths.has(String(path))
|
|
14306
|
+
}
|
|
14307
|
+
];
|
|
14308
|
+
});
|
|
14309
|
+
return { requires: members(requires), requiredBy: members(requiredBy) };
|
|
14310
|
+
}
|
|
14311
|
+
function memberPath(leaf, name) {
|
|
14312
|
+
const parent = immediateContainer(leaf);
|
|
14313
|
+
return parent === null ? configurationPath(name) : configurationPath(...pathSegments(parent.path), name);
|
|
14314
|
+
}
|
|
14315
|
+
function settingContainer(container, requiredByParent) {
|
|
14316
|
+
return {
|
|
14317
|
+
path: container.path,
|
|
14318
|
+
printablePath: printableConfigurationPath(container.path),
|
|
14319
|
+
title: container.property.title,
|
|
14320
|
+
kind: container.kind,
|
|
14321
|
+
required: requiredByParent.has(container.name)
|
|
14322
|
+
};
|
|
14323
|
+
}
|
|
14324
|
+
|
|
14325
|
+
// ../product-configuration/dist/manifest-yaml.js
|
|
14326
|
+
var import_yaml = __toESM(require_dist(), 1);
|
|
14327
|
+
function manifestYaml(document) {
|
|
14328
|
+
return (0, import_yaml.stringify)(document, { compat: "yaml-1.1" });
|
|
14329
|
+
}
|
|
14330
|
+
|
|
14213
14331
|
// ../platform-schemas/dist/index.js
|
|
14214
14332
|
var TENANT_KEY_REGEX = /^[a-z][a-z0-9-]{2,23}[a-z0-9]$/;
|
|
14215
14333
|
var RESERVED_TENANT_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -17868,7 +17986,7 @@ withJsonSchemaAnnex(ProductSubmissionSchema, PUBLISH_RULE_ANNEX);
|
|
|
17868
17986
|
withJsonSchemaAnnex(ProductSubmissionV2Schema, PUBLISH_RULE_ANNEX);
|
|
17869
17987
|
|
|
17870
17988
|
// src/manifest.ts
|
|
17871
|
-
var
|
|
17989
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
17872
17990
|
function readManifest(path) {
|
|
17873
17991
|
let text;
|
|
17874
17992
|
try {
|
|
@@ -17878,7 +17996,7 @@ function readManifest(path) {
|
|
|
17878
17996
|
}
|
|
17879
17997
|
let parsed;
|
|
17880
17998
|
try {
|
|
17881
|
-
parsed = (0,
|
|
17999
|
+
parsed = (0, import_yaml2.parse)(text, { prettyErrors: false });
|
|
17882
18000
|
} catch (error) {
|
|
17883
18001
|
return {
|
|
17884
18002
|
ok: false,
|
|
@@ -18041,8 +18159,14 @@ async function ensureSession(args) {
|
|
|
18041
18159
|
}
|
|
18042
18160
|
};
|
|
18043
18161
|
}
|
|
18162
|
+
function resolveProjectWithSource(flag, stored) {
|
|
18163
|
+
if (flag !== void 0) return { value: flag, source: "--project" };
|
|
18164
|
+
const selected = stored.context?.projectId;
|
|
18165
|
+
if (selected !== void 0) return { value: selected, source: "the stored context" };
|
|
18166
|
+
return null;
|
|
18167
|
+
}
|
|
18044
18168
|
function resolveProject(flag, stored) {
|
|
18045
|
-
return flag
|
|
18169
|
+
return resolveProjectWithSource(flag, stored)?.value ?? null;
|
|
18046
18170
|
}
|
|
18047
18171
|
|
|
18048
18172
|
// src/operations.ts
|
|
@@ -18692,13 +18816,18 @@ async function runDoctor(parsed) {
|
|
|
18692
18816
|
detail: `${endpoint} (from ${resolved.source})`,
|
|
18693
18817
|
facts: { endpoint, source: resolved.source }
|
|
18694
18818
|
});
|
|
18695
|
-
const
|
|
18819
|
+
const project = resolveProjectWithSource(parsed.flags["project"], stored);
|
|
18820
|
+
const storedProjectId = stored.context?.projectId ?? null;
|
|
18696
18821
|
checks.push({
|
|
18697
18822
|
name: "Project",
|
|
18698
18823
|
ok: true,
|
|
18699
|
-
note:
|
|
18700
|
-
detail:
|
|
18701
|
-
facts: {
|
|
18824
|
+
note: storedProjectId === null,
|
|
18825
|
+
detail: project === 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." : project.source === "--project" ? `${project.value} (from --project, for this command only). ` + (storedProjectId === null ? "Nothing is selected in this context, so every other command needs the flag too. " : `The stored context still selects ${storedProjectId}, which is what a command with no --project uses. `) + "Which Projects the credential reaches is a separate question." : `${project.value} (from the stored context; a command with no --project uses it, and which Projects the credential reaches is a separate question)`,
|
|
18826
|
+
facts: {
|
|
18827
|
+
selectedProjectId: project?.value ?? null,
|
|
18828
|
+
source: project?.source ?? null,
|
|
18829
|
+
storedProjectId
|
|
18830
|
+
}
|
|
18702
18831
|
});
|
|
18703
18832
|
const probe = await probeMachineApi({ endpoint });
|
|
18704
18833
|
if (!probe.ok) {
|
|
@@ -18733,13 +18862,13 @@ async function runDoctor(parsed) {
|
|
|
18733
18862
|
return report2(checks, json);
|
|
18734
18863
|
}
|
|
18735
18864
|
const access = who.data.access;
|
|
18736
|
-
const projects = access.projects.map((
|
|
18865
|
+
const projects = access.projects.map((project2) => project2.projectId);
|
|
18737
18866
|
const mutating = access.projects.filter(
|
|
18738
|
-
(
|
|
18867
|
+
(project2) => project2.permissions.some((permission) => !permission.endsWith(".read"))
|
|
18739
18868
|
);
|
|
18740
18869
|
const organizationWide = access.tenantPermissions.includes("project.read");
|
|
18741
18870
|
const alsoOrganizationWide = access.tenantPermissions.length > 0 ? `Organization-wide it holds ${access.tenantPermissions.join(", ")}, which reaches no Project. ` : "";
|
|
18742
|
-
const perProject = projects.length === 0 ? "" : `. Granted per Project: ${projects.join(", ")}` + (mutating.length > 0 ? ` \u2014 you can deploy in ${mutating.map((
|
|
18871
|
+
const perProject = projects.length === 0 ? "" : `. Granted per Project: ${projects.join(", ")}` + (mutating.length > 0 ? ` \u2014 you can deploy in ${mutating.map((project2) => project2.projectId).join(", ")}` : " \u2014 read-only there");
|
|
18743
18872
|
checks.push(
|
|
18744
18873
|
organizationWide ? {
|
|
18745
18874
|
name: "Access",
|
|
@@ -18898,7 +19027,6 @@ function report2(checks, json) {
|
|
|
18898
19027
|
}
|
|
18899
19028
|
|
|
18900
19029
|
// src/commands/export.ts
|
|
18901
|
-
var import_yaml2 = __toESM(require_dist(), 1);
|
|
18902
19030
|
async function runExport(parsed) {
|
|
18903
19031
|
if (parsed.command[1] !== "product-instance" && parsed.command[1] !== "resource") {
|
|
18904
19032
|
process.stderr.write("Usage: vfac export product-instance pri_\u2026\n");
|
|
@@ -18926,7 +19054,7 @@ async function runExport(parsed) {
|
|
|
18926
19054
|
if (!result.ok) return printError(result.error, parsed.flags["output"] === "json");
|
|
18927
19055
|
process.stdout.write(
|
|
18928
19056
|
parsed.flags["output"] === "json" ? `${JSON.stringify(result.data, null, 2)}
|
|
18929
|
-
` : (
|
|
19057
|
+
` : manifestYaml(result.data)
|
|
18930
19058
|
);
|
|
18931
19059
|
const metadata = result.data["metadata"];
|
|
18932
19060
|
const hasKey = typeof metadata === "object" && metadata !== null && "key" in metadata;
|
|
@@ -19338,16 +19466,44 @@ function renderProduct(product) {
|
|
|
19338
19466
|
(profile) => `${profile.id}${profile.default ? " (default)" : ""}`
|
|
19339
19467
|
);
|
|
19340
19468
|
lines.push(` profile ${profiles.join(", ") || "(none declared)"}`);
|
|
19341
|
-
const
|
|
19342
|
-
if (
|
|
19343
|
-
lines.push("",
|
|
19344
|
-
for (const
|
|
19345
|
-
lines.push(
|
|
19346
|
-
}
|
|
19347
|
-
|
|
19348
|
-
|
|
19469
|
+
const settings = configurationRequirements(product.configuration);
|
|
19470
|
+
if (settings.length > 0) {
|
|
19471
|
+
lines.push("", ` Settings (${settings.length})`);
|
|
19472
|
+
for (const setting of settings) {
|
|
19473
|
+
lines.push(
|
|
19474
|
+
` ${identityOf(setting)} ${setting.secret ? "secret" : setting.type} ${TOKEN[setting.requiredness]}`
|
|
19475
|
+
);
|
|
19476
|
+
const requirement = requirementOf(setting);
|
|
19477
|
+
if (requirement !== null) lines.push(...continuation(requirement));
|
|
19478
|
+
if (setting.requires.length > 0 && !mutualClause(setting)) {
|
|
19479
|
+
lines.push(
|
|
19480
|
+
...continuation(
|
|
19481
|
+
`answering it also requires ${listOf(
|
|
19482
|
+
setting.requires.map((member) => identityOf(member)),
|
|
19483
|
+
"and"
|
|
19484
|
+
)}`
|
|
19485
|
+
)
|
|
19486
|
+
);
|
|
19487
|
+
}
|
|
19488
|
+
if (setting.condition?.carrier === "container") {
|
|
19489
|
+
lines.push(
|
|
19490
|
+
...continuation(
|
|
19491
|
+
`${printableConfigurationPath(setting.condition.carrierPath)} is required when ${setting.condition.printableSetting} is ${valueList(setting.condition.anyOf)}`
|
|
19492
|
+
)
|
|
19493
|
+
);
|
|
19494
|
+
}
|
|
19495
|
+
if (setting.secret) {
|
|
19496
|
+
lines.push(...continuation(`--secret ${String(setting.path)}=env:VAR`));
|
|
19497
|
+
}
|
|
19498
|
+
if (setting.allowed.length > 0) {
|
|
19499
|
+
lines.push(...continuation(`one of ${valueList(setting.allowed)}`));
|
|
19500
|
+
}
|
|
19501
|
+
if (setting.defaultValue !== void 0) {
|
|
19502
|
+
lines.push(...continuation(`default ${JSON.stringify(setting.defaultValue)}`));
|
|
19503
|
+
}
|
|
19349
19504
|
}
|
|
19350
19505
|
}
|
|
19506
|
+
const seed = seedConfiguration(product.configuration);
|
|
19351
19507
|
const together = seed.groups.filter((group) => group.within !== null);
|
|
19352
19508
|
if (together.length > 0) {
|
|
19353
19509
|
lines.push("", " Settings that go together");
|
|
@@ -19397,9 +19553,66 @@ function renderProduct(product) {
|
|
|
19397
19553
|
lines.push(` ${condition.key ?? ""} ${condition.displayName ?? ""}`.trimEnd());
|
|
19398
19554
|
}
|
|
19399
19555
|
}
|
|
19400
|
-
lines.push(
|
|
19556
|
+
lines.push(
|
|
19557
|
+
"",
|
|
19558
|
+
" `--output json` carries the whole declaration. Every setting is listed above;",
|
|
19559
|
+
" descriptions and value constraints are in the JSON form."
|
|
19560
|
+
);
|
|
19561
|
+
if (settings.some((setting) => setting.secret)) {
|
|
19562
|
+
lines.push(" A credential is supplied per apply and never written into a manifest.");
|
|
19563
|
+
}
|
|
19401
19564
|
return lines.join("\n");
|
|
19402
19565
|
}
|
|
19566
|
+
var TOKEN = {
|
|
19567
|
+
always: "required",
|
|
19568
|
+
"when-value": "required-when",
|
|
19569
|
+
"when-group": "required-if",
|
|
19570
|
+
"with-siblings": "required-with",
|
|
19571
|
+
optional: "optional"
|
|
19572
|
+
};
|
|
19573
|
+
var MAX_LISTED_VALUES = 8;
|
|
19574
|
+
var identityOf = (setting) => setting.secret ? String(setting.path) : setting.printablePath;
|
|
19575
|
+
function valueList(values) {
|
|
19576
|
+
const shown = values.slice(0, MAX_LISTED_VALUES).map((value) => JSON.stringify(value));
|
|
19577
|
+
const rest = values.length - shown.length;
|
|
19578
|
+
const joined = shown.length === 2 ? shown.join(" or ") : shown.join(", ");
|
|
19579
|
+
return rest > 0 ? `${joined} and ${rest} more` : joined;
|
|
19580
|
+
}
|
|
19581
|
+
function requirementOf(setting) {
|
|
19582
|
+
const list = setting.list === null ? "" : ` ${setting.list.printablePath}`;
|
|
19583
|
+
switch (setting.requiredness) {
|
|
19584
|
+
case "always":
|
|
19585
|
+
return setting.perRow ? `in every${list} entry` : null;
|
|
19586
|
+
case "when-value": {
|
|
19587
|
+
const condition = setting.condition;
|
|
19588
|
+
if (condition === null) return null;
|
|
19589
|
+
const rows = condition.anyRow ? " in any entry" : "";
|
|
19590
|
+
return `when ${condition.printableSetting} is ${valueList(condition.anyOf)}${rows}`;
|
|
19591
|
+
}
|
|
19592
|
+
case "when-group": {
|
|
19593
|
+
const owner = setting.containers[setting.containers.length - 1];
|
|
19594
|
+
const base = `once ${owner?.printablePath ?? ""} is configured`;
|
|
19595
|
+
return setting.perRow ? `${base}, in every${list} entry` : base;
|
|
19596
|
+
}
|
|
19597
|
+
case "with-siblings": {
|
|
19598
|
+
const names = (members) => members.map((member) => identityOf(member));
|
|
19599
|
+
const triggers = names(setting.requiredBy);
|
|
19600
|
+
return mutualClause(setting) ? `with ${names(setting.requires).join(", ")}` : `once ${listOf(triggers, "or")} is set`;
|
|
19601
|
+
}
|
|
19602
|
+
case "optional":
|
|
19603
|
+
return setting.perRow ? `one per${list} entry` : null;
|
|
19604
|
+
}
|
|
19605
|
+
}
|
|
19606
|
+
function mutualClause(setting) {
|
|
19607
|
+
const requires = setting.requires.map((member) => String(member.path)).sort();
|
|
19608
|
+
const requiredBy = setting.requiredBy.map((member) => String(member.path)).sort();
|
|
19609
|
+
return requires.length > 0 && requires.join("\0") === requiredBy.join("\0");
|
|
19610
|
+
}
|
|
19611
|
+
function listOf(items, conjunction) {
|
|
19612
|
+
if (items.length <= 1) return items[0] ?? "";
|
|
19613
|
+
return `${items.slice(0, -1).join(", ")} ${conjunction} ${items[items.length - 1]}`;
|
|
19614
|
+
}
|
|
19615
|
+
var continuation = (sentence) => wrap(sentence, 72).map((line) => ` ${line}`);
|
|
19403
19616
|
function wrap(text, width) {
|
|
19404
19617
|
const lines = [];
|
|
19405
19618
|
for (const paragraph of text.split(/\n\s*\n/)) {
|
|
@@ -19582,7 +19795,6 @@ Only approve a code you are looking at right now. Waiting\u2026
|
|
|
19582
19795
|
}
|
|
19583
19796
|
|
|
19584
19797
|
// src/commands/manifest-init.ts
|
|
19585
|
-
var import_yaml3 = __toESM(require_dist(), 1);
|
|
19586
19798
|
async function runManifestInit(parsed) {
|
|
19587
19799
|
const verb = parsed.command[1];
|
|
19588
19800
|
if (verb !== "init") {
|
|
@@ -19687,7 +19899,7 @@ ${where}`);
|
|
|
19687
19899
|
}
|
|
19688
19900
|
process.stdout.write(
|
|
19689
19901
|
parsed.flags["output"] === "json" ? `${JSON.stringify(document, null, 2)}
|
|
19690
|
-
` : (
|
|
19902
|
+
` : manifestYaml(document)
|
|
19691
19903
|
);
|
|
19692
19904
|
if (notes.length > 0) {
|
|
19693
19905
|
process.stderr.write("\nStill yours to fill in:\n");
|
|
@@ -19901,12 +20113,16 @@ Options
|
|
|
19901
20113
|
--output json, for a pipeline that reads the answer
|
|
19902
20114
|
|
|
19903
20115
|
Diagnosing
|
|
19904
|
-
vfac doctor checks the
|
|
19905
|
-
|
|
19906
|
-
|
|
19907
|
-
|
|
19908
|
-
|
|
19909
|
-
|
|
20116
|
+
vfac doctor checks the config it could read, the endpoint, which Project this
|
|
20117
|
+
terminal has selected and which one the command will act in, the
|
|
20118
|
+
machine API, whether this client is new enough for that platform,
|
|
20119
|
+
how this terminal is signed in and what that credential can reach
|
|
20120
|
+
\u2014 in that order, so the first thing that is actually wrong is the
|
|
20121
|
+
thing it reports. Pass --project to ask about the Project a
|
|
20122
|
+
command would name, which changes nothing on disk. It ends by
|
|
20123
|
+
asking npm whether a newer vfac has been published, which is a
|
|
20124
|
+
note and never a failure. Set VFAC_NO_UPDATE_CHECK to skip that
|
|
20125
|
+
one request
|
|
19910
20126
|
vfac whoami what this credential is, and which Project scopes it has been
|
|
19911
20127
|
GRANTED. A credential scoped to one Project deploys fine and
|
|
19912
20128
|
cannot make organization-wide reads \u2014 this is where that is said.
|