@open-mercato/shared 0.6.2-develop.3467.1.2a1818709d → 0.6.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.
Files changed (67) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +24 -0
  3. package/dist/lib/bootstrap/factory.js +3 -1
  4. package/dist/lib/bootstrap/factory.js.map +2 -2
  5. package/dist/lib/commands/command-interceptor-store.js +3 -1
  6. package/dist/lib/commands/command-interceptor-store.js.map +2 -2
  7. package/dist/lib/crud/enricher-registry.js +3 -1
  8. package/dist/lib/crud/enricher-registry.js.map +2 -2
  9. package/dist/lib/crud/factory.js.map +1 -1
  10. package/dist/lib/crud/interceptor-registry.js +3 -1
  11. package/dist/lib/crud/interceptor-registry.js.map +2 -2
  12. package/dist/lib/crud/sync-event-runner.js +2 -8
  13. package/dist/lib/crud/sync-event-runner.js.map +2 -2
  14. package/dist/lib/db/mikro.js +27 -3
  15. package/dist/lib/db/mikro.js.map +2 -2
  16. package/dist/lib/di/container.js +16 -0
  17. package/dist/lib/di/container.js.map +2 -2
  18. package/dist/lib/events/patterns.js +2 -10
  19. package/dist/lib/events/patterns.js.map +2 -2
  20. package/dist/lib/middleware/page-executor.js +2 -1
  21. package/dist/lib/middleware/page-executor.js.map +2 -2
  22. package/dist/lib/modules/registry.js +2 -1
  23. package/dist/lib/modules/registry.js.map +2 -2
  24. package/dist/lib/notifications/handler-registry.js +3 -1
  25. package/dist/lib/notifications/handler-registry.js.map +2 -2
  26. package/dist/lib/patterns/wildcard.js +42 -0
  27. package/dist/lib/patterns/wildcard.js.map +7 -0
  28. package/dist/lib/regex/linear.js +31 -0
  29. package/dist/lib/regex/linear.js.map +7 -0
  30. package/dist/lib/version.js +1 -1
  31. package/dist/lib/version.js.map +1 -1
  32. package/dist/modules/entities/validation.js +15 -7
  33. package/dist/modules/entities/validation.js.map +2 -2
  34. package/dist/modules/overrides.js +857 -0
  35. package/dist/modules/overrides.js.map +2 -2
  36. package/dist/modules/registry.js +17 -4
  37. package/dist/modules/registry.js.map +2 -2
  38. package/dist/modules/widgets/injection-loader.js +12 -6
  39. package/dist/modules/widgets/injection-loader.js.map +2 -2
  40. package/jest.config.cjs +3 -1
  41. package/package.json +8 -8
  42. package/src/lib/bootstrap/factory.ts +3 -1
  43. package/src/lib/commands/command-interceptor-store.ts +3 -1
  44. package/src/lib/crud/__tests__/sync-event-runner.test.ts +5 -0
  45. package/src/lib/crud/enricher-registry.ts +3 -1
  46. package/src/lib/crud/factory.ts +2 -2
  47. package/src/lib/crud/interceptor-registry.ts +3 -1
  48. package/src/lib/crud/sync-event-runner.ts +2 -11
  49. package/src/lib/db/mikro.ts +27 -2
  50. package/src/lib/di/container.ts +24 -4
  51. package/src/lib/events/__tests__/patterns.test.ts +5 -0
  52. package/src/lib/events/patterns.ts +3 -16
  53. package/src/lib/middleware/page-executor.ts +2 -1
  54. package/src/lib/modules/registry.ts +2 -1
  55. package/src/lib/notifications/handler-registry.ts +3 -1
  56. package/src/lib/patterns/__tests__/wildcard.test.ts +27 -0
  57. package/src/lib/patterns/wildcard.ts +59 -0
  58. package/src/lib/regex/linear.ts +48 -0
  59. package/src/modules/__tests__/contract-overrides.test.ts +332 -0
  60. package/src/modules/__tests__/overrides.test.ts +23 -22
  61. package/src/modules/__tests__/route-overrides.test.ts +441 -0
  62. package/src/modules/entities/__tests__/validation.test.ts +97 -2
  63. package/src/modules/entities/validation.ts +14 -9
  64. package/src/modules/overrides.ts +1297 -27
  65. package/src/modules/registry.ts +27 -4
  66. package/src/modules/widgets/__tests__/injection-loader.required-modules.test.ts +21 -0
  67. package/src/modules/widgets/injection-loader.ts +12 -6
@@ -6,6 +6,7 @@ function registerModuleOverrideApplier(domain, applier) {
6
6
  function resetModuleOverrideAppliersForTests() {
7
7
  appliers.clear();
8
8
  warnedUnwiredDomains.clear();
9
+ registerBuiltInModuleOverrideAppliers();
9
10
  }
10
11
  const DOMAIN_KEYS = [
11
12
  "ai",
@@ -56,9 +57,865 @@ function applyModuleOverridesFromEnabledModules(modules) {
56
57
  applier(entries);
57
58
  }
58
59
  }
60
+ const pageRouteOverrideStore = { modules: {}, programmatic: {} };
61
+ const subscriberOverrideStore = { modules: {}, programmatic: {} };
62
+ const workerOverrideStore = { modules: {}, programmatic: {} };
63
+ const cliOverrideStore = { modules: {}, programmatic: {} };
64
+ const injectionWidgetOverrideStore = { modules: {}, programmatic: {} };
65
+ const dashboardWidgetOverrideStore = { modules: {}, programmatic: {} };
66
+ const componentOverrideStore = { modules: {}, programmatic: {} };
67
+ const notificationTypeOverrideStore = { modules: {}, programmatic: {} };
68
+ const notificationHandlerOverrideStore = { modules: {}, programmatic: {} };
69
+ const apiInterceptorOverrideStore = { modules: {}, programmatic: {} };
70
+ const commandInterceptorOverrideStore = { modules: {}, programmatic: {} };
71
+ const responseEnricherOverrideStore = { modules: {}, programmatic: {} };
72
+ const pageGuardOverrideStore = { modules: {}, programmatic: {} };
73
+ const aclFeatureOverrideStore = { modules: {}, programmatic: {} };
74
+ const encryptionMapOverrideStore = { modules: {}, programmatic: {} };
75
+ const diOverrideStore = { modules: {}, programmatic: {} };
76
+ const setupOverridesByModule = {};
77
+ function normalizeIdOverrideKey(key, label) {
78
+ if (typeof key !== "string") return null;
79
+ const trimmed = key.trim();
80
+ if (trimmed) return trimmed;
81
+ console.warn(`[Module Overrides] Skipping malformed ${label} key "${key}" \u2014 expected a non-empty string.`);
82
+ return null;
83
+ }
84
+ function clearStore(store) {
85
+ for (const key of Object.keys(store.modules)) delete store.modules[key];
86
+ for (const key of Object.keys(store.programmatic)) delete store.programmatic[key];
87
+ }
88
+ const EMPTY_OVERRIDE_MAP = Object.freeze({});
89
+ function applyStoreOverrides(store, target, overrides, options) {
90
+ if (!overrides || typeof overrides !== "object") return;
91
+ const normalize = options.normalizeKey ?? ((key) => normalizeIdOverrideKey(key, options.label));
92
+ for (const [rawKey, value] of Object.entries(overrides)) {
93
+ const key = normalize(rawKey);
94
+ if (!key) continue;
95
+ store[target][key] = value;
96
+ }
97
+ }
98
+ function composeStore(store) {
99
+ const modulesKeys = Object.keys(store.modules);
100
+ const programmaticKeys = Object.keys(store.programmatic);
101
+ if (modulesKeys.length === 0 && programmaticKeys.length === 0) {
102
+ return EMPTY_OVERRIDE_MAP;
103
+ }
104
+ return { ...store.modules, ...store.programmatic };
105
+ }
106
+ function applyArrayOverrides(items, overrides, options) {
107
+ if (!items || Object.keys(overrides).length === 0) {
108
+ return { items: items ? Array.from(items) : items, consumed: /* @__PURE__ */ new Set(), changed: false };
109
+ }
110
+ const consumed = /* @__PURE__ */ new Set();
111
+ const result = [];
112
+ let changed = false;
113
+ for (const item of items) {
114
+ const id = options.getId(item);
115
+ if (!id || !Object.prototype.hasOwnProperty.call(overrides, id)) {
116
+ result.push(item);
117
+ continue;
118
+ }
119
+ consumed.add(id);
120
+ changed = true;
121
+ const replacement = overrides[id];
122
+ if (replacement === null) continue;
123
+ if (options.isReplacement && !options.isReplacement(replacement)) {
124
+ console.warn(
125
+ `[Module Overrides] Skipping malformed ${options.label} override for "${id}" \u2014 replacement has the wrong shape.`
126
+ );
127
+ result.push(item);
128
+ continue;
129
+ }
130
+ const replacementId = options.getId(replacement);
131
+ if (replacementId !== id) {
132
+ console.warn(
133
+ `[Module Overrides] Skipping malformed ${options.label} override for "${id}" \u2014 replacement id must match the override key.`
134
+ );
135
+ result.push(item);
136
+ continue;
137
+ }
138
+ result.push(replacement);
139
+ }
140
+ return { items: result, consumed, changed };
141
+ }
142
+ function warnStaleOverrides(label, overrides, consumed) {
143
+ for (const key of Object.keys(overrides)) {
144
+ if (!consumed.has(key)) {
145
+ console.warn(`[Module Overrides] ${label} override "${key}" did not match any registered entry \u2014 override skipped.`);
146
+ }
147
+ }
148
+ }
149
+ function isObjectWithId(value) {
150
+ return !!value && typeof value === "object" && typeof value.id === "string";
151
+ }
152
+ function isModuleSubscriber(value) {
153
+ return isObjectWithId(value) && typeof value.event === "string" && typeof value.handler === "function";
154
+ }
155
+ function isModuleWorker(value) {
156
+ return isObjectWithId(value) && typeof value.queue === "string" && typeof value.handler === "function";
157
+ }
158
+ function isModuleCli(value) {
159
+ return !!value && typeof value === "object" && typeof value.command === "string" && typeof value.run === "function";
160
+ }
161
+ function isInjectionWidgetEntry(value) {
162
+ return !!value && typeof value === "object" && typeof value.key === "string" && typeof value.loader === "function";
163
+ }
164
+ function isDashboardWidgetEntry(value) {
165
+ return !!value && typeof value === "object" && typeof value.key === "string" && typeof value.loader === "function";
166
+ }
167
+ function isComponentOverrideValue(value) {
168
+ const items = Array.isArray(value) ? value : [value];
169
+ return items.every(
170
+ (item) => !!item && typeof item === "object" && !!item.target && typeof item.target.componentId === "string"
171
+ );
172
+ }
173
+ function isNotificationType(value) {
174
+ return !!value && typeof value === "object" && typeof value.type === "string";
175
+ }
176
+ function isNotificationHandler(value) {
177
+ return isObjectWithId(value) && typeof value.handle === "function";
178
+ }
179
+ function isApiInterceptor(value) {
180
+ return isObjectWithId(value) && typeof value.targetRoute === "string";
181
+ }
182
+ function isCommandInterceptor(value) {
183
+ return isObjectWithId(value) && typeof value.targetCommand === "string";
184
+ }
185
+ function isResponseEnricher(value) {
186
+ return isObjectWithId(value) && typeof value.targetEntity === "string" && typeof value.enrichOne === "function";
187
+ }
188
+ function isPageRouteMiddleware(value) {
189
+ return isObjectWithId(value) && typeof value.run === "function";
190
+ }
191
+ function isEncryptionMap(value) {
192
+ return !!value && typeof value === "object" && typeof value.entityId === "string" && Array.isArray(value.fields);
193
+ }
194
+ function getFeatureId(value) {
195
+ if (typeof value === "string" && value.trim()) return value.trim();
196
+ if (value && typeof value === "object" && typeof value.id === "string") {
197
+ return value.id;
198
+ }
199
+ return null;
200
+ }
201
+ const VALID_HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
202
+ const programmaticApiRouteOverrides = {};
203
+ const modulesConfigApiRouteOverrides = {};
204
+ function normalizeApiRouteOverrideKey(key) {
205
+ if (typeof key !== "string") return null;
206
+ const trimmed = key.trim();
207
+ if (!trimmed) return null;
208
+ const parts = trimmed.split(/\s+/);
209
+ if (parts.length < 2) return null;
210
+ const method = parts[0].toUpperCase();
211
+ if (!VALID_HTTP_METHODS.includes(method)) return null;
212
+ const rawPath = parts.slice(1).join(" ").trim();
213
+ if (!rawPath) return null;
214
+ const withLead = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
215
+ const normalized = withLead.replace(/\/+$/, "") || "/";
216
+ return `${method} ${normalized}`;
217
+ }
218
+ function normalizePageRouteOverrideKey(key) {
219
+ if (typeof key !== "string") return null;
220
+ const trimmed = key.trim();
221
+ if (!trimmed) return null;
222
+ if (trimmed.startsWith("backend:") || trimmed.startsWith("frontend:")) return trimmed;
223
+ const withLead = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
224
+ const stripped = withLead.replace(/\/+$/, "") || "/";
225
+ if (stripped === "/frontend") return "frontend:/";
226
+ if (stripped.startsWith("/frontend/")) return `frontend:/${stripped.slice("/frontend/".length)}`;
227
+ if (stripped === "/backend" || stripped.startsWith("/backend/")) return `backend:${stripped}`;
228
+ return `frontend:${stripped}`;
229
+ }
230
+ function applyApiRouteOverrides(overrides) {
231
+ if (!overrides) return;
232
+ for (const [rawKey, value] of Object.entries(overrides)) {
233
+ const key = normalizeApiRouteOverrideKey(rawKey);
234
+ if (!key) {
235
+ console.warn(
236
+ `[Module Overrides] Skipping malformed routes.api key "${rawKey}" \u2014 expected "METHOD /api/path".`
237
+ );
238
+ continue;
239
+ }
240
+ programmaticApiRouteOverrides[key] = value;
241
+ }
242
+ }
243
+ function resetApiRouteOverridesForTests() {
244
+ for (const key of Object.keys(programmaticApiRouteOverrides)) {
245
+ delete programmaticApiRouteOverrides[key];
246
+ }
247
+ for (const key of Object.keys(modulesConfigApiRouteOverrides)) {
248
+ delete modulesConfigApiRouteOverrides[key];
249
+ }
250
+ }
251
+ function resetModuleContractOverridesForTests() {
252
+ resetApiRouteOverridesForTests();
253
+ clearStore(pageRouteOverrideStore);
254
+ clearStore(subscriberOverrideStore);
255
+ clearStore(workerOverrideStore);
256
+ clearStore(cliOverrideStore);
257
+ clearStore(injectionWidgetOverrideStore);
258
+ clearStore(dashboardWidgetOverrideStore);
259
+ clearStore(componentOverrideStore);
260
+ clearStore(notificationTypeOverrideStore);
261
+ clearStore(notificationHandlerOverrideStore);
262
+ clearStore(apiInterceptorOverrideStore);
263
+ clearStore(commandInterceptorOverrideStore);
264
+ clearStore(responseEnricherOverrideStore);
265
+ clearStore(pageGuardOverrideStore);
266
+ clearStore(aclFeatureOverrideStore);
267
+ clearStore(encryptionMapOverrideStore);
268
+ clearStore(diOverrideStore);
269
+ for (const key of Object.keys(setupOverridesByModule)) delete setupOverridesByModule[key];
270
+ }
271
+ function composeApiRouteOverrides() {
272
+ const modulesKeys = Object.keys(modulesConfigApiRouteOverrides);
273
+ const programmaticKeys = Object.keys(programmaticApiRouteOverrides);
274
+ if (modulesKeys.length === 0 && programmaticKeys.length === 0) {
275
+ return EMPTY_OVERRIDE_MAP;
276
+ }
277
+ const out = {};
278
+ for (const k of modulesKeys) out[k] = modulesConfigApiRouteOverrides[k];
279
+ for (const k of programmaticKeys) out[k] = programmaticApiRouteOverrides[k];
280
+ return out;
281
+ }
282
+ function applyPageRouteOverrides(overrides) {
283
+ applyStoreOverrides(pageRouteOverrideStore, "programmatic", overrides, {
284
+ label: "routes.pages",
285
+ normalizeKey: normalizePageRouteOverrideKey
286
+ });
287
+ }
288
+ function composePageRouteOverrides() {
289
+ return composeStore(pageRouteOverrideStore);
290
+ }
291
+ function applySubscriberOverrides(overrides) {
292
+ applyStoreOverrides(subscriberOverrideStore, "programmatic", overrides, { label: "events.subscribers" });
293
+ }
294
+ function composeSubscriberOverrides() {
295
+ return composeStore(subscriberOverrideStore);
296
+ }
297
+ function applyWorkerOverrides(overrides) {
298
+ applyStoreOverrides(workerOverrideStore, "programmatic", overrides, { label: "workers" });
299
+ }
300
+ function composeWorkerOverrides() {
301
+ return composeStore(workerOverrideStore);
302
+ }
303
+ function applyCliOverrides(overrides) {
304
+ applyStoreOverrides(cliOverrideStore, "programmatic", overrides, { label: "cli" });
305
+ }
306
+ function composeCliOverrides() {
307
+ return composeStore(cliOverrideStore);
308
+ }
309
+ function applyInjectionWidgetOverrides(overrides) {
310
+ applyStoreOverrides(injectionWidgetOverrideStore, "programmatic", overrides, { label: "widgets.injection" });
311
+ }
312
+ function composeInjectionWidgetOverrides() {
313
+ return composeStore(injectionWidgetOverrideStore);
314
+ }
315
+ function applyDashboardWidgetOverrides(overrides) {
316
+ applyStoreOverrides(dashboardWidgetOverrideStore, "programmatic", overrides, { label: "widgets.dashboard" });
317
+ }
318
+ function composeDashboardWidgetOverrides() {
319
+ return composeStore(dashboardWidgetOverrideStore);
320
+ }
321
+ function applyComponentOverrides(overrides) {
322
+ applyStoreOverrides(componentOverrideStore, "programmatic", overrides, { label: "widgets.components" });
323
+ }
324
+ function composeComponentOverrides() {
325
+ return composeStore(componentOverrideStore);
326
+ }
327
+ function applyNotificationTypeOverrides(overrides) {
328
+ applyStoreOverrides(notificationTypeOverrideStore, "programmatic", overrides, { label: "notifications.types" });
329
+ }
330
+ function composeNotificationTypeOverrides() {
331
+ return composeStore(notificationTypeOverrideStore);
332
+ }
333
+ function applyNotificationHandlerOverrides(overrides) {
334
+ applyStoreOverrides(notificationHandlerOverrideStore, "programmatic", overrides, { label: "notifications.handlers" });
335
+ }
336
+ function composeNotificationHandlerOverrides() {
337
+ return composeStore(notificationHandlerOverrideStore);
338
+ }
339
+ function applyApiInterceptorOverrides(overrides) {
340
+ applyStoreOverrides(apiInterceptorOverrideStore, "programmatic", overrides, { label: "interceptors" });
341
+ }
342
+ function composeApiInterceptorOverrides() {
343
+ return composeStore(apiInterceptorOverrideStore);
344
+ }
345
+ function applyCommandInterceptorOverrides(overrides) {
346
+ applyStoreOverrides(commandInterceptorOverrideStore, "programmatic", overrides, { label: "commandInterceptors" });
347
+ }
348
+ function composeCommandInterceptorOverrides() {
349
+ return composeStore(commandInterceptorOverrideStore);
350
+ }
351
+ function applyResponseEnricherOverrides(overrides) {
352
+ applyStoreOverrides(responseEnricherOverrideStore, "programmatic", overrides, { label: "enrichers" });
353
+ }
354
+ function composeResponseEnricherOverrides() {
355
+ return composeStore(responseEnricherOverrideStore);
356
+ }
357
+ function applyPageGuardOverrides(overrides) {
358
+ applyStoreOverrides(pageGuardOverrideStore, "programmatic", overrides, { label: "guards" });
359
+ }
360
+ function composePageGuardOverrides() {
361
+ return composeStore(pageGuardOverrideStore);
362
+ }
363
+ function applyAclFeatureOverrides(overrides) {
364
+ applyStoreOverrides(aclFeatureOverrideStore, "programmatic", overrides, { label: "acl.features" });
365
+ }
366
+ function composeAclFeatureOverrides() {
367
+ return composeStore(aclFeatureOverrideStore);
368
+ }
369
+ function applyEncryptionMapOverrides(overrides) {
370
+ applyStoreOverrides(encryptionMapOverrideStore, "programmatic", overrides, { label: "encryption.maps" });
371
+ }
372
+ function composeEncryptionMapOverrides() {
373
+ return composeStore(encryptionMapOverrideStore);
374
+ }
375
+ function applyDiOverrides(overrides) {
376
+ applyStoreOverrides(diOverrideStore, "programmatic", overrides, { label: "di" });
377
+ }
378
+ function composeDiOverrides() {
379
+ return composeStore(diOverrideStore);
380
+ }
381
+ function applyApiOverridesToManifests(routes, overrides) {
382
+ if (!routes || routes.length === 0) return Array.from(routes);
383
+ const overrideKeys = Object.keys(overrides);
384
+ if (overrideKeys.length === 0) return Array.from(routes);
385
+ const consumedKeys = /* @__PURE__ */ new Set();
386
+ const result = [];
387
+ for (const entry of routes) {
388
+ const path = entry.path;
389
+ const remainingMethods = [];
390
+ const methodOverrides = /* @__PURE__ */ new Map();
391
+ for (const method of entry.methods) {
392
+ const manifestKey = `${method} ${path}`;
393
+ const publicKey = path.startsWith("/api/") ? manifestKey : `${method} /api${path === "/" ? "" : path}`;
394
+ const key = Object.prototype.hasOwnProperty.call(overrides, manifestKey) ? manifestKey : Object.prototype.hasOwnProperty.call(overrides, publicKey) ? publicKey : null;
395
+ if (!key) {
396
+ remainingMethods.push(method);
397
+ continue;
398
+ }
399
+ consumedKeys.add(key);
400
+ const value = overrides[key];
401
+ if (value === null) continue;
402
+ if (value && typeof value === "object" && typeof value.handler === "function") {
403
+ methodOverrides.set(method, value);
404
+ remainingMethods.push(method);
405
+ } else {
406
+ console.warn(
407
+ `[Module Overrides] Skipping malformed routes.api override for "${key}" \u2014 expected { handler, metadata? } or null.`
408
+ );
409
+ remainingMethods.push(method);
410
+ }
411
+ }
412
+ if (remainingMethods.length === 0) continue;
413
+ const methodsChanged = remainingMethods.length !== entry.methods.length;
414
+ const hasReplacements = methodOverrides.size > 0;
415
+ if (!methodsChanged && !hasReplacements) {
416
+ result.push(entry);
417
+ continue;
418
+ }
419
+ const originalLoad = entry.load;
420
+ const wrappedLoad = hasReplacements ? async () => {
421
+ const original = await originalLoad();
422
+ const out = { ...original };
423
+ const baseMetadata = original && typeof original === "object" && original.metadata !== void 0 ? original.metadata : null;
424
+ const mergedMetadata = baseMetadata && typeof baseMetadata === "object" ? { ...baseMetadata } : {};
425
+ for (const [method, def] of methodOverrides) {
426
+ out[method] = def.handler;
427
+ if (def.metadata !== void 0) mergedMetadata[method] = def.metadata;
428
+ }
429
+ if (Object.keys(mergedMetadata).length > 0) out.metadata = mergedMetadata;
430
+ return out;
431
+ } : originalLoad;
432
+ result.push({ ...entry, methods: remainingMethods, load: wrappedLoad });
433
+ }
434
+ for (const key of overrideKeys) {
435
+ if (!consumedKeys.has(key)) {
436
+ console.warn(
437
+ `[Module Overrides] routes.api override "${key}" did not match any registered API route \u2014 override skipped.`
438
+ );
439
+ }
440
+ }
441
+ return result;
442
+ }
443
+ function applyPageOverridesToManifests(routes, overrides, kind) {
444
+ if (!routes || routes.length === 0) return Array.from(routes);
445
+ const normalizedOverrides = {};
446
+ for (const [rawKey, value] of Object.entries(overrides)) {
447
+ const key = normalizePageRouteOverrideKey(rawKey);
448
+ if (!key) {
449
+ console.warn(
450
+ `[Module Overrides] Skipping malformed routes.pages key "${rawKey}" \u2014 expected "/backend/path" or "/frontend/path".`
451
+ );
452
+ continue;
453
+ }
454
+ normalizedOverrides[key] = value;
455
+ }
456
+ const overrideKeys = Object.keys(normalizedOverrides).filter((key) => key.startsWith(`${kind}:`));
457
+ if (overrideKeys.length === 0) return Array.from(routes);
458
+ const consumed = /* @__PURE__ */ new Set();
459
+ const result = [];
460
+ for (const entry of routes) {
461
+ const path = entry.pattern ?? entry.path ?? "/";
462
+ const key = `${kind}:${path.replace(/\/+$/, "") || "/"}`;
463
+ if (!Object.prototype.hasOwnProperty.call(normalizedOverrides, key)) {
464
+ result.push(entry);
465
+ continue;
466
+ }
467
+ consumed.add(key);
468
+ const override = normalizedOverrides[key];
469
+ if (override === null) continue;
470
+ if (!override || typeof override !== "object") {
471
+ console.warn(
472
+ `[Module Overrides] Skipping malformed routes.pages override for "${key}" \u2014 expected { load?, Component?, metadata? } or null.`
473
+ );
474
+ result.push(entry);
475
+ continue;
476
+ }
477
+ const hasLoad = typeof override.load === "function";
478
+ const hasComponent = typeof override.Component === "function";
479
+ if (!hasLoad && !hasComponent && override.metadata === void 0) {
480
+ console.warn(
481
+ `[Module Overrides] Skipping malformed routes.pages override for "${key}" \u2014 expected a loader, component, metadata, or null.`
482
+ );
483
+ result.push(entry);
484
+ continue;
485
+ }
486
+ const metadata = override.metadata && typeof override.metadata === "object" ? override.metadata : {};
487
+ const load = hasLoad ? override.load : hasComponent ? async () => override.Component : entry.load;
488
+ result.push({ ...entry, ...metadata, load });
489
+ }
490
+ warnStaleOverrides("routes.pages", Object.fromEntries(
491
+ overrideKeys.map((key) => [key, normalizedOverrides[key]])
492
+ ), consumed);
493
+ return result;
494
+ }
495
+ function applyEntryListOverrides(entries, overrides, options) {
496
+ if (!entries || Object.keys(overrides).length === 0) return entries;
497
+ const consumed = /* @__PURE__ */ new Set();
498
+ let changed = false;
499
+ const result = entries.map((entry) => {
500
+ const list = entry[options.listKey];
501
+ if (!Array.isArray(list)) return entry;
502
+ const applied = applyArrayOverrides(list, overrides, {
503
+ label: options.label,
504
+ getId: options.getId,
505
+ isReplacement: options.isReplacement
506
+ });
507
+ for (const key of applied.consumed) consumed.add(key);
508
+ if (!applied.changed) return entry;
509
+ changed = true;
510
+ return { ...entry, [options.listKey]: applied.items ?? [] };
511
+ });
512
+ warnStaleOverrides(options.label, overrides, consumed);
513
+ return changed ? result : Array.from(entries);
514
+ }
515
+ function applyInjectionWidgetOverridesToEntries(entries, overrides = composeInjectionWidgetOverrides()) {
516
+ const applied = applyArrayOverrides(entries, overrides, {
517
+ label: "widgets.injection",
518
+ getId: (entry) => entry.key,
519
+ isReplacement: isInjectionWidgetEntry
520
+ });
521
+ warnStaleOverrides("widgets.injection", overrides, applied.consumed);
522
+ return applied.items ?? [];
523
+ }
524
+ function applyDashboardWidgetOverridesToEntries(entries, overrides = composeDashboardWidgetOverrides()) {
525
+ const applied = applyArrayOverrides(entries, overrides, {
526
+ label: "widgets.dashboard",
527
+ getId: (entry) => entry.key,
528
+ isReplacement: isDashboardWidgetEntry
529
+ });
530
+ warnStaleOverrides("widgets.dashboard", overrides, applied.consumed);
531
+ return applied.items ?? [];
532
+ }
533
+ function applyWorkerOverridesToDescriptors(entries, overrides = composeWorkerOverrides()) {
534
+ const applied = applyArrayOverrides(entries, overrides, {
535
+ label: "workers",
536
+ getId: (entry) => entry.id,
537
+ isReplacement: (value) => !!value && typeof value === "object" && typeof value.id === "string" && typeof value.queue === "string" && typeof value.concurrency === "number" && typeof value.handler === "function"
538
+ });
539
+ warnStaleOverrides("workers", overrides, applied.consumed);
540
+ return applied.items ?? [];
541
+ }
542
+ function applyInjectionWidgetOverridesToTables(tables, overrides = composeInjectionWidgetOverrides()) {
543
+ const disabled = new Set(Object.entries(overrides).filter(([, value]) => value === null).map(([key]) => key));
544
+ if (disabled.size === 0) return Array.from(tables);
545
+ const filterSlot = (slot) => {
546
+ if (typeof slot === "string") return disabled.has(slot) ? null : slot;
547
+ if (slot && typeof slot === "object") {
548
+ const widgetId = slot.widgetId;
549
+ return typeof widgetId === "string" && disabled.has(widgetId) ? null : slot;
550
+ }
551
+ return slot;
552
+ };
553
+ return tables.map((entry) => {
554
+ const nextTable = {};
555
+ for (const [spotId, rawSlot] of Object.entries(entry.table)) {
556
+ const filtered = Array.isArray(rawSlot) ? rawSlot.map(filterSlot).filter((slot) => slot !== null) : filterSlot(rawSlot);
557
+ if (Array.isArray(filtered)) {
558
+ if (filtered.length > 0) nextTable[spotId] = filtered;
559
+ } else if (filtered !== null) {
560
+ nextTable[spotId] = filtered;
561
+ }
562
+ }
563
+ return { ...entry, table: nextTable };
564
+ });
565
+ }
566
+ function applyComponentOverridesToEntries(entries, overrides = composeComponentOverrides()) {
567
+ const overrideKeys = Object.keys(overrides);
568
+ if (overrideKeys.length === 0) return Array.from(entries);
569
+ const consumed = /* @__PURE__ */ new Set();
570
+ const additions = [];
571
+ const result = entries.map((entry) => {
572
+ const next = entry.componentOverrides.filter((override) => {
573
+ const id = override.target.componentId;
574
+ if (!Object.prototype.hasOwnProperty.call(overrides, id)) return true;
575
+ consumed.add(id);
576
+ return false;
577
+ });
578
+ return { ...entry, componentOverrides: next };
579
+ });
580
+ for (const key of overrideKeys) {
581
+ const value = overrides[key];
582
+ if (value === null) continue;
583
+ if (!isComponentOverrideValue(value)) {
584
+ console.warn(`[Module Overrides] Skipping malformed widgets.components override for "${key}" \u2014 expected ComponentOverride, ComponentOverride[], or null.`);
585
+ continue;
586
+ }
587
+ const values = Array.isArray(value) ? value : [value];
588
+ for (const override of values) {
589
+ if (override.target.componentId !== key) {
590
+ console.warn(`[Module Overrides] Skipping malformed widgets.components override for "${key}" \u2014 target.componentId must match the override key.`);
591
+ continue;
592
+ }
593
+ additions.push(override);
594
+ consumed.add(key);
595
+ }
596
+ }
597
+ if (additions.length > 0) {
598
+ result.push({ moduleId: "overrides", componentOverrides: additions });
599
+ }
600
+ warnStaleOverrides("widgets.components", overrides, consumed);
601
+ return result;
602
+ }
603
+ function applyNotificationTypeOverridesToEntries(entries, overrides = composeNotificationTypeOverrides()) {
604
+ return applyEntryListOverrides(entries, overrides, {
605
+ listKey: "types",
606
+ label: "notifications.types",
607
+ getId: (entry) => entry.type,
608
+ isReplacement: isNotificationType
609
+ }) ?? [];
610
+ }
611
+ function applyNotificationHandlerOverridesToEntries(entries, overrides = composeNotificationHandlerOverrides()) {
612
+ return applyEntryListOverrides(entries, overrides, {
613
+ listKey: "handlers",
614
+ label: "notifications.handlers",
615
+ getId: (entry) => entry.id,
616
+ isReplacement: isNotificationHandler
617
+ }) ?? [];
618
+ }
619
+ function applyApiInterceptorOverridesToEntries(entries, overrides = composeApiInterceptorOverrides()) {
620
+ return applyEntryListOverrides(entries, overrides, {
621
+ listKey: "interceptors",
622
+ label: "interceptors",
623
+ getId: (entry) => entry.id,
624
+ isReplacement: isApiInterceptor
625
+ }) ?? [];
626
+ }
627
+ function applyCommandInterceptorOverridesToEntries(entries, overrides = composeCommandInterceptorOverrides()) {
628
+ return applyEntryListOverrides(entries, overrides, {
629
+ listKey: "interceptors",
630
+ label: "commandInterceptors",
631
+ getId: (entry) => entry.id,
632
+ isReplacement: isCommandInterceptor
633
+ }) ?? [];
634
+ }
635
+ function applyResponseEnricherOverridesToEntries(entries, overrides = composeResponseEnricherOverrides()) {
636
+ return applyEntryListOverrides(entries, overrides, {
637
+ listKey: "enrichers",
638
+ label: "enrichers",
639
+ getId: (entry) => entry.id,
640
+ isReplacement: isResponseEnricher
641
+ }) ?? [];
642
+ }
643
+ function applyPageGuardOverridesToEntries(entries, overrides = composePageGuardOverrides()) {
644
+ return applyEntryListOverrides(entries, overrides, {
645
+ listKey: "middleware",
646
+ label: "guards",
647
+ getId: (entry) => entry.id,
648
+ isReplacement: isPageRouteMiddleware
649
+ }) ?? [];
650
+ }
651
+ function applySetupOverride(setup, override) {
652
+ if (!override) return setup;
653
+ const next = { ...setup ?? {} };
654
+ if (override.defaultRoleFeatures) {
655
+ next.defaultRoleFeatures = Object.fromEntries(
656
+ Object.entries(override.defaultRoleFeatures).map(([role, features]) => [role, Array.from(features)])
657
+ );
658
+ }
659
+ if (override.defaultCustomerRoleFeatures) {
660
+ next.defaultCustomerRoleFeatures = Object.fromEntries(
661
+ Object.entries(override.defaultCustomerRoleFeatures).map(([role, features]) => [role, Array.from(features)])
662
+ );
663
+ }
664
+ if (override.seedDefaults === false) delete next.seedDefaults;
665
+ if (override.seedExamples === false) delete next.seedExamples;
666
+ if (override.onTenantCreated === false) delete next.onTenantCreated;
667
+ return next;
668
+ }
669
+ function applyModuleOverridesToModules(modules) {
670
+ const subscriberOverrides = composeSubscriberOverrides();
671
+ const workerOverrides = composeWorkerOverrides();
672
+ const cliOverrides = composeCliOverrides();
673
+ const aclOverrides = composeAclFeatureOverrides();
674
+ const encryptionOverrides = composeEncryptionMapOverrides();
675
+ const hasSetupOverrides = Object.keys(setupOverridesByModule).length > 0;
676
+ const hasAny = Object.keys(subscriberOverrides).length > 0 || Object.keys(workerOverrides).length > 0 || Object.keys(cliOverrides).length > 0 || Object.keys(aclOverrides).length > 0 || Object.keys(encryptionOverrides).length > 0 || hasSetupOverrides;
677
+ if (!hasAny) return modules;
678
+ const subscriberConsumed = /* @__PURE__ */ new Set();
679
+ const workerConsumed = /* @__PURE__ */ new Set();
680
+ const cliConsumed = /* @__PURE__ */ new Set();
681
+ const aclConsumed = /* @__PURE__ */ new Set();
682
+ const encryptionConsumed = /* @__PURE__ */ new Set();
683
+ const result = modules.map((module) => {
684
+ let next = module;
685
+ const subscribers = applyArrayOverrides(module.subscribers, subscriberOverrides, {
686
+ label: "events.subscribers",
687
+ getId: (entry) => entry.id,
688
+ isReplacement: isModuleSubscriber
689
+ });
690
+ for (const key of subscribers.consumed) subscriberConsumed.add(key);
691
+ if (subscribers.changed) next = { ...next, subscribers: subscribers.items };
692
+ const workers = applyArrayOverrides(module.workers, workerOverrides, {
693
+ label: "workers",
694
+ getId: (entry) => entry.id,
695
+ isReplacement: isModuleWorker
696
+ });
697
+ for (const key of workers.consumed) workerConsumed.add(key);
698
+ if (workers.changed) next = { ...next, workers: workers.items };
699
+ const cli = applyArrayOverrides(module.cli, cliOverrides, {
700
+ label: "cli",
701
+ getId: (entry) => entry.command,
702
+ isReplacement: isModuleCli
703
+ });
704
+ for (const key of cli.consumed) cliConsumed.add(key);
705
+ if (cli.changed) next = { ...next, cli: cli.items };
706
+ const features = applyArrayOverrides(module.features, aclOverrides, {
707
+ label: "acl.features",
708
+ getId: getFeatureId,
709
+ isReplacement: (value) => getFeatureId(value) !== null
710
+ });
711
+ for (const key of features.consumed) aclConsumed.add(key);
712
+ if (features.changed) next = { ...next, features: features.items };
713
+ const maps = applyArrayOverrides(module.defaultEncryptionMaps, encryptionOverrides, {
714
+ label: "encryption.maps",
715
+ getId: (entry) => entry.entityId,
716
+ isReplacement: isEncryptionMap
717
+ });
718
+ for (const key of maps.consumed) encryptionConsumed.add(key);
719
+ if (maps.changed) next = { ...next, defaultEncryptionMaps: maps.items };
720
+ const setupOverride = setupOverridesByModule[module.id];
721
+ if (setupOverride) {
722
+ next = { ...next, setup: applySetupOverride(module.setup, setupOverride) };
723
+ }
724
+ return next;
725
+ });
726
+ warnStaleOverrides("events.subscribers", subscriberOverrides, subscriberConsumed);
727
+ warnStaleOverrides("workers", workerOverrides, workerConsumed);
728
+ warnStaleOverrides("cli", cliOverrides, cliConsumed);
729
+ warnStaleOverrides("acl.features", aclOverrides, aclConsumed);
730
+ warnStaleOverrides("encryption.maps", encryptionOverrides, encryptionConsumed);
731
+ return result;
732
+ }
733
+ function applyDiOverridesToContainer(container) {
734
+ const overrides = composeDiOverrides();
735
+ for (const [key, value] of Object.entries(overrides)) {
736
+ if (value === null) {
737
+ if (typeof container.unregister === "function") {
738
+ container.unregister(key);
739
+ } else if (container.registrations && key in container.registrations) {
740
+ delete container.registrations[key];
741
+ }
742
+ continue;
743
+ }
744
+ if (value && typeof value === "object" && typeof value.register === "function") {
745
+ ;
746
+ value.register(container, key);
747
+ continue;
748
+ }
749
+ container.register({ [key]: value });
750
+ }
751
+ }
752
+ function routesOverridesApplier(entries) {
753
+ for (const entry of entries) {
754
+ const shape = entry.overrides;
755
+ if (!shape || typeof shape !== "object") continue;
756
+ const api = shape.api;
757
+ if (api && typeof api === "object") {
758
+ for (const [rawKey, value] of Object.entries(api)) {
759
+ const key = normalizeApiRouteOverrideKey(rawKey);
760
+ if (!key) {
761
+ console.warn(
762
+ `[Module Overrides] Skipping malformed routes.api key "${rawKey}" \u2014 expected "METHOD /api/path".`
763
+ );
764
+ continue;
765
+ }
766
+ modulesConfigApiRouteOverrides[key] = value;
767
+ }
768
+ }
769
+ const pages = shape.pages;
770
+ if (pages && typeof pages === "object" && Object.keys(pages).length > 0) {
771
+ applyStoreOverrides(pageRouteOverrideStore, "modules", pages, {
772
+ label: "routes.pages",
773
+ normalizeKey: normalizePageRouteOverrideKey
774
+ });
775
+ }
776
+ }
777
+ }
778
+ function eventsOverridesApplier(entries) {
779
+ for (const entry of entries) {
780
+ const subscribers = entry.overrides?.subscribers;
781
+ applyStoreOverrides(subscriberOverrideStore, "modules", subscribers, { label: "events.subscribers" });
782
+ }
783
+ }
784
+ function workersOverridesApplier(entries) {
785
+ for (const entry of entries) {
786
+ applyStoreOverrides(workerOverrideStore, "modules", entry.overrides, { label: "workers" });
787
+ }
788
+ }
789
+ function widgetsOverridesApplier(entries) {
790
+ for (const entry of entries) {
791
+ applyStoreOverrides(injectionWidgetOverrideStore, "modules", entry.overrides?.injection, { label: "widgets.injection" });
792
+ applyStoreOverrides(componentOverrideStore, "modules", entry.overrides?.components, { label: "widgets.components" });
793
+ applyStoreOverrides(dashboardWidgetOverrideStore, "modules", entry.overrides?.dashboard, { label: "widgets.dashboard" });
794
+ }
795
+ }
796
+ function notificationsOverridesApplier(entries) {
797
+ for (const entry of entries) {
798
+ applyStoreOverrides(notificationTypeOverrideStore, "modules", entry.overrides?.types, { label: "notifications.types" });
799
+ applyStoreOverrides(notificationHandlerOverrideStore, "modules", entry.overrides?.handlers, { label: "notifications.handlers" });
800
+ }
801
+ }
802
+ function interceptorsOverridesApplier(entries) {
803
+ for (const entry of entries) {
804
+ applyStoreOverrides(apiInterceptorOverrideStore, "modules", entry.overrides, { label: "interceptors" });
805
+ }
806
+ }
807
+ function commandInterceptorsOverridesApplier(entries) {
808
+ for (const entry of entries) {
809
+ applyStoreOverrides(commandInterceptorOverrideStore, "modules", entry.overrides, { label: "commandInterceptors" });
810
+ }
811
+ }
812
+ function enrichersOverridesApplier(entries) {
813
+ for (const entry of entries) {
814
+ applyStoreOverrides(responseEnricherOverrideStore, "modules", entry.overrides, { label: "enrichers" });
815
+ }
816
+ }
817
+ function guardsOverridesApplier(entries) {
818
+ for (const entry of entries) {
819
+ applyStoreOverrides(pageGuardOverrideStore, "modules", entry.overrides, { label: "guards" });
820
+ }
821
+ }
822
+ function cliOverridesApplier(entries) {
823
+ for (const entry of entries) {
824
+ applyStoreOverrides(cliOverrideStore, "modules", entry.overrides, { label: "cli" });
825
+ }
826
+ }
827
+ function setupOverridesApplier(entries) {
828
+ for (const entry of entries) {
829
+ if (!entry.overrides || typeof entry.overrides !== "object") continue;
830
+ setupOverridesByModule[entry.moduleId] = entry.overrides;
831
+ }
832
+ }
833
+ function aclOverridesApplier(entries) {
834
+ for (const entry of entries) {
835
+ applyStoreOverrides(aclFeatureOverrideStore, "modules", entry.overrides?.features, { label: "acl.features" });
836
+ }
837
+ }
838
+ function diOverridesApplier(entries) {
839
+ for (const entry of entries) {
840
+ applyStoreOverrides(diOverrideStore, "modules", entry.overrides, { label: "di" });
841
+ }
842
+ }
843
+ function encryptionOverridesApplier(entries) {
844
+ for (const entry of entries) {
845
+ applyStoreOverrides(encryptionMapOverrideStore, "modules", entry.overrides?.maps, { label: "encryption.maps" });
846
+ }
847
+ }
848
+ function registerBuiltInModuleOverrideAppliers() {
849
+ registerModuleOverrideApplier("routes", routesOverridesApplier);
850
+ registerModuleOverrideApplier("events", eventsOverridesApplier);
851
+ registerModuleOverrideApplier("workers", workersOverridesApplier);
852
+ registerModuleOverrideApplier("widgets", widgetsOverridesApplier);
853
+ registerModuleOverrideApplier("notifications", notificationsOverridesApplier);
854
+ registerModuleOverrideApplier("interceptors", interceptorsOverridesApplier);
855
+ registerModuleOverrideApplier("commandInterceptors", commandInterceptorsOverridesApplier);
856
+ registerModuleOverrideApplier("enrichers", enrichersOverridesApplier);
857
+ registerModuleOverrideApplier("guards", guardsOverridesApplier);
858
+ registerModuleOverrideApplier("cli", cliOverridesApplier);
859
+ registerModuleOverrideApplier("setup", setupOverridesApplier);
860
+ registerModuleOverrideApplier("acl", aclOverridesApplier);
861
+ registerModuleOverrideApplier("di", diOverridesApplier);
862
+ registerModuleOverrideApplier("encryption", encryptionOverridesApplier);
863
+ }
864
+ registerBuiltInModuleOverrideAppliers();
59
865
  export {
866
+ applyAclFeatureOverrides,
867
+ applyApiInterceptorOverrides,
868
+ applyApiInterceptorOverridesToEntries,
869
+ applyApiOverridesToManifests,
870
+ applyApiRouteOverrides,
871
+ applyCliOverrides,
872
+ applyCommandInterceptorOverrides,
873
+ applyCommandInterceptorOverridesToEntries,
874
+ applyComponentOverrides,
875
+ applyComponentOverridesToEntries,
876
+ applyDashboardWidgetOverrides,
877
+ applyDashboardWidgetOverridesToEntries,
878
+ applyDiOverrides,
879
+ applyDiOverridesToContainer,
880
+ applyEncryptionMapOverrides,
881
+ applyInjectionWidgetOverrides,
882
+ applyInjectionWidgetOverridesToEntries,
883
+ applyInjectionWidgetOverridesToTables,
60
884
  applyModuleOverridesFromEnabledModules,
885
+ applyModuleOverridesToModules,
886
+ applyNotificationHandlerOverrides,
887
+ applyNotificationHandlerOverridesToEntries,
888
+ applyNotificationTypeOverrides,
889
+ applyNotificationTypeOverridesToEntries,
890
+ applyPageGuardOverrides,
891
+ applyPageGuardOverridesToEntries,
892
+ applyPageOverridesToManifests,
893
+ applyPageRouteOverrides,
894
+ applyResponseEnricherOverrides,
895
+ applyResponseEnricherOverridesToEntries,
896
+ applySubscriberOverrides,
897
+ applyWorkerOverrides,
898
+ applyWorkerOverridesToDescriptors,
899
+ composeAclFeatureOverrides,
900
+ composeApiInterceptorOverrides,
901
+ composeApiRouteOverrides,
902
+ composeCliOverrides,
903
+ composeCommandInterceptorOverrides,
904
+ composeComponentOverrides,
905
+ composeDashboardWidgetOverrides,
906
+ composeDiOverrides,
907
+ composeEncryptionMapOverrides,
908
+ composeInjectionWidgetOverrides,
909
+ composeNotificationHandlerOverrides,
910
+ composeNotificationTypeOverrides,
911
+ composePageGuardOverrides,
912
+ composePageRouteOverrides,
913
+ composeResponseEnricherOverrides,
914
+ composeSubscriberOverrides,
915
+ composeWorkerOverrides,
61
916
  registerModuleOverrideApplier,
917
+ resetApiRouteOverridesForTests,
918
+ resetModuleContractOverridesForTests,
62
919
  resetModuleOverrideAppliersForTests
63
920
  };
64
921
  //# sourceMappingURL=overrides.js.map