@timeax/digital-service-engine 0.2.0 → 0.2.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.
@@ -4706,6 +4706,9 @@ function toFiniteNumber(v) {
4706
4706
  const n = Number(v);
4707
4707
  return Number.isFinite(n) ? n : NaN;
4708
4708
  }
4709
+ function isValidServiceIdRef(value) {
4710
+ return typeof value === "number" && Number.isFinite(value) || typeof value === "string" && value.trim().length > 0;
4711
+ }
4709
4712
  function constraintFitOk(svcMap, candidate, constraints) {
4710
4713
  const cap = getServiceCapability(svcMap, candidate);
4711
4714
  if (!cap) return false;
@@ -4714,18 +4717,27 @@ function constraintFitOk(svcMap, candidate, constraints) {
4714
4717
  return !(constraints.cancel === true && !cap.cancel);
4715
4718
  }
4716
4719
  function getServiceCapability(svcMap, candidate) {
4717
- if (candidate === void 0 || candidate === null) return void 0;
4718
- const direct = svcMap[candidate];
4719
- if (direct) return direct;
4720
- const byString = svcMap[String(candidate)];
4721
- if (byString) return byString;
4722
- if (typeof candidate === "string") {
4723
- const maybeNumber = Number(candidate);
4724
- if (Number.isFinite(maybeNumber)) {
4725
- return svcMap[maybeNumber];
4726
- }
4720
+ var _a;
4721
+ return (_a = getServiceCapabilityEntry(svcMap, candidate)) == null ? void 0 : _a.capability;
4722
+ }
4723
+ function getServiceCapabilityAliases(svcMap, candidate) {
4724
+ const entry = getServiceCapabilityEntry(svcMap, candidate);
4725
+ if (!entry) return [];
4726
+ return collectServiceRefAliases(entry.key, entry.capability);
4727
+ }
4728
+ function isSameServiceCapabilityRef(svcMap, left, right) {
4729
+ if (!isValidServiceIdRef(left) || !isValidServiceIdRef(right)) return false;
4730
+ const leftAliases = new Set(
4731
+ getServiceCapabilityAliases(svcMap, left).map((value) => String(value))
4732
+ );
4733
+ if (!leftAliases.size) {
4734
+ leftAliases.add(String(left));
4727
4735
  }
4728
- return void 0;
4736
+ const rightAliases = getServiceCapabilityAliases(svcMap, right);
4737
+ if (!rightAliases.length) {
4738
+ return leftAliases.has(String(right));
4739
+ }
4740
+ return rightAliases.some((value) => leftAliases.has(String(value)));
4729
4741
  }
4730
4742
  function normalizeRatePolicy(policy) {
4731
4743
  var _a;
@@ -4761,18 +4773,84 @@ function rateOk(svcMap, candidate, primary, policy) {
4761
4773
  if (!Number.isFinite(cRate) || !Number.isFinite(pRate)) return false;
4762
4774
  return passesRatePolicy(policy.ratePolicy, pRate, cRate);
4763
4775
  }
4776
+ function getServiceCapabilityEntry(svcMap, candidate) {
4777
+ if (candidate === void 0 || candidate === null) return void 0;
4778
+ const direct = svcMap[candidate];
4779
+ if (direct) {
4780
+ return { key: String(candidate), capability: direct };
4781
+ }
4782
+ const byString = svcMap[String(candidate)];
4783
+ if (byString) {
4784
+ return { key: String(candidate), capability: byString };
4785
+ }
4786
+ if (typeof candidate === "string") {
4787
+ const maybeNumber = Number(candidate);
4788
+ if (Number.isFinite(maybeNumber)) {
4789
+ const byNumber = svcMap[maybeNumber];
4790
+ if (byNumber) {
4791
+ return { key: String(maybeNumber), capability: byNumber };
4792
+ }
4793
+ }
4794
+ }
4795
+ const target = String(candidate);
4796
+ for (const [key, capability] of Object.entries(svcMap != null ? svcMap : {})) {
4797
+ if (collectServiceRefAliases(key, capability).some(
4798
+ (alias) => String(alias) === target
4799
+ )) {
4800
+ return { key, capability };
4801
+ }
4802
+ }
4803
+ return void 0;
4804
+ }
4805
+ function collectServiceRefAliases(key, capability) {
4806
+ const out = [];
4807
+ const seen = /* @__PURE__ */ new Set();
4808
+ const push = (value) => {
4809
+ if (!isValidServiceIdRef(value)) return;
4810
+ const normalized = normalizeServiceRef(value);
4811
+ if (!normalized) return;
4812
+ const aliasKey = String(normalized);
4813
+ if (seen.has(aliasKey)) return;
4814
+ seen.add(aliasKey);
4815
+ out.push(normalized);
4816
+ };
4817
+ push(getCanonicalServiceRef(key, capability));
4818
+ push(capability.service);
4819
+ push(capability.key);
4820
+ push(capability.id);
4821
+ return out;
4822
+ }
4823
+ function getCanonicalServiceRef(key, capability) {
4824
+ const explicitRefs = [capability.service, capability.key, capability.id];
4825
+ for (const ref of explicitRefs) {
4826
+ if (!isValidServiceIdRef(ref)) continue;
4827
+ if (String(ref) === key) {
4828
+ return ref;
4829
+ }
4830
+ }
4831
+ return normalizeServiceRef(key);
4832
+ }
4833
+ function normalizeServiceRef(value) {
4834
+ if (!isValidServiceIdRef(value)) return void 0;
4835
+ if (typeof value === "number") return value;
4836
+ const trimmed = value.trim();
4837
+ if (!trimmed) return void 0;
4838
+ const asNumber = Number(trimmed);
4839
+ if (Number.isFinite(asNumber) && String(asNumber) === trimmed) {
4840
+ return asNumber;
4841
+ }
4842
+ return trimmed;
4843
+ }
4764
4844
 
4765
4845
  // src/core/validate/steps/rates.ts
4766
4846
  function validateRates(v) {
4767
- var _a, _b, _c, _d;
4768
- const ratePolicy = normalizeRatePolicy(
4769
- (_a = v.options.fallbackSettings) == null ? void 0 : _a.ratePolicy
4770
- );
4847
+ var _a, _b, _c;
4848
+ const ratePolicy = normalizeRatePolicy(v.options.ratePolicy);
4771
4849
  for (const f of v.fields) {
4772
4850
  if (!isMultiField(f)) continue;
4773
4851
  const baseRates = [];
4774
- for (const o of (_b = f.options) != null ? _b : []) {
4775
- const role = (_d = (_c = o.pricing_role) != null ? _c : f.pricing_role) != null ? _d : "base";
4852
+ for (const o of (_a = f.options) != null ? _a : []) {
4853
+ const role = (_c = (_b = o.pricing_role) != null ? _b : f.pricing_role) != null ? _c : "base";
4776
4854
  if (role !== "base") continue;
4777
4855
  const sid = o.service_id;
4778
4856
  if (!isServiceIdRef(sid)) continue;
@@ -5546,6 +5624,38 @@ function applyPolicies(errors, props, serviceMap, policies, fieldsVisibleUnder,
5546
5624
  }
5547
5625
  }
5548
5626
 
5627
+ // src/core/governance.ts
5628
+ var DEFAULT_FALLBACK_SETTINGS = {
5629
+ requireConstraintFit: true,
5630
+ ratePolicy: { kind: "lte_primary", pct: 5 },
5631
+ selectionStrategy: "priority",
5632
+ mode: "strict"
5633
+ };
5634
+ function resolveGlobalRatePolicy(options) {
5635
+ return normalizeRatePolicy(options.ratePolicy);
5636
+ }
5637
+ function resolveFallbackSettings(options) {
5638
+ var _a;
5639
+ return {
5640
+ ...DEFAULT_FALLBACK_SETTINGS,
5641
+ ...(_a = options.fallbackSettings) != null ? _a : {}
5642
+ };
5643
+ }
5644
+ function mergeValidatorOptions(defaults = {}, overrides = {}) {
5645
+ var _a, _b, _c, _d;
5646
+ const mergedFallbackSettings = {
5647
+ ...(_a = defaults.fallbackSettings) != null ? _a : {},
5648
+ ...(_b = overrides.fallbackSettings) != null ? _b : {}
5649
+ };
5650
+ return {
5651
+ ...defaults,
5652
+ ...overrides,
5653
+ policies: (_c = overrides.policies) != null ? _c : defaults.policies,
5654
+ ratePolicy: (_d = overrides.ratePolicy) != null ? _d : defaults.ratePolicy,
5655
+ fallbackSettings: Object.keys(mergedFallbackSettings).length > 0 ? mergedFallbackSettings : void 0
5656
+ };
5657
+ }
5658
+
5549
5659
  // src/core/builder.ts
5550
5660
  var import_lodash_es2 = require("lodash-es");
5551
5661
  function createBuilder(opts = {}) {
@@ -5788,7 +5898,7 @@ var BuilderImpl = class {
5788
5898
  return out;
5789
5899
  }
5790
5900
  errors() {
5791
- return validate(this.props, this.options);
5901
+ return validate(this.props, mergeValidatorOptions({}, this.options));
5792
5902
  }
5793
5903
  getOptions() {
5794
5904
  return (0, import_lodash_es2.cloneDeep)(this.options);
@@ -6075,11 +6185,14 @@ function readVisibilitySimOpts(ctx) {
6075
6185
  };
6076
6186
  }
6077
6187
  function validate(props, ctx = {}) {
6078
- var _a, _b, _c, _d;
6188
+ var _a, _b, _c;
6189
+ const options = mergeValidatorOptions({}, ctx);
6190
+ const fallbackSettings = resolveFallbackSettings(options);
6191
+ const ratePolicy = resolveGlobalRatePolicy(options);
6079
6192
  const errors = [];
6080
- const serviceMap = (_a = ctx.serviceMap) != null ? _a : {};
6193
+ const serviceMap = (_a = options.serviceMap) != null ? _a : {};
6081
6194
  const selectedKeys = new Set(
6082
- (_b = ctx.selectedOptionKeys) != null ? _b : []
6195
+ (_b = options.selectedOptionKeys) != null ? _b : []
6083
6196
  );
6084
6197
  const tags = Array.isArray(props.filters) ? props.filters : [];
6085
6198
  const fields = Array.isArray(props.fields) ? props.fields : [];
@@ -6089,8 +6202,12 @@ function validate(props, ctx = {}) {
6089
6202
  for (const f of fields) fieldById.set(f.id, f);
6090
6203
  const v = {
6091
6204
  props,
6092
- nodeMap: (_c = ctx.nodeMap) != null ? _c : buildNodeMap(props),
6093
- options: ctx,
6205
+ nodeMap: (_c = options.nodeMap) != null ? _c : buildNodeMap(props),
6206
+ options: {
6207
+ ...options,
6208
+ ratePolicy,
6209
+ fallbackSettings
6210
+ },
6094
6211
  errors,
6095
6212
  serviceMap,
6096
6213
  selectedKeys,
@@ -6105,7 +6222,7 @@ function validate(props, ctx = {}) {
6105
6222
  validateIdentity(v);
6106
6223
  validateOptionMaps(v);
6107
6224
  v.fieldsVisibleUnder = createFieldsVisibleUnder(v);
6108
- const visSim = readVisibilitySimOpts(ctx);
6225
+ const visSim = readVisibilitySimOpts(options);
6109
6226
  validateVisibility(v, visSim);
6110
6227
  applyPolicies(
6111
6228
  v.errors,
@@ -6126,7 +6243,7 @@ function validate(props, ctx = {}) {
6126
6243
  builder,
6127
6244
  services: serviceMap,
6128
6245
  tagId: tag.id,
6129
- ratePolicy: (_d = ctx.fallbackSettings) == null ? void 0 : _d.ratePolicy,
6246
+ ratePolicy,
6130
6247
  invalidFieldIds: v.invalidRateFieldIds
6131
6248
  });
6132
6249
  for (const diag of diags) {
@@ -6169,7 +6286,7 @@ function collectFailedFallbacks(props, services, settings) {
6169
6286
  const s = { ...DEFAULT_SETTINGS, ...settings != null ? settings : {} };
6170
6287
  const out = [];
6171
6288
  const fb = (_a = props.fallbacks) != null ? _a : {};
6172
- const primaryRate = (p) => rateOf(services, p);
6289
+ const primaryRate = (primary) => rateOf(services, primary);
6173
6290
  for (const [nodeId, list] of Object.entries((_b = fb.nodes) != null ? _b : {})) {
6174
6291
  const { primary, tagContexts } = primaryForNode(props, nodeId);
6175
6292
  if (!primary) {
@@ -6182,34 +6299,34 @@ function collectFailedFallbacks(props, services, settings) {
6182
6299
  });
6183
6300
  continue;
6184
6301
  }
6185
- for (const cand of list) {
6186
- const cap = getCap(services, cand);
6187
- if (!cap) {
6302
+ for (const candidate of list) {
6303
+ const capability = getCap(services, candidate);
6304
+ if (!capability) {
6188
6305
  out.push({
6189
6306
  scope: "node",
6190
6307
  nodeId,
6191
6308
  primary,
6192
- candidate: cand,
6309
+ candidate,
6193
6310
  reason: "unknown_service"
6194
6311
  });
6195
6312
  continue;
6196
6313
  }
6197
- if (String(cand) === String(primary)) {
6314
+ if (isSameServiceCapabilityRef(services, candidate, primary)) {
6198
6315
  out.push({
6199
6316
  scope: "node",
6200
6317
  nodeId,
6201
6318
  primary,
6202
- candidate: cand,
6319
+ candidate,
6203
6320
  reason: "cycle"
6204
6321
  });
6205
6322
  continue;
6206
6323
  }
6207
- if (!passesRate(s.ratePolicy, primaryRate(primary), cap.rate)) {
6324
+ if (!passesRate(s.ratePolicy, primaryRate(primary), capability.rate)) {
6208
6325
  out.push({
6209
6326
  scope: "node",
6210
6327
  nodeId,
6211
6328
  primary,
6212
- candidate: cand,
6329
+ candidate,
6213
6330
  reason: "rate_violation"
6214
6331
  });
6215
6332
  continue;
@@ -6219,58 +6336,55 @@ function collectFailedFallbacks(props, services, settings) {
6219
6336
  scope: "node",
6220
6337
  nodeId,
6221
6338
  primary,
6222
- candidate: cand,
6339
+ candidate,
6223
6340
  reason: "no_tag_context"
6224
6341
  });
6225
6342
  continue;
6226
6343
  }
6227
- let anyPass = false;
6228
- let anyFail = false;
6229
6344
  for (const tagId of tagContexts) {
6230
- const ok2 = s.requireConstraintFit ? satisfiesTagConstraints(tagId, { services, props }, cap) : true;
6231
- if (ok2) anyPass = true;
6232
- else {
6233
- anyFail = true;
6234
- out.push({
6235
- scope: "node",
6236
- nodeId,
6237
- primary,
6238
- candidate: cand,
6239
- tagContext: tagId,
6240
- reason: "constraint_mismatch"
6241
- });
6242
- }
6345
+ const fitsConstraints = s.requireConstraintFit ? satisfiesTagConstraints(
6346
+ tagId,
6347
+ { services, props },
6348
+ capability
6349
+ ) : true;
6350
+ if (fitsConstraints) continue;
6351
+ out.push({
6352
+ scope: "node",
6353
+ nodeId,
6354
+ primary,
6355
+ candidate,
6356
+ tagContext: tagId,
6357
+ reason: "constraint_mismatch"
6358
+ });
6243
6359
  }
6244
- void anyPass;
6245
- void anyFail;
6246
6360
  }
6247
6361
  }
6248
6362
  for (const [primary, list] of Object.entries((_c = fb.global) != null ? _c : {})) {
6249
- for (const cand of list) {
6250
- const cap = getCap(services, cand);
6251
- if (!cap) {
6363
+ for (const candidate of list) {
6364
+ const capability = getCap(services, candidate);
6365
+ if (!capability) {
6252
6366
  out.push({
6253
6367
  scope: "global",
6254
6368
  primary,
6255
- candidate: cand,
6369
+ candidate,
6256
6370
  reason: "unknown_service"
6257
6371
  });
6258
6372
  continue;
6259
6373
  }
6260
- if (String(cand) === String(primary)) {
6374
+ if (isSameServiceCapabilityRef(services, candidate, primary)) {
6261
6375
  out.push({
6262
6376
  scope: "global",
6263
6377
  primary,
6264
- candidate: cand,
6378
+ candidate,
6265
6379
  reason: "cycle"
6266
6380
  });
6267
6381
  continue;
6268
6382
  }
6269
- if (!passesRate(s.ratePolicy, primaryRate(primary), cap.rate)) {
6383
+ if (!passesRate(s.ratePolicy, primaryRate(primary), capability.rate)) {
6270
6384
  out.push({
6271
6385
  scope: "global",
6272
6386
  primary,
6273
- candidate: cand,
6387
+ candidate,
6274
6388
  reason: "rate_violation"
6275
6389
  });
6276
6390
  }
@@ -6279,52 +6393,61 @@ function collectFailedFallbacks(props, services, settings) {
6279
6393
  return out;
6280
6394
  }
6281
6395
  function rateOf(map, id) {
6282
- var _a;
6396
+ var _a, _b;
6283
6397
  if (id === void 0 || id === null) return void 0;
6284
- const c = getCap(map, id);
6285
- return (_a = c == null ? void 0 : c.rate) != null ? _a : void 0;
6398
+ return (_b = (_a = getCap(map, id)) == null ? void 0 : _a.rate) != null ? _b : void 0;
6286
6399
  }
6287
- function passesRate(policy, primaryRate, candRate) {
6288
- if (typeof candRate !== "number" || !Number.isFinite(candRate))
6400
+ function passesRate(policy, primaryRate, candidateRate) {
6401
+ if (typeof candidateRate !== "number" || !Number.isFinite(candidateRate)) {
6289
6402
  return false;
6290
- if (typeof primaryRate !== "number" || !Number.isFinite(primaryRate))
6403
+ }
6404
+ if (typeof primaryRate !== "number" || !Number.isFinite(primaryRate)) {
6291
6405
  return false;
6292
- return passesRatePolicy(normalizeRatePolicy(policy), primaryRate, candRate);
6406
+ }
6407
+ return passesRatePolicy(
6408
+ normalizeRatePolicy(policy),
6409
+ primaryRate,
6410
+ candidateRate
6411
+ );
6293
6412
  }
6294
6413
  function getCap(map, id) {
6295
6414
  return getServiceCapability(map, id);
6296
6415
  }
6297
- function isCapFlagEnabled(cap, flagId) {
6416
+ function isCapFlagEnabled(capability, flagId) {
6298
6417
  var _a, _b;
6299
- const fromFlags = (_b = (_a = cap.flags) == null ? void 0 : _a[flagId]) == null ? void 0 : _b.enabled;
6418
+ const fromFlags = (_b = (_a = capability.flags) == null ? void 0 : _a[flagId]) == null ? void 0 : _b.enabled;
6300
6419
  if (fromFlags === true) return true;
6301
6420
  if (fromFlags === false) return false;
6302
- const legacy = cap[flagId];
6421
+ const legacy = capability[flagId];
6303
6422
  return legacy === true;
6304
6423
  }
6305
- function satisfiesTagConstraints(tagId, ctx, cap) {
6306
- const tag = ctx.props.filters.find((t) => t.id === tagId);
6307
- const eff = tag == null ? void 0 : tag.constraints;
6308
- if (!eff) return true;
6309
- for (const [key, value] of Object.entries(eff)) {
6310
- if (value === true && !isCapFlagEnabled(cap, key)) {
6424
+ function satisfiesTagConstraints(tagId, ctx, capability) {
6425
+ const tag = ctx.props.filters.find((item) => item.id === tagId);
6426
+ const effectiveConstraints2 = tag == null ? void 0 : tag.constraints;
6427
+ if (!effectiveConstraints2) return true;
6428
+ for (const [key, value] of Object.entries(effectiveConstraints2)) {
6429
+ if (value === true && !isCapFlagEnabled(capability, key)) {
6311
6430
  return false;
6312
6431
  }
6313
6432
  }
6314
6433
  return true;
6315
6434
  }
6316
6435
  function primaryForNode(props, nodeId) {
6317
- const tag = props.filters.find((t) => t.id === nodeId);
6436
+ const tag = props.filters.find((item) => item.id === nodeId);
6318
6437
  if (tag) {
6319
6438
  return { primary: tag.service_id, tagContexts: [tag.id] };
6320
6439
  }
6321
6440
  const field = props.fields.find(
6322
- (f) => Array.isArray(f.options) && f.options.some((o) => o.id === nodeId)
6441
+ (item) => Array.isArray(item.options) && item.options.some((option2) => option2.id === nodeId)
6323
6442
  );
6324
- if (!field) return { tagContexts: [], reasonNoPrimary: "no_parent_field" };
6325
- const opt = field.options.find((o) => o.id === nodeId);
6326
- const contexts = bindIdsToArray(field.bind_id);
6327
- return { primary: opt.service_id, tagContexts: contexts };
6443
+ if (!field) {
6444
+ return { tagContexts: [], reasonNoPrimary: "no_parent_field" };
6445
+ }
6446
+ const option = field.options.find((item) => item.id === nodeId);
6447
+ return {
6448
+ primary: option.service_id,
6449
+ tagContexts: bindIdsToArray(field.bind_id)
6450
+ };
6328
6451
  }
6329
6452
  function bindIdsToArray(bind) {
6330
6453
  if (!bind) return [];
@@ -6695,18 +6818,23 @@ function createNodeIndex(builder) {
6695
6818
 
6696
6819
  // src/core/service-filter.ts
6697
6820
  function filterServicesForVisibleGroup(input, deps) {
6698
- var _a, _b, _c, _d, _e, _f;
6821
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
6699
6822
  const svcMap = (_c = (_b = (_a = deps.builder).getServiceMap) == null ? void 0 : _b.call(_a)) != null ? _c : {};
6823
+ const builderOptions = (_e = (_d = deps.builder).getOptions) == null ? void 0 : _e.call(_d);
6700
6824
  const { context } = input;
6701
6825
  const usedSet = new Set(context.usedServiceIds.map(String));
6702
6826
  const primary = context.usedServiceIds[0];
6827
+ const explicitFallbackSettings = (_f = context.fallbackSettings) != null ? _f : context.fallback;
6828
+ const resolvedRatePolicy = normalizeRatePolicy(
6829
+ (_h = (_g = context.ratePolicy) != null ? _g : explicitFallbackSettings == null ? void 0 : explicitFallbackSettings.ratePolicy) != null ? _h : builderOptions == null ? void 0 : builderOptions.ratePolicy
6830
+ );
6831
+ const fallbackSettingsSource = explicitFallbackSettings != null ? explicitFallbackSettings : builderOptions == null ? void 0 : builderOptions.fallbackSettings;
6703
6832
  const fb = {
6704
- requireConstraintFit: true,
6705
- ratePolicy: { kind: "lte_primary", pct: 5 },
6706
- selectionStrategy: "priority",
6707
- mode: "strict",
6708
- ...(_d = context.fallback) != null ? _d : {}
6833
+ ...DEFAULT_FALLBACK_SETTINGS,
6834
+ ...fallbackSettingsSource != null ? fallbackSettingsSource : {},
6835
+ ratePolicy: resolvedRatePolicy
6709
6836
  };
6837
+ const policySource = (_j = (_i = context.policies) != null ? _i : builderOptions == null ? void 0 : builderOptions.policies) != null ? _j : [];
6710
6838
  const visibleServiceIds = context.selectedButtons === void 0 ? void 0 : collectVisibleServiceIds(
6711
6839
  deps.builder,
6712
6840
  context.tagId,
@@ -6731,11 +6859,11 @@ function filterServicesForVisibleGroup(input, deps) {
6731
6859
  const fitsConstraints = constraintFitOk(
6732
6860
  svcMap,
6733
6861
  cap.id,
6734
- (_e = context.effectiveConstraints) != null ? _e : {}
6862
+ (_k = context.effectiveConstraints) != null ? _k : {}
6735
6863
  );
6736
6864
  const passesRate2 = primary == null ? true : rateOk(svcMap, id, primary, fb);
6737
6865
  const polRes = evaluatePoliciesRaw(
6738
- (_f = context.policies) != null ? _f : [],
6866
+ policySource,
6739
6867
  [...context.usedServiceIds, id],
6740
6868
  svcMap,
6741
6869
  context.tagId,
@@ -8419,6 +8547,8 @@ function filterServicesForVisibleGroup2(ctx, candidates, input) {
8419
8547
  usedServiceIds: input.usedServiceIds,
8420
8548
  effectiveConstraints: input.effectiveConstraints,
8421
8549
  policies: input.policies,
8550
+ ratePolicy: input.ratePolicy,
8551
+ fallbackSettings: input.fallbackSettings,
8422
8552
  fallback: input.fallback
8423
8553
  }
8424
8554
  };
@@ -9840,6 +9970,8 @@ function CanvasProviderWorkspaceRuntime({
9840
9970
  children,
9841
9971
  builderOpts,
9842
9972
  canvasOpts,
9973
+ ratePolicy,
9974
+ fallbackSettings,
9843
9975
  attachToWorkspace = true
9844
9976
  }) {
9845
9977
  const ws = useWorkspaceMaybe();
@@ -9858,11 +9990,23 @@ function CanvasProviderWorkspaceRuntime({
9858
9990
  const resolvedBuilderOpts = (0, import_react2.useMemo)(() => {
9859
9991
  const svc = ws.services.data;
9860
9992
  const hasMap = svc != null && typeof svc === "object" && !Array.isArray(svc);
9861
- return hasMap ? {
9993
+ const policies = ws.policies.policies.data;
9994
+ return {
9862
9995
  ...builderOpts != null ? builderOpts : {},
9863
- serviceMap: svc
9864
- } : builderOpts;
9865
- }, [builderOpts, ws.services.data]);
9996
+ ...hasMap ? {
9997
+ serviceMap: svc
9998
+ } : {},
9999
+ policies: policies != null ? policies : void 0,
10000
+ ratePolicy: ratePolicy != null ? ratePolicy : builderOpts == null ? void 0 : builderOpts.ratePolicy,
10001
+ fallbackSettings: fallbackSettings != null ? fallbackSettings : builderOpts == null ? void 0 : builderOpts.fallbackSettings
10002
+ };
10003
+ }, [
10004
+ builderOpts,
10005
+ fallbackSettings,
10006
+ ratePolicy,
10007
+ ws.policies.policies.data,
10008
+ ws.services.data
10009
+ ]);
9866
10010
  if (canMountCanvas) {
9867
10011
  hasMountedOnceRef.current = true;
9868
10012
  }
@@ -10200,7 +10344,7 @@ function useCanvasOwned(initialProps, canvasOpts, builderOpts) {
10200
10344
  } else if (((_a = window.SITE) == null ? void 0 : _a.env) !== "production") {
10201
10345
  if (builderOptsRef.current !== builderOpts) {
10202
10346
  console.warn(
10203
- "[useCanvasOwned] builderOpts changed after init; new values are ignored. If you need to recreate the builder, remount the hook (e.g. change a React key)."
10347
+ "[useCanvasOwned] builderOpts changed after init. Reactive keys (serviceMap/policies/ratePolicy/fallbackSettings/selectedOptionKeys) are applied via setOptions(); other keys may still require remounting to fully reinitialize."
10204
10348
  );
10205
10349
  builderOptsRef.current = builderOpts;
10206
10350
  }
@@ -10212,6 +10356,23 @@ function useCanvasOwned(initialProps, canvasOpts, builderOpts) {
10212
10356
  loadedOnceRef.current = true;
10213
10357
  }
10214
10358
  }, [initialProps]);
10359
+ (0, import_react2.useEffect)(() => {
10360
+ if (!builderOpts) return;
10361
+ builder.setOptions({
10362
+ serviceMap: builderOpts.serviceMap,
10363
+ policies: builderOpts.policies,
10364
+ ratePolicy: builderOpts.ratePolicy,
10365
+ fallbackSettings: builderOpts.fallbackSettings,
10366
+ selectedOptionKeys: builderOpts.selectedOptionKeys
10367
+ });
10368
+ }, [
10369
+ builder,
10370
+ builderOpts == null ? void 0 : builderOpts.fallbackSettings,
10371
+ builderOpts == null ? void 0 : builderOpts.policies,
10372
+ builderOpts == null ? void 0 : builderOpts.ratePolicy,
10373
+ builderOpts == null ? void 0 : builderOpts.selectedOptionKeys,
10374
+ builderOpts == null ? void 0 : builderOpts.serviceMap
10375
+ ]);
10215
10376
  const lastCanvasOptsRef = (0, import_react2.useRef)();
10216
10377
  const stableCanvasOpts = (0, import_react2.useMemo)(() => {
10217
10378
  var _a2;
@@ -10537,18 +10698,18 @@ function useErrors(opts = {}) {
10537
10698
  setValidating(true);
10538
10699
  schedule(
10539
10700
  () => {
10540
- var _a2, _b2;
10701
+ var _a2, _b2, _c2, _d2, _e2;
10541
10702
  if (token !== runTokenRef.current) return;
10542
10703
  try {
10543
10704
  const props = api.editor.getProps();
10544
- const res = validate(props);
10705
+ const res = validate(props, (_c2 = (_b2 = (_a2 = api.builder).getOptions) == null ? void 0 : _b2.call(_a2)) != null ? _c2 : {});
10545
10706
  if (token !== runTokenRef.current) return;
10546
10707
  setValidation(toValidationRows(res != null ? res : []));
10547
10708
  } catch (err) {
10548
10709
  if (token !== runTokenRef.current) return;
10549
10710
  pushLog({
10550
- message: (_a2 = err == null ? void 0 : err.message) != null ? _a2 : "validate() threw",
10551
- code: (_b2 = err == null ? void 0 : err.code) != null ? _b2 : "validate_throw",
10711
+ message: (_d2 = err == null ? void 0 : err.message) != null ? _d2 : "validate() threw",
10712
+ code: (_e2 = err == null ? void 0 : err.code) != null ? _e2 : "validate_throw",
10552
10713
  meta: err
10553
10714
  });
10554
10715
  setValidation([]);
@@ -12010,6 +12171,8 @@ function Workspace(props) {
12010
12171
  liveDebounceMs,
12011
12172
  autosaveMs,
12012
12173
  autoAutosave,
12174
+ ratePolicy,
12175
+ fallbackSettings,
12013
12176
  tools,
12014
12177
  children
12015
12178
  } = props;
@@ -12025,7 +12188,14 @@ function Workspace(props) {
12025
12188
  liveDebounceMs,
12026
12189
  autosaveMs,
12027
12190
  autoAutosave,
12028
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(CanvasProvider, { children: children(tools) })
12191
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
12192
+ CanvasProvider,
12193
+ {
12194
+ ratePolicy,
12195
+ fallbackSettings,
12196
+ children: children(tools)
12197
+ }
12198
+ )
12029
12199
  }
12030
12200
  );
12031
12201
  }