@varde-flyt/vfac 0.8.0 → 0.9.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.
Files changed (2) hide show
  1. package/dist/vfac.mjs +336 -259
  2. package/package.json +1 -1
package/dist/vfac.mjs CHANGED
@@ -11989,9 +11989,10 @@ var coerce = {
11989
11989
  var NEVER = INVALID;
11990
11990
 
11991
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;
11992
+ var MAX_CONFIGURATION_DEPTH = 6;
11993
+ var MAX_CONFIGURATION_LEAVES = 256;
11994
+ var MAX_CONFIGURATION_NODES = 512;
11995
+ var MAX_CONFIGURATION_CHILDREN = 64;
11995
11996
  var MAX_CONFIGURATION_VALUE_LEAVES = 1e3;
11996
11997
  var MAX_CONFIGURATION_ISSUES = 50;
11997
11998
  var MAX_CONFIGURATION_VALUE_BYTES = 16384;
@@ -12002,6 +12003,11 @@ function withJsonSchemaAnnex(schema, annex) {
12002
12003
  ANNEXES.set(schema, annex);
12003
12004
  return schema;
12004
12005
  }
12006
+ var DEFINITION_NAMES = /* @__PURE__ */ new WeakMap();
12007
+ function withJsonSchemaDefinition(schema, name) {
12008
+ DEFINITION_NAMES.set(schema, name);
12009
+ return schema;
12010
+ }
12005
12011
 
12006
12012
  // ../product-configuration/dist/infrastructure-vocabulary.js
12007
12013
  function tokenizeIdentifier(identifier) {
@@ -12219,7 +12225,20 @@ var ConfigurationGroupSchema = external_exports.enum([
12219
12225
  var CONFIGURATION_PROPERTY_NAME_REGEX = /^[a-z][a-zA-Z0-9]{1,47}$/;
12220
12226
  var PropertyNameSchema = external_exports.string().regex(CONFIGURATION_PROPERTY_NAME_REGEX, "Configuration property names must be camelCase, start with a lowercase letter, and be 2\u201348 characters.");
12221
12227
  var TitleSchema = external_exports.string().min(2).max(80).describe("Customer-facing field label.");
12222
- var HelpTextSchema = external_exports.string().min(10).max(400).describe("Customer-facing explanation. Required for security-sensitive choices.");
12228
+ var V1_LEAF_BOUNDS = {
12229
+ help: 400,
12230
+ enumValues: 40,
12231
+ stringLength: 4096,
12232
+ defaultLength: 400
12233
+ };
12234
+ var V2_LEAF_BOUNDS = {
12235
+ help: 2e3,
12236
+ enumValues: 256,
12237
+ stringLength: 16384,
12238
+ defaultLength: 2e3
12239
+ };
12240
+ var MAX_DECLARABLE_STRING_LENGTH = V2_LEAF_BOUNDS.stringLength;
12241
+ var helpTextSchema = (bounds) => external_exports.string().min(10).max(bounds.help).describe("Customer-facing explanation. Required for security-sensitive choices.");
12223
12242
  var SECRET_COUPLING_ANNEX = {
12224
12243
  allOf: [
12225
12244
  {
@@ -12238,63 +12257,74 @@ var SECRET_COUPLING_ANNEX = {
12238
12257
  }
12239
12258
  ]
12240
12259
  };
12241
- var StringPropertySchema = external_exports.object({
12242
- type: external_exports.literal("string"),
12243
- title: TitleSchema,
12244
- description: HelpTextSchema.optional(),
12245
- group: ConfigurationGroupSchema,
12246
- enum: external_exports.array(external_exports.string().min(1).max(80)).min(1).max(40).optional(),
12247
- minLength: external_exports.number().int().min(0).max(4096).optional(),
12248
- /**
12249
- * Required unless the value is constrained by `enum`. An unbounded string
12250
- * reaching the Control Plane as desired state is an unbounded write.
12251
- */
12252
- maxLength: external_exports.number().int().min(1).max(4096).optional(),
12253
- pattern: external_exports.string().min(1).max(200).optional(),
12254
- default: external_exports.string().max(400).optional(),
12255
- /**
12256
- * docs/PRODUCT_DEFINITION_GUIDE.md "Secrets": secret input is marked
12257
- * write-only AND secret. Both flags, and the refinement below makes one
12258
- * without the other a validation error.
12259
- */
12260
- writeOnly: external_exports.boolean().optional(),
12261
- "x-secret": external_exports.boolean().optional()
12262
- }).strict();
12263
- withJsonSchemaAnnex(StringPropertySchema, SECRET_COUPLING_ANNEX);
12264
- var NumberPropertySchema = external_exports.object({
12265
- type: external_exports.enum(["integer", "number"]),
12266
- title: TitleSchema,
12267
- description: HelpTextSchema.optional(),
12268
- group: ConfigurationGroupSchema,
12269
- /** Both bounds required — "numeric limits" in the guide is not optional. */
12270
- minimum: external_exports.number(),
12271
- maximum: external_exports.number(),
12272
- default: external_exports.number().optional()
12273
- }).strict();
12274
- var BooleanPropertySchema = external_exports.object({
12275
- type: external_exports.literal("boolean"),
12276
- title: TitleSchema,
12277
- description: HelpTextSchema.optional(),
12278
- group: ConfigurationGroupSchema,
12279
- default: external_exports.boolean().optional()
12280
- }).strict();
12281
- var ArrayItemsSchema = external_exports.object({
12282
- type: external_exports.literal("string"),
12283
- enum: external_exports.array(external_exports.string().min(1).max(80)).min(1).max(40).optional(),
12284
- maxLength: external_exports.number().int().min(1).max(400).optional()
12285
- }).strict();
12286
- var ArrayPropertySchema = external_exports.object({
12287
- type: external_exports.literal("array"),
12288
- title: TitleSchema,
12289
- description: HelpTextSchema.optional(),
12290
- group: ConfigurationGroupSchema,
12291
- items: ArrayItemsSchema,
12292
- minItems: external_exports.number().int().min(0).max(100).optional(),
12293
- /** Required: an unbounded list is an unbounded write. */
12294
- maxItems: external_exports.number().int().min(1).max(100),
12295
- uniqueItems: external_exports.boolean().optional(),
12296
- default: external_exports.array(external_exports.string().max(200)).max(100).optional()
12297
- }).strict();
12260
+ function leafShapes(bounds) {
12261
+ const help = helpTextSchema(bounds);
12262
+ const enumMembers = external_exports.array(external_exports.string().min(1).max(80)).min(1).max(bounds.enumValues).optional();
12263
+ const string = external_exports.object({
12264
+ type: external_exports.literal("string"),
12265
+ title: TitleSchema,
12266
+ description: help.optional(),
12267
+ group: ConfigurationGroupSchema,
12268
+ enum: enumMembers,
12269
+ minLength: external_exports.number().int().min(0).max(bounds.stringLength).optional(),
12270
+ /**
12271
+ * Required unless the value is constrained by `enum`. An unbounded string
12272
+ * reaching the Control Plane as desired state is an unbounded write.
12273
+ */
12274
+ maxLength: external_exports.number().int().min(1).max(bounds.stringLength).optional(),
12275
+ pattern: external_exports.string().min(1).max(200).optional(),
12276
+ default: external_exports.string().max(bounds.defaultLength).optional(),
12277
+ /**
12278
+ * docs/PRODUCT_DEFINITION_GUIDE.md "Secrets": secret input is marked
12279
+ * write-only AND secret. Both flags, and the refinement below makes one
12280
+ * without the other a validation error.
12281
+ */
12282
+ writeOnly: external_exports.boolean().optional(),
12283
+ "x-secret": external_exports.boolean().optional()
12284
+ }).strict();
12285
+ withJsonSchemaAnnex(string, SECRET_COUPLING_ANNEX);
12286
+ const number = external_exports.object({
12287
+ type: external_exports.enum(["integer", "number"]),
12288
+ title: TitleSchema,
12289
+ description: help.optional(),
12290
+ group: ConfigurationGroupSchema,
12291
+ /** Both bounds required — "numeric limits" in the guide is not optional. */
12292
+ minimum: external_exports.number(),
12293
+ maximum: external_exports.number(),
12294
+ default: external_exports.number().optional()
12295
+ }).strict();
12296
+ const boolean = external_exports.object({
12297
+ type: external_exports.literal("boolean"),
12298
+ title: TitleSchema,
12299
+ description: help.optional(),
12300
+ group: ConfigurationGroupSchema,
12301
+ default: external_exports.boolean().optional()
12302
+ }).strict();
12303
+ const items = external_exports.object({
12304
+ type: external_exports.literal("string"),
12305
+ enum: enumMembers,
12306
+ maxLength: external_exports.number().int().min(1).max(bounds.defaultLength).optional()
12307
+ }).strict();
12308
+ const array = external_exports.object({
12309
+ type: external_exports.literal("array"),
12310
+ title: TitleSchema,
12311
+ description: help.optional(),
12312
+ group: ConfigurationGroupSchema,
12313
+ items,
12314
+ minItems: external_exports.number().int().min(0).max(100).optional(),
12315
+ /** Required: an unbounded list is an unbounded write. */
12316
+ maxItems: external_exports.number().int().min(1).max(100),
12317
+ uniqueItems: external_exports.boolean().optional(),
12318
+ default: external_exports.array(external_exports.string().max(200)).max(100).optional()
12319
+ }).strict();
12320
+ return { string, number, boolean, items, array };
12321
+ }
12322
+ var V1_LEAVES = leafShapes(V1_LEAF_BOUNDS);
12323
+ var V2_LEAVES = leafShapes(V2_LEAF_BOUNDS);
12324
+ var StringPropertySchema = V1_LEAVES.string;
12325
+ var NumberPropertySchema = V1_LEAVES.number;
12326
+ var BooleanPropertySchema = V1_LEAVES.boolean;
12327
+ var ArrayPropertySchema = V1_LEAVES.array;
12298
12328
  var MAX_CONFIGURATION_PROPERTIES = 40;
12299
12329
  var ConfigurationPropertySchema = external_exports.discriminatedUnion("type", [
12300
12330
  StringPropertySchema,
@@ -12302,42 +12332,81 @@ var ConfigurationPropertySchema = external_exports.discriminatedUnion("type", [
12302
12332
  BooleanPropertySchema,
12303
12333
  ArrayPropertySchema
12304
12334
  ]);
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)
12335
+ var NestedStringPropertySchema = V2_LEAVES.string.omit({ "x-secret": true, writeOnly: true }).extend({ group: ConfigurationGroupSchema.optional() });
12336
+ var V2_NESTED_LEAVES = {
12337
+ string: NestedStringPropertySchema,
12338
+ number: V2_LEAVES.number.extend({ group: ConfigurationGroupSchema.optional() }),
12339
+ boolean: V2_LEAVES.boolean.extend({ group: ConfigurationGroupSchema.optional() }),
12340
+ array: V2_LEAVES.array.extend({ group: ConfigurationGroupSchema.optional() }),
12341
+ items: V2_LEAVES.items
12319
12342
  };
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
- ]);
12343
+ function childBagShape(child) {
12344
+ return {
12345
+ properties: external_exports.record(PropertyNameSchema, child),
12346
+ required: external_exports.array(PropertyNameSchema).max(MAX_CONFIGURATION_CHILDREN).optional(),
12347
+ /**
12348
+ * All-or-none rules, scoped to THIS container.
12349
+ *
12350
+ * ON THE CONTAINER, NEVER AS ROOT CLAUSES NAMING PATHS. The published key
12351
+ * promises that "a publisher running an off-the-shelf validator over that
12352
+ * file must get the answer the platform gives", and JSON Schema 2020-12
12353
+ * scopes `dependentRequired` to the object that CARRIES it. A root clause
12354
+ * naming `/upstream/token` would be a rule no standard validator applies —
12355
+ * the one thing this key may not become. Written here it keeps exactly the
12356
+ * meaning it has everywhere else, and the generated artifact carries it on
12357
+ * the right node.
12358
+ *
12359
+ * A REPEATABLE GROUP GETS ONE PER ROW, which is the honest reading: "if this
12360
+ * server has a URL it needs a token" is a fact about a server, not about the
12361
+ * list.
12362
+ */
12363
+ dependentRequired: external_exports.record(PropertyNameSchema, external_exports.array(PropertyNameSchema).min(1).max(MAX_CONFIGURATION_CHILDREN)).optional().describe("Settings inside this group that must be supplied together."),
12364
+ additionalProperties: external_exports.literal(false)
12365
+ };
12366
+ }
12367
+ function propertyUnion(levelsBelow, leafSet) {
12368
+ const leaves = [leafSet.string, leafSet.number, leafSet.boolean];
12369
+ if (levelsBelow <= 0) {
12370
+ return [...leaves, leafSet.array];
12371
+ }
12372
+ const level = MAX_CONFIGURATION_DEPTH - levelsBelow + 1;
12373
+ const child = withJsonSchemaDefinition(external_exports.discriminatedUnion("type", propertyUnion(levelsBelow - 1, V2_NESTED_LEAVES)), `configurationPropertyLevel${level}`);
12374
+ const bag = childBagShape(child);
12375
+ const groupItems = external_exports.object({ type: external_exports.literal("object"), ...bag }).strict();
12376
+ return [
12377
+ ...leaves,
12378
+ // ONE `array` BRANCH, NOT TWO, because a discriminated union may not carry
12379
+ // two options with the same discriminator value ("duplicate value array" —
12380
+ // zod refuses it at construction). The item shape is the inner
12381
+ // discriminator, which is also what keeps a v1 document's
12382
+ // `items: {type: 'string'}` reading exactly as it always did.
12383
+ leafSet.array.extend({
12384
+ items: external_exports.discriminatedUnion("type", [V2_LEAVES.items, groupItems])
12385
+ }),
12386
+ /**
12387
+ * A group of related settings.
12388
+ *
12389
+ * NO `default`. A container cannot carry one, structurally — `.strict()`
12390
+ * refuses the key — and that removes a whole class of question rather than
12391
+ * answering it: what a whole-subtree default means when the customer
12392
+ * supplied half of it, how it interacts with `dependentRequired`'s
12393
+ * load-bearing "a defaulted setting is never absent", and what
12394
+ * `seedConfiguration` should write into a served example and a file on
12395
+ * disk. Defaults are a LEAF concept here.
12396
+ */
12397
+ external_exports.object({
12398
+ type: external_exports.literal("object"),
12399
+ title: TitleSchema,
12400
+ description: helpTextSchema(V2_LEAF_BOUNDS).optional(),
12401
+ // INHERITED BELOW THE ROOT, for the reason `V2_NESTED_LEAVES` states: a
12402
+ // group is a bucket for a whole subtree, and repeating it is the only
12403
+ // value that could be written.
12404
+ group: levelsBelow === MAX_CONFIGURATION_DEPTH - 1 ? ConfigurationGroupSchema : ConfigurationGroupSchema.optional(),
12405
+ ...bag
12406
+ }).strict()
12407
+ ];
12408
+ }
12409
+ var RootConfigurationPropertySchema = external_exports.discriminatedUnion("type", propertyUnion(MAX_CONFIGURATION_DEPTH - 1, V2_LEAVES));
12341
12410
  var CustomerConfigurationObjectSchema = external_exports.object({
12342
12411
  type: external_exports.literal("object"),
12343
12412
  properties: external_exports.record(PropertyNameSchema, ConfigurationPropertySchema).describe("Customer-editable settings, keyed by camelCase property name."),
@@ -12568,19 +12637,19 @@ function checkDeclaredProperty(name, property, path, ctx, atRoot) {
12568
12637
  }
12569
12638
  }
12570
12639
  }
12571
- function checkDependentRequired(config, ctx) {
12640
+ function checkDependentRequired(config, ctx, at = []) {
12572
12641
  const clauses = Object.entries(config.dependentRequired ?? {});
12573
12642
  if (clauses.length === 0)
12574
12643
  return;
12575
12644
  if (clauses.length > MAX_CONFIGURATION_PROPERTIES) {
12576
12645
  ctx.addIssue({
12577
12646
  code: external_exports.ZodIssueCode.custom,
12578
- path: ["dependentRequired"],
12647
+ path: [...at, "dependentRequired"],
12579
12648
  message: `A Product may declare at most ${MAX_CONFIGURATION_PROPERTIES} dependent-required groups; found ${clauses.length}.`
12580
12649
  });
12581
12650
  }
12582
12651
  for (const [trigger, dependents] of clauses) {
12583
- const path = ["dependentRequired", trigger];
12652
+ const path = [...at, "dependentRequired", trigger];
12584
12653
  const declaredTrigger = config.properties[trigger];
12585
12654
  if (declaredTrigger === void 0) {
12586
12655
  ctx.addIssue({
@@ -12692,7 +12761,7 @@ function checkOneSecretPerGroup(config, ctx) {
12692
12761
  var CustomerConfigurationV2ObjectSchema = external_exports.object({
12693
12762
  type: external_exports.literal("object"),
12694
12763
  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(),
12764
+ required: external_exports.array(PropertyNameSchema).max(MAX_CONFIGURATION_CHILDREN).optional(),
12696
12765
  /**
12697
12766
  * ROOT PROPERTIES ONLY, in v2.0.
12698
12767
  *
@@ -12704,23 +12773,25 @@ var CustomerConfigurationV2ObjectSchema = external_exports.object({
12704
12773
  * nested object may not carry its own clause either — that is expressible
12705
12774
  * and honest, and it is deliberately left for when something needs it.
12706
12775
  */
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."),
12776
+ dependentRequired: external_exports.record(PropertyNameSchema, external_exports.array(PropertyNameSchema).min(1).max(MAX_CONFIGURATION_CHILDREN)).optional().describe("Settings that must be supplied together, keyed by the triggering property."),
12708
12777
  additionalProperties: external_exports.literal(false)
12709
12778
  }).strict();
12710
12779
  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 };
12714
- }
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
- };
12722
- }
12723
- return { leaves: 1, nodes: 1, instantiated: 1 };
12780
+ const children = childrenOf(property);
12781
+ if (children === null)
12782
+ return { leaves: 1, nodes: 1, instantiated: 1 };
12783
+ let leaves = 0;
12784
+ let nodes = 1;
12785
+ let instantiated = 0;
12786
+ for (const child of Object.values(children.properties)) {
12787
+ const inner = countNodes(child);
12788
+ leaves += inner.leaves;
12789
+ nodes += inner.nodes;
12790
+ instantiated += inner.instantiated;
12791
+ }
12792
+ if (property.type === "array")
12793
+ instantiated *= property.maxItems;
12794
+ return { leaves, nodes, instantiated };
12724
12795
  }
12725
12796
  function childrenOf(property) {
12726
12797
  if (property.type === "object")
@@ -12730,34 +12801,26 @@ function childrenOf(property) {
12730
12801
  return null;
12731
12802
  }
12732
12803
  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;
12804
+ return minimumGroupBytes(config.properties, config.required ?? []);
12749
12805
  }
12750
12806
  function minimumGroupBytes(properties, required) {
12751
12807
  const names = new Set(required);
12752
12808
  let total = 2;
12753
12809
  for (const [name, property] of Object.entries(properties)) {
12754
- if (!names.has(name) && declaredLeafDefault(property) === void 0)
12810
+ const isContainer = childrenOf(property) !== null;
12811
+ if (isContainer ? !names.has(name) : !names.has(name) && declaredLeafDefault(property) === void 0) {
12755
12812
  continue;
12756
- total += name.length + 3 + minimumLeafBytes(property);
12813
+ }
12814
+ total += name.length + 3 + minimumPropertyBytes(property);
12757
12815
  }
12758
12816
  return total;
12759
12817
  }
12760
- function minimumLeafBytes(property) {
12818
+ function minimumPropertyBytes(property) {
12819
+ const children = childrenOf(property);
12820
+ if (children !== null) {
12821
+ const inner = minimumGroupBytes(children.properties, children.required ?? []);
12822
+ return property.type === "array" ? 2 + (property.minItems ?? 0) * inner : inner;
12823
+ }
12761
12824
  switch (property.type) {
12762
12825
  case "string": {
12763
12826
  const shortestEnum = property.enum?.reduce((a, b) => a.length <= b.length ? a : b);
@@ -12778,13 +12841,85 @@ function minimumLeafBytes(property) {
12778
12841
  function declaredLeafDefault(property) {
12779
12842
  return property.type === "object" ? void 0 : property.default;
12780
12843
  }
12844
+ function checkPropertyDeclaration(name, property, path, ctx, atRoot) {
12845
+ const children = childrenOf(property);
12846
+ if (children === null) {
12847
+ checkDeclaredProperty(name, property, path, ctx, atRoot);
12848
+ return;
12849
+ }
12850
+ const infrastructure = infrastructureVocabularyViolation(name);
12851
+ if (infrastructure) {
12852
+ ctx.addIssue({
12853
+ code: external_exports.ZodIssueCode.custom,
12854
+ path,
12855
+ message: `${infrastructure}. Customer settings describe outcomes, not infrastructure.`
12856
+ });
12857
+ }
12858
+ if (atRoot) {
12859
+ const platformOwned = platformOwnedFieldViolation(name);
12860
+ if (platformOwned) {
12861
+ ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path, message: `${platformOwned}.` });
12862
+ }
12863
+ }
12864
+ const childNames = Object.keys(children.properties);
12865
+ if (childNames.length === 0) {
12866
+ ctx.addIssue({
12867
+ code: external_exports.ZodIssueCode.custom,
12868
+ path: [...path, "properties"],
12869
+ message: `"${name}" declares no settings. A group with nothing in it renders as an empty section.`
12870
+ });
12871
+ }
12872
+ if (childNames.length > MAX_CONFIGURATION_CHILDREN) {
12873
+ ctx.addIssue({
12874
+ code: external_exports.ZodIssueCode.custom,
12875
+ path: [...path, "properties"],
12876
+ message: `"${name}" may declare at most ${MAX_CONFIGURATION_CHILDREN} settings; found ${childNames.length}.`
12877
+ });
12878
+ }
12879
+ if (property.type === "array" && property.default !== void 0) {
12880
+ ctx.addIssue({
12881
+ code: external_exports.ZodIssueCode.custom,
12882
+ path: [...path, "default"],
12883
+ message: `"${name}" is a list of groups and cannot declare a default. Declare defaults on the settings inside it.`
12884
+ });
12885
+ }
12886
+ if (property.type === "array" && property.minItems !== void 0 && property.minItems > property.maxItems) {
12887
+ ctx.addIssue({
12888
+ code: external_exports.ZodIssueCode.custom,
12889
+ path,
12890
+ message: `"${name}" has minItems greater than maxItems.`
12891
+ });
12892
+ }
12893
+ for (const childName of childNames) {
12894
+ checkPropertyDeclaration(childName, children.properties[childName], [...path, "properties", childName], ctx, false);
12895
+ }
12896
+ for (const required of children.required ?? []) {
12897
+ if (!Object.hasOwn(children.properties, required)) {
12898
+ ctx.addIssue({
12899
+ code: external_exports.ZodIssueCode.custom,
12900
+ path: [...path, "required"],
12901
+ message: `"${required}" is listed as required in "${name}" but is not one of its settings.`
12902
+ });
12903
+ }
12904
+ }
12905
+ const scoped = children;
12906
+ if (scoped.dependentRequired !== void 0) {
12907
+ checkDependentRequired(
12908
+ { properties: children.properties, dependentRequired: scoped.dependentRequired },
12909
+ ctx,
12910
+ // An ARRAY's children live under `items`, which is where the key it
12911
+ // constrains actually sits in the document.
12912
+ property.type === "array" ? [...path, "items"] : path
12913
+ );
12914
+ }
12915
+ }
12781
12916
  var CustomerConfigurationV2Schema = CustomerConfigurationV2ObjectSchema.superRefine((config, ctx) => {
12782
12917
  const names = Object.keys(config.properties);
12783
- if (names.length > MAX_CONFIGURATION_PROPERTIES) {
12918
+ if (names.length > MAX_CONFIGURATION_CHILDREN) {
12784
12919
  ctx.addIssue({
12785
12920
  code: external_exports.ZodIssueCode.custom,
12786
12921
  path: ["properties"],
12787
- message: `A Product may declare at most ${MAX_CONFIGURATION_PROPERTIES} customer settings; found ${names.length}.`
12922
+ message: `A Product may declare at most ${MAX_CONFIGURATION_CHILDREN} root settings; found ${names.length}. Group them, or declare fewer.`
12788
12923
  });
12789
12924
  }
12790
12925
  let leaves = 0;
@@ -12797,64 +12932,7 @@ var CustomerConfigurationV2Schema = CustomerConfigurationV2ObjectSchema.superRef
12797
12932
  leaves += counted.leaves;
12798
12933
  nodes += counted.nodes;
12799
12934
  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
- }
12935
+ checkPropertyDeclaration(name, property, path, ctx, true);
12858
12936
  }
12859
12937
  if (leaves > MAX_CONFIGURATION_LEAVES) {
12860
12938
  ctx.addIssue({
@@ -12874,7 +12952,7 @@ var CustomerConfigurationV2Schema = CustomerConfigurationV2ObjectSchema.superRef
12874
12952
  ctx.addIssue({
12875
12953
  code: external_exports.ZodIssueCode.custom,
12876
12954
  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.`
12955
+ message: `This Product's settings could expand to ${instantiated} values. A list instantiates everything inside it once per item, so lists inside lists MULTIPLY. At most ${MAX_CONFIGURATION_VALUE_LEAVES} are allowed; reduce maxItems on the lists, or the number of settings inside them.`
12878
12956
  });
12879
12957
  }
12880
12958
  for (const name of config.required ?? []) {
@@ -12926,7 +13004,7 @@ function isSecretProperty(property) {
12926
13004
  }
12927
13005
 
12928
13006
  // ../product-configuration/dist/configuration-path.js
12929
- var MAX_CONFIGURATION_PATH_SEGMENTS = MAX_CONFIGURATION_DEPTH + 1;
13007
+ var MAX_CONFIGURATION_PATH_SEGMENTS = 2 * MAX_CONFIGURATION_DEPTH - 1;
12930
13008
  function isIndexSegment(raw) {
12931
13009
  return /^\d+$/.test(raw) && String(Number(raw)) === raw;
12932
13010
  }
@@ -13003,6 +13081,9 @@ function canonicalJson(value) {
13003
13081
  }
13004
13082
 
13005
13083
  // ../product-configuration/dist/configuration-tree.js
13084
+ function underList(node) {
13085
+ return node.containers.some((container) => container.kind === "array");
13086
+ }
13006
13087
  function containerChildren(property) {
13007
13088
  if (property.type === "object" && property.properties !== void 0) {
13008
13089
  return {
@@ -13028,52 +13109,38 @@ function isConfigurationContainer(property) {
13028
13109
  }
13029
13110
  function configurationLeaves(schema) {
13030
13111
  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
- }
13112
+ walkDeclarations(schema.properties, [], [], (leaf) => out.push(leaf));
13057
13113
  return out;
13058
13114
  }
13059
13115
  function configurationContainers(schema) {
13060
13116
  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);
13117
+ walkDeclarations(schema.properties, [], [], () => {
13118
+ }, (container) => out.push(container));
13119
+ return out;
13120
+ }
13121
+ function walkDeclarations(properties, ancestors, base, onLeaf, onContainer = () => {
13122
+ }) {
13123
+ for (const [name, property] of Object.entries(properties)) {
13124
+ const segments = [...base, name];
13125
+ const path = configurationPath(...segments);
13066
13126
  if (path === null)
13067
13127
  continue;
13068
- out.push({
13128
+ const children = containerChildren(property);
13129
+ if (children === null) {
13130
+ onLeaf({ path, name, property, containers: ancestors });
13131
+ continue;
13132
+ }
13133
+ const container = {
13069
13134
  path,
13070
13135
  name,
13071
13136
  kind: children.kind,
13072
13137
  property,
13073
- required: children.required
13074
- });
13138
+ required: children.required,
13139
+ containers: ancestors
13140
+ };
13141
+ onContainer(container);
13142
+ walkDeclarations(children.properties, [...ancestors, container], segments, onLeaf, onContainer);
13075
13143
  }
13076
- return out;
13077
13144
  }
13078
13145
  function leafAt(schema, path) {
13079
13146
  const declaration = declarationPathOf(path);
@@ -13086,7 +13153,7 @@ function declaresPath(schema, path) {
13086
13153
  }
13087
13154
 
13088
13155
  // ../product-configuration/dist/customer-configuration-input.js
13089
- var ABSOLUTE_MAX_STRING = 8192;
13156
+ var ABSOLUTE_MAX_STRING = MAX_DECLARABLE_STRING_LENGTH;
13090
13157
  var MAX_REPORTED_UNDECLARED_KEYS = 10;
13091
13158
  function isPlainObject(value) {
13092
13159
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -13228,6 +13295,18 @@ function validateObject(declaration, input, container, walk, root) {
13228
13295
  }
13229
13296
  out[name] = checked;
13230
13297
  }
13298
+ if (declaration.dependentRequired !== void 0) {
13299
+ const suppliedHere = new Set(Object.keys(out));
13300
+ for (const [trigger, dependents] of Object.entries(declaration.dependentRequired)) {
13301
+ if (!suppliedHere.has(trigger) && !containsReferenced(walk, fieldFor(trigger)))
13302
+ continue;
13303
+ for (const dependent of dependents) {
13304
+ if (suppliedHere.has(dependent) || containsReferenced(walk, fieldFor(dependent)))
13305
+ continue;
13306
+ report(walk, fieldFor(dependent), `This setting is required when ${labelOf(declaration, trigger)} is configured.`);
13307
+ }
13308
+ }
13309
+ }
13231
13310
  return out;
13232
13311
  }
13233
13312
  function containerDeclaration(property) {
@@ -13236,6 +13315,9 @@ function containerDeclaration(property) {
13236
13315
  kind: "object",
13237
13316
  properties: property.properties,
13238
13317
  required: property.required,
13318
+ // CARRIED THROUGH, or the rule the container declares is one the walk
13319
+ // never sees — it publishes cleanly and enforces nothing.
13320
+ dependentRequired: property.dependentRequired,
13239
13321
  maxItems: 1
13240
13322
  };
13241
13323
  }
@@ -13247,6 +13329,7 @@ function containerDeclaration(property) {
13247
13329
  kind: "array",
13248
13330
  properties: items.properties,
13249
13331
  required: items.required,
13332
+ dependentRequired: items.dependentRequired,
13250
13333
  maxItems: property.maxItems ?? 0,
13251
13334
  minItems: property.minItems,
13252
13335
  uniqueItems: property.uniqueItems === true
@@ -13331,7 +13414,7 @@ function crossFieldIssues(schema, supplied, presence) {
13331
13414
  }
13332
13415
  function labelOf(schema, name) {
13333
13416
  const property = schema.properties[name];
13334
- return property === void 0 ? `"${name}"` : `"${property.title}"`;
13417
+ return property?.title === void 0 ? `"${name}"` : `"${property.title}"`;
13335
13418
  }
13336
13419
  function withoutCrossFieldRules(schema) {
13337
13420
  if (schema.dependentRequired === void 0)
@@ -13489,7 +13572,6 @@ function isSecret(declaration) {
13489
13572
  function seedConfiguration(configuration) {
13490
13573
  const properties = configuration?.properties ?? {};
13491
13574
  const required = new Set(configuration?.required ?? []);
13492
- const values = {};
13493
13575
  const open = [];
13494
13576
  const requiredSecrets = [];
13495
13577
  const groups = Object.entries(configuration?.dependentRequired ?? {}).map(([trigger, dependents]) => {
@@ -13500,8 +13582,13 @@ function seedConfiguration(configuration) {
13500
13582
  secrets: members.filter((name) => isSecret(properties[name] ?? {}))
13501
13583
  };
13502
13584
  }).sort((a, b) => a.trigger.localeCompare(b.trigger));
13585
+ const values = seedProperties(properties, required, [], open, requiredSecrets);
13586
+ return { values, open, requiredSecrets, groups };
13587
+ }
13588
+ function seedProperties(properties, required, ancestors, open, requiredSecrets) {
13589
+ const values = {};
13503
13590
  for (const [name, declaration] of Object.entries(properties)) {
13504
- if (isSecret(declaration)) {
13591
+ if (requiredSecrets !== null && isSecret(declaration)) {
13505
13592
  if (required.has(name))
13506
13593
  requiredSecrets.push(name);
13507
13594
  continue;
@@ -13510,12 +13597,14 @@ function seedConfiguration(configuration) {
13510
13597
  if (children !== null) {
13511
13598
  if (!required.has(name))
13512
13599
  continue;
13600
+ const childRequired = new Set(children.required);
13601
+ const inner = [...ancestors, name];
13513
13602
  if (children.kind === "object") {
13514
- values[name] = seedGroup(children, name, open);
13603
+ values[name] = seedProperties(children.properties, childRequired, inner, open, null);
13515
13604
  continue;
13516
13605
  }
13517
13606
  const count = children.minItems ?? 0;
13518
- values[name] = Array.from({ length: count }, () => seedGroup(children, name, open));
13607
+ values[name] = Array.from({ length: count }, () => seedProperties(children.properties, childRequired, inner, open, null));
13519
13608
  if (count > 1)
13520
13609
  dedupeOpen(open);
13521
13610
  continue;
@@ -13526,10 +13615,15 @@ function seedConfiguration(configuration) {
13526
13615
  }
13527
13616
  if (required.has(name)) {
13528
13617
  values[name] = "";
13529
- open.push({ name, label: name, type: declaration.type ?? null });
13618
+ const path = configurationPath(...ancestors, name);
13619
+ open.push({
13620
+ name: path ?? name,
13621
+ label: path === null ? name : printableConfigurationPath(path),
13622
+ type: declaration.type ?? null
13623
+ });
13530
13624
  }
13531
13625
  }
13532
- return { values, open, requiredSecrets, groups };
13626
+ return values;
13533
13627
  }
13534
13628
  function containerChildren2(declaration) {
13535
13629
  const node = declaration;
@@ -13564,26 +13658,6 @@ function dedupeOpen(open) {
13564
13658
  open.length = 0;
13565
13659
  open.push(...unique);
13566
13660
  }
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
- }
13587
13661
  function productInstanceExample(input) {
13588
13662
  return {
13589
13663
  apiVersion: RESOURCE_API_VERSION,
@@ -14506,7 +14580,7 @@ function checkProductDefinition(definition, ctx) {
14506
14580
  });
14507
14581
  return;
14508
14582
  }
14509
- if (leaf.container?.kind === "array") {
14583
+ if (underList(leaf)) {
14510
14584
  ctx.addIssue({
14511
14585
  code: external_exports.ZodIssueCode.custom,
14512
14586
  path: [...at, member],
@@ -16535,6 +16609,9 @@ function isTerminalAction(action) {
16535
16609
  }
16536
16610
  var ManifestActionSchema = external_exports.enum(MANIFEST_ACTIONS);
16537
16611
 
16612
+ // ../product-contracts/dist/contract-issue.js
16613
+ var MAX_SEGMENTS = MAX_CONFIGURATION_PATH_SEGMENTS + 2;
16614
+
16538
16615
  // ../product-contracts/dist/resource-output-reference.js
16539
16616
  var OUTPUT_KEY_RULE = "Output keys are camelCase.";
16540
16617
  var ResourceOutputReferenceSchema = external_exports.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@varde-flyt/vfac",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Deploy and manage Varde Flyt Products from a manifest.",
5
5
  "repository": {
6
6
  "type": "git",