@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.
@@ -4663,6 +4663,9 @@ function toFiniteNumber(v) {
4663
4663
  const n = Number(v);
4664
4664
  return Number.isFinite(n) ? n : NaN;
4665
4665
  }
4666
+ function isValidServiceIdRef(value) {
4667
+ return typeof value === "number" && Number.isFinite(value) || typeof value === "string" && value.trim().length > 0;
4668
+ }
4666
4669
  function constraintFitOk(svcMap, candidate, constraints) {
4667
4670
  const cap = getServiceCapability(svcMap, candidate);
4668
4671
  if (!cap) return false;
@@ -4671,18 +4674,27 @@ function constraintFitOk(svcMap, candidate, constraints) {
4671
4674
  return !(constraints.cancel === true && !cap.cancel);
4672
4675
  }
4673
4676
  function getServiceCapability(svcMap, candidate) {
4674
- if (candidate === void 0 || candidate === null) return void 0;
4675
- const direct = svcMap[candidate];
4676
- if (direct) return direct;
4677
- const byString = svcMap[String(candidate)];
4678
- if (byString) return byString;
4679
- if (typeof candidate === "string") {
4680
- const maybeNumber = Number(candidate);
4681
- if (Number.isFinite(maybeNumber)) {
4682
- return svcMap[maybeNumber];
4683
- }
4677
+ var _a;
4678
+ return (_a = getServiceCapabilityEntry(svcMap, candidate)) == null ? void 0 : _a.capability;
4679
+ }
4680
+ function getServiceCapabilityAliases(svcMap, candidate) {
4681
+ const entry = getServiceCapabilityEntry(svcMap, candidate);
4682
+ if (!entry) return [];
4683
+ return collectServiceRefAliases(entry.key, entry.capability);
4684
+ }
4685
+ function isSameServiceCapabilityRef(svcMap, left, right) {
4686
+ if (!isValidServiceIdRef(left) || !isValidServiceIdRef(right)) return false;
4687
+ const leftAliases = new Set(
4688
+ getServiceCapabilityAliases(svcMap, left).map((value) => String(value))
4689
+ );
4690
+ if (!leftAliases.size) {
4691
+ leftAliases.add(String(left));
4684
4692
  }
4685
- return void 0;
4693
+ const rightAliases = getServiceCapabilityAliases(svcMap, right);
4694
+ if (!rightAliases.length) {
4695
+ return leftAliases.has(String(right));
4696
+ }
4697
+ return rightAliases.some((value) => leftAliases.has(String(value)));
4686
4698
  }
4687
4699
  function normalizeRatePolicy(policy) {
4688
4700
  var _a;
@@ -4718,18 +4730,84 @@ function rateOk(svcMap, candidate, primary, policy) {
4718
4730
  if (!Number.isFinite(cRate) || !Number.isFinite(pRate)) return false;
4719
4731
  return passesRatePolicy(policy.ratePolicy, pRate, cRate);
4720
4732
  }
4733
+ function getServiceCapabilityEntry(svcMap, candidate) {
4734
+ if (candidate === void 0 || candidate === null) return void 0;
4735
+ const direct = svcMap[candidate];
4736
+ if (direct) {
4737
+ return { key: String(candidate), capability: direct };
4738
+ }
4739
+ const byString = svcMap[String(candidate)];
4740
+ if (byString) {
4741
+ return { key: String(candidate), capability: byString };
4742
+ }
4743
+ if (typeof candidate === "string") {
4744
+ const maybeNumber = Number(candidate);
4745
+ if (Number.isFinite(maybeNumber)) {
4746
+ const byNumber = svcMap[maybeNumber];
4747
+ if (byNumber) {
4748
+ return { key: String(maybeNumber), capability: byNumber };
4749
+ }
4750
+ }
4751
+ }
4752
+ const target = String(candidate);
4753
+ for (const [key, capability] of Object.entries(svcMap != null ? svcMap : {})) {
4754
+ if (collectServiceRefAliases(key, capability).some(
4755
+ (alias) => String(alias) === target
4756
+ )) {
4757
+ return { key, capability };
4758
+ }
4759
+ }
4760
+ return void 0;
4761
+ }
4762
+ function collectServiceRefAliases(key, capability) {
4763
+ const out = [];
4764
+ const seen = /* @__PURE__ */ new Set();
4765
+ const push = (value) => {
4766
+ if (!isValidServiceIdRef(value)) return;
4767
+ const normalized = normalizeServiceRef(value);
4768
+ if (!normalized) return;
4769
+ const aliasKey = String(normalized);
4770
+ if (seen.has(aliasKey)) return;
4771
+ seen.add(aliasKey);
4772
+ out.push(normalized);
4773
+ };
4774
+ push(getCanonicalServiceRef(key, capability));
4775
+ push(capability.service);
4776
+ push(capability.key);
4777
+ push(capability.id);
4778
+ return out;
4779
+ }
4780
+ function getCanonicalServiceRef(key, capability) {
4781
+ const explicitRefs = [capability.service, capability.key, capability.id];
4782
+ for (const ref of explicitRefs) {
4783
+ if (!isValidServiceIdRef(ref)) continue;
4784
+ if (String(ref) === key) {
4785
+ return ref;
4786
+ }
4787
+ }
4788
+ return normalizeServiceRef(key);
4789
+ }
4790
+ function normalizeServiceRef(value) {
4791
+ if (!isValidServiceIdRef(value)) return void 0;
4792
+ if (typeof value === "number") return value;
4793
+ const trimmed = value.trim();
4794
+ if (!trimmed) return void 0;
4795
+ const asNumber = Number(trimmed);
4796
+ if (Number.isFinite(asNumber) && String(asNumber) === trimmed) {
4797
+ return asNumber;
4798
+ }
4799
+ return trimmed;
4800
+ }
4721
4801
 
4722
4802
  // src/core/validate/steps/rates.ts
4723
4803
  function validateRates(v) {
4724
- var _a, _b, _c, _d;
4725
- const ratePolicy = normalizeRatePolicy(
4726
- (_a = v.options.fallbackSettings) == null ? void 0 : _a.ratePolicy
4727
- );
4804
+ var _a, _b, _c;
4805
+ const ratePolicy = normalizeRatePolicy(v.options.ratePolicy);
4728
4806
  for (const f of v.fields) {
4729
4807
  if (!isMultiField(f)) continue;
4730
4808
  const baseRates = [];
4731
- for (const o of (_b = f.options) != null ? _b : []) {
4732
- const role = (_d = (_c = o.pricing_role) != null ? _c : f.pricing_role) != null ? _d : "base";
4809
+ for (const o of (_a = f.options) != null ? _a : []) {
4810
+ const role = (_c = (_b = o.pricing_role) != null ? _b : f.pricing_role) != null ? _c : "base";
4733
4811
  if (role !== "base") continue;
4734
4812
  const sid = o.service_id;
4735
4813
  if (!isServiceIdRef(sid)) continue;
@@ -5503,6 +5581,38 @@ function applyPolicies(errors, props, serviceMap, policies, fieldsVisibleUnder,
5503
5581
  }
5504
5582
  }
5505
5583
 
5584
+ // src/core/governance.ts
5585
+ var DEFAULT_FALLBACK_SETTINGS = {
5586
+ requireConstraintFit: true,
5587
+ ratePolicy: { kind: "lte_primary", pct: 5 },
5588
+ selectionStrategy: "priority",
5589
+ mode: "strict"
5590
+ };
5591
+ function resolveGlobalRatePolicy(options) {
5592
+ return normalizeRatePolicy(options.ratePolicy);
5593
+ }
5594
+ function resolveFallbackSettings(options) {
5595
+ var _a;
5596
+ return {
5597
+ ...DEFAULT_FALLBACK_SETTINGS,
5598
+ ...(_a = options.fallbackSettings) != null ? _a : {}
5599
+ };
5600
+ }
5601
+ function mergeValidatorOptions(defaults = {}, overrides = {}) {
5602
+ var _a, _b, _c, _d;
5603
+ const mergedFallbackSettings = {
5604
+ ...(_a = defaults.fallbackSettings) != null ? _a : {},
5605
+ ...(_b = overrides.fallbackSettings) != null ? _b : {}
5606
+ };
5607
+ return {
5608
+ ...defaults,
5609
+ ...overrides,
5610
+ policies: (_c = overrides.policies) != null ? _c : defaults.policies,
5611
+ ratePolicy: (_d = overrides.ratePolicy) != null ? _d : defaults.ratePolicy,
5612
+ fallbackSettings: Object.keys(mergedFallbackSettings).length > 0 ? mergedFallbackSettings : void 0
5613
+ };
5614
+ }
5615
+
5506
5616
  // src/core/builder.ts
5507
5617
  import { cloneDeep as cloneDeep2 } from "lodash-es";
5508
5618
  function createBuilder(opts = {}) {
@@ -5745,7 +5855,7 @@ var BuilderImpl = class {
5745
5855
  return out;
5746
5856
  }
5747
5857
  errors() {
5748
- return validate(this.props, this.options);
5858
+ return validate(this.props, mergeValidatorOptions({}, this.options));
5749
5859
  }
5750
5860
  getOptions() {
5751
5861
  return cloneDeep2(this.options);
@@ -6032,11 +6142,14 @@ function readVisibilitySimOpts(ctx) {
6032
6142
  };
6033
6143
  }
6034
6144
  function validate(props, ctx = {}) {
6035
- var _a, _b, _c, _d;
6145
+ var _a, _b, _c;
6146
+ const options = mergeValidatorOptions({}, ctx);
6147
+ const fallbackSettings = resolveFallbackSettings(options);
6148
+ const ratePolicy = resolveGlobalRatePolicy(options);
6036
6149
  const errors = [];
6037
- const serviceMap = (_a = ctx.serviceMap) != null ? _a : {};
6150
+ const serviceMap = (_a = options.serviceMap) != null ? _a : {};
6038
6151
  const selectedKeys = new Set(
6039
- (_b = ctx.selectedOptionKeys) != null ? _b : []
6152
+ (_b = options.selectedOptionKeys) != null ? _b : []
6040
6153
  );
6041
6154
  const tags = Array.isArray(props.filters) ? props.filters : [];
6042
6155
  const fields = Array.isArray(props.fields) ? props.fields : [];
@@ -6046,8 +6159,12 @@ function validate(props, ctx = {}) {
6046
6159
  for (const f of fields) fieldById.set(f.id, f);
6047
6160
  const v = {
6048
6161
  props,
6049
- nodeMap: (_c = ctx.nodeMap) != null ? _c : buildNodeMap(props),
6050
- options: ctx,
6162
+ nodeMap: (_c = options.nodeMap) != null ? _c : buildNodeMap(props),
6163
+ options: {
6164
+ ...options,
6165
+ ratePolicy,
6166
+ fallbackSettings
6167
+ },
6051
6168
  errors,
6052
6169
  serviceMap,
6053
6170
  selectedKeys,
@@ -6062,7 +6179,7 @@ function validate(props, ctx = {}) {
6062
6179
  validateIdentity(v);
6063
6180
  validateOptionMaps(v);
6064
6181
  v.fieldsVisibleUnder = createFieldsVisibleUnder(v);
6065
- const visSim = readVisibilitySimOpts(ctx);
6182
+ const visSim = readVisibilitySimOpts(options);
6066
6183
  validateVisibility(v, visSim);
6067
6184
  applyPolicies(
6068
6185
  v.errors,
@@ -6083,7 +6200,7 @@ function validate(props, ctx = {}) {
6083
6200
  builder,
6084
6201
  services: serviceMap,
6085
6202
  tagId: tag.id,
6086
- ratePolicy: (_d = ctx.fallbackSettings) == null ? void 0 : _d.ratePolicy,
6203
+ ratePolicy,
6087
6204
  invalidFieldIds: v.invalidRateFieldIds
6088
6205
  });
6089
6206
  for (const diag of diags) {
@@ -6126,7 +6243,7 @@ function collectFailedFallbacks(props, services, settings) {
6126
6243
  const s = { ...DEFAULT_SETTINGS, ...settings != null ? settings : {} };
6127
6244
  const out = [];
6128
6245
  const fb = (_a = props.fallbacks) != null ? _a : {};
6129
- const primaryRate = (p) => rateOf(services, p);
6246
+ const primaryRate = (primary) => rateOf(services, primary);
6130
6247
  for (const [nodeId, list] of Object.entries((_b = fb.nodes) != null ? _b : {})) {
6131
6248
  const { primary, tagContexts } = primaryForNode(props, nodeId);
6132
6249
  if (!primary) {
@@ -6139,34 +6256,34 @@ function collectFailedFallbacks(props, services, settings) {
6139
6256
  });
6140
6257
  continue;
6141
6258
  }
6142
- for (const cand of list) {
6143
- const cap = getCap(services, cand);
6144
- if (!cap) {
6259
+ for (const candidate of list) {
6260
+ const capability = getCap(services, candidate);
6261
+ if (!capability) {
6145
6262
  out.push({
6146
6263
  scope: "node",
6147
6264
  nodeId,
6148
6265
  primary,
6149
- candidate: cand,
6266
+ candidate,
6150
6267
  reason: "unknown_service"
6151
6268
  });
6152
6269
  continue;
6153
6270
  }
6154
- if (String(cand) === String(primary)) {
6271
+ if (isSameServiceCapabilityRef(services, candidate, primary)) {
6155
6272
  out.push({
6156
6273
  scope: "node",
6157
6274
  nodeId,
6158
6275
  primary,
6159
- candidate: cand,
6276
+ candidate,
6160
6277
  reason: "cycle"
6161
6278
  });
6162
6279
  continue;
6163
6280
  }
6164
- if (!passesRate(s.ratePolicy, primaryRate(primary), cap.rate)) {
6281
+ if (!passesRate(s.ratePolicy, primaryRate(primary), capability.rate)) {
6165
6282
  out.push({
6166
6283
  scope: "node",
6167
6284
  nodeId,
6168
6285
  primary,
6169
- candidate: cand,
6286
+ candidate,
6170
6287
  reason: "rate_violation"
6171
6288
  });
6172
6289
  continue;
@@ -6176,58 +6293,55 @@ function collectFailedFallbacks(props, services, settings) {
6176
6293
  scope: "node",
6177
6294
  nodeId,
6178
6295
  primary,
6179
- candidate: cand,
6296
+ candidate,
6180
6297
  reason: "no_tag_context"
6181
6298
  });
6182
6299
  continue;
6183
6300
  }
6184
- let anyPass = false;
6185
- let anyFail = false;
6186
6301
  for (const tagId of tagContexts) {
6187
- const ok2 = s.requireConstraintFit ? satisfiesTagConstraints(tagId, { services, props }, cap) : true;
6188
- if (ok2) anyPass = true;
6189
- else {
6190
- anyFail = true;
6191
- out.push({
6192
- scope: "node",
6193
- nodeId,
6194
- primary,
6195
- candidate: cand,
6196
- tagContext: tagId,
6197
- reason: "constraint_mismatch"
6198
- });
6199
- }
6302
+ const fitsConstraints = s.requireConstraintFit ? satisfiesTagConstraints(
6303
+ tagId,
6304
+ { services, props },
6305
+ capability
6306
+ ) : true;
6307
+ if (fitsConstraints) continue;
6308
+ out.push({
6309
+ scope: "node",
6310
+ nodeId,
6311
+ primary,
6312
+ candidate,
6313
+ tagContext: tagId,
6314
+ reason: "constraint_mismatch"
6315
+ });
6200
6316
  }
6201
- void anyPass;
6202
- void anyFail;
6203
6317
  }
6204
6318
  }
6205
6319
  for (const [primary, list] of Object.entries((_c = fb.global) != null ? _c : {})) {
6206
- for (const cand of list) {
6207
- const cap = getCap(services, cand);
6208
- if (!cap) {
6320
+ for (const candidate of list) {
6321
+ const capability = getCap(services, candidate);
6322
+ if (!capability) {
6209
6323
  out.push({
6210
6324
  scope: "global",
6211
6325
  primary,
6212
- candidate: cand,
6326
+ candidate,
6213
6327
  reason: "unknown_service"
6214
6328
  });
6215
6329
  continue;
6216
6330
  }
6217
- if (String(cand) === String(primary)) {
6331
+ if (isSameServiceCapabilityRef(services, candidate, primary)) {
6218
6332
  out.push({
6219
6333
  scope: "global",
6220
6334
  primary,
6221
- candidate: cand,
6335
+ candidate,
6222
6336
  reason: "cycle"
6223
6337
  });
6224
6338
  continue;
6225
6339
  }
6226
- if (!passesRate(s.ratePolicy, primaryRate(primary), cap.rate)) {
6340
+ if (!passesRate(s.ratePolicy, primaryRate(primary), capability.rate)) {
6227
6341
  out.push({
6228
6342
  scope: "global",
6229
6343
  primary,
6230
- candidate: cand,
6344
+ candidate,
6231
6345
  reason: "rate_violation"
6232
6346
  });
6233
6347
  }
@@ -6236,52 +6350,61 @@ function collectFailedFallbacks(props, services, settings) {
6236
6350
  return out;
6237
6351
  }
6238
6352
  function rateOf(map, id) {
6239
- var _a;
6353
+ var _a, _b;
6240
6354
  if (id === void 0 || id === null) return void 0;
6241
- const c = getCap(map, id);
6242
- return (_a = c == null ? void 0 : c.rate) != null ? _a : void 0;
6355
+ return (_b = (_a = getCap(map, id)) == null ? void 0 : _a.rate) != null ? _b : void 0;
6243
6356
  }
6244
- function passesRate(policy, primaryRate, candRate) {
6245
- if (typeof candRate !== "number" || !Number.isFinite(candRate))
6357
+ function passesRate(policy, primaryRate, candidateRate) {
6358
+ if (typeof candidateRate !== "number" || !Number.isFinite(candidateRate)) {
6246
6359
  return false;
6247
- if (typeof primaryRate !== "number" || !Number.isFinite(primaryRate))
6360
+ }
6361
+ if (typeof primaryRate !== "number" || !Number.isFinite(primaryRate)) {
6248
6362
  return false;
6249
- return passesRatePolicy(normalizeRatePolicy(policy), primaryRate, candRate);
6363
+ }
6364
+ return passesRatePolicy(
6365
+ normalizeRatePolicy(policy),
6366
+ primaryRate,
6367
+ candidateRate
6368
+ );
6250
6369
  }
6251
6370
  function getCap(map, id) {
6252
6371
  return getServiceCapability(map, id);
6253
6372
  }
6254
- function isCapFlagEnabled(cap, flagId) {
6373
+ function isCapFlagEnabled(capability, flagId) {
6255
6374
  var _a, _b;
6256
- const fromFlags = (_b = (_a = cap.flags) == null ? void 0 : _a[flagId]) == null ? void 0 : _b.enabled;
6375
+ const fromFlags = (_b = (_a = capability.flags) == null ? void 0 : _a[flagId]) == null ? void 0 : _b.enabled;
6257
6376
  if (fromFlags === true) return true;
6258
6377
  if (fromFlags === false) return false;
6259
- const legacy = cap[flagId];
6378
+ const legacy = capability[flagId];
6260
6379
  return legacy === true;
6261
6380
  }
6262
- function satisfiesTagConstraints(tagId, ctx, cap) {
6263
- const tag = ctx.props.filters.find((t) => t.id === tagId);
6264
- const eff = tag == null ? void 0 : tag.constraints;
6265
- if (!eff) return true;
6266
- for (const [key, value] of Object.entries(eff)) {
6267
- if (value === true && !isCapFlagEnabled(cap, key)) {
6381
+ function satisfiesTagConstraints(tagId, ctx, capability) {
6382
+ const tag = ctx.props.filters.find((item) => item.id === tagId);
6383
+ const effectiveConstraints2 = tag == null ? void 0 : tag.constraints;
6384
+ if (!effectiveConstraints2) return true;
6385
+ for (const [key, value] of Object.entries(effectiveConstraints2)) {
6386
+ if (value === true && !isCapFlagEnabled(capability, key)) {
6268
6387
  return false;
6269
6388
  }
6270
6389
  }
6271
6390
  return true;
6272
6391
  }
6273
6392
  function primaryForNode(props, nodeId) {
6274
- const tag = props.filters.find((t) => t.id === nodeId);
6393
+ const tag = props.filters.find((item) => item.id === nodeId);
6275
6394
  if (tag) {
6276
6395
  return { primary: tag.service_id, tagContexts: [tag.id] };
6277
6396
  }
6278
6397
  const field = props.fields.find(
6279
- (f) => Array.isArray(f.options) && f.options.some((o) => o.id === nodeId)
6398
+ (item) => Array.isArray(item.options) && item.options.some((option2) => option2.id === nodeId)
6280
6399
  );
6281
- if (!field) return { tagContexts: [], reasonNoPrimary: "no_parent_field" };
6282
- const opt = field.options.find((o) => o.id === nodeId);
6283
- const contexts = bindIdsToArray(field.bind_id);
6284
- return { primary: opt.service_id, tagContexts: contexts };
6400
+ if (!field) {
6401
+ return { tagContexts: [], reasonNoPrimary: "no_parent_field" };
6402
+ }
6403
+ const option = field.options.find((item) => item.id === nodeId);
6404
+ return {
6405
+ primary: option.service_id,
6406
+ tagContexts: bindIdsToArray(field.bind_id)
6407
+ };
6285
6408
  }
6286
6409
  function bindIdsToArray(bind) {
6287
6410
  if (!bind) return [];
@@ -6652,18 +6775,23 @@ function createNodeIndex(builder) {
6652
6775
 
6653
6776
  // src/core/service-filter.ts
6654
6777
  function filterServicesForVisibleGroup(input, deps) {
6655
- var _a, _b, _c, _d, _e, _f;
6778
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
6656
6779
  const svcMap = (_c = (_b = (_a = deps.builder).getServiceMap) == null ? void 0 : _b.call(_a)) != null ? _c : {};
6780
+ const builderOptions = (_e = (_d = deps.builder).getOptions) == null ? void 0 : _e.call(_d);
6657
6781
  const { context } = input;
6658
6782
  const usedSet = new Set(context.usedServiceIds.map(String));
6659
6783
  const primary = context.usedServiceIds[0];
6784
+ const explicitFallbackSettings = (_f = context.fallbackSettings) != null ? _f : context.fallback;
6785
+ const resolvedRatePolicy = normalizeRatePolicy(
6786
+ (_h = (_g = context.ratePolicy) != null ? _g : explicitFallbackSettings == null ? void 0 : explicitFallbackSettings.ratePolicy) != null ? _h : builderOptions == null ? void 0 : builderOptions.ratePolicy
6787
+ );
6788
+ const fallbackSettingsSource = explicitFallbackSettings != null ? explicitFallbackSettings : builderOptions == null ? void 0 : builderOptions.fallbackSettings;
6660
6789
  const fb = {
6661
- requireConstraintFit: true,
6662
- ratePolicy: { kind: "lte_primary", pct: 5 },
6663
- selectionStrategy: "priority",
6664
- mode: "strict",
6665
- ...(_d = context.fallback) != null ? _d : {}
6790
+ ...DEFAULT_FALLBACK_SETTINGS,
6791
+ ...fallbackSettingsSource != null ? fallbackSettingsSource : {},
6792
+ ratePolicy: resolvedRatePolicy
6666
6793
  };
6794
+ const policySource = (_j = (_i = context.policies) != null ? _i : builderOptions == null ? void 0 : builderOptions.policies) != null ? _j : [];
6667
6795
  const visibleServiceIds = context.selectedButtons === void 0 ? void 0 : collectVisibleServiceIds(
6668
6796
  deps.builder,
6669
6797
  context.tagId,
@@ -6688,11 +6816,11 @@ function filterServicesForVisibleGroup(input, deps) {
6688
6816
  const fitsConstraints = constraintFitOk(
6689
6817
  svcMap,
6690
6818
  cap.id,
6691
- (_e = context.effectiveConstraints) != null ? _e : {}
6819
+ (_k = context.effectiveConstraints) != null ? _k : {}
6692
6820
  );
6693
6821
  const passesRate2 = primary == null ? true : rateOk(svcMap, id, primary, fb);
6694
6822
  const polRes = evaluatePoliciesRaw(
6695
- (_f = context.policies) != null ? _f : [],
6823
+ policySource,
6696
6824
  [...context.usedServiceIds, id],
6697
6825
  svcMap,
6698
6826
  context.tagId,
@@ -8376,6 +8504,8 @@ function filterServicesForVisibleGroup2(ctx, candidates, input) {
8376
8504
  usedServiceIds: input.usedServiceIds,
8377
8505
  effectiveConstraints: input.effectiveConstraints,
8378
8506
  policies: input.policies,
8507
+ ratePolicy: input.ratePolicy,
8508
+ fallbackSettings: input.fallbackSettings,
8379
8509
  fallback: input.fallback
8380
8510
  }
8381
8511
  };
@@ -9797,6 +9927,8 @@ function CanvasProviderWorkspaceRuntime({
9797
9927
  children,
9798
9928
  builderOpts,
9799
9929
  canvasOpts,
9930
+ ratePolicy,
9931
+ fallbackSettings,
9800
9932
  attachToWorkspace = true
9801
9933
  }) {
9802
9934
  const ws = useWorkspaceMaybe();
@@ -9815,11 +9947,23 @@ function CanvasProviderWorkspaceRuntime({
9815
9947
  const resolvedBuilderOpts = useMemo13(() => {
9816
9948
  const svc = ws.services.data;
9817
9949
  const hasMap = svc != null && typeof svc === "object" && !Array.isArray(svc);
9818
- return hasMap ? {
9950
+ const policies = ws.policies.policies.data;
9951
+ return {
9819
9952
  ...builderOpts != null ? builderOpts : {},
9820
- serviceMap: svc
9821
- } : builderOpts;
9822
- }, [builderOpts, ws.services.data]);
9953
+ ...hasMap ? {
9954
+ serviceMap: svc
9955
+ } : {},
9956
+ policies: policies != null ? policies : void 0,
9957
+ ratePolicy: ratePolicy != null ? ratePolicy : builderOpts == null ? void 0 : builderOpts.ratePolicy,
9958
+ fallbackSettings: fallbackSettings != null ? fallbackSettings : builderOpts == null ? void 0 : builderOpts.fallbackSettings
9959
+ };
9960
+ }, [
9961
+ builderOpts,
9962
+ fallbackSettings,
9963
+ ratePolicy,
9964
+ ws.policies.policies.data,
9965
+ ws.services.data
9966
+ ]);
9823
9967
  if (canMountCanvas) {
9824
9968
  hasMountedOnceRef.current = true;
9825
9969
  }
@@ -10157,7 +10301,7 @@ function useCanvasOwned(initialProps, canvasOpts, builderOpts) {
10157
10301
  } else if (((_a = window.SITE) == null ? void 0 : _a.env) !== "production") {
10158
10302
  if (builderOptsRef.current !== builderOpts) {
10159
10303
  console.warn(
10160
- "[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)."
10304
+ "[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."
10161
10305
  );
10162
10306
  builderOptsRef.current = builderOpts;
10163
10307
  }
@@ -10169,6 +10313,23 @@ function useCanvasOwned(initialProps, canvasOpts, builderOpts) {
10169
10313
  loadedOnceRef.current = true;
10170
10314
  }
10171
10315
  }, [initialProps]);
10316
+ useEffect7(() => {
10317
+ if (!builderOpts) return;
10318
+ builder.setOptions({
10319
+ serviceMap: builderOpts.serviceMap,
10320
+ policies: builderOpts.policies,
10321
+ ratePolicy: builderOpts.ratePolicy,
10322
+ fallbackSettings: builderOpts.fallbackSettings,
10323
+ selectedOptionKeys: builderOpts.selectedOptionKeys
10324
+ });
10325
+ }, [
10326
+ builder,
10327
+ builderOpts == null ? void 0 : builderOpts.fallbackSettings,
10328
+ builderOpts == null ? void 0 : builderOpts.policies,
10329
+ builderOpts == null ? void 0 : builderOpts.ratePolicy,
10330
+ builderOpts == null ? void 0 : builderOpts.selectedOptionKeys,
10331
+ builderOpts == null ? void 0 : builderOpts.serviceMap
10332
+ ]);
10172
10333
  const lastCanvasOptsRef = useRef6();
10173
10334
  const stableCanvasOpts = useMemo13(() => {
10174
10335
  var _a2;
@@ -10494,18 +10655,18 @@ function useErrors(opts = {}) {
10494
10655
  setValidating(true);
10495
10656
  schedule(
10496
10657
  () => {
10497
- var _a2, _b2;
10658
+ var _a2, _b2, _c2, _d2, _e2;
10498
10659
  if (token !== runTokenRef.current) return;
10499
10660
  try {
10500
10661
  const props = api.editor.getProps();
10501
- const res = validate(props);
10662
+ const res = validate(props, (_c2 = (_b2 = (_a2 = api.builder).getOptions) == null ? void 0 : _b2.call(_a2)) != null ? _c2 : {});
10502
10663
  if (token !== runTokenRef.current) return;
10503
10664
  setValidation(toValidationRows(res != null ? res : []));
10504
10665
  } catch (err) {
10505
10666
  if (token !== runTokenRef.current) return;
10506
10667
  pushLog({
10507
- message: (_a2 = err == null ? void 0 : err.message) != null ? _a2 : "validate() threw",
10508
- code: (_b2 = err == null ? void 0 : err.code) != null ? _b2 : "validate_throw",
10668
+ message: (_d2 = err == null ? void 0 : err.message) != null ? _d2 : "validate() threw",
10669
+ code: (_e2 = err == null ? void 0 : err.code) != null ? _e2 : "validate_throw",
10509
10670
  meta: err
10510
10671
  });
10511
10672
  setValidation([]);
@@ -11967,6 +12128,8 @@ function Workspace(props) {
11967
12128
  liveDebounceMs,
11968
12129
  autosaveMs,
11969
12130
  autoAutosave,
12131
+ ratePolicy,
12132
+ fallbackSettings,
11970
12133
  tools,
11971
12134
  children
11972
12135
  } = props;
@@ -11982,7 +12145,14 @@ function Workspace(props) {
11982
12145
  liveDebounceMs,
11983
12146
  autosaveMs,
11984
12147
  autoAutosave,
11985
- children: /* @__PURE__ */ jsx3(CanvasProvider, { children: children(tools) })
12148
+ children: /* @__PURE__ */ jsx3(
12149
+ CanvasProvider,
12150
+ {
12151
+ ratePolicy,
12152
+ fallbackSettings,
12153
+ children: children(tools)
12154
+ }
12155
+ )
11986
12156
  }
11987
12157
  );
11988
12158
  }