@open-mercato/shared 0.6.4-develop.3968.1.9d87f5fa16 → 0.6.4-develop.3978.1.2f05baffed
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/version.js +1 -1
- package/dist/lib/version.js.map +1 -1
- package/dist/modules/events/factory.js +12 -6
- package/dist/modules/events/factory.js.map +2 -2
- package/package.json +2 -2
- package/src/lib/data/__tests__/engine.event-validation.test.ts +38 -1
- package/src/modules/events/factory.ts +15 -8
package/dist/lib/version.js
CHANGED
package/dist/lib/version.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/version.ts"],
|
|
4
|
-
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.4-develop.
|
|
4
|
+
"sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.4-develop.3978.1.2f05baffed'\nexport const appVersion = APP_VERSION\n"],
|
|
5
5
|
"mappings": "AACO,MAAM,cAAc;AACpB,MAAM,aAAa;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -20,6 +20,12 @@ function getGlobalEventBus() {
|
|
|
20
20
|
}
|
|
21
21
|
const allDeclaredEventIds = /* @__PURE__ */ new Set();
|
|
22
22
|
const allDeclaredEvents = [];
|
|
23
|
+
function addDeclaredEvent(event) {
|
|
24
|
+
allDeclaredEventIds.add(event.id);
|
|
25
|
+
if (!allDeclaredEvents.find((e) => e.id === event.id)) {
|
|
26
|
+
allDeclaredEvents.push(event);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
23
29
|
function isEventDeclared(eventId) {
|
|
24
30
|
return allDeclaredEventIds.has(eventId);
|
|
25
31
|
}
|
|
@@ -43,6 +49,11 @@ function registerEventModuleConfigs(configs) {
|
|
|
43
49
|
console.debug("[Bootstrap] Event module configs re-registered (this may occur during HMR)");
|
|
44
50
|
}
|
|
45
51
|
_registeredEventConfigs = configs;
|
|
52
|
+
for (const config of configs) {
|
|
53
|
+
for (const event of config.events) {
|
|
54
|
+
addDeclaredEvent(event);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
46
57
|
}
|
|
47
58
|
function getEventModuleConfigs() {
|
|
48
59
|
return _registeredEventConfigs ?? [];
|
|
@@ -54,13 +65,8 @@ function createModuleEvents(options) {
|
|
|
54
65
|
...e,
|
|
55
66
|
module: moduleId
|
|
56
67
|
}));
|
|
57
|
-
for (const eventId of validEventIds) {
|
|
58
|
-
allDeclaredEventIds.add(eventId);
|
|
59
|
-
}
|
|
60
68
|
for (const event of fullEvents) {
|
|
61
|
-
|
|
62
|
-
allDeclaredEvents.push(event);
|
|
63
|
-
}
|
|
69
|
+
addDeclaredEvent(event);
|
|
64
70
|
}
|
|
65
71
|
const emit = async (eventId, payload, emitOptions) => {
|
|
66
72
|
if (!validEventIds.has(eventId)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/modules/events/factory.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Event Module Factory\n *\n * Provides factory functions for creating type-safe event configurations.\n */\n\nimport type {\n EventDefinition,\n EventModuleConfig,\n EventPayload,\n EmitOptions,\n CreateModuleEventsOptions,\n ModuleEventEmitter,\n} from './types'\n\n// =============================================================================\n// Global Event Bus Reference\n// =============================================================================\n\n/**\n * Type for the global event bus interface\n */\ninterface GlobalEventBus {\n emit(event: string, payload: unknown, options?: EmitOptions): Promise<void>\n}\n\nconst GLOBAL_EVENT_BUS_KEY = '__openMercatoGlobalEventBus__'\n\n// Global event bus reference (set during bootstrap)\nlet globalEventBus: GlobalEventBus | null = null\n\n/**\n * Set the global event bus instance.\n * Called during app bootstrap to wire up event emission.\n */\nexport function setGlobalEventBus(bus: GlobalEventBus): void {\n globalEventBus = bus\n try {\n ;(globalThis as Record<string, unknown>)[GLOBAL_EVENT_BUS_KEY] = bus\n } catch {\n // ignore global assignment failures\n }\n}\n\n/**\n * Get the global event bus instance.\n * Returns null if not yet bootstrapped.\n */\nexport function getGlobalEventBus(): GlobalEventBus | null {\n try {\n const sharedBus = (globalThis as Record<string, unknown>)[GLOBAL_EVENT_BUS_KEY]\n if (sharedBus && typeof sharedBus === 'object' && typeof (sharedBus as GlobalEventBus).emit === 'function') {\n return sharedBus as GlobalEventBus\n }\n } catch {\n // ignore global read failures\n }\n return globalEventBus\n}\n\n// =============================================================================\n// Event Registry for Validation\n// =============================================================================\n\n// Global set of all declared event IDs for runtime validation\nconst allDeclaredEventIds = new Set<string>()\n\n// Global registry of all declared events with their full definitions\nconst allDeclaredEvents: EventDefinition[] = []\n\n/**\n * Check if an event ID has been declared by any module.\n * Used for runtime validation to ensure only declared events are emitted.\n */\nexport function isEventDeclared(eventId: string): boolean {\n return allDeclaredEventIds.has(eventId)\n}\n\n/**\n * Get all declared event IDs.\n * Useful for debugging and introspection.\n */\nexport function getAllDeclaredEventIds(): string[] {\n return Array.from(allDeclaredEventIds)\n}\n\n/**\n * Get all declared events with their full definitions.\n * Used by the API to return available events for workflow triggers.\n */\nexport function getDeclaredEvents(): EventDefinition[] {\n return [...allDeclaredEvents]\n}\n\n/**\n * Check if an event has clientBroadcast enabled.\n * Used by the SSE endpoint to filter events for the DOM Event Bridge.\n */\nexport function isBroadcastEvent(eventId: string): boolean {\n const event = allDeclaredEvents.find(e => e.id === eventId)\n return event?.clientBroadcast === true\n}\n\n/**\n * Check if an event has portalBroadcast enabled.\n * Used by the portal SSE endpoint to filter events for the Portal Event Bridge.\n */\nexport function isPortalBroadcastEvent(eventId: string): boolean {\n const event = allDeclaredEvents.find(e => e.id === eventId)\n return event?.portalBroadcast === true\n}\n\n// =============================================================================\n// Bootstrap Registration (similar to searchModuleConfigs pattern)\n// =============================================================================\n\nlet _registeredEventConfigs: EventModuleConfig[] | null = null\n\n/**\n * Register event module configurations globally.\n * Called during app bootstrap with configs from events.generated.ts.\n */\nexport function registerEventModuleConfigs(configs: EventModuleConfig[]): void {\n if (_registeredEventConfigs !== null && process.env.NODE_ENV === 'development') {\n console.debug('[Bootstrap] Event module configs re-registered (this may occur during HMR)')\n }\n _registeredEventConfigs = configs\n}\n\n/**\n * Get registered event module configurations.\n * Returns empty array if not registered.\n */\nexport function getEventModuleConfigs(): EventModuleConfig[] {\n return _registeredEventConfigs ?? []\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Creates a type-safe event configuration for a module.\n *\n * Usage in module events.ts:\n * ```typescript\n * import { createModuleEvents } from '@open-mercato/shared/modules/events'\n *\n * const events = [\n * { id: 'customers.people.created', label: 'Person Created', category: 'crud' },\n * { id: 'customers.people.updated', label: 'Person Updated', category: 'crud' },\n * ] as const\n *\n * export const eventsConfig = createModuleEvents({\n * moduleId: 'customers',\n * events,\n * })\n *\n * // Export the typed emit function for use in commands\n * export const emitCustomersEvent = eventsConfig.emit\n *\n * // Export event IDs as a type for external use\n * export type CustomersEventId = typeof events[number]['id']\n *\n * export default eventsConfig\n * ```\n *\n * TypeScript will enforce that only declared event IDs can be emitted:\n * ```typescript\n * // \u2705 This compiles - event is declared\n * emitCustomersEvent('customers.people.created', { id: '123', tenantId: 'abc' })\n *\n * // \u274C TypeScript error - event not declared\n * emitCustomersEvent('customers.people.exploded', { id: '123' })\n * ```\n */\nexport function createModuleEvents<\n const TEvents extends readonly { id: string }[],\n TEventIds extends TEvents[number]['id'] = TEvents[number]['id']\n>(options: CreateModuleEventsOptions<TEventIds>): EventModuleConfig<TEventIds> {\n const { moduleId, events, strict = false } = options\n\n // Build set of valid event IDs for runtime validation\n const validEventIds = new Set(events.map(e => e.id))\n\n // Build full event definitions with module added\n const fullEvents: EventDefinition[] = events.map(e => ({\n ...e,\n module: moduleId,\n }))\n\n // Register all event IDs and definitions in the global registry
|
|
5
|
-
"mappings": "AA0BA,MAAM,uBAAuB;AAG7B,IAAI,iBAAwC;AAMrC,SAAS,kBAAkB,KAA2B;AAC3D,mBAAiB;AACjB,MAAI;AACF;AAAC,IAAC,WAAuC,oBAAoB,IAAI;AAAA,EACnE,QAAQ;AAAA,EAER;AACF;AAMO,SAAS,oBAA2C;AACzD,MAAI;AACF,UAAM,YAAa,WAAuC,oBAAoB;AAC9E,QAAI,aAAa,OAAO,cAAc,YAAY,OAAQ,UAA6B,SAAS,YAAY;AAC1G,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAOA,MAAM,sBAAsB,oBAAI,IAAY;AAG5C,MAAM,oBAAuC,CAAC;
|
|
4
|
+
"sourcesContent": ["/**\n * Event Module Factory\n *\n * Provides factory functions for creating type-safe event configurations.\n */\n\nimport type {\n EventDefinition,\n EventModuleConfig,\n EventPayload,\n EmitOptions,\n CreateModuleEventsOptions,\n ModuleEventEmitter,\n} from './types'\n\n// =============================================================================\n// Global Event Bus Reference\n// =============================================================================\n\n/**\n * Type for the global event bus interface\n */\ninterface GlobalEventBus {\n emit(event: string, payload: unknown, options?: EmitOptions): Promise<void>\n}\n\nconst GLOBAL_EVENT_BUS_KEY = '__openMercatoGlobalEventBus__'\n\n// Global event bus reference (set during bootstrap)\nlet globalEventBus: GlobalEventBus | null = null\n\n/**\n * Set the global event bus instance.\n * Called during app bootstrap to wire up event emission.\n */\nexport function setGlobalEventBus(bus: GlobalEventBus): void {\n globalEventBus = bus\n try {\n ;(globalThis as Record<string, unknown>)[GLOBAL_EVENT_BUS_KEY] = bus\n } catch {\n // ignore global assignment failures\n }\n}\n\n/**\n * Get the global event bus instance.\n * Returns null if not yet bootstrapped.\n */\nexport function getGlobalEventBus(): GlobalEventBus | null {\n try {\n const sharedBus = (globalThis as Record<string, unknown>)[GLOBAL_EVENT_BUS_KEY]\n if (sharedBus && typeof sharedBus === 'object' && typeof (sharedBus as GlobalEventBus).emit === 'function') {\n return sharedBus as GlobalEventBus\n }\n } catch {\n // ignore global read failures\n }\n return globalEventBus\n}\n\n// =============================================================================\n// Event Registry for Validation\n// =============================================================================\n\n// Global set of all declared event IDs for runtime validation\nconst allDeclaredEventIds = new Set<string>()\n\n// Global registry of all declared events with their full definitions\nconst allDeclaredEvents: EventDefinition[] = []\n\nfunction addDeclaredEvent(event: EventDefinition): void {\n allDeclaredEventIds.add(event.id)\n // Avoid duplicates if createModuleEvents/registerEventModuleConfigs is called multiple times (e.g., HMR)\n if (!allDeclaredEvents.find(e => e.id === event.id)) {\n allDeclaredEvents.push(event)\n }\n}\n\n/**\n * Check if an event ID has been declared by any module.\n * Used for runtime validation to ensure only declared events are emitted.\n */\nexport function isEventDeclared(eventId: string): boolean {\n return allDeclaredEventIds.has(eventId)\n}\n\n/**\n * Get all declared event IDs.\n * Useful for debugging and introspection.\n */\nexport function getAllDeclaredEventIds(): string[] {\n return Array.from(allDeclaredEventIds)\n}\n\n/**\n * Get all declared events with their full definitions.\n * Used by the API to return available events for workflow triggers.\n */\nexport function getDeclaredEvents(): EventDefinition[] {\n return [...allDeclaredEvents]\n}\n\n/**\n * Check if an event has clientBroadcast enabled.\n * Used by the SSE endpoint to filter events for the DOM Event Bridge.\n */\nexport function isBroadcastEvent(eventId: string): boolean {\n const event = allDeclaredEvents.find(e => e.id === eventId)\n return event?.clientBroadcast === true\n}\n\n/**\n * Check if an event has portalBroadcast enabled.\n * Used by the portal SSE endpoint to filter events for the Portal Event Bridge.\n */\nexport function isPortalBroadcastEvent(eventId: string): boolean {\n const event = allDeclaredEvents.find(e => e.id === eventId)\n return event?.portalBroadcast === true\n}\n\n// =============================================================================\n// Bootstrap Registration (similar to searchModuleConfigs pattern)\n// =============================================================================\n\nlet _registeredEventConfigs: EventModuleConfig[] | null = null\n\n/**\n * Register event module configurations globally.\n * Called during app bootstrap with configs from events.generated.ts.\n */\nexport function registerEventModuleConfigs(configs: EventModuleConfig[]): void {\n if (_registeredEventConfigs !== null && process.env.NODE_ENV === 'development') {\n console.debug('[Bootstrap] Event module configs re-registered (this may occur during HMR)')\n }\n _registeredEventConfigs = configs\n for (const config of configs) {\n for (const event of config.events) {\n addDeclaredEvent(event)\n }\n }\n}\n\n/**\n * Get registered event module configurations.\n * Returns empty array if not registered.\n */\nexport function getEventModuleConfigs(): EventModuleConfig[] {\n return _registeredEventConfigs ?? []\n}\n\n// =============================================================================\n// Factory Function\n// =============================================================================\n\n/**\n * Creates a type-safe event configuration for a module.\n *\n * Usage in module events.ts:\n * ```typescript\n * import { createModuleEvents } from '@open-mercato/shared/modules/events'\n *\n * const events = [\n * { id: 'customers.people.created', label: 'Person Created', category: 'crud' },\n * { id: 'customers.people.updated', label: 'Person Updated', category: 'crud' },\n * ] as const\n *\n * export const eventsConfig = createModuleEvents({\n * moduleId: 'customers',\n * events,\n * })\n *\n * // Export the typed emit function for use in commands\n * export const emitCustomersEvent = eventsConfig.emit\n *\n * // Export event IDs as a type for external use\n * export type CustomersEventId = typeof events[number]['id']\n *\n * export default eventsConfig\n * ```\n *\n * TypeScript will enforce that only declared event IDs can be emitted:\n * ```typescript\n * // \u2705 This compiles - event is declared\n * emitCustomersEvent('customers.people.created', { id: '123', tenantId: 'abc' })\n *\n * // \u274C TypeScript error - event not declared\n * emitCustomersEvent('customers.people.exploded', { id: '123' })\n * ```\n */\nexport function createModuleEvents<\n const TEvents extends readonly { id: string }[],\n TEventIds extends TEvents[number]['id'] = TEvents[number]['id']\n>(options: CreateModuleEventsOptions<TEventIds>): EventModuleConfig<TEventIds> {\n const { moduleId, events, strict = false } = options\n\n // Build set of valid event IDs for runtime validation\n const validEventIds = new Set(events.map(e => e.id))\n\n // Build full event definitions with module added\n const fullEvents: EventDefinition[] = events.map(e => ({\n ...e,\n module: moduleId,\n }))\n\n // Register all event IDs and definitions in the global registry.\n for (const event of fullEvents) {\n addDeclaredEvent(event)\n }\n\n /**\n * The emit function - validates events and delegates to the global event bus\n */\n const emit = async (\n eventId: TEventIds,\n payload: EventPayload,\n emitOptions?: EmitOptions\n ): Promise<void> => {\n // Runtime validation - event must be declared\n if (!validEventIds.has(eventId)) {\n const message =\n `[events] Module \"${moduleId}\" tried to emit undeclared event \"${eventId}\". ` +\n `Add it to the module's events.ts file first.`\n\n if (strict) {\n throw new Error(message)\n } else {\n console.error(message)\n // In non-strict mode, still emit but with warning\n }\n }\n\n // Get event bus from global reference\n const eventBus = getGlobalEventBus()\n if (!eventBus) {\n console.warn(`[events] Event bus not available, cannot emit \"${eventId}\"`)\n return\n }\n\n await eventBus.emit(eventId, payload, emitOptions)\n }\n\n return {\n moduleId,\n events: fullEvents,\n emit: emit as unknown as ModuleEventEmitter<TEventIds>,\n }\n}\n"],
|
|
5
|
+
"mappings": "AA0BA,MAAM,uBAAuB;AAG7B,IAAI,iBAAwC;AAMrC,SAAS,kBAAkB,KAA2B;AAC3D,mBAAiB;AACjB,MAAI;AACF;AAAC,IAAC,WAAuC,oBAAoB,IAAI;AAAA,EACnE,QAAQ;AAAA,EAER;AACF;AAMO,SAAS,oBAA2C;AACzD,MAAI;AACF,UAAM,YAAa,WAAuC,oBAAoB;AAC9E,QAAI,aAAa,OAAO,cAAc,YAAY,OAAQ,UAA6B,SAAS,YAAY;AAC1G,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAOA,MAAM,sBAAsB,oBAAI,IAAY;AAG5C,MAAM,oBAAuC,CAAC;AAE9C,SAAS,iBAAiB,OAA8B;AACtD,sBAAoB,IAAI,MAAM,EAAE;AAEhC,MAAI,CAAC,kBAAkB,KAAK,OAAK,EAAE,OAAO,MAAM,EAAE,GAAG;AACnD,sBAAkB,KAAK,KAAK;AAAA,EAC9B;AACF;AAMO,SAAS,gBAAgB,SAA0B;AACxD,SAAO,oBAAoB,IAAI,OAAO;AACxC;AAMO,SAAS,yBAAmC;AACjD,SAAO,MAAM,KAAK,mBAAmB;AACvC;AAMO,SAAS,oBAAuC;AACrD,SAAO,CAAC,GAAG,iBAAiB;AAC9B;AAMO,SAAS,iBAAiB,SAA0B;AACzD,QAAM,QAAQ,kBAAkB,KAAK,OAAK,EAAE,OAAO,OAAO;AAC1D,SAAO,OAAO,oBAAoB;AACpC;AAMO,SAAS,uBAAuB,SAA0B;AAC/D,QAAM,QAAQ,kBAAkB,KAAK,OAAK,EAAE,OAAO,OAAO;AAC1D,SAAO,OAAO,oBAAoB;AACpC;AAMA,IAAI,0BAAsD;AAMnD,SAAS,2BAA2B,SAAoC;AAC7E,MAAI,4BAA4B,QAAQ,QAAQ,IAAI,aAAa,eAAe;AAC9E,YAAQ,MAAM,4EAA4E;AAAA,EAC5F;AACA,4BAA0B;AAC1B,aAAW,UAAU,SAAS;AAC5B,eAAW,SAAS,OAAO,QAAQ;AACjC,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF;AACF;AAMO,SAAS,wBAA6C;AAC3D,SAAO,2BAA2B,CAAC;AACrC;AAyCO,SAAS,mBAGd,SAA6E;AAC7E,QAAM,EAAE,UAAU,QAAQ,SAAS,MAAM,IAAI;AAG7C,QAAM,gBAAgB,IAAI,IAAI,OAAO,IAAI,OAAK,EAAE,EAAE,CAAC;AAGnD,QAAM,aAAgC,OAAO,IAAI,QAAM;AAAA,IACrD,GAAG;AAAA,IACH,QAAQ;AAAA,EACV,EAAE;AAGF,aAAW,SAAS,YAAY;AAC9B,qBAAiB,KAAK;AAAA,EACxB;AAKA,QAAM,OAAO,OACX,SACA,SACA,gBACkB;AAElB,QAAI,CAAC,cAAc,IAAI,OAAO,GAAG;AAC/B,YAAM,UACJ,oBAAoB,QAAQ,qCAAqC,OAAO;AAG1E,UAAI,QAAQ;AACV,cAAM,IAAI,MAAM,OAAO;AAAA,MACzB,OAAO;AACL,gBAAQ,MAAM,OAAO;AAAA,MAEvB;AAAA,IACF;AAGA,UAAM,WAAW,kBAAkB;AACnC,QAAI,CAAC,UAAU;AACb,cAAQ,KAAK,kDAAkD,OAAO,GAAG;AACzE;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,SAAS,SAAS,WAAW;AAAA,EACnD;AAEA,SAAO;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,IACR;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/shared",
|
|
3
|
-
"version": "0.6.4-develop.
|
|
3
|
+
"version": "0.6.4-develop.3978.1.2f05baffed",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"@mikro-orm/core": "^7.1.1",
|
|
93
93
|
"@mikro-orm/decorators": "^7.1.1",
|
|
94
94
|
"@mikro-orm/postgresql": "^7.1.1",
|
|
95
|
-
"@open-mercato/cache": "0.6.4-develop.
|
|
95
|
+
"@open-mercato/cache": "0.6.4-develop.3978.1.2f05baffed",
|
|
96
96
|
"dotenv": "^17.4.2",
|
|
97
97
|
"rate-limiter-flexible": "^11.1.0",
|
|
98
98
|
"re2js": "2.8.3",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { AwilixContainer } from 'awilix'
|
|
2
2
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
3
3
|
import { DefaultDataEngine, __resetUndeclaredEventWarningsForTests } from '../engine'
|
|
4
|
-
import { createModuleEvents } from '../../../modules/events'
|
|
4
|
+
import { createModuleEvents, registerEventModuleConfigs } from '../../../modules/events'
|
|
5
5
|
|
|
6
6
|
const testEvents = [
|
|
7
7
|
{ id: 'issue1421_test.widget.created', label: 'Widget Created', entity: 'widget', category: 'crud' as const },
|
|
@@ -61,6 +61,43 @@ describe('DataEngine event contract validation (issue #1421)', () => {
|
|
|
61
61
|
}
|
|
62
62
|
})
|
|
63
63
|
|
|
64
|
+
it('accepts events declared through bootstrap-registered module configs', async () => {
|
|
65
|
+
registerEventModuleConfigs([
|
|
66
|
+
{
|
|
67
|
+
moduleId: 'issue1421_bootstrap',
|
|
68
|
+
events: [
|
|
69
|
+
{
|
|
70
|
+
id: 'issue1421_bootstrap.widget.deleted',
|
|
71
|
+
label: 'Widget Deleted',
|
|
72
|
+
module: 'issue1421_bootstrap',
|
|
73
|
+
entity: 'widget',
|
|
74
|
+
category: 'crud',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
emit: jest.fn(),
|
|
78
|
+
},
|
|
79
|
+
])
|
|
80
|
+
|
|
81
|
+
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
82
|
+
try {
|
|
83
|
+
const { engine, emitted } = makeFixture()
|
|
84
|
+
|
|
85
|
+
await engine.emitOrmEntityEvent({
|
|
86
|
+
action: 'deleted',
|
|
87
|
+
entity: { id: identifiers.id },
|
|
88
|
+
identifiers,
|
|
89
|
+
events: { module: 'issue1421_bootstrap', entity: 'widget' },
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
expect(emitted).toEqual([
|
|
93
|
+
expect.objectContaining({ name: 'issue1421_bootstrap.widget.deleted' }),
|
|
94
|
+
])
|
|
95
|
+
expect(warnSpy).not.toHaveBeenCalled()
|
|
96
|
+
} finally {
|
|
97
|
+
warnSpy.mockRestore()
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
|
|
64
101
|
it('warns when emitting an event that is not registered', async () => {
|
|
65
102
|
const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
66
103
|
try {
|
|
@@ -68,6 +68,14 @@ const allDeclaredEventIds = new Set<string>()
|
|
|
68
68
|
// Global registry of all declared events with their full definitions
|
|
69
69
|
const allDeclaredEvents: EventDefinition[] = []
|
|
70
70
|
|
|
71
|
+
function addDeclaredEvent(event: EventDefinition): void {
|
|
72
|
+
allDeclaredEventIds.add(event.id)
|
|
73
|
+
// Avoid duplicates if createModuleEvents/registerEventModuleConfigs is called multiple times (e.g., HMR)
|
|
74
|
+
if (!allDeclaredEvents.find(e => e.id === event.id)) {
|
|
75
|
+
allDeclaredEvents.push(event)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
71
79
|
/**
|
|
72
80
|
* Check if an event ID has been declared by any module.
|
|
73
81
|
* Used for runtime validation to ensure only declared events are emitted.
|
|
@@ -125,6 +133,11 @@ export function registerEventModuleConfigs(configs: EventModuleConfig[]): void {
|
|
|
125
133
|
console.debug('[Bootstrap] Event module configs re-registered (this may occur during HMR)')
|
|
126
134
|
}
|
|
127
135
|
_registeredEventConfigs = configs
|
|
136
|
+
for (const config of configs) {
|
|
137
|
+
for (const event of config.events) {
|
|
138
|
+
addDeclaredEvent(event)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
128
141
|
}
|
|
129
142
|
|
|
130
143
|
/**
|
|
@@ -189,15 +202,9 @@ export function createModuleEvents<
|
|
|
189
202
|
module: moduleId,
|
|
190
203
|
}))
|
|
191
204
|
|
|
192
|
-
// Register all event IDs and definitions in the global registry
|
|
193
|
-
for (const eventId of validEventIds) {
|
|
194
|
-
allDeclaredEventIds.add(eventId)
|
|
195
|
-
}
|
|
205
|
+
// Register all event IDs and definitions in the global registry.
|
|
196
206
|
for (const event of fullEvents) {
|
|
197
|
-
|
|
198
|
-
if (!allDeclaredEvents.find(e => e.id === event.id)) {
|
|
199
|
-
allDeclaredEvents.push(event)
|
|
200
|
-
}
|
|
207
|
+
addDeclaredEvent(event)
|
|
201
208
|
}
|
|
202
209
|
|
|
203
210
|
/**
|