@vritti/api-sdk 0.3.3 → 0.3.6
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/auth.cjs +942 -0
- package/dist/auth.cjs.map +1 -0
- package/dist/auth.d.cts +95 -0
- package/dist/auth.d.ts +95 -0
- package/dist/auth.js +884 -0
- package/dist/auth.js.map +1 -0
- package/dist/cache.cjs +182 -14
- package/dist/cache.cjs.map +1 -1
- package/dist/cache.d.cts +48 -4
- package/dist/cache.d.ts +48 -4
- package/dist/cache.js +177 -12
- package/dist/cache.js.map +1 -1
- package/dist/catalog-resolver.cjs +337 -140
- package/dist/catalog-resolver.cjs.map +1 -1
- package/dist/catalog-resolver.d.cts +70 -45
- package/dist/catalog-resolver.d.ts +70 -45
- package/dist/catalog-resolver.js +322 -135
- package/dist/catalog-resolver.js.map +1 -1
- package/dist/code-pattern-BP4zkNtT.d.cts +12 -0
- package/dist/code-pattern-BP4zkNtT.d.ts +12 -0
- package/dist/context.cjs +93 -0
- package/dist/context.cjs.map +1 -0
- package/dist/context.d.cts +19 -0
- package/dist/context.d.ts +19 -0
- package/dist/context.js +64 -0
- package/dist/context.js.map +1 -0
- package/dist/countries.cjs +1559 -0
- package/dist/countries.cjs.map +1 -0
- package/dist/countries.d.cts +13 -0
- package/dist/countries.d.ts +13 -0
- package/dist/countries.js +1532 -0
- package/dist/countries.js.map +1 -0
- package/dist/data-table.cjs +1280 -0
- package/dist/data-table.cjs.map +1 -0
- package/dist/data-table.d.cts +123 -0
- package/dist/data-table.d.ts +123 -0
- package/dist/data-table.js +1260 -0
- package/dist/data-table.js.map +1 -0
- package/dist/database.cjs +1510 -0
- package/dist/database.cjs.map +1 -0
- package/dist/database.d.cts +287 -0
- package/dist/database.d.ts +287 -0
- package/dist/database.js +1469 -0
- package/dist/database.js.map +1 -0
- package/dist/decimal.d.cts +0 -1
- package/dist/decimal.d.ts +0 -1
- package/dist/decorators.cjs +1817 -0
- package/dist/decorators.cjs.map +1 -0
- package/dist/decorators.d.cts +24 -0
- package/dist/decorators.d.ts +24 -0
- package/dist/decorators.js +1780 -0
- package/dist/decorators.js.map +1 -0
- package/dist/drizzle-pg-core.cjs +25 -0
- package/dist/drizzle-pg-core.cjs.map +1 -1
- package/dist/drizzle-pg-core.d.cts +7 -0
- package/dist/drizzle-pg-core.d.ts +7 -0
- package/dist/drizzle-pg-core.js +22 -0
- package/dist/drizzle-pg-core.js.map +1 -1
- package/dist/exceptions.cjs +301 -0
- package/dist/exceptions.cjs.map +1 -0
- package/dist/exceptions.d.cts +90 -0
- package/dist/exceptions.d.ts +90 -0
- package/dist/exceptions.js +257 -0
- package/dist/exceptions.js.map +1 -0
- package/dist/filter.types-PuARU9XD.d.cts +50 -0
- package/dist/filter.types-PuARU9XD.d.ts +50 -0
- package/dist/filters.cjs +407 -0
- package/dist/filters.cjs.map +1 -0
- package/dist/filters.d.cts +55 -0
- package/dist/filters.d.ts +55 -0
- package/dist/filters.js +377 -0
- package/dist/filters.js.map +1 -0
- package/dist/index.cjs +0 -5423
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -854
- package/dist/index.d.ts +93 -854
- package/dist/index.js +0 -5301
- package/dist/index.js.map +1 -1
- package/dist/is-country.decorator-CcNwSSr5.d.cts +5 -0
- package/dist/is-country.decorator-CcNwSSr5.d.ts +5 -0
- package/dist/license.d.cts +1 -1
- package/dist/license.d.ts +1 -1
- package/dist/lodash.cjs.map +1 -1
- package/dist/lodash.js.map +1 -1
- package/dist/logger.cjs +862 -0
- package/dist/logger.cjs.map +1 -0
- package/dist/logger.d.cts +118 -0
- package/dist/logger.d.ts +118 -0
- package/dist/logger.js +816 -0
- package/dist/logger.js.map +1 -0
- package/dist/migrate.cjs +2 -2
- package/dist/migrate.cjs.map +1 -1
- package/dist/migrate.d.cts +2 -0
- package/dist/migrate.d.ts +2 -0
- package/dist/migrate.js +2 -2
- package/dist/migrate.js.map +1 -1
- package/dist/money.cjs +18 -3
- package/dist/money.cjs.map +1 -1
- package/dist/money.d.cts +13 -13
- package/dist/money.d.ts +13 -13
- package/dist/money.js +18 -3
- package/dist/money.js.map +1 -1
- package/dist/nats.cjs +34 -35
- package/dist/nats.cjs.map +1 -1
- package/dist/nats.d.cts +14 -14
- package/dist/nats.d.ts +14 -14
- package/dist/nats.js +32 -33
- package/dist/nats.js.map +1 -1
- package/dist/root.cjs +225 -0
- package/dist/root.cjs.map +1 -0
- package/dist/root.d.cts +4 -0
- package/dist/root.d.ts +4 -0
- package/dist/root.js +200 -0
- package/dist/root.js.map +1 -0
- package/dist/{types-DQRwj5rr.d.cts → types-BBK6MG-U.d.cts} +37 -6
- package/dist/{types-DQRwj5rr.d.ts → types-BBK6MG-U.d.ts} +37 -6
- package/dist/types.cjs +19 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +17 -0
- package/dist/types.d.ts +17 -0
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.cjs +273 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +8 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.js +245 -0
- package/dist/utils.js.map +1 -0
- package/package.json +122 -1
- package/dist/cache.service-_SuJIcNA.d.cts +0 -20
- package/dist/cache.service-_SuJIcNA.d.ts +0 -20
- package/dist/fastify-augmentation-CQPBNS5a.d.cts +0 -105
- package/dist/fastify-augmentation-CQPBNS5a.d.ts +0 -105
package/dist/catalog-resolver.js
CHANGED
|
@@ -1,26 +1,130 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
3
|
|
|
4
|
+
// src/catalog-resolver/permission-deps.ts
|
|
5
|
+
function buildDependsMap(permissions) {
|
|
6
|
+
const present = new Set(permissions.map((p) => p.code));
|
|
7
|
+
const map = /* @__PURE__ */ new Map();
|
|
8
|
+
for (const p of permissions) {
|
|
9
|
+
map.set(p.code, (p.dependsOn ?? []).filter((dep) => dep !== p.code && present.has(dep)));
|
|
10
|
+
}
|
|
11
|
+
return map;
|
|
12
|
+
}
|
|
13
|
+
__name(buildDependsMap, "buildDependsMap");
|
|
14
|
+
function prereqClosure(code, deps) {
|
|
15
|
+
const out = /* @__PURE__ */ new Set();
|
|
16
|
+
const seen = /* @__PURE__ */ new Set([
|
|
17
|
+
code
|
|
18
|
+
]);
|
|
19
|
+
const stack = [
|
|
20
|
+
code
|
|
21
|
+
];
|
|
22
|
+
while (stack.length > 0) {
|
|
23
|
+
const current = stack.pop();
|
|
24
|
+
for (const dep of deps.get(current) ?? []) {
|
|
25
|
+
if (seen.has(dep)) continue;
|
|
26
|
+
seen.add(dep);
|
|
27
|
+
out.add(dep);
|
|
28
|
+
stack.push(dep);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return [
|
|
32
|
+
...out
|
|
33
|
+
];
|
|
34
|
+
}
|
|
35
|
+
__name(prereqClosure, "prereqClosure");
|
|
36
|
+
function cascadeLocked(codes, directlyLocked, deps) {
|
|
37
|
+
const locked = /* @__PURE__ */ new Set();
|
|
38
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
39
|
+
const check = /* @__PURE__ */ __name((code) => {
|
|
40
|
+
if (locked.has(code)) return true;
|
|
41
|
+
if (directlyLocked.has(code)) {
|
|
42
|
+
locked.add(code);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
if (visiting.has(code)) return false;
|
|
46
|
+
visiting.add(code);
|
|
47
|
+
const viaDep = (deps.get(code) ?? []).some(check);
|
|
48
|
+
visiting.delete(code);
|
|
49
|
+
if (viaDep) locked.add(code);
|
|
50
|
+
return viaDep;
|
|
51
|
+
}, "check");
|
|
52
|
+
for (const code of codes) check(code);
|
|
53
|
+
return locked;
|
|
54
|
+
}
|
|
55
|
+
__name(cascadeLocked, "cascadeLocked");
|
|
56
|
+
function filterGrantedByDeps(granted, deps) {
|
|
57
|
+
const ok = /* @__PURE__ */ new Set();
|
|
58
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
59
|
+
const check = /* @__PURE__ */ __name((code) => {
|
|
60
|
+
if (ok.has(code)) return true;
|
|
61
|
+
if (!granted.has(code)) return false;
|
|
62
|
+
if (visiting.has(code)) return true;
|
|
63
|
+
visiting.add(code);
|
|
64
|
+
const satisfied = (deps.get(code) ?? []).every(check);
|
|
65
|
+
visiting.delete(code);
|
|
66
|
+
if (satisfied) ok.add(code);
|
|
67
|
+
return satisfied;
|
|
68
|
+
}, "check");
|
|
69
|
+
for (const code of granted) check(code);
|
|
70
|
+
return ok;
|
|
71
|
+
}
|
|
72
|
+
__name(filterGrantedByDeps, "filterGrantedByDeps");
|
|
73
|
+
|
|
74
|
+
// src/catalog-resolver/types.ts
|
|
75
|
+
var PLATFORMS = [
|
|
76
|
+
"web",
|
|
77
|
+
"mobile"
|
|
78
|
+
];
|
|
79
|
+
var SITE_TYPES = [
|
|
80
|
+
"OUTLET",
|
|
81
|
+
"WAREHOUSE",
|
|
82
|
+
"PRODUCTION"
|
|
83
|
+
];
|
|
84
|
+
var SERVICE_CODES = [
|
|
85
|
+
"GITEA"
|
|
86
|
+
];
|
|
87
|
+
function snapshotFeatureKey(code, scope) {
|
|
88
|
+
return `${scope}.${code}`;
|
|
89
|
+
}
|
|
90
|
+
__name(snapshotFeatureKey, "snapshotFeatureKey");
|
|
91
|
+
var SNAPSHOT_SCHEMA_VERSION = 2;
|
|
92
|
+
|
|
4
93
|
// src/catalog-resolver/catalog.builder.ts
|
|
5
|
-
function
|
|
94
|
+
function featureAppliesAtNode(applicableSiteTypes, siteType) {
|
|
95
|
+
return applicableSiteTypes.includes(siteType);
|
|
96
|
+
}
|
|
97
|
+
__name(featureAppliesAtNode, "featureAppliesAtNode");
|
|
98
|
+
function findFeatureByCode(snapshot, code) {
|
|
99
|
+
for (const feature of Object.values(snapshot.features ?? {})) {
|
|
100
|
+
if (feature?.code === code) return feature;
|
|
101
|
+
}
|
|
102
|
+
return void 0;
|
|
103
|
+
}
|
|
104
|
+
__name(findFeatureByCode, "findFeatureByCode");
|
|
105
|
+
function buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices = []) {
|
|
6
106
|
if (!businessCode) return [];
|
|
7
107
|
const business = snapshot.businesses?.[businessCode];
|
|
8
108
|
if (!business) return [];
|
|
9
109
|
const plan = planCode ? business.plans?.[planCode] : void 0;
|
|
10
110
|
const plans = business.plans ?? {};
|
|
11
111
|
const catalog = [];
|
|
12
|
-
|
|
13
|
-
|
|
112
|
+
const sortedApps = [
|
|
113
|
+
...business.apps
|
|
114
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
115
|
+
for (const app of sortedApps) {
|
|
116
|
+
const businessAppFeatures = app.features.filter((ref) => scope === void 0 || ref.scope === scope).map((ref) => snapshot.features?.[snapshotFeatureKey(ref.code, ref.scope)]).filter((f) => !!f && !!(f.microfrontends?.web || f.microfrontends?.mobile) && (siteType === void 0 || featureAppliesAtNode(f.applicableSiteTypes, siteType)));
|
|
14
117
|
if (businessAppFeatures.length === 0) continue;
|
|
15
118
|
for (const feature of businessAppFeatures) {
|
|
16
119
|
const membership = plan?.unlockedPermissions?.[feature.code];
|
|
17
120
|
const web = feature.microfrontends?.web;
|
|
18
121
|
const mobile = feature.microfrontends?.mobile;
|
|
19
|
-
const permissions = buildPermissions(feature, businessCode, membership, buLocks, plans, bucket);
|
|
20
122
|
const memberOnBucket = membership?.[bucket] !== void 0;
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
123
|
+
const sitePlatformLocked = siteLocks?.[feature.code]?.[bucket] === null;
|
|
124
|
+
const missingServices = unmetServices(feature, availableServices);
|
|
125
|
+
const permissions = buildPermissions(feature, businessCode, membership, siteLocks, plans, bucket, missingServices);
|
|
126
|
+
const lockReason = resolveLockReason(!memberOnBucket, sitePlatformLocked, missingServices);
|
|
127
|
+
const locked = lockReason !== null;
|
|
24
128
|
const unlockPlans = lockReason === "PLAN" ? plansIncludingFeature(plans, feature.code, bucket) : [];
|
|
25
129
|
catalog.push({
|
|
26
130
|
code: feature.code,
|
|
@@ -46,48 +150,81 @@ function buildBuCatalog(snapshot, businessCode, planCode, buLocks, bucket) {
|
|
|
46
150
|
locked,
|
|
47
151
|
lockReason,
|
|
48
152
|
unlockPlans,
|
|
153
|
+
missingServices,
|
|
49
154
|
permissions
|
|
50
155
|
});
|
|
51
156
|
}
|
|
52
157
|
}
|
|
53
158
|
return catalog;
|
|
54
159
|
}
|
|
55
|
-
__name(
|
|
160
|
+
__name(buildSiteCatalog, "buildSiteCatalog");
|
|
56
161
|
function isPlanMember(entry) {
|
|
57
162
|
return !!entry && (entry.web !== void 0 || entry.mobile !== void 0);
|
|
58
163
|
}
|
|
59
164
|
__name(isPlanMember, "isPlanMember");
|
|
60
|
-
function
|
|
165
|
+
function resolveLockReason(planLocked, siteLocked, missingServices) {
|
|
166
|
+
if (planLocked) return "PLAN";
|
|
167
|
+
if (siteLocked) return "SITE";
|
|
168
|
+
if (missingServices.length > 0) return "SERVICE";
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
__name(resolveLockReason, "resolveLockReason");
|
|
172
|
+
function unmetServices(feature, availableServices) {
|
|
173
|
+
return (feature.requiredServices ?? []).filter((service) => !availableServices.includes(service));
|
|
174
|
+
}
|
|
175
|
+
__name(unmetServices, "unmetServices");
|
|
176
|
+
function isSiteLockedOnPlatform(entry, platform, code) {
|
|
61
177
|
const locks = entry?.[platform];
|
|
62
178
|
return locks === null || (locks?.includes(code) ?? false);
|
|
63
179
|
}
|
|
64
|
-
__name(
|
|
65
|
-
function buildPermissions(feature, businessCode, planMembership,
|
|
180
|
+
__name(isSiteLockedOnPlatform, "isSiteLockedOnPlatform");
|
|
181
|
+
function buildPermissions(feature, businessCode, planMembership, siteLocks, plans, bucket, missingServices = []) {
|
|
66
182
|
const planUnlocked = new Set(planMembership?.[bucket] ?? []);
|
|
67
|
-
const lockEntry =
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
183
|
+
const lockEntry = siteLocks?.[feature.code];
|
|
184
|
+
const perms = (feature.permissions ?? []).filter((p) => p.isGlobal || p.businesses.includes(businessCode));
|
|
185
|
+
const deps = buildDependsMap(perms);
|
|
186
|
+
const codes = perms.map((p) => p.code);
|
|
187
|
+
const directlyPlanLocked = /* @__PURE__ */ new Set();
|
|
188
|
+
const directlySiteLocked = /* @__PURE__ */ new Set();
|
|
189
|
+
for (const p of perms) {
|
|
190
|
+
if (!planUnlocked.has(p.code)) directlyPlanLocked.add(p.code);
|
|
191
|
+
if (isSiteLockedOnPlatform(lockEntry, bucket, p.code)) directlySiteLocked.add(p.code);
|
|
192
|
+
}
|
|
193
|
+
const directlyLocked = /* @__PURE__ */ new Set([
|
|
194
|
+
...directlyPlanLocked,
|
|
195
|
+
...directlySiteLocked
|
|
196
|
+
]);
|
|
197
|
+
const lockedSet = cascadeLocked(codes, directlyLocked, deps);
|
|
198
|
+
return perms.map((p) => {
|
|
199
|
+
const closure = [
|
|
200
|
+
p.code,
|
|
201
|
+
...prereqClosure(p.code, deps)
|
|
202
|
+
];
|
|
203
|
+
const cascaded = lockedSet.has(p.code);
|
|
204
|
+
const planReason = cascaded && closure.some((c) => directlyPlanLocked.has(c));
|
|
205
|
+
const siteReason = cascaded && closure.some((c) => directlySiteLocked.has(c));
|
|
206
|
+
const lockReason = resolveLockReason(planReason, siteReason, missingServices);
|
|
207
|
+
const locked = lockReason !== null;
|
|
208
|
+
const unlockPlans = lockReason === "PLAN" ? plansUnlockingClosure(plans, feature.code, closure, bucket) : [];
|
|
74
209
|
return {
|
|
75
210
|
code: p.code,
|
|
76
211
|
locked,
|
|
77
212
|
lockReason,
|
|
78
|
-
unlockPlans
|
|
213
|
+
unlockPlans,
|
|
214
|
+
missingServices
|
|
79
215
|
};
|
|
80
216
|
});
|
|
81
217
|
}
|
|
82
218
|
__name(buildPermissions, "buildPermissions");
|
|
83
|
-
function
|
|
219
|
+
function plansUnlockingClosure(plans, featureCode, closure, bucket) {
|
|
84
220
|
const result = [];
|
|
85
221
|
for (const [code, plan] of Object.entries(plans)) {
|
|
86
|
-
|
|
222
|
+
const unlocked = plan.unlockedPermissions?.[featureCode]?.[bucket];
|
|
223
|
+
if (unlocked && closure.every((c) => unlocked.includes(c))) result.push(code);
|
|
87
224
|
}
|
|
88
225
|
return result;
|
|
89
226
|
}
|
|
90
|
-
__name(
|
|
227
|
+
__name(plansUnlockingClosure, "plansUnlockingClosure");
|
|
91
228
|
function plansIncludingFeature(plans, featureCode, bucket) {
|
|
92
229
|
const result = [];
|
|
93
230
|
for (const [code, plan] of Object.entries(plans)) {
|
|
@@ -96,115 +233,13 @@ function plansIncludingFeature(plans, featureCode, bucket) {
|
|
|
96
233
|
return result;
|
|
97
234
|
}
|
|
98
235
|
__name(plansIncludingFeature, "plansIncludingFeature");
|
|
99
|
-
function
|
|
236
|
+
function buildSiteRoles(snapshot, businessCode) {
|
|
100
237
|
if (!businessCode) return [];
|
|
101
238
|
const business = snapshot.businesses?.[businessCode];
|
|
102
239
|
if (!business) return [];
|
|
103
240
|
return Object.values(business.roleTemplates ?? {});
|
|
104
241
|
}
|
|
105
|
-
__name(
|
|
106
|
-
|
|
107
|
-
// src/catalog-resolver/types.ts
|
|
108
|
-
var PLATFORMS = [
|
|
109
|
-
"web",
|
|
110
|
-
"mobile"
|
|
111
|
-
];
|
|
112
|
-
var SNAPSHOT_SCHEMA_VERSION = 1;
|
|
113
|
-
|
|
114
|
-
// src/catalog-resolver/bu-matrix.builder.ts
|
|
115
|
-
function buildBuMatrix(snapshot, businessCode, planCode, buLocks) {
|
|
116
|
-
const business = businessCode ? snapshot.businesses?.[businessCode] : void 0;
|
|
117
|
-
const plans = business?.plans ?? {};
|
|
118
|
-
const plan = planCode ? plans[planCode] : void 0;
|
|
119
|
-
const planMeta = {
|
|
120
|
-
code: planCode ?? "",
|
|
121
|
-
name: plan?.name ?? planCode ?? ""
|
|
122
|
-
};
|
|
123
|
-
const locks = buLocks ?? {};
|
|
124
|
-
if (!business || !plan) return {
|
|
125
|
-
plan: planMeta,
|
|
126
|
-
apps: [],
|
|
127
|
-
locks
|
|
128
|
-
};
|
|
129
|
-
const apps = [];
|
|
130
|
-
for (const app of business.apps) {
|
|
131
|
-
let unlockedCount = 0;
|
|
132
|
-
let totalCount = 0;
|
|
133
|
-
const features = [];
|
|
134
|
-
for (const code of app.features) {
|
|
135
|
-
const feature = snapshot.features?.[code];
|
|
136
|
-
if (!feature) continue;
|
|
137
|
-
const platforms = PLATFORMS.filter((p) => !!feature.microfrontends?.[p]);
|
|
138
|
-
if (platforms.length === 0) continue;
|
|
139
|
-
const membership = plan.unlockedPermissions?.[code];
|
|
140
|
-
const featureInPlan = isPlanMember(membership);
|
|
141
|
-
const buEntry = buLocks?.[code];
|
|
142
|
-
const permissions = (feature.permissions ?? []).filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? "")).map((p) => {
|
|
143
|
-
const cell = /* @__PURE__ */ __name((plat) => {
|
|
144
|
-
if (!platforms.includes(plat)) return null;
|
|
145
|
-
const planCodes = membership?.[plat];
|
|
146
|
-
const inPlan = featureInPlan && planCodes !== void 0 && planCodes.includes(p.code);
|
|
147
|
-
const selected = inPlan && !isBuLockedOnPlatform(buEntry, plat, p.code);
|
|
148
|
-
const availableIn = inPlan ? [] : plansUnlockingPerm(plans, code, p.code, plat, planCode);
|
|
149
|
-
totalCount += 1;
|
|
150
|
-
if (inPlan) unlockedCount += 1;
|
|
151
|
-
return {
|
|
152
|
-
inPlan,
|
|
153
|
-
selected,
|
|
154
|
-
availableIn
|
|
155
|
-
};
|
|
156
|
-
}, "cell");
|
|
157
|
-
return {
|
|
158
|
-
code: p.code,
|
|
159
|
-
label: p.label,
|
|
160
|
-
web: cell("web"),
|
|
161
|
-
mobile: cell("mobile")
|
|
162
|
-
};
|
|
163
|
-
});
|
|
164
|
-
features.push({
|
|
165
|
-
code: feature.code,
|
|
166
|
-
name: feature.name,
|
|
167
|
-
icon: feature.lucideIcon ?? null,
|
|
168
|
-
platforms,
|
|
169
|
-
inPlan: featureInPlan,
|
|
170
|
-
availableIn: featureInPlan ? [] : plansIncludingFeature2(plans, code, planCode),
|
|
171
|
-
permissions
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
apps.push({
|
|
175
|
-
code: app.code,
|
|
176
|
-
name: app.name,
|
|
177
|
-
icon: app.icon ?? null,
|
|
178
|
-
unlockedCount,
|
|
179
|
-
totalCount,
|
|
180
|
-
features
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
plan: planMeta,
|
|
185
|
-
apps,
|
|
186
|
-
locks
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
__name(buildBuMatrix, "buildBuMatrix");
|
|
190
|
-
function plansUnlockingPerm(plans, featureCode, permCode, platform, excludeCode) {
|
|
191
|
-
const names = [];
|
|
192
|
-
for (const [code, p] of Object.entries(plans)) {
|
|
193
|
-
if (code === excludeCode) continue;
|
|
194
|
-
if ((p.unlockedPermissions?.[featureCode]?.[platform] ?? []).includes(permCode)) names.push(p.name);
|
|
195
|
-
}
|
|
196
|
-
return names;
|
|
197
|
-
}
|
|
198
|
-
__name(plansUnlockingPerm, "plansUnlockingPerm");
|
|
199
|
-
function plansIncludingFeature2(plans, featureCode, excludeCode) {
|
|
200
|
-
const names = [];
|
|
201
|
-
for (const [code, p] of Object.entries(plans)) {
|
|
202
|
-
if (code === excludeCode) continue;
|
|
203
|
-
if (isPlanMember(p.unlockedPermissions?.[featureCode])) names.push(p.name);
|
|
204
|
-
}
|
|
205
|
-
return names;
|
|
206
|
-
}
|
|
207
|
-
__name(plansIncludingFeature2, "plansIncludingFeature");
|
|
242
|
+
__name(buildSiteRoles, "buildSiteRoles");
|
|
208
243
|
|
|
209
244
|
// src/catalog-resolver/compose-role-grants.ts
|
|
210
245
|
function unionBucket(base, add) {
|
|
@@ -245,13 +280,35 @@ __name(composeRoleGrants, "composeRoleGrants");
|
|
|
245
280
|
|
|
246
281
|
// src/catalog-resolver/resolve-user-features.ts
|
|
247
282
|
function resolveUserFeatures(params) {
|
|
248
|
-
const { snapshot, businessCode, planCode,
|
|
283
|
+
const { snapshot, businessCode, planCode, siteLocks, roleFeatures, platform, siteType, scope, availableServices } = params;
|
|
249
284
|
const bucket = platform === "web" ? "web" : "mobile";
|
|
250
|
-
const
|
|
285
|
+
const featureByCode = /* @__PURE__ */ __name((code) => scope ? snapshot.features?.[snapshotFeatureKey(code, scope)] : findFeatureByCode(snapshot, code), "featureByCode");
|
|
286
|
+
const catalog = buildSiteCatalog(snapshot, businessCode, planCode, siteLocks, bucket, siteType, scope, availableServices);
|
|
251
287
|
const catalogMap = new Map(catalog.map((f) => [
|
|
252
288
|
f.code,
|
|
253
289
|
f
|
|
254
290
|
]));
|
|
291
|
+
const businessPlans = snapshot.businesses[businessCode]?.plans ?? {};
|
|
292
|
+
const currentUnlockedCodes = /* @__PURE__ */ new Set();
|
|
293
|
+
if (planCode && businessPlans[planCode]) {
|
|
294
|
+
for (const [featureCode, platforms] of Object.entries(businessPlans[planCode].unlockedPermissions ?? {})) {
|
|
295
|
+
if (platforms?.[bucket] !== void 0) currentUnlockedCodes.add(featureCode);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
const planAdds = /* @__PURE__ */ new Map();
|
|
299
|
+
for (const [planKey, plan] of Object.entries(businessPlans)) {
|
|
300
|
+
if (planKey === planCode) continue;
|
|
301
|
+
const adds = [];
|
|
302
|
+
for (const [featureCode, platforms] of Object.entries(plan.unlockedPermissions ?? {})) {
|
|
303
|
+
if (platforms?.[bucket] === void 0 || currentUnlockedCodes.has(featureCode)) continue;
|
|
304
|
+
const name = featureByCode(featureCode)?.name;
|
|
305
|
+
if (name) adds.push({
|
|
306
|
+
code: featureCode,
|
|
307
|
+
name
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
planAdds.set(planKey, adds);
|
|
311
|
+
}
|
|
255
312
|
const grantedFeatures = /* @__PURE__ */ new Map();
|
|
256
313
|
for (const [code, grant] of Object.entries(roleFeatures ?? {})) {
|
|
257
314
|
const granted = grant?.[bucket];
|
|
@@ -265,18 +322,24 @@ function resolveUserFeatures(params) {
|
|
|
265
322
|
if (!catalogEntry) continue;
|
|
266
323
|
const route = pickRouteForPlatform(catalogEntry, platform);
|
|
267
324
|
if (!route) continue;
|
|
325
|
+
const featureDeps = buildDependsMap(featureByCode(code)?.permissions ?? []);
|
|
268
326
|
const permByCode = new Map((catalogEntry.permissions ?? []).map((p) => [
|
|
269
327
|
p.code,
|
|
270
328
|
p
|
|
271
329
|
]));
|
|
272
330
|
const grantedPerms = [
|
|
273
|
-
...permsSet
|
|
331
|
+
...filterGrantedByDeps(permsSet, featureDeps)
|
|
274
332
|
];
|
|
275
333
|
const lockedPermissions = grantedPerms.map((c) => permByCode.get(c)).filter((p) => !!p?.locked).map((p) => ({
|
|
276
334
|
code: p.code,
|
|
277
335
|
reason: p.lockReason ?? null,
|
|
278
|
-
unlockPlans: p.unlockPlans ?? []
|
|
336
|
+
unlockPlans: p.unlockPlans ?? [],
|
|
337
|
+
missingServices: p.missingServices ?? []
|
|
279
338
|
}));
|
|
339
|
+
const upsell = catalogEntry.locked && catalogEntry.lockReason === "PLAN" ? (catalogEntry.unlockPlans ?? []).map((plan) => ({
|
|
340
|
+
plan,
|
|
341
|
+
features: (planAdds.get(plan) ?? []).filter((f) => f.code !== code).map((f) => f.name)
|
|
342
|
+
})).filter((group) => group.features.length > 0) : [];
|
|
280
343
|
features.push({
|
|
281
344
|
code,
|
|
282
345
|
name: catalogEntry.name,
|
|
@@ -287,7 +350,9 @@ function resolveUserFeatures(params) {
|
|
|
287
350
|
locked: catalogEntry.locked ?? false,
|
|
288
351
|
lockReason: catalogEntry.lockReason ?? null,
|
|
289
352
|
unlockPlans: catalogEntry.unlockPlans ?? [],
|
|
353
|
+
missingServices: catalogEntry.missingServices ?? [],
|
|
290
354
|
lockedPermissions,
|
|
355
|
+
upsell,
|
|
291
356
|
route,
|
|
292
357
|
appCode: catalogEntry.appCode,
|
|
293
358
|
appName: catalogEntry.appName,
|
|
@@ -295,6 +360,7 @@ function resolveUserFeatures(params) {
|
|
|
295
360
|
appSortOrder: catalogEntry.appSortOrder
|
|
296
361
|
});
|
|
297
362
|
}
|
|
363
|
+
features.sort((a, b) => a.appName.localeCompare(b.appName));
|
|
298
364
|
return features;
|
|
299
365
|
}
|
|
300
366
|
__name(resolveUserFeatures, "resolveUserFeatures");
|
|
@@ -315,16 +381,137 @@ function pickRouteForPlatform(entry, platform) {
|
|
|
315
381
|
};
|
|
316
382
|
}
|
|
317
383
|
__name(pickRouteForPlatform, "pickRouteForPlatform");
|
|
384
|
+
|
|
385
|
+
// src/catalog-resolver/site-matrix.builder.ts
|
|
386
|
+
function buildSiteMatrix(snapshot, businessCode, planCode, siteLocks, siteType) {
|
|
387
|
+
return buildMatrix(snapshot, businessCode, planCode, siteLocks, false, siteType);
|
|
388
|
+
}
|
|
389
|
+
__name(buildSiteMatrix, "buildSiteMatrix");
|
|
390
|
+
function buildPlanMatrix(snapshot, businessCode, planCode, siteLocks) {
|
|
391
|
+
return buildMatrix(snapshot, businessCode, planCode, siteLocks, true);
|
|
392
|
+
}
|
|
393
|
+
__name(buildPlanMatrix, "buildPlanMatrix");
|
|
394
|
+
function buildMatrix(snapshot, businessCode, planCode, siteLocks, allScopes, siteType) {
|
|
395
|
+
const business = businessCode ? snapshot.businesses?.[businessCode] : void 0;
|
|
396
|
+
const plans = business?.plans ?? {};
|
|
397
|
+
const plan = planCode ? plans[planCode] : void 0;
|
|
398
|
+
const planMeta = {
|
|
399
|
+
code: planCode ?? "",
|
|
400
|
+
name: plan?.name ?? planCode ?? ""
|
|
401
|
+
};
|
|
402
|
+
const locks = siteLocks ?? {};
|
|
403
|
+
if (!business || !plan) return {
|
|
404
|
+
plan: planMeta,
|
|
405
|
+
apps: [],
|
|
406
|
+
locks
|
|
407
|
+
};
|
|
408
|
+
const apps = [];
|
|
409
|
+
for (const app of business.apps) {
|
|
410
|
+
let unlockedCount = 0;
|
|
411
|
+
let totalCount = 0;
|
|
412
|
+
const features = [];
|
|
413
|
+
for (const ref of app.features) {
|
|
414
|
+
if (!allScopes && ref.scope !== "SITE") continue;
|
|
415
|
+
const code = ref.code;
|
|
416
|
+
const feature = snapshot.features?.[snapshotFeatureKey(code, ref.scope)];
|
|
417
|
+
if (!feature) continue;
|
|
418
|
+
if (siteType !== void 0 && !featureAppliesAtNode(feature.applicableSiteTypes, siteType)) continue;
|
|
419
|
+
const platforms = PLATFORMS.filter((p) => !!feature.microfrontends?.[p]);
|
|
420
|
+
if (platforms.length === 0) continue;
|
|
421
|
+
const membership = plan.unlockedPermissions?.[code];
|
|
422
|
+
const featureInPlan = isPlanMember(membership);
|
|
423
|
+
const siteEntry = siteLocks?.[code];
|
|
424
|
+
const permissions = (feature.permissions ?? []).filter((p) => p.isGlobal || p.businesses.includes(businessCode ?? "")).map((p) => {
|
|
425
|
+
const cell = /* @__PURE__ */ __name((plat) => {
|
|
426
|
+
if (!platforms.includes(plat)) return null;
|
|
427
|
+
const planCodes = membership?.[plat];
|
|
428
|
+
const inPlan = featureInPlan && planCodes !== void 0 && planCodes.includes(p.code);
|
|
429
|
+
const selected = inPlan && !isSiteLockedOnPlatform(siteEntry, plat, p.code);
|
|
430
|
+
const availableIn = inPlan ? [] : plansUnlockingPerm(plans, code, p.code, plat, planCode);
|
|
431
|
+
totalCount += 1;
|
|
432
|
+
if (inPlan) unlockedCount += 1;
|
|
433
|
+
return {
|
|
434
|
+
inPlan,
|
|
435
|
+
selected,
|
|
436
|
+
availableIn
|
|
437
|
+
};
|
|
438
|
+
}, "cell");
|
|
439
|
+
return {
|
|
440
|
+
code: p.code,
|
|
441
|
+
label: p.label,
|
|
442
|
+
dependsOn: p.dependsOn ?? [],
|
|
443
|
+
web: cell("web"),
|
|
444
|
+
mobile: cell("mobile")
|
|
445
|
+
};
|
|
446
|
+
});
|
|
447
|
+
features.push({
|
|
448
|
+
code: feature.code,
|
|
449
|
+
name: feature.name,
|
|
450
|
+
icon: feature.lucideIcon ?? null,
|
|
451
|
+
scope: feature.scope,
|
|
452
|
+
applicableSiteTypes: feature.applicableSiteTypes,
|
|
453
|
+
platforms,
|
|
454
|
+
inPlan: featureInPlan,
|
|
455
|
+
availableIn: featureInPlan ? [] : plansIncludingFeature2(plans, code, planCode),
|
|
456
|
+
permissions
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
if (features.length === 0) continue;
|
|
460
|
+
apps.push({
|
|
461
|
+
code: app.code,
|
|
462
|
+
name: app.name,
|
|
463
|
+
icon: app.icon ?? null,
|
|
464
|
+
unlockedCount,
|
|
465
|
+
totalCount,
|
|
466
|
+
features
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
apps.sort((a, b) => a.name.localeCompare(b.name));
|
|
470
|
+
return {
|
|
471
|
+
plan: planMeta,
|
|
472
|
+
apps,
|
|
473
|
+
locks
|
|
474
|
+
};
|
|
475
|
+
}
|
|
476
|
+
__name(buildMatrix, "buildMatrix");
|
|
477
|
+
function plansUnlockingPerm(plans, featureCode, permCode, platform, excludeCode) {
|
|
478
|
+
const names = [];
|
|
479
|
+
for (const [code, p] of Object.entries(plans)) {
|
|
480
|
+
if (code === excludeCode) continue;
|
|
481
|
+
if ((p.unlockedPermissions?.[featureCode]?.[platform] ?? []).includes(permCode)) names.push(p.name);
|
|
482
|
+
}
|
|
483
|
+
return names;
|
|
484
|
+
}
|
|
485
|
+
__name(plansUnlockingPerm, "plansUnlockingPerm");
|
|
486
|
+
function plansIncludingFeature2(plans, featureCode, excludeCode) {
|
|
487
|
+
const names = [];
|
|
488
|
+
for (const [code, p] of Object.entries(plans)) {
|
|
489
|
+
if (code === excludeCode) continue;
|
|
490
|
+
if (isPlanMember(p.unlockedPermissions?.[featureCode])) names.push(p.name);
|
|
491
|
+
}
|
|
492
|
+
return names;
|
|
493
|
+
}
|
|
494
|
+
__name(plansIncludingFeature2, "plansIncludingFeature");
|
|
318
495
|
export {
|
|
319
496
|
PLATFORMS,
|
|
497
|
+
SERVICE_CODES,
|
|
498
|
+
SITE_TYPES,
|
|
320
499
|
SNAPSHOT_SCHEMA_VERSION,
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
500
|
+
buildDependsMap,
|
|
501
|
+
buildPlanMatrix,
|
|
502
|
+
buildSiteCatalog,
|
|
503
|
+
buildSiteMatrix,
|
|
504
|
+
buildSiteRoles,
|
|
505
|
+
cascadeLocked,
|
|
324
506
|
composeRoleGrants,
|
|
325
|
-
|
|
507
|
+
featureAppliesAtNode,
|
|
508
|
+
filterGrantedByDeps,
|
|
509
|
+
findFeatureByCode,
|
|
326
510
|
isPlanMember,
|
|
511
|
+
isSiteLockedOnPlatform,
|
|
327
512
|
pickRouteForPlatform,
|
|
328
|
-
|
|
513
|
+
prereqClosure,
|
|
514
|
+
resolveUserFeatures,
|
|
515
|
+
snapshotFeatureKey
|
|
329
516
|
};
|
|
330
517
|
//# sourceMappingURL=catalog-resolver.js.map
|