@timeax/digital-service-engine 0.2.1 → 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.
- package/dist/core/index.cjs +364 -119
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +8 -11
- package/dist/core/index.d.ts +8 -11
- package/dist/core/index.js +363 -119
- package/dist/core/index.js.map +1 -1
- package/dist/react/index.cjs +561 -335
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +2 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.js +561 -335
- package/dist/react/index.js.map +1 -1
- package/dist/schema/index.d.cts +12 -1
- package/dist/schema/index.d.ts +12 -1
- package/dist/workspace/index.cjs +154 -68
- package/dist/workspace/index.cjs.map +1 -1
- package/dist/workspace/index.js +154 -68
- package/dist/workspace/index.js.map +1 -1
- package/package.json +1 -1
package/dist/core/index.js
CHANGED
|
@@ -1192,6 +1192,9 @@ function toFiniteNumber(v) {
|
|
|
1192
1192
|
const n = Number(v);
|
|
1193
1193
|
return Number.isFinite(n) ? n : NaN;
|
|
1194
1194
|
}
|
|
1195
|
+
function isValidServiceIdRef(value) {
|
|
1196
|
+
return typeof value === "number" && Number.isFinite(value) || typeof value === "string" && value.trim().length > 0;
|
|
1197
|
+
}
|
|
1195
1198
|
function constraintFitOk(svcMap, candidate, constraints) {
|
|
1196
1199
|
const cap = getServiceCapability(svcMap, candidate);
|
|
1197
1200
|
if (!cap) return false;
|
|
@@ -1200,18 +1203,32 @@ function constraintFitOk(svcMap, candidate, constraints) {
|
|
|
1200
1203
|
return !(constraints.cancel === true && !cap.cancel);
|
|
1201
1204
|
}
|
|
1202
1205
|
function getServiceCapability(svcMap, candidate) {
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
if (
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1206
|
+
var _a;
|
|
1207
|
+
return (_a = getServiceCapabilityEntry(svcMap, candidate)) == null ? void 0 : _a.capability;
|
|
1208
|
+
}
|
|
1209
|
+
function getServiceCapabilityCanonicalRef(svcMap, candidate) {
|
|
1210
|
+
const entry = getServiceCapabilityEntry(svcMap, candidate);
|
|
1211
|
+
if (!entry) return void 0;
|
|
1212
|
+
return getCanonicalServiceRef(entry.key, entry.capability);
|
|
1213
|
+
}
|
|
1214
|
+
function getServiceCapabilityAliases(svcMap, candidate) {
|
|
1215
|
+
const entry = getServiceCapabilityEntry(svcMap, candidate);
|
|
1216
|
+
if (!entry) return [];
|
|
1217
|
+
return collectServiceRefAliases(entry.key, entry.capability);
|
|
1218
|
+
}
|
|
1219
|
+
function isSameServiceCapabilityRef(svcMap, left, right) {
|
|
1220
|
+
if (!isValidServiceIdRef(left) || !isValidServiceIdRef(right)) return false;
|
|
1221
|
+
const leftAliases = new Set(
|
|
1222
|
+
getServiceCapabilityAliases(svcMap, left).map((value) => String(value))
|
|
1223
|
+
);
|
|
1224
|
+
if (!leftAliases.size) {
|
|
1225
|
+
leftAliases.add(String(left));
|
|
1213
1226
|
}
|
|
1214
|
-
|
|
1227
|
+
const rightAliases = getServiceCapabilityAliases(svcMap, right);
|
|
1228
|
+
if (!rightAliases.length) {
|
|
1229
|
+
return leftAliases.has(String(right));
|
|
1230
|
+
}
|
|
1231
|
+
return rightAliases.some((value) => leftAliases.has(String(value)));
|
|
1215
1232
|
}
|
|
1216
1233
|
function normalizeRatePolicy(policy) {
|
|
1217
1234
|
var _a;
|
|
@@ -1247,6 +1264,74 @@ function rateOk(svcMap, candidate, primary, policy) {
|
|
|
1247
1264
|
if (!Number.isFinite(cRate) || !Number.isFinite(pRate)) return false;
|
|
1248
1265
|
return passesRatePolicy(policy.ratePolicy, pRate, cRate);
|
|
1249
1266
|
}
|
|
1267
|
+
function getServiceCapabilityEntry(svcMap, candidate) {
|
|
1268
|
+
if (candidate === void 0 || candidate === null) return void 0;
|
|
1269
|
+
const direct = svcMap[candidate];
|
|
1270
|
+
if (direct) {
|
|
1271
|
+
return { key: String(candidate), capability: direct };
|
|
1272
|
+
}
|
|
1273
|
+
const byString = svcMap[String(candidate)];
|
|
1274
|
+
if (byString) {
|
|
1275
|
+
return { key: String(candidate), capability: byString };
|
|
1276
|
+
}
|
|
1277
|
+
if (typeof candidate === "string") {
|
|
1278
|
+
const maybeNumber = Number(candidate);
|
|
1279
|
+
if (Number.isFinite(maybeNumber)) {
|
|
1280
|
+
const byNumber = svcMap[maybeNumber];
|
|
1281
|
+
if (byNumber) {
|
|
1282
|
+
return { key: String(maybeNumber), capability: byNumber };
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
const target = String(candidate);
|
|
1287
|
+
for (const [key, capability] of Object.entries(svcMap != null ? svcMap : {})) {
|
|
1288
|
+
if (collectServiceRefAliases(key, capability).some(
|
|
1289
|
+
(alias) => String(alias) === target
|
|
1290
|
+
)) {
|
|
1291
|
+
return { key, capability };
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
return void 0;
|
|
1295
|
+
}
|
|
1296
|
+
function collectServiceRefAliases(key, capability) {
|
|
1297
|
+
const out = [];
|
|
1298
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1299
|
+
const push = (value) => {
|
|
1300
|
+
if (!isValidServiceIdRef(value)) return;
|
|
1301
|
+
const normalized = normalizeServiceRef(value);
|
|
1302
|
+
if (!normalized) return;
|
|
1303
|
+
const aliasKey = String(normalized);
|
|
1304
|
+
if (seen.has(aliasKey)) return;
|
|
1305
|
+
seen.add(aliasKey);
|
|
1306
|
+
out.push(normalized);
|
|
1307
|
+
};
|
|
1308
|
+
push(getCanonicalServiceRef(key, capability));
|
|
1309
|
+
push(capability.service);
|
|
1310
|
+
push(capability.key);
|
|
1311
|
+
push(capability.id);
|
|
1312
|
+
return out;
|
|
1313
|
+
}
|
|
1314
|
+
function getCanonicalServiceRef(key, capability) {
|
|
1315
|
+
const explicitRefs = [capability.service, capability.key, capability.id];
|
|
1316
|
+
for (const ref of explicitRefs) {
|
|
1317
|
+
if (!isValidServiceIdRef(ref)) continue;
|
|
1318
|
+
if (String(ref) === key) {
|
|
1319
|
+
return ref;
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
return normalizeServiceRef(key);
|
|
1323
|
+
}
|
|
1324
|
+
function normalizeServiceRef(value) {
|
|
1325
|
+
if (!isValidServiceIdRef(value)) return void 0;
|
|
1326
|
+
if (typeof value === "number") return value;
|
|
1327
|
+
const trimmed = value.trim();
|
|
1328
|
+
if (!trimmed) return void 0;
|
|
1329
|
+
const asNumber = Number(trimmed);
|
|
1330
|
+
if (Number.isFinite(asNumber) && String(asNumber) === trimmed) {
|
|
1331
|
+
return asNumber;
|
|
1332
|
+
}
|
|
1333
|
+
return trimmed;
|
|
1334
|
+
}
|
|
1250
1335
|
|
|
1251
1336
|
// src/core/validate/steps/rates.ts
|
|
1252
1337
|
function validateRates(v) {
|
|
@@ -2699,27 +2784,42 @@ var DEFAULT_SETTINGS = {
|
|
|
2699
2784
|
mode: "strict"
|
|
2700
2785
|
};
|
|
2701
2786
|
function resolveServiceFallback(params) {
|
|
2702
|
-
var _a, _b
|
|
2787
|
+
var _a, _b;
|
|
2703
2788
|
const s = { ...DEFAULT_SETTINGS, ...(_a = params.settings) != null ? _a : {} };
|
|
2704
2789
|
const { primary, nodeId, tagId, services } = params;
|
|
2705
|
-
const
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2790
|
+
const fallbackLists = listRegisteredFallbackCandidates(
|
|
2791
|
+
(_b = params.fallbacks) != null ? _b : {},
|
|
2792
|
+
primary,
|
|
2793
|
+
nodeId,
|
|
2794
|
+
services
|
|
2795
|
+
);
|
|
2796
|
+
const tried = /* @__PURE__ */ new Set();
|
|
2710
2797
|
const primaryRate = rateOf(services, primary);
|
|
2711
|
-
for (const list of
|
|
2712
|
-
for (const
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
if (
|
|
2798
|
+
for (const list of fallbackLists) {
|
|
2799
|
+
for (const candidate of list) {
|
|
2800
|
+
const candidateIdentity = getComparableServiceRefKey(
|
|
2801
|
+
services,
|
|
2802
|
+
candidate
|
|
2803
|
+
);
|
|
2804
|
+
if (tried.has(candidateIdentity)) continue;
|
|
2805
|
+
tried.add(candidateIdentity);
|
|
2806
|
+
const capability = getCap(services, candidate);
|
|
2807
|
+
if (!capability) continue;
|
|
2808
|
+
if (isSameServiceCapabilityRef(services, candidate, primary)) {
|
|
2809
|
+
continue;
|
|
2810
|
+
}
|
|
2811
|
+
if (!passesRate(s.ratePolicy, primaryRate, capability.rate)) {
|
|
2812
|
+
continue;
|
|
2813
|
+
}
|
|
2718
2814
|
if (s.requireConstraintFit && tagId) {
|
|
2719
|
-
const
|
|
2720
|
-
|
|
2815
|
+
const fitsConstraints = satisfiesTagConstraints(
|
|
2816
|
+
tagId,
|
|
2817
|
+
params,
|
|
2818
|
+
capability
|
|
2819
|
+
);
|
|
2820
|
+
if (!fitsConstraints) continue;
|
|
2721
2821
|
}
|
|
2722
|
-
return
|
|
2822
|
+
return candidate;
|
|
2723
2823
|
}
|
|
2724
2824
|
}
|
|
2725
2825
|
return null;
|
|
@@ -2729,7 +2829,7 @@ function collectFailedFallbacks(props, services, settings) {
|
|
|
2729
2829
|
const s = { ...DEFAULT_SETTINGS, ...settings != null ? settings : {} };
|
|
2730
2830
|
const out = [];
|
|
2731
2831
|
const fb = (_a = props.fallbacks) != null ? _a : {};
|
|
2732
|
-
const primaryRate = (
|
|
2832
|
+
const primaryRate = (primary) => rateOf(services, primary);
|
|
2733
2833
|
for (const [nodeId, list] of Object.entries((_b = fb.nodes) != null ? _b : {})) {
|
|
2734
2834
|
const { primary, tagContexts } = primaryForNode(props, nodeId);
|
|
2735
2835
|
if (!primary) {
|
|
@@ -2742,34 +2842,34 @@ function collectFailedFallbacks(props, services, settings) {
|
|
|
2742
2842
|
});
|
|
2743
2843
|
continue;
|
|
2744
2844
|
}
|
|
2745
|
-
for (const
|
|
2746
|
-
const
|
|
2747
|
-
if (!
|
|
2845
|
+
for (const candidate of list) {
|
|
2846
|
+
const capability = getCap(services, candidate);
|
|
2847
|
+
if (!capability) {
|
|
2748
2848
|
out.push({
|
|
2749
2849
|
scope: "node",
|
|
2750
2850
|
nodeId,
|
|
2751
2851
|
primary,
|
|
2752
|
-
candidate
|
|
2852
|
+
candidate,
|
|
2753
2853
|
reason: "unknown_service"
|
|
2754
2854
|
});
|
|
2755
2855
|
continue;
|
|
2756
2856
|
}
|
|
2757
|
-
if (
|
|
2857
|
+
if (isSameServiceCapabilityRef(services, candidate, primary)) {
|
|
2758
2858
|
out.push({
|
|
2759
2859
|
scope: "node",
|
|
2760
2860
|
nodeId,
|
|
2761
2861
|
primary,
|
|
2762
|
-
candidate
|
|
2862
|
+
candidate,
|
|
2763
2863
|
reason: "cycle"
|
|
2764
2864
|
});
|
|
2765
2865
|
continue;
|
|
2766
2866
|
}
|
|
2767
|
-
if (!passesRate(s.ratePolicy, primaryRate(primary),
|
|
2867
|
+
if (!passesRate(s.ratePolicy, primaryRate(primary), capability.rate)) {
|
|
2768
2868
|
out.push({
|
|
2769
2869
|
scope: "node",
|
|
2770
2870
|
nodeId,
|
|
2771
2871
|
primary,
|
|
2772
|
-
candidate
|
|
2872
|
+
candidate,
|
|
2773
2873
|
reason: "rate_violation"
|
|
2774
2874
|
});
|
|
2775
2875
|
continue;
|
|
@@ -2779,58 +2879,55 @@ function collectFailedFallbacks(props, services, settings) {
|
|
|
2779
2879
|
scope: "node",
|
|
2780
2880
|
nodeId,
|
|
2781
2881
|
primary,
|
|
2782
|
-
candidate
|
|
2882
|
+
candidate,
|
|
2783
2883
|
reason: "no_tag_context"
|
|
2784
2884
|
});
|
|
2785
2885
|
continue;
|
|
2786
2886
|
}
|
|
2787
|
-
let anyPass = false;
|
|
2788
|
-
let anyFail = false;
|
|
2789
2887
|
for (const tagId of tagContexts) {
|
|
2790
|
-
const
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2888
|
+
const fitsConstraints = s.requireConstraintFit ? satisfiesTagConstraints(
|
|
2889
|
+
tagId,
|
|
2890
|
+
{ services, props },
|
|
2891
|
+
capability
|
|
2892
|
+
) : true;
|
|
2893
|
+
if (fitsConstraints) continue;
|
|
2894
|
+
out.push({
|
|
2895
|
+
scope: "node",
|
|
2896
|
+
nodeId,
|
|
2897
|
+
primary,
|
|
2898
|
+
candidate,
|
|
2899
|
+
tagContext: tagId,
|
|
2900
|
+
reason: "constraint_mismatch"
|
|
2901
|
+
});
|
|
2803
2902
|
}
|
|
2804
|
-
void anyPass;
|
|
2805
|
-
void anyFail;
|
|
2806
2903
|
}
|
|
2807
2904
|
}
|
|
2808
2905
|
for (const [primary, list] of Object.entries((_c = fb.global) != null ? _c : {})) {
|
|
2809
|
-
for (const
|
|
2810
|
-
const
|
|
2811
|
-
if (!
|
|
2906
|
+
for (const candidate of list) {
|
|
2907
|
+
const capability = getCap(services, candidate);
|
|
2908
|
+
if (!capability) {
|
|
2812
2909
|
out.push({
|
|
2813
2910
|
scope: "global",
|
|
2814
2911
|
primary,
|
|
2815
|
-
candidate
|
|
2912
|
+
candidate,
|
|
2816
2913
|
reason: "unknown_service"
|
|
2817
2914
|
});
|
|
2818
2915
|
continue;
|
|
2819
2916
|
}
|
|
2820
|
-
if (
|
|
2917
|
+
if (isSameServiceCapabilityRef(services, candidate, primary)) {
|
|
2821
2918
|
out.push({
|
|
2822
2919
|
scope: "global",
|
|
2823
2920
|
primary,
|
|
2824
|
-
candidate
|
|
2921
|
+
candidate,
|
|
2825
2922
|
reason: "cycle"
|
|
2826
2923
|
});
|
|
2827
2924
|
continue;
|
|
2828
2925
|
}
|
|
2829
|
-
if (!passesRate(s.ratePolicy, primaryRate(primary),
|
|
2926
|
+
if (!passesRate(s.ratePolicy, primaryRate(primary), capability.rate)) {
|
|
2830
2927
|
out.push({
|
|
2831
2928
|
scope: "global",
|
|
2832
2929
|
primary,
|
|
2833
|
-
candidate
|
|
2930
|
+
candidate,
|
|
2834
2931
|
reason: "rate_violation"
|
|
2835
2932
|
});
|
|
2836
2933
|
}
|
|
@@ -2839,52 +2936,61 @@ function collectFailedFallbacks(props, services, settings) {
|
|
|
2839
2936
|
return out;
|
|
2840
2937
|
}
|
|
2841
2938
|
function rateOf(map, id) {
|
|
2842
|
-
var _a;
|
|
2939
|
+
var _a, _b;
|
|
2843
2940
|
if (id === void 0 || id === null) return void 0;
|
|
2844
|
-
|
|
2845
|
-
return (_a = c == null ? void 0 : c.rate) != null ? _a : void 0;
|
|
2941
|
+
return (_b = (_a = getCap(map, id)) == null ? void 0 : _a.rate) != null ? _b : void 0;
|
|
2846
2942
|
}
|
|
2847
|
-
function passesRate(policy, primaryRate,
|
|
2848
|
-
if (typeof
|
|
2943
|
+
function passesRate(policy, primaryRate, candidateRate) {
|
|
2944
|
+
if (typeof candidateRate !== "number" || !Number.isFinite(candidateRate)) {
|
|
2849
2945
|
return false;
|
|
2850
|
-
|
|
2946
|
+
}
|
|
2947
|
+
if (typeof primaryRate !== "number" || !Number.isFinite(primaryRate)) {
|
|
2851
2948
|
return false;
|
|
2852
|
-
|
|
2949
|
+
}
|
|
2950
|
+
return passesRatePolicy(
|
|
2951
|
+
normalizeRatePolicy(policy),
|
|
2952
|
+
primaryRate,
|
|
2953
|
+
candidateRate
|
|
2954
|
+
);
|
|
2853
2955
|
}
|
|
2854
2956
|
function getCap(map, id) {
|
|
2855
2957
|
return getServiceCapability(map, id);
|
|
2856
2958
|
}
|
|
2857
|
-
function isCapFlagEnabled(
|
|
2959
|
+
function isCapFlagEnabled(capability, flagId) {
|
|
2858
2960
|
var _a, _b;
|
|
2859
|
-
const fromFlags = (_b = (_a =
|
|
2961
|
+
const fromFlags = (_b = (_a = capability.flags) == null ? void 0 : _a[flagId]) == null ? void 0 : _b.enabled;
|
|
2860
2962
|
if (fromFlags === true) return true;
|
|
2861
2963
|
if (fromFlags === false) return false;
|
|
2862
|
-
const legacy =
|
|
2964
|
+
const legacy = capability[flagId];
|
|
2863
2965
|
return legacy === true;
|
|
2864
2966
|
}
|
|
2865
|
-
function satisfiesTagConstraints(tagId, ctx,
|
|
2866
|
-
const tag = ctx.props.filters.find((
|
|
2867
|
-
const
|
|
2868
|
-
if (!
|
|
2869
|
-
for (const [key, value] of Object.entries(
|
|
2870
|
-
if (value === true && !isCapFlagEnabled(
|
|
2967
|
+
function satisfiesTagConstraints(tagId, ctx, capability) {
|
|
2968
|
+
const tag = ctx.props.filters.find((item) => item.id === tagId);
|
|
2969
|
+
const effectiveConstraints2 = tag == null ? void 0 : tag.constraints;
|
|
2970
|
+
if (!effectiveConstraints2) return true;
|
|
2971
|
+
for (const [key, value] of Object.entries(effectiveConstraints2)) {
|
|
2972
|
+
if (value === true && !isCapFlagEnabled(capability, key)) {
|
|
2871
2973
|
return false;
|
|
2872
2974
|
}
|
|
2873
2975
|
}
|
|
2874
2976
|
return true;
|
|
2875
2977
|
}
|
|
2876
2978
|
function primaryForNode(props, nodeId) {
|
|
2877
|
-
const tag = props.filters.find((
|
|
2979
|
+
const tag = props.filters.find((item) => item.id === nodeId);
|
|
2878
2980
|
if (tag) {
|
|
2879
2981
|
return { primary: tag.service_id, tagContexts: [tag.id] };
|
|
2880
2982
|
}
|
|
2881
2983
|
const field = props.fields.find(
|
|
2882
|
-
(
|
|
2984
|
+
(item) => Array.isArray(item.options) && item.options.some((option2) => option2.id === nodeId)
|
|
2883
2985
|
);
|
|
2884
|
-
if (!field)
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2986
|
+
if (!field) {
|
|
2987
|
+
return { tagContexts: [], reasonNoPrimary: "no_parent_field" };
|
|
2988
|
+
}
|
|
2989
|
+
const option = field.options.find((item) => item.id === nodeId);
|
|
2990
|
+
return {
|
|
2991
|
+
primary: option.service_id,
|
|
2992
|
+
tagContexts: bindIdsToArray(field.bind_id)
|
|
2993
|
+
};
|
|
2888
2994
|
}
|
|
2889
2995
|
function bindIdsToArray(bind) {
|
|
2890
2996
|
if (!bind) return [];
|
|
@@ -2894,43 +3000,54 @@ function getEligibleFallbacks(params) {
|
|
|
2894
3000
|
var _a, _b, _c, _d, _e, _f;
|
|
2895
3001
|
const s = { ...DEFAULT_SETTINGS, ...(_a = params.settings) != null ? _a : {} };
|
|
2896
3002
|
const { primary, nodeId, tagId, services } = params;
|
|
2897
|
-
const
|
|
2898
|
-
const
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
3003
|
+
const excludes = /* @__PURE__ */ new Set();
|
|
3004
|
+
for (const ref of (_b = params.exclude) != null ? _b : []) {
|
|
3005
|
+
addComparableServiceRef(excludes, services, ref);
|
|
3006
|
+
}
|
|
3007
|
+
addComparableServiceRef(excludes, services, primary);
|
|
3008
|
+
const source = (_c = params.source) != null ? _c : "registered";
|
|
3009
|
+
const candidateLists = source === "all_services" ? [listServicePoolCandidates(services)] : listRegisteredFallbackCandidates(
|
|
3010
|
+
(_d = params.fallbacks) != null ? _d : {},
|
|
3011
|
+
primary,
|
|
3012
|
+
nodeId,
|
|
3013
|
+
services
|
|
3014
|
+
);
|
|
3015
|
+
if (!candidateLists.length) return [];
|
|
2905
3016
|
const primaryRate = rateOf(services, primary);
|
|
2906
3017
|
const seen = /* @__PURE__ */ new Set();
|
|
2907
3018
|
const eligible = [];
|
|
2908
|
-
for (const list of
|
|
2909
|
-
for (const
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
if (
|
|
2913
|
-
|
|
2914
|
-
const
|
|
2915
|
-
|
|
2916
|
-
|
|
3019
|
+
for (const list of candidateLists) {
|
|
3020
|
+
for (const candidate of list) {
|
|
3021
|
+
if (hasComparableServiceRef(excludes, services, candidate)) continue;
|
|
3022
|
+
const capability = getCap(services, candidate);
|
|
3023
|
+
if (!capability) continue;
|
|
3024
|
+
const candidateId = (_e = getServiceCapabilityCanonicalRef(services, candidate)) != null ? _e : candidate;
|
|
3025
|
+
const candidateIdentity = getComparableServiceRefKey(
|
|
3026
|
+
services,
|
|
3027
|
+
candidateId
|
|
3028
|
+
);
|
|
3029
|
+
if (((_f = params.unique) != null ? _f : true) && seen.has(candidateIdentity)) continue;
|
|
3030
|
+
seen.add(candidateIdentity);
|
|
3031
|
+
if (!passesRate(s.ratePolicy, primaryRate, capability.rate)) {
|
|
3032
|
+
continue;
|
|
3033
|
+
}
|
|
2917
3034
|
if (s.requireConstraintFit && tagId) {
|
|
2918
|
-
const
|
|
3035
|
+
const fitsConstraints = satisfiesTagConstraints(
|
|
2919
3036
|
tagId,
|
|
2920
3037
|
{ props: params.props, services },
|
|
2921
|
-
|
|
3038
|
+
capability
|
|
2922
3039
|
);
|
|
2923
|
-
if (!
|
|
3040
|
+
if (!fitsConstraints) continue;
|
|
2924
3041
|
}
|
|
2925
|
-
eligible.push(
|
|
3042
|
+
eligible.push(candidateId);
|
|
2926
3043
|
}
|
|
2927
3044
|
}
|
|
2928
3045
|
if (s.selectionStrategy === "cheapest") {
|
|
2929
|
-
eligible.sort((
|
|
3046
|
+
eligible.sort((left, right) => {
|
|
2930
3047
|
var _a2, _b2;
|
|
2931
|
-
const
|
|
2932
|
-
const
|
|
2933
|
-
return
|
|
3048
|
+
const leftRate = (_a2 = rateOf(services, left)) != null ? _a2 : Infinity;
|
|
3049
|
+
const rightRate = (_b2 = rateOf(services, right)) != null ? _b2 : Infinity;
|
|
3050
|
+
return leftRate - rightRate;
|
|
2934
3051
|
});
|
|
2935
3052
|
}
|
|
2936
3053
|
if (typeof params.limit === "number" && params.limit >= 0) {
|
|
@@ -2938,10 +3055,104 @@ function getEligibleFallbacks(params) {
|
|
|
2938
3055
|
}
|
|
2939
3056
|
return eligible;
|
|
2940
3057
|
}
|
|
3058
|
+
function getAssignedServiceIds(params) {
|
|
3059
|
+
var _a, _b, _c, _d, _e;
|
|
3060
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3061
|
+
const out = [];
|
|
3062
|
+
const push = (value) => {
|
|
3063
|
+
if (!isValidServiceIdRef(value)) return;
|
|
3064
|
+
const key = String(value);
|
|
3065
|
+
if (seen.has(key)) return;
|
|
3066
|
+
seen.add(key);
|
|
3067
|
+
out.push(value);
|
|
3068
|
+
};
|
|
3069
|
+
const props = params.props;
|
|
3070
|
+
if (props) {
|
|
3071
|
+
for (const tag of (_a = props.filters) != null ? _a : []) {
|
|
3072
|
+
push(tag.service_id);
|
|
3073
|
+
}
|
|
3074
|
+
for (const field of (_b = props.fields) != null ? _b : []) {
|
|
3075
|
+
const fieldService = field.service_id;
|
|
3076
|
+
if (field.button === true) {
|
|
3077
|
+
push(fieldService);
|
|
3078
|
+
}
|
|
3079
|
+
for (const option of (_c = field.options) != null ? _c : []) {
|
|
3080
|
+
if (option.pricing_role === "utility") continue;
|
|
3081
|
+
push(option.service_id);
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
const snapshot = params.snapshot;
|
|
3086
|
+
if (snapshot) {
|
|
3087
|
+
for (const serviceId of (_d = snapshot.services) != null ? _d : []) {
|
|
3088
|
+
push(serviceId);
|
|
3089
|
+
}
|
|
3090
|
+
for (const list of Object.values((_e = snapshot.serviceMap) != null ? _e : {})) {
|
|
3091
|
+
for (const serviceId of list != null ? list : []) {
|
|
3092
|
+
push(serviceId);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
return out;
|
|
3097
|
+
}
|
|
2941
3098
|
function getFallbackRegistrationInfo(props, nodeId) {
|
|
2942
3099
|
const { primary, tagContexts } = primaryForNode(props, nodeId);
|
|
2943
3100
|
return { primary, tagContexts };
|
|
2944
3101
|
}
|
|
3102
|
+
function listRegisteredFallbackCandidates(fallbacks, primary, nodeId, services) {
|
|
3103
|
+
var _a, _b;
|
|
3104
|
+
const lists = [];
|
|
3105
|
+
if (nodeId && ((_a = fallbacks.nodes) == null ? void 0 : _a[nodeId])) {
|
|
3106
|
+
lists.push(fallbacks.nodes[nodeId]);
|
|
3107
|
+
}
|
|
3108
|
+
for (const [registeredPrimary, list] of Object.entries((_b = fallbacks.global) != null ? _b : {})) {
|
|
3109
|
+
if (!isMatchingServiceRef(services, registeredPrimary, primary)) continue;
|
|
3110
|
+
lists.push(list);
|
|
3111
|
+
}
|
|
3112
|
+
return lists;
|
|
3113
|
+
}
|
|
3114
|
+
function listServicePoolCandidates(services) {
|
|
3115
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3116
|
+
const out = [];
|
|
3117
|
+
for (const [key, capability] of Object.entries(services != null ? services : {})) {
|
|
3118
|
+
const candidate = getServicePoolCandidateId(key, capability);
|
|
3119
|
+
if (!isValidServiceIdRef(candidate)) continue;
|
|
3120
|
+
const identity = getComparableServiceRefKey(services, candidate);
|
|
3121
|
+
if (seen.has(identity)) continue;
|
|
3122
|
+
seen.add(identity);
|
|
3123
|
+
out.push(candidate);
|
|
3124
|
+
}
|
|
3125
|
+
return out;
|
|
3126
|
+
}
|
|
3127
|
+
function getServicePoolCandidateId(key, capability) {
|
|
3128
|
+
var _a;
|
|
3129
|
+
return (_a = getServiceCapabilityCanonicalRef({ [key]: capability }, key)) != null ? _a : key;
|
|
3130
|
+
}
|
|
3131
|
+
function addComparableServiceRef(target, services, value) {
|
|
3132
|
+
for (const ref of getComparableServiceRefs(services, value)) {
|
|
3133
|
+
target.add(ref);
|
|
3134
|
+
}
|
|
3135
|
+
}
|
|
3136
|
+
function hasComparableServiceRef(target, services, value) {
|
|
3137
|
+
return getComparableServiceRefs(services, value).some((ref) => target.has(ref));
|
|
3138
|
+
}
|
|
3139
|
+
function getComparableServiceRefKey(services, value) {
|
|
3140
|
+
if (!isValidServiceIdRef(value)) return "";
|
|
3141
|
+
const canonical = getServiceCapabilityCanonicalRef(services, value);
|
|
3142
|
+
return String(canonical != null ? canonical : value);
|
|
3143
|
+
}
|
|
3144
|
+
function getComparableServiceRefs(services, value) {
|
|
3145
|
+
if (!isValidServiceIdRef(value)) return [];
|
|
3146
|
+
const aliases = getServiceCapabilityAliases(services, value);
|
|
3147
|
+
if (!aliases.length) {
|
|
3148
|
+
return [String(value)];
|
|
3149
|
+
}
|
|
3150
|
+
return aliases.map((ref) => String(ref));
|
|
3151
|
+
}
|
|
3152
|
+
function isMatchingServiceRef(services, left, right) {
|
|
3153
|
+
if (!services) return String(left) === String(right);
|
|
3154
|
+
return isSameServiceCapabilityRef(services, left, right);
|
|
3155
|
+
}
|
|
2945
3156
|
|
|
2946
3157
|
// src/core/tag-relations.ts
|
|
2947
3158
|
var toId = (x) => typeof x === "string" ? x : x.id;
|
|
@@ -4480,6 +4691,7 @@ function createFallbackEditor(options = {}) {
|
|
|
4480
4691
|
const original = cloneFallbacks(options.fallbacks);
|
|
4481
4692
|
let current = cloneFallbacks(options.fallbacks);
|
|
4482
4693
|
const props = options.props;
|
|
4694
|
+
const snapshot = options.snapshot;
|
|
4483
4695
|
const services = (_a = options.services) != null ? _a : {};
|
|
4484
4696
|
const settings = (_b = options.settings) != null ? _b : {};
|
|
4485
4697
|
function state() {
|
|
@@ -4574,7 +4786,11 @@ function createFallbackEditor(options = {}) {
|
|
|
4574
4786
|
const allowed2 = [];
|
|
4575
4787
|
for (const candidate of normalized) {
|
|
4576
4788
|
const reasons = [];
|
|
4577
|
-
if (
|
|
4789
|
+
if (isSameServiceCapabilityRef(
|
|
4790
|
+
services,
|
|
4791
|
+
candidate,
|
|
4792
|
+
context.primary
|
|
4793
|
+
)) {
|
|
4578
4794
|
reasons.push("self_reference");
|
|
4579
4795
|
}
|
|
4580
4796
|
if (reasons.length) {
|
|
@@ -4662,7 +4878,19 @@ function createFallbackEditor(options = {}) {
|
|
|
4662
4878
|
return writeScope(context, []);
|
|
4663
4879
|
}
|
|
4664
4880
|
function eligible(context, opt) {
|
|
4881
|
+
var _a2, _b2;
|
|
4665
4882
|
if (!props) return [];
|
|
4883
|
+
const source = (_a2 = opt == null ? void 0 : opt.source) != null ? _a2 : "all_services";
|
|
4884
|
+
const exclude = normalizeCandidateList(
|
|
4885
|
+
[
|
|
4886
|
+
...(_b2 = opt == null ? void 0 : opt.exclude) != null ? _b2 : [],
|
|
4887
|
+
...source === "all_services" ? [
|
|
4888
|
+
...getAssignedServiceIds({ props, snapshot }),
|
|
4889
|
+
...getScope(context)
|
|
4890
|
+
] : []
|
|
4891
|
+
],
|
|
4892
|
+
true
|
|
4893
|
+
);
|
|
4666
4894
|
if (context.scope === "global") {
|
|
4667
4895
|
return getEligibleFallbacks({
|
|
4668
4896
|
primary: context.primary,
|
|
@@ -4670,9 +4898,10 @@ function createFallbackEditor(options = {}) {
|
|
|
4670
4898
|
fallbacks: current,
|
|
4671
4899
|
settings,
|
|
4672
4900
|
props,
|
|
4673
|
-
exclude
|
|
4901
|
+
exclude,
|
|
4674
4902
|
unique: opt == null ? void 0 : opt.unique,
|
|
4675
|
-
limit: opt == null ? void 0 : opt.limit
|
|
4903
|
+
limit: opt == null ? void 0 : opt.limit,
|
|
4904
|
+
source
|
|
4676
4905
|
});
|
|
4677
4906
|
}
|
|
4678
4907
|
const info = getFallbackRegistrationInfo(props, context.nodeId);
|
|
@@ -4680,14 +4909,19 @@ function createFallbackEditor(options = {}) {
|
|
|
4680
4909
|
return getEligibleFallbacks({
|
|
4681
4910
|
primary: info.primary,
|
|
4682
4911
|
nodeId: context.nodeId,
|
|
4683
|
-
tagId:
|
|
4912
|
+
tagId: resolveNodeTagContext({
|
|
4913
|
+
nodeId: context.nodeId,
|
|
4914
|
+
snapshot,
|
|
4915
|
+
fallbackTagContexts: info.tagContexts
|
|
4916
|
+
}),
|
|
4684
4917
|
services,
|
|
4685
4918
|
fallbacks: current,
|
|
4686
4919
|
settings,
|
|
4687
4920
|
props,
|
|
4688
|
-
exclude
|
|
4921
|
+
exclude,
|
|
4689
4922
|
unique: opt == null ? void 0 : opt.unique,
|
|
4690
|
-
limit: opt == null ? void 0 : opt.limit
|
|
4923
|
+
limit: opt == null ? void 0 : opt.limit,
|
|
4924
|
+
source
|
|
4691
4925
|
});
|
|
4692
4926
|
}
|
|
4693
4927
|
function writeScope(context, nextList) {
|
|
@@ -4745,14 +4979,14 @@ function sameFallbacks(a, b) {
|
|
|
4745
4979
|
function normalizeCandidateList(input, preserveOrder) {
|
|
4746
4980
|
const out = [];
|
|
4747
4981
|
for (const item of input != null ? input : []) {
|
|
4748
|
-
if (!
|
|
4982
|
+
if (!isValidServiceIdRef2(item)) continue;
|
|
4749
4983
|
const exists = out.some((x) => String(x) === String(item));
|
|
4750
4984
|
if (exists) continue;
|
|
4751
4985
|
out.push(item);
|
|
4752
4986
|
}
|
|
4753
4987
|
return preserveOrder ? out : out;
|
|
4754
4988
|
}
|
|
4755
|
-
function
|
|
4989
|
+
function isValidServiceIdRef2(value) {
|
|
4756
4990
|
return typeof value === "number" && Number.isFinite(value) || typeof value === "string" && value.trim().length > 0;
|
|
4757
4991
|
}
|
|
4758
4992
|
function clamp(n, min, max) {
|
|
@@ -4761,7 +4995,7 @@ function clamp(n, min, max) {
|
|
|
4761
4995
|
function getNodeRegistrationInfo(props, nodeId) {
|
|
4762
4996
|
const tag = props.filters.find((t) => t.id === nodeId);
|
|
4763
4997
|
if (tag) {
|
|
4764
|
-
if (!
|
|
4998
|
+
if (!isValidServiceIdRef2(tag.service_id)) {
|
|
4765
4999
|
return { ok: false, reasons: ["no_primary"] };
|
|
4766
5000
|
}
|
|
4767
5001
|
return {
|
|
@@ -4774,7 +5008,7 @@ function getNodeRegistrationInfo(props, nodeId) {
|
|
|
4774
5008
|
if (!hit) {
|
|
4775
5009
|
return { ok: false, reasons: ["node_not_found"] };
|
|
4776
5010
|
}
|
|
4777
|
-
if (!
|
|
5011
|
+
if (!isValidServiceIdRef2(hit.option.service_id)) {
|
|
4778
5012
|
return { ok: false, reasons: ["no_primary"] };
|
|
4779
5013
|
}
|
|
4780
5014
|
return {
|
|
@@ -4796,6 +5030,15 @@ function bindIdsToArray2(v) {
|
|
|
4796
5030
|
if (Array.isArray(v)) return v.filter(Boolean);
|
|
4797
5031
|
return v ? [v] : [];
|
|
4798
5032
|
}
|
|
5033
|
+
function resolveNodeTagContext(params) {
|
|
5034
|
+
var _a, _b, _c;
|
|
5035
|
+
const nodeContexts = (_c = (_b = (_a = params.snapshot) == null ? void 0 : _a.meta) == null ? void 0 : _b.context) == null ? void 0 : _c.nodeContexts;
|
|
5036
|
+
if (nodeContexts && Object.prototype.hasOwnProperty.call(nodeContexts, params.nodeId)) {
|
|
5037
|
+
const tagId = nodeContexts[params.nodeId];
|
|
5038
|
+
return typeof tagId === "string" && tagId.trim().length > 0 ? tagId : void 0;
|
|
5039
|
+
}
|
|
5040
|
+
return params.fallbackTagContexts[0];
|
|
5041
|
+
}
|
|
4799
5042
|
function mapDiagReason(reason) {
|
|
4800
5043
|
switch (String(reason)) {
|
|
4801
5044
|
case "unknown_service":
|
|
@@ -4821,6 +5064,7 @@ export {
|
|
|
4821
5064
|
createFallbackEditor,
|
|
4822
5065
|
createNodeIndex,
|
|
4823
5066
|
filterServicesForVisibleGroup,
|
|
5067
|
+
getAssignedServiceIds,
|
|
4824
5068
|
getEligibleFallbacks,
|
|
4825
5069
|
getFallbackRegistrationInfo,
|
|
4826
5070
|
normalise,
|