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