@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.
- package/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +24 -0
- package/dist/lib/bootstrap/factory.js +3 -1
- package/dist/lib/bootstrap/factory.js.map +2 -2
- package/dist/lib/commands/command-interceptor-store.js +3 -1
- package/dist/lib/commands/command-interceptor-store.js.map +2 -2
- package/dist/lib/crud/enricher-registry.js +3 -1
- package/dist/lib/crud/enricher-registry.js.map +2 -2
- package/dist/lib/crud/factory.js.map +1 -1
- package/dist/lib/crud/interceptor-registry.js +3 -1
- package/dist/lib/crud/interceptor-registry.js.map +2 -2
- package/dist/lib/crud/sync-event-runner.js +2 -8
- package/dist/lib/crud/sync-event-runner.js.map +2 -2
- package/dist/lib/db/mikro.js +27 -3
- package/dist/lib/db/mikro.js.map +2 -2
- package/dist/lib/di/container.js +16 -0
- package/dist/lib/di/container.js.map +2 -2
- package/dist/lib/events/patterns.js +2 -10
- package/dist/lib/events/patterns.js.map +2 -2
- package/dist/lib/middleware/page-executor.js +2 -1
- package/dist/lib/middleware/page-executor.js.map +2 -2
- package/dist/lib/modules/registry.js +2 -1
- package/dist/lib/modules/registry.js.map +2 -2
- package/dist/lib/notifications/handler-registry.js +3 -1
- package/dist/lib/notifications/handler-registry.js.map +2 -2
- package/dist/lib/patterns/wildcard.js +42 -0
- package/dist/lib/patterns/wildcard.js.map +7 -0
- package/dist/lib/regex/linear.js +31 -0
- package/dist/lib/regex/linear.js.map +7 -0
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/modules/entities/validation.js +15 -7
- package/dist/modules/entities/validation.js.map +2 -2
- package/dist/modules/overrides.js +857 -0
- package/dist/modules/overrides.js.map +2 -2
- package/dist/modules/registry.js +17 -4
- package/dist/modules/registry.js.map +2 -2
- package/dist/modules/widgets/injection-loader.js +12 -6
- package/dist/modules/widgets/injection-loader.js.map +2 -2
- package/jest.config.cjs +3 -1
- package/package.json +8 -8
- package/src/lib/bootstrap/factory.ts +3 -1
- package/src/lib/commands/command-interceptor-store.ts +3 -1
- package/src/lib/crud/__tests__/sync-event-runner.test.ts +5 -0
- package/src/lib/crud/enricher-registry.ts +3 -1
- package/src/lib/crud/factory.ts +2 -2
- package/src/lib/crud/interceptor-registry.ts +3 -1
- package/src/lib/crud/sync-event-runner.ts +2 -11
- package/src/lib/db/mikro.ts +27 -2
- package/src/lib/di/container.ts +24 -4
- package/src/lib/events/__tests__/patterns.test.ts +5 -0
- package/src/lib/events/patterns.ts +3 -16
- package/src/lib/middleware/page-executor.ts +2 -1
- package/src/lib/modules/registry.ts +2 -1
- package/src/lib/notifications/handler-registry.ts +3 -1
- package/src/lib/patterns/__tests__/wildcard.test.ts +27 -0
- package/src/lib/patterns/wildcard.ts +59 -0
- package/src/lib/regex/linear.ts +48 -0
- package/src/modules/__tests__/contract-overrides.test.ts +332 -0
- package/src/modules/__tests__/overrides.test.ts +23 -22
- package/src/modules/__tests__/route-overrides.test.ts +441 -0
- package/src/modules/entities/__tests__/validation.test.ts +97 -2
- package/src/modules/entities/validation.ts +14 -9
- package/src/modules/overrides.ts +1297 -27
- package/src/modules/registry.ts +27 -4
- package/src/modules/widgets/__tests__/injection-loader.required-modules.test.ts +21 -0
- package/src/modules/widgets/injection-loader.ts +12 -6
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
[build:shared] found
|
|
1
|
+
[build:shared] found 211 entry points
|
|
2
2
|
[build:shared] built successfully
|
package/AGENTS.md
CHANGED
|
@@ -43,6 +43,7 @@ When you need shared type definitions, import from these:
|
|
|
43
43
|
| Search config types (`SearchModuleConfig`) | `@open-mercato/shared/modules/search` |
|
|
44
44
|
| Module setup types (`ModuleSetupConfig`) | `@open-mercato/shared/modules/setup` |
|
|
45
45
|
| Module registry types (`Module`) | `@open-mercato/shared/modules/registry` |
|
|
46
|
+
| Module-level overrides (`ModuleOverrides`, dispatcher, per-domain compose helpers) | `@open-mercato/shared/modules/overrides` |
|
|
46
47
|
|
|
47
48
|
## Key Patterns
|
|
48
49
|
|
|
@@ -94,6 +95,29 @@ import { hasFeature, hasAllFeatures } from '@open-mercato/shared/security/featur
|
|
|
94
95
|
- Use `parseIdsParam()` and `mergeIdFilter()` from `@open-mercato/shared/lib/crud/ids` for factory-level `ids` query support.
|
|
95
96
|
- Keep `ids` format as comma-separated UUIDs (`?ids=uuid1,uuid2`) and intersect with existing `id` filters.
|
|
96
97
|
|
|
98
|
+
### Module-Level Overrides (`@open-mercato/shared/modules/overrides`)
|
|
99
|
+
|
|
100
|
+
Downstream apps replace or disable any contract a module presents through a single `entry.overrides` field on a `ModuleEntry`. The umbrella spec is `.ai/specs/2026-05-04-modules-ts-unified-overrides.md`; phases 1-18 are wired.
|
|
101
|
+
|
|
102
|
+
| Use case | Helper |
|
|
103
|
+
|----------|--------|
|
|
104
|
+
| Walk `enabledModules` and dispatch every `overrides.<domain>` shape to wired appliers | `applyModuleOverridesFromEnabledModules(enabledModules)` |
|
|
105
|
+
| Register a per-domain runtime hook (used by each wired phase) | `registerModuleOverrideApplier('<domain>', applier)` |
|
|
106
|
+
| API routes | `applyApiRouteOverrides()`, `composeApiRouteOverrides()`, `applyApiOverridesToManifests()` |
|
|
107
|
+
| Page routes | `applyPageRouteOverrides()`, `composePageRouteOverrides()`, `applyPageOverridesToManifests()` |
|
|
108
|
+
| Subscribers / workers / CLI / ACL / encryption / setup | `applyModuleOverridesToModules()` plus `applySubscriberOverrides()`, `applyWorkerOverrides()`, `applyCliOverrides()`, `applyAclFeatureOverrides()`, `applyEncryptionMapOverrides()` |
|
|
109
|
+
| Widgets | `applyInjectionWidgetOverridesToEntries()`, `applyInjectionWidgetOverridesToTables()`, `applyDashboardWidgetOverridesToEntries()`, `applyComponentOverridesToEntries()` |
|
|
110
|
+
| Notifications / interceptors / enrichers / guards | `applyNotificationTypeOverridesToEntries()`, `applyNotificationHandlerOverridesToEntries()`, `applyApiInterceptorOverridesToEntries()`, `applyCommandInterceptorOverridesToEntries()`, `applyResponseEnricherOverridesToEntries()`, `applyPageGuardOverridesToEntries()` |
|
|
111
|
+
| DI | `applyDiOverridesToContainer()` |
|
|
112
|
+
|
|
113
|
+
MUST rules:
|
|
114
|
+
- `entry.overrides` is the ONLY canonical override surface — never patch upstream module source.
|
|
115
|
+
- API-route override keys are `'METHOD /api/path'` (method case-insensitive, path leading slash optional). Trailing slashes are stripped.
|
|
116
|
+
- Page-route override keys are `'/backend/path'` or `'/frontend/path'`.
|
|
117
|
+
- `null` disables the matching method; `{ handler, metadata? }` replaces it. Disabling every method on an entry drops the entry.
|
|
118
|
+
- The dispatcher SHOULD run from `bootstrap.ts` BEFORE any registry first-loads (`registerApiRouteManifests`, widget registries, notification registries, etc.) so the overrides take effect when the registry stores entries.
|
|
119
|
+
- Adding a new override domain MUST follow the umbrella spec: typed sub-shape + composer + runtime hook + tests + AGENTS.md/docs update + status-table tick.
|
|
120
|
+
|
|
97
121
|
### Query Engine Extensibility (UMES)
|
|
98
122
|
|
|
99
123
|
Query engines support optional extension hooks via `QueryOptions.extensions`:
|
|
@@ -12,6 +12,7 @@ import { registerMutationGuards } from "../crud/mutation-guard-store.js";
|
|
|
12
12
|
import { registerCommandInterceptors } from "../commands/command-interceptor-store.js";
|
|
13
13
|
import { registerNotificationHandlers } from "../notifications/handler-registry.js";
|
|
14
14
|
import { clearRegisteredIntegrations, registerBundles, registerIntegrations } from "../../modules/integrations/types.js";
|
|
15
|
+
import { applyComponentOverridesToEntries } from "../../modules/overrides.js";
|
|
15
16
|
let _bootstrapped = false;
|
|
16
17
|
let _asyncRegistrationPromise = null;
|
|
17
18
|
function createBootstrap(data, options = {}) {
|
|
@@ -47,7 +48,8 @@ function createBootstrap(data, options = {}) {
|
|
|
47
48
|
registerApiInterceptors(data.interceptorEntries);
|
|
48
49
|
}
|
|
49
50
|
if (data.componentOverrideEntries) {
|
|
50
|
-
const
|
|
51
|
+
const finalEntries = applyComponentOverridesToEntries(data.componentOverrideEntries);
|
|
52
|
+
const allOverrides = finalEntries.flatMap((entry) => entry.componentOverrides ?? []);
|
|
51
53
|
registerComponentOverrides(allOverrides);
|
|
52
54
|
}
|
|
53
55
|
if (data.guardEntries) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/bootstrap/factory.ts"],
|
|
4
|
-
"sourcesContent": ["import type { BootstrapData, BootstrapOptions } from './types'\nimport { registerOrmEntities } from '../db/mikro'\nimport { registerDiRegistrars } from '../di/container'\nimport { registerModules } from '../modules/registry'\nimport { registerEntityIds } from '../encryption/entityIds'\nimport { registerEntityFields } from '../encryption/entityFields'\nimport { registerSearchModuleConfigs } from '../../modules/search'\nimport { registerAnalyticsModuleConfigs } from '../../modules/analytics'\nimport { registerResponseEnrichers } from '../crud/enricher-registry'\nimport { registerApiInterceptors } from '../crud/interceptor-registry'\nimport { registerComponentOverrides } from '../../modules/widgets/component-registry'\nimport { registerMutationGuards } from '../crud/mutation-guard-store'\nimport { registerCommandInterceptors } from '../commands/command-interceptor-store'\nimport { registerNotificationHandlers } from '../notifications/handler-registry'\nimport { clearRegisteredIntegrations, registerBundles, registerIntegrations } from '../../modules/integrations/types'\n\nlet _bootstrapped = false\n\n// Store the async registration promise so callers can await it if needed\nlet _asyncRegistrationPromise: Promise<void> | null = null\n\n/**\n * Creates a bootstrap function that registers all application dependencies.\n *\n * The returned function should be called once at application startup.\n * In development mode, it can be called multiple times (for HMR).\n *\n * @param data - All generated registry data from .mercato/generated/\n * @param options - Optional configuration\n * @returns A bootstrap function to call at app startup\n */\nexport function createBootstrap(data: BootstrapData, options: BootstrapOptions = {}) {\n return function bootstrap(): void {\n // In development, always re-run registrations to handle HMR\n // (Module state may be reset when Turbopack reloads packages)\n if (_bootstrapped && process.env.NODE_ENV !== 'development') return\n _bootstrapped = true\n\n // === 1. Foundation: ORM entities and DI registrars ===\n registerOrmEntities(data.entities)\n registerDiRegistrars(data.diRegistrars.filter((r): r is NonNullable<typeof r> => r != null))\n\n // === 2. Modules registry (required by i18n, query engine, dashboards, CLI) ===\n registerModules(data.modules)\n clearRegisteredIntegrations()\n for (const module of data.modules) {\n if (module.integrations?.length) {\n registerIntegrations(module.integrations)\n }\n if (module.bundles?.length) {\n registerBundles(module.bundles)\n }\n }\n\n // === 3. Entity IDs (required by encryption, indexing, entity links) ===\n registerEntityIds(data.entityIds)\n\n // === 4. Entity fields registry (for encryption manager, Turbopack compatibility) ===\n if (data.entityFieldsRegistry) {\n registerEntityFields(data.entityFieldsRegistry)\n }\n\n // === 5. Search module configs (for search service registration in DI) ===\n if (data.searchModuleConfigs) {\n registerSearchModuleConfigs(data.searchModuleConfigs)\n }\n\n // === 6. Analytics module configs (for dashboard widgets and analytics API) ===\n if (data.analyticsModuleConfigs) {\n registerAnalyticsModuleConfigs(data.analyticsModuleConfigs)\n }\n\n // === 6b. Response enrichers (for CRUD response enrichment) ===\n if (data.enricherEntries) {\n registerResponseEnrichers(data.enricherEntries)\n }\n\n // === 6c. API interceptors (for CRUD route interception) ===\n if (data.interceptorEntries) {\n registerApiInterceptors(data.interceptorEntries)\n }\n\n // === 6d. Component overrides (for page/component replacement) ===\n if (data.componentOverrideEntries) {\n const
|
|
5
|
-
"mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,4BAA4B;AACrC,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,mCAAmC;AAC5C,SAAS,sCAAsC;AAC/C,SAAS,iCAAiC;AAC1C,SAAS,+BAA+B;AACxC,SAAS,kCAAkC;AAC3C,SAAS,8BAA8B;AACvC,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,6BAA6B,iBAAiB,4BAA4B;
|
|
4
|
+
"sourcesContent": ["import type { BootstrapData, BootstrapOptions } from './types'\nimport { registerOrmEntities } from '../db/mikro'\nimport { registerDiRegistrars } from '../di/container'\nimport { registerModules } from '../modules/registry'\nimport { registerEntityIds } from '../encryption/entityIds'\nimport { registerEntityFields } from '../encryption/entityFields'\nimport { registerSearchModuleConfigs } from '../../modules/search'\nimport { registerAnalyticsModuleConfigs } from '../../modules/analytics'\nimport { registerResponseEnrichers } from '../crud/enricher-registry'\nimport { registerApiInterceptors } from '../crud/interceptor-registry'\nimport { registerComponentOverrides } from '../../modules/widgets/component-registry'\nimport { registerMutationGuards } from '../crud/mutation-guard-store'\nimport { registerCommandInterceptors } from '../commands/command-interceptor-store'\nimport { registerNotificationHandlers } from '../notifications/handler-registry'\nimport { clearRegisteredIntegrations, registerBundles, registerIntegrations } from '../../modules/integrations/types'\nimport { applyComponentOverridesToEntries } from '../../modules/overrides'\n\nlet _bootstrapped = false\n\n// Store the async registration promise so callers can await it if needed\nlet _asyncRegistrationPromise: Promise<void> | null = null\n\n/**\n * Creates a bootstrap function that registers all application dependencies.\n *\n * The returned function should be called once at application startup.\n * In development mode, it can be called multiple times (for HMR).\n *\n * @param data - All generated registry data from .mercato/generated/\n * @param options - Optional configuration\n * @returns A bootstrap function to call at app startup\n */\nexport function createBootstrap(data: BootstrapData, options: BootstrapOptions = {}) {\n return function bootstrap(): void {\n // In development, always re-run registrations to handle HMR\n // (Module state may be reset when Turbopack reloads packages)\n if (_bootstrapped && process.env.NODE_ENV !== 'development') return\n _bootstrapped = true\n\n // === 1. Foundation: ORM entities and DI registrars ===\n registerOrmEntities(data.entities)\n registerDiRegistrars(data.diRegistrars.filter((r): r is NonNullable<typeof r> => r != null))\n\n // === 2. Modules registry (required by i18n, query engine, dashboards, CLI) ===\n registerModules(data.modules)\n clearRegisteredIntegrations()\n for (const module of data.modules) {\n if (module.integrations?.length) {\n registerIntegrations(module.integrations)\n }\n if (module.bundles?.length) {\n registerBundles(module.bundles)\n }\n }\n\n // === 3. Entity IDs (required by encryption, indexing, entity links) ===\n registerEntityIds(data.entityIds)\n\n // === 4. Entity fields registry (for encryption manager, Turbopack compatibility) ===\n if (data.entityFieldsRegistry) {\n registerEntityFields(data.entityFieldsRegistry)\n }\n\n // === 5. Search module configs (for search service registration in DI) ===\n if (data.searchModuleConfigs) {\n registerSearchModuleConfigs(data.searchModuleConfigs)\n }\n\n // === 6. Analytics module configs (for dashboard widgets and analytics API) ===\n if (data.analyticsModuleConfigs) {\n registerAnalyticsModuleConfigs(data.analyticsModuleConfigs)\n }\n\n // === 6b. Response enrichers (for CRUD response enrichment) ===\n if (data.enricherEntries) {\n registerResponseEnrichers(data.enricherEntries)\n }\n\n // === 6c. API interceptors (for CRUD route interception) ===\n if (data.interceptorEntries) {\n registerApiInterceptors(data.interceptorEntries)\n }\n\n // === 6d. Component overrides (for page/component replacement) ===\n if (data.componentOverrideEntries) {\n const finalEntries = applyComponentOverridesToEntries(data.componentOverrideEntries)\n const allOverrides = finalEntries.flatMap((entry) => entry.componentOverrides ?? [])\n registerComponentOverrides(allOverrides)\n }\n\n // === 6e. Mutation guards (for CRUD mutation lifecycle) ===\n if (data.guardEntries) {\n registerMutationGuards(data.guardEntries)\n }\n\n // === 6f. Command interceptors (for command bus lifecycle) ===\n if (data.commandInterceptorEntries) {\n registerCommandInterceptors(data.commandInterceptorEntries)\n }\n\n // === 6g. Notification handlers (reactive notification side-effects) ===\n if (data.notificationHandlerEntries) {\n registerNotificationHandlers(data.notificationHandlerEntries)\n }\n\n // === 7-8. UI Widgets and Optional packages (async to avoid circular deps) ===\n // Store the promise so CLI context can await it\n _asyncRegistrationPromise = registerWidgetsAndOptionalPackages(data, options)\n void _asyncRegistrationPromise\n\n options.onRegistrationComplete?.()\n }\n}\n\n/**\n * Wait for async registrations (CLI modules, widgets, etc.) to complete.\n * Call this after bootstrap() in CLI context where you need modules immediately.\n */\nexport async function waitForAsyncRegistration(): Promise<void> {\n if (_asyncRegistrationPromise) {\n await _asyncRegistrationPromise\n }\n}\n\nasync function registerWidgetsAndOptionalPackages(data: BootstrapData, options: BootstrapOptions): Promise<void> {\n // Register UI widgets (dynamic imports to avoid circular deps with ui/core packages)\n try {\n const [dashboardRegistry, injectionRegistry, coreInjection] = await Promise.all([\n import('@open-mercato/ui/backend/dashboard/widgetRegistry'),\n import('@open-mercato/ui/backend/injection/widgetRegistry'),\n import('@open-mercato/core/modules/widgets/lib/injection'),\n ])\n\n dashboardRegistry.registerDashboardWidgets(data.dashboardWidgetEntries)\n injectionRegistry.registerInjectionWidgets(data.injectionWidgetEntries)\n coreInjection.registerCoreInjectionWidgets(data.injectionWidgetEntries)\n coreInjection.registerCoreInjectionTables(data.injectionTables)\n coreInjection.registerEnabledModuleIds(\n data.modules.map((module) => module.id).filter((id): id is string => typeof id === 'string' && id.length > 0),\n )\n } catch {\n // UI packages may not be available in all contexts\n }\n\n // Note: Search module configs are registered synchronously in the main bootstrap.\n // The actual registerSearchModule() call happens in core/bootstrap.ts when the\n // DI container is created, using getSearchModuleConfigs() from the global registry.\n\n // Note: CLI module registration is handled separately in CLI context\n // via bootstrapFromAppRoot in dynamicLoader. We don't import CLI here\n // to avoid Turbopack tracing through the CLI package in Next.js context.\n}\n\n/**\n * Check if bootstrap has been called.\n */\nexport function isBootstrapped(): boolean {\n return _bootstrapped\n}\n\n/**\n * Reset bootstrap state. Useful for testing.\n */\nexport function resetBootstrapState(): void {\n _bootstrapped = false\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,2BAA2B;AACpC,SAAS,4BAA4B;AACrC,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAClC,SAAS,4BAA4B;AACrC,SAAS,mCAAmC;AAC5C,SAAS,sCAAsC;AAC/C,SAAS,iCAAiC;AAC1C,SAAS,+BAA+B;AACxC,SAAS,kCAAkC;AAC3C,SAAS,8BAA8B;AACvC,SAAS,mCAAmC;AAC5C,SAAS,oCAAoC;AAC7C,SAAS,6BAA6B,iBAAiB,4BAA4B;AACnF,SAAS,wCAAwC;AAEjD,IAAI,gBAAgB;AAGpB,IAAI,4BAAkD;AAY/C,SAAS,gBAAgB,MAAqB,UAA4B,CAAC,GAAG;AACnF,SAAO,SAAS,YAAkB;AAGhC,QAAI,iBAAiB,QAAQ,IAAI,aAAa,cAAe;AAC7D,oBAAgB;AAGhB,wBAAoB,KAAK,QAAQ;AACjC,yBAAqB,KAAK,aAAa,OAAO,CAAC,MAAkC,KAAK,IAAI,CAAC;AAG3F,oBAAgB,KAAK,OAAO;AAC5B,gCAA4B;AAC5B,eAAW,UAAU,KAAK,SAAS;AACjC,UAAI,OAAO,cAAc,QAAQ;AAC/B,6BAAqB,OAAO,YAAY;AAAA,MAC1C;AACA,UAAI,OAAO,SAAS,QAAQ;AAC1B,wBAAgB,OAAO,OAAO;AAAA,MAChC;AAAA,IACF;AAGA,sBAAkB,KAAK,SAAS;AAGhC,QAAI,KAAK,sBAAsB;AAC7B,2BAAqB,KAAK,oBAAoB;AAAA,IAChD;AAGA,QAAI,KAAK,qBAAqB;AAC5B,kCAA4B,KAAK,mBAAmB;AAAA,IACtD;AAGA,QAAI,KAAK,wBAAwB;AAC/B,qCAA+B,KAAK,sBAAsB;AAAA,IAC5D;AAGA,QAAI,KAAK,iBAAiB;AACxB,gCAA0B,KAAK,eAAe;AAAA,IAChD;AAGA,QAAI,KAAK,oBAAoB;AAC3B,8BAAwB,KAAK,kBAAkB;AAAA,IACjD;AAGA,QAAI,KAAK,0BAA0B;AACjC,YAAM,eAAe,iCAAiC,KAAK,wBAAwB;AACnF,YAAM,eAAe,aAAa,QAAQ,CAAC,UAAU,MAAM,sBAAsB,CAAC,CAAC;AACnF,iCAA2B,YAAY;AAAA,IACzC;AAGA,QAAI,KAAK,cAAc;AACrB,6BAAuB,KAAK,YAAY;AAAA,IAC1C;AAGA,QAAI,KAAK,2BAA2B;AAClC,kCAA4B,KAAK,yBAAyB;AAAA,IAC5D;AAGA,QAAI,KAAK,4BAA4B;AACnC,mCAA6B,KAAK,0BAA0B;AAAA,IAC9D;AAIA,gCAA4B,mCAAmC,MAAM,OAAO;AAC5E,SAAK;AAEL,YAAQ,yBAAyB;AAAA,EACnC;AACF;AAMA,eAAsB,2BAA0C;AAC9D,MAAI,2BAA2B;AAC7B,UAAM;AAAA,EACR;AACF;AAEA,eAAe,mCAAmC,MAAqB,SAA0C;AAE/G,MAAI;AACF,UAAM,CAAC,mBAAmB,mBAAmB,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC9E,OAAO,mDAAmD;AAAA,MAC1D,OAAO,mDAAmD;AAAA,MAC1D,OAAO,kDAAkD;AAAA,IAC3D,CAAC;AAED,sBAAkB,yBAAyB,KAAK,sBAAsB;AACtE,sBAAkB,yBAAyB,KAAK,sBAAsB;AACtE,kBAAc,6BAA6B,KAAK,sBAAsB;AACtE,kBAAc,4BAA4B,KAAK,eAAe;AAC9D,kBAAc;AAAA,MACZ,KAAK,QAAQ,IAAI,CAAC,WAAW,OAAO,EAAE,EAAE,OAAO,CAAC,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AAAA,IAC9G;AAAA,EACF,QAAQ;AAAA,EAER;AASF;AAKO,SAAS,iBAA0B;AACxC,SAAO;AACT;AAKO,SAAS,sBAA4B;AAC1C,kBAAgB;AAClB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { applyCommandInterceptorOverridesToEntries } from "../../modules/overrides.js";
|
|
1
2
|
const GLOBAL_KEY = "__openMercatoCommandInterceptors__";
|
|
2
3
|
let _entries = null;
|
|
3
4
|
function readGlobal() {
|
|
@@ -16,8 +17,9 @@ function writeGlobal(entries) {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
function registerCommandInterceptors(entries) {
|
|
20
|
+
const finalEntries = applyCommandInterceptorOverridesToEntries(entries);
|
|
19
21
|
const flat = [];
|
|
20
|
-
for (const entry of
|
|
22
|
+
for (const entry of finalEntries) {
|
|
21
23
|
for (const interceptor of entry.interceptors) {
|
|
22
24
|
flat.push({ moduleId: entry.moduleId, interceptor });
|
|
23
25
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/commands/command-interceptor-store.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Command Interceptor Store\n *\n * Global registry for command interceptors using the same globalThis pattern\n * as interceptor-registry.ts for HMR-safe storage.\n */\n\nimport type { CommandInterceptor } from './command-interceptor'\n\nexport interface CommandInterceptorRegistryEntry {\n moduleId: string\n interceptor: CommandInterceptor\n}\n\nconst GLOBAL_KEY = '__openMercatoCommandInterceptors__'\n\nlet _entries: CommandInterceptorRegistryEntry[] | null = null\n\nfunction readGlobal(): CommandInterceptorRegistryEntry[] | null {\n try {\n const value = (globalThis as Record<string, unknown>)[GLOBAL_KEY]\n return Array.isArray(value) ? (value as CommandInterceptorRegistryEntry[]) : null\n } catch {\n // globalThis access can throw in restricted environments (e.g., edge runtimes); fall back to local cache\n return null\n }\n}\n\nfunction writeGlobal(entries: CommandInterceptorRegistryEntry[]) {\n try {\n ;(globalThis as Record<string, unknown>)[GLOBAL_KEY] = entries\n } catch {\n // ignore global assignment failures\n }\n}\n\n/**\n * Register command interceptors from all modules.\n * Called during bootstrap after generated interceptors are imported.\n */\nexport function registerCommandInterceptors(\n entries: Array<{ moduleId: string; interceptors: CommandInterceptor[] }>,\n) {\n const flat: CommandInterceptorRegistryEntry[] = []\n for (const entry of
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * Command Interceptor Store\n *\n * Global registry for command interceptors using the same globalThis pattern\n * as interceptor-registry.ts for HMR-safe storage.\n */\n\nimport type { CommandInterceptor } from './command-interceptor'\nimport { applyCommandInterceptorOverridesToEntries } from '../../modules/overrides'\n\nexport interface CommandInterceptorRegistryEntry {\n moduleId: string\n interceptor: CommandInterceptor\n}\n\nconst GLOBAL_KEY = '__openMercatoCommandInterceptors__'\n\nlet _entries: CommandInterceptorRegistryEntry[] | null = null\n\nfunction readGlobal(): CommandInterceptorRegistryEntry[] | null {\n try {\n const value = (globalThis as Record<string, unknown>)[GLOBAL_KEY]\n return Array.isArray(value) ? (value as CommandInterceptorRegistryEntry[]) : null\n } catch {\n // globalThis access can throw in restricted environments (e.g., edge runtimes); fall back to local cache\n return null\n }\n}\n\nfunction writeGlobal(entries: CommandInterceptorRegistryEntry[]) {\n try {\n ;(globalThis as Record<string, unknown>)[GLOBAL_KEY] = entries\n } catch {\n // ignore global assignment failures\n }\n}\n\n/**\n * Register command interceptors from all modules.\n * Called during bootstrap after generated interceptors are imported.\n */\nexport function registerCommandInterceptors(\n entries: Array<{ moduleId: string; interceptors: CommandInterceptor[] }>,\n) {\n const finalEntries = applyCommandInterceptorOverridesToEntries(entries)\n const flat: CommandInterceptorRegistryEntry[] = []\n for (const entry of finalEntries) {\n for (const interceptor of entry.interceptors) {\n flat.push({ moduleId: entry.moduleId, interceptor })\n }\n }\n _entries = flat\n writeGlobal(flat)\n}\n\n/**\n * Get all registered command interceptors.\n */\nexport function getAllCommandInterceptors(): CommandInterceptorRegistryEntry[] {\n const globalEntries = readGlobal()\n if (globalEntries) return globalEntries\n if (!_entries) return []\n return _entries\n}\n\n/**\n * Get all command interceptor instances (unwrapped from registry entries).\n */\nexport function getAllCommandInterceptorInstances(): CommandInterceptor[] {\n return getAllCommandInterceptors().map((entry) => entry.interceptor)\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,iDAAiD;AAO1D,MAAM,aAAa;AAEnB,IAAI,WAAqD;AAEzD,SAAS,aAAuD;AAC9D,MAAI;AACF,UAAM,QAAS,WAAuC,UAAU;AAChE,WAAO,MAAM,QAAQ,KAAK,IAAK,QAA8C;AAAA,EAC/E,QAAQ;AAEN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,YAAY,SAA4C;AAC/D,MAAI;AACF;AAAC,IAAC,WAAuC,UAAU,IAAI;AAAA,EACzD,QAAQ;AAAA,EAER;AACF;AAMO,SAAS,4BACd,SACA;AACA,QAAM,eAAe,0CAA0C,OAAO;AACtE,QAAM,OAA0C,CAAC;AACjD,aAAW,SAAS,cAAc;AAChC,eAAW,eAAe,MAAM,cAAc;AAC5C,WAAK,KAAK,EAAE,UAAU,MAAM,UAAU,YAAY,CAAC;AAAA,IACrD;AAAA,EACF;AACA,aAAW;AACX,cAAY,IAAI;AAClB;AAKO,SAAS,4BAA+D;AAC7E,QAAM,gBAAgB,WAAW;AACjC,MAAI,cAAe,QAAO;AAC1B,MAAI,CAAC,SAAU,QAAO,CAAC;AACvB,SAAO;AACT;AAKO,SAAS,oCAA0D;AACxE,SAAO,0BAA0B,EAAE,IAAI,CAAC,UAAU,MAAM,WAAW;AACrE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { applyResponseEnricherOverridesToEntries } from "../../modules/overrides.js";
|
|
1
2
|
const GLOBAL_ENRICHERS_KEY = "__openMercatoResponseEnrichers__";
|
|
2
3
|
let _enricherEntries = null;
|
|
3
4
|
function readGlobalEnrichers() {
|
|
@@ -16,8 +17,9 @@ function writeGlobalEnrichers(entries) {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
function registerResponseEnrichers(entries) {
|
|
20
|
+
const finalEntries = applyResponseEnricherOverridesToEntries(entries);
|
|
19
21
|
const flat = [];
|
|
20
|
-
for (const entry of
|
|
22
|
+
for (const entry of finalEntries) {
|
|
21
23
|
for (const enricher of entry.enrichers) {
|
|
22
24
|
flat.push({ moduleId: entry.moduleId, enricher });
|
|
23
25
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/lib/crud/enricher-registry.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Response Enricher Registry\n *\n * Global registry for response enrichers using the same globalThis pattern\n * as injection widgets for HMR-safe storage.\n */\n\nimport type { EnricherRegistryEntry, EnricherQueryEngineConfig, ResponseEnricher } from './response-enricher'\n\n/**\n * Selector for filtering enrichers by execution surface.\n *\n * - `'api-response'`: returns all enrichers matching the entity (existing behavior).\n * - `'query-engine'`: returns only enrichers with `queryEngine.enabled === true`\n * and matching the specified engine type.\n */\nexport interface EnricherSurfaceSelector {\n surface: 'api-response' | 'query-engine'\n engine?: 'basic' | 'hybrid'\n}\n\nconst GLOBAL_ENRICHERS_KEY = '__openMercatoResponseEnrichers__'\n\nlet _enricherEntries: EnricherRegistryEntry[] | null = null\n\nfunction readGlobalEnrichers(): EnricherRegistryEntry[] | null {\n try {\n const value = (globalThis as Record<string, unknown>)[GLOBAL_ENRICHERS_KEY]\n return Array.isArray(value) ? (value as EnricherRegistryEntry[]) : null\n } catch {\n return null\n }\n}\n\nfunction writeGlobalEnrichers(entries: EnricherRegistryEntry[]) {\n try {\n ;(globalThis as Record<string, unknown>)[GLOBAL_ENRICHERS_KEY] = entries\n } catch {\n // ignore global assignment failures\n }\n}\n\n/**\n * Register response enrichers from all modules.\n * Called during bootstrap after generated enrichers are imported.\n */\nexport function registerResponseEnrichers(\n entries: Array<{ moduleId: string; enrichers: ResponseEnricher[] }>,\n) {\n const flat: EnricherRegistryEntry[] = []\n for (const entry of
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * Response Enricher Registry\n *\n * Global registry for response enrichers using the same globalThis pattern\n * as injection widgets for HMR-safe storage.\n */\n\nimport type { EnricherRegistryEntry, EnricherQueryEngineConfig, ResponseEnricher } from './response-enricher'\nimport { applyResponseEnricherOverridesToEntries } from '../../modules/overrides'\n\n/**\n * Selector for filtering enrichers by execution surface.\n *\n * - `'api-response'`: returns all enrichers matching the entity (existing behavior).\n * - `'query-engine'`: returns only enrichers with `queryEngine.enabled === true`\n * and matching the specified engine type.\n */\nexport interface EnricherSurfaceSelector {\n surface: 'api-response' | 'query-engine'\n engine?: 'basic' | 'hybrid'\n}\n\nconst GLOBAL_ENRICHERS_KEY = '__openMercatoResponseEnrichers__'\n\nlet _enricherEntries: EnricherRegistryEntry[] | null = null\n\nfunction readGlobalEnrichers(): EnricherRegistryEntry[] | null {\n try {\n const value = (globalThis as Record<string, unknown>)[GLOBAL_ENRICHERS_KEY]\n return Array.isArray(value) ? (value as EnricherRegistryEntry[]) : null\n } catch {\n return null\n }\n}\n\nfunction writeGlobalEnrichers(entries: EnricherRegistryEntry[]) {\n try {\n ;(globalThis as Record<string, unknown>)[GLOBAL_ENRICHERS_KEY] = entries\n } catch {\n // ignore global assignment failures\n }\n}\n\n/**\n * Register response enrichers from all modules.\n * Called during bootstrap after generated enrichers are imported.\n */\nexport function registerResponseEnrichers(\n entries: Array<{ moduleId: string; enrichers: ResponseEnricher[] }>,\n) {\n const finalEntries = applyResponseEnricherOverridesToEntries(entries)\n const flat: EnricherRegistryEntry[] = []\n for (const entry of finalEntries) {\n for (const enricher of entry.enrichers) {\n flat.push({ moduleId: entry.moduleId, enricher })\n }\n }\n flat.sort((a, b) => (b.enricher.priority ?? 0) - (a.enricher.priority ?? 0))\n _enricherEntries = flat\n writeGlobalEnrichers(flat)\n}\n\n/**\n * Get all registered response enrichers.\n */\nexport function getResponseEnrichers(): EnricherRegistryEntry[] {\n const globalEntries = readGlobalEnrichers()\n if (globalEntries) return globalEntries\n if (!_enricherEntries) {\n return []\n }\n return _enricherEntries\n}\n\n/**\n * Get enrichers targeting a specific entity, sorted by priority (higher first).\n *\n * When `selector` is omitted the function returns all enrichers for the entity\n * (backward compatible with existing callers).\n *\n * When `selector.surface === 'api-response'` \u2014 same as omitted (all enrichers).\n * When `selector.surface === 'query-engine'` \u2014 returns only enrichers with\n * `queryEngine.enabled === true` and matching `engines` (defaults to both).\n */\nexport function getEnrichersForEntity(\n targetEntity: string,\n selector?: EnricherSurfaceSelector,\n): EnricherRegistryEntry[] {\n const entityEntries = getResponseEnrichers().filter(\n (entry) => entry.enricher.targetEntity === targetEntity,\n )\n\n if (!selector || selector.surface === 'api-response') {\n return entityEntries\n }\n\n return entityEntries.filter((entry) => {\n const qeConfig: EnricherQueryEngineConfig | undefined = entry.enricher.queryEngine\n if (!qeConfig || !qeConfig.enabled) return false\n if (selector.engine && qeConfig.engines && qeConfig.engines.length > 0) {\n return qeConfig.engines.includes(selector.engine)\n }\n return true\n })\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,+CAA+C;AAcxD,MAAM,uBAAuB;AAE7B,IAAI,mBAAmD;AAEvD,SAAS,sBAAsD;AAC7D,MAAI;AACF,UAAM,QAAS,WAAuC,oBAAoB;AAC1E,WAAO,MAAM,QAAQ,KAAK,IAAK,QAAoC;AAAA,EACrE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,qBAAqB,SAAkC;AAC9D,MAAI;AACF;AAAC,IAAC,WAAuC,oBAAoB,IAAI;AAAA,EACnE,QAAQ;AAAA,EAER;AACF;AAMO,SAAS,0BACd,SACA;AACA,QAAM,eAAe,wCAAwC,OAAO;AACpE,QAAM,OAAgC,CAAC;AACvC,aAAW,SAAS,cAAc;AAChC,eAAW,YAAY,MAAM,WAAW;AACtC,WAAK,KAAK,EAAE,UAAU,MAAM,UAAU,SAAS,CAAC;AAAA,IAClD;AAAA,EACF;AACA,OAAK,KAAK,CAAC,GAAG,OAAO,EAAE,SAAS,YAAY,MAAM,EAAE,SAAS,YAAY,EAAE;AAC3E,qBAAmB;AACnB,uBAAqB,IAAI;AAC3B;AAKO,SAAS,uBAAgD;AAC9D,QAAM,gBAAgB,oBAAoB;AAC1C,MAAI,cAAe,QAAO;AAC1B,MAAI,CAAC,kBAAkB;AACrB,WAAO,CAAC;AAAA,EACV;AACA,SAAO;AACT;AAYO,SAAS,sBACd,cACA,UACyB;AACzB,QAAM,gBAAgB,qBAAqB,EAAE;AAAA,IAC3C,CAAC,UAAU,MAAM,SAAS,iBAAiB;AAAA,EAC7C;AAEA,MAAI,CAAC,YAAY,SAAS,YAAY,gBAAgB;AACpD,WAAO;AAAA,EACT;AAEA,SAAO,cAAc,OAAO,CAAC,UAAU;AACrC,UAAM,WAAkD,MAAM,SAAS;AACvE,QAAI,CAAC,YAAY,CAAC,SAAS,QAAS,QAAO;AAC3C,QAAI,SAAS,UAAU,SAAS,WAAW,SAAS,QAAQ,SAAS,GAAG;AACtE,aAAO,SAAS,QAAQ,SAAS,SAAS,MAAM;AAAA,IAClD;AACA,WAAO;AAAA,EACT,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|