@parsrun/service 0.1.29 → 0.1.30
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/client.d.ts +30 -3
- package/dist/client.js +1 -0
- package/dist/client.js.map +1 -1
- package/dist/define.d.ts +29 -6
- package/dist/define.js.map +1 -1
- package/dist/events/index.d.ts +95 -15
- package/dist/events/index.js.map +1 -1
- package/dist/{handler-CmiDUWZv.d.ts → handler-eCIZLODd.d.ts} +45 -3
- package/dist/{index-CVOAoJjZ.d.ts → index-reEpIe1R.d.ts} +82 -11
- package/dist/index.d.ts +53 -9
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/resilience/index.d.ts +76 -9
- package/dist/resilience/index.js +1 -0
- package/dist/resilience/index.js.map +1 -1
- package/dist/rpc/index.d.ts +3 -3
- package/dist/rpc/index.js +1 -0
- package/dist/rpc/index.js.map +1 -1
- package/dist/serialization/index.d.ts +27 -2
- package/dist/serialization/index.js.map +1 -1
- package/dist/{server-DFE8n2Sx.d.ts → server-BB9AbnkP.d.ts} +50 -6
- package/dist/tracing/index.d.ts +94 -15
- package/dist/tracing/index.js.map +1 -1
- package/dist/transports/cloudflare/index.d.ts +72 -10
- package/dist/transports/cloudflare/index.js.map +1 -1
- package/dist/{types-n4LLSPQU.d.ts → types-DHZaZwAt.d.ts} +51 -0
- package/package.json +3 -3
package/dist/define.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Q as QueryDefinition, M as MutationDefinition, c as EventDefinition, b as ServiceDefinition } from './types-
|
|
1
|
+
import { Q as QueryDefinition, M as MutationDefinition, c as EventDefinition, b as ServiceDefinition } from './types-DHZaZwAt.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @parsrun/service - Service Definition
|
|
@@ -42,21 +42,32 @@ import { Q as QueryDefinition, M as MutationDefinition, c as EventDefinition, b
|
|
|
42
42
|
*/
|
|
43
43
|
declare function defineService<TQueries extends Record<string, QueryDefinition> = Record<string, QueryDefinition>, TMutations extends Record<string, MutationDefinition> = Record<string, MutationDefinition>, TEmits extends Record<string, EventDefinition> = Record<string, EventDefinition>, THandles extends string[] = string[]>(definition: ServiceDefinition<TQueries, TMutations, TEmits, THandles>): ServiceDefinition<TQueries, TMutations, TEmits, THandles>;
|
|
44
44
|
/**
|
|
45
|
-
* Get all method names from a service definition
|
|
45
|
+
* Get all method names from a service definition.
|
|
46
|
+
*
|
|
47
|
+
* @param definition - The service definition
|
|
48
|
+
* @returns Object containing arrays of query and mutation names
|
|
46
49
|
*/
|
|
47
50
|
declare function getServiceMethods(definition: ServiceDefinition): {
|
|
48
51
|
queries: string[];
|
|
49
52
|
mutations: string[];
|
|
50
53
|
};
|
|
51
54
|
/**
|
|
52
|
-
* Get all event types from a service definition
|
|
55
|
+
* Get all event types from a service definition.
|
|
56
|
+
*
|
|
57
|
+
* @param definition - The service definition
|
|
58
|
+
* @returns Object containing arrays of emitted and handled event types
|
|
53
59
|
*/
|
|
54
60
|
declare function getServiceEvents(definition: ServiceDefinition): {
|
|
55
61
|
emits: string[];
|
|
56
62
|
handles: string[];
|
|
57
63
|
};
|
|
58
64
|
/**
|
|
59
|
-
* Check if a service version satisfies a version requirement
|
|
65
|
+
* Check if a service version satisfies a version requirement.
|
|
66
|
+
* Supports wildcards (x or *) in version requirements.
|
|
67
|
+
*
|
|
68
|
+
* @param version - The actual version to check
|
|
69
|
+
* @param requirement - The version requirement with optional wildcards
|
|
70
|
+
* @returns True if the version satisfies the requirement
|
|
60
71
|
*
|
|
61
72
|
* @example
|
|
62
73
|
* ```typescript
|
|
@@ -67,7 +78,12 @@ declare function getServiceEvents(definition: ServiceDefinition): {
|
|
|
67
78
|
*/
|
|
68
79
|
declare function satisfiesVersion(version: string, requirement: string): boolean;
|
|
69
80
|
/**
|
|
70
|
-
* Check if a method is deprecated in the service definition
|
|
81
|
+
* Check if a method is deprecated in the service definition.
|
|
82
|
+
*
|
|
83
|
+
* @param definition - The service definition
|
|
84
|
+
* @param methodName - Name of the method to check
|
|
85
|
+
* @param type - Type of method ("query" or "mutation")
|
|
86
|
+
* @returns Object with deprecation status and optional metadata
|
|
71
87
|
*/
|
|
72
88
|
declare function isMethodDeprecated(definition: ServiceDefinition, methodName: string, type: "query" | "mutation"): {
|
|
73
89
|
deprecated: boolean;
|
|
@@ -75,7 +91,14 @@ declare function isMethodDeprecated(definition: ServiceDefinition, methodName: s
|
|
|
75
91
|
replacement?: string;
|
|
76
92
|
};
|
|
77
93
|
/**
|
|
78
|
-
* Get method timeout
|
|
94
|
+
* Get method timeout from the service definition.
|
|
95
|
+
* Uses method-specific timeout if defined, otherwise falls back to default.
|
|
96
|
+
*
|
|
97
|
+
* @param definition - The service definition
|
|
98
|
+
* @param methodName - Name of the method
|
|
99
|
+
* @param type - Type of method ("query" or "mutation")
|
|
100
|
+
* @param defaultTimeout - Default timeout to use if not specified
|
|
101
|
+
* @returns Timeout value in milliseconds
|
|
79
102
|
*/
|
|
80
103
|
declare function getMethodTimeout(definition: ServiceDefinition, methodName: string, type: "query" | "mutation", defaultTimeout: number): number;
|
|
81
104
|
|
package/dist/define.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/define.ts"],"sourcesContent":["/**\n * @parsrun/service - Service Definition\n * Factory function for defining services\n */\n\nimport type {\n ServiceDefinition,\n QueryDefinition,\n MutationDefinition,\n EventDefinition,\n} from \"./types.js\";\n\n// ============================================================================\n// SERVICE DEFINITION FACTORY\n// ============================================================================\n\n/**\n * Define a service with type-safe queries, mutations, and events\n *\n * @example\n * ```typescript\n * const paymentsService = defineService({\n * name: 'payments',\n * version: '1.0.0',\n *\n * queries: {\n * getSubscription: {\n * input: { subscriptionId: 'string' },\n * output: { status: 'string', plan: 'string' },\n * },\n * },\n *\n * mutations: {\n * subscribe: {\n * input: { email: 'string', planId: 'string' },\n * output: { checkoutUrl: 'string' },\n * },\n * },\n *\n * events: {\n * emits: {\n * 'subscription.created': {\n * data: { customerId: 'string', planId: 'string' },\n * delivery: 'at-least-once',\n * },\n * },\n * handles: ['user.deleted', 'tenant.suspended'],\n * },\n * });\n * ```\n */\nexport function defineService<\n TQueries extends Record<string, QueryDefinition> = Record<string, QueryDefinition>,\n TMutations extends Record<string, MutationDefinition> = Record<string, MutationDefinition>,\n TEmits extends Record<string, EventDefinition> = Record<string, EventDefinition>,\n THandles extends string[] = string[],\n>(\n definition: ServiceDefinition<TQueries, TMutations, TEmits, THandles>\n): ServiceDefinition<TQueries, TMutations, TEmits, THandles> {\n // Validate service definition\n validateServiceDefinition(definition);\n\n // Freeze the definition to prevent mutation\n return Object.freeze({\n ...definition,\n queries: definition.queries ? Object.freeze({ ...definition.queries }) : undefined,\n mutations: definition.mutations ? Object.freeze({ ...definition.mutations }) : undefined,\n events: definition.events\n ? Object.freeze({\n emits: definition.events.emits\n ? Object.freeze({ ...definition.events.emits })\n : undefined,\n handles: definition.events.handles\n ? Object.freeze([...definition.events.handles])\n : undefined,\n })\n : undefined,\n }) as ServiceDefinition<TQueries, TMutations, TEmits, THandles>;\n}\n\n/**\n * Validate service definition\n */\nfunction validateServiceDefinition(definition: ServiceDefinition): void {\n if (!definition.name) {\n throw new Error(\"Service name is required\");\n }\n\n if (!definition.version) {\n throw new Error(\"Service version is required\");\n }\n\n // Validate version format (semver-like)\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?$/;\n if (!versionRegex.test(definition.version)) {\n throw new Error(`Invalid version format: ${definition.version}. Expected semver (e.g., 1.0.0)`);\n }\n\n // Validate query/mutation names (no dots or special chars)\n const nameRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\n if (definition.queries) {\n for (const name of Object.keys(definition.queries)) {\n if (!nameRegex.test(name)) {\n throw new Error(\n `Invalid query name: ${name}. Must start with letter and contain only alphanumeric and underscore`\n );\n }\n }\n }\n\n if (definition.mutations) {\n for (const name of Object.keys(definition.mutations)) {\n if (!nameRegex.test(name)) {\n throw new Error(\n `Invalid mutation name: ${name}. Must start with letter and contain only alphanumeric and underscore`\n );\n }\n }\n }\n\n // Validate event names (dot notation allowed)\n const eventNameRegex = /^[a-zA-Z][a-zA-Z0-9_.]*$/;\n\n if (definition.events?.emits) {\n for (const name of Object.keys(definition.events.emits)) {\n if (!eventNameRegex.test(name)) {\n throw new Error(\n `Invalid event name: ${name}. Must start with letter and contain only alphanumeric, underscore, and dot`\n );\n }\n }\n }\n\n if (definition.events?.handles) {\n for (const name of definition.events.handles) {\n if (!eventNameRegex.test(name)) {\n throw new Error(\n `Invalid handled event name: ${name}. Must start with letter and contain only alphanumeric, underscore, and dot`\n );\n }\n }\n }\n}\n\n// ============================================================================\n// SERVICE DEFINITION UTILITIES\n// ============================================================================\n\n/**\n * Get all method names from a service definition\n */\nexport function getServiceMethods(definition: ServiceDefinition): {\n queries: string[];\n mutations: string[];\n} {\n return {\n queries: definition.queries ? Object.keys(definition.queries) : [],\n mutations: definition.mutations ? Object.keys(definition.mutations) : [],\n };\n}\n\n/**\n * Get all event types from a service definition\n */\nexport function getServiceEvents(definition: ServiceDefinition): {\n emits: string[];\n handles: string[];\n} {\n return {\n emits: definition.events?.emits ? Object.keys(definition.events.emits) : [],\n handles: definition.events?.handles ?? [],\n };\n}\n\n/**\n * Check if a service version satisfies a version requirement\n *\n * @example\n * ```typescript\n * satisfiesVersion('1.2.3', '1.x') // true\n * satisfiesVersion('1.2.3', '1.2.x') // true\n * satisfiesVersion('2.0.0', '1.x') // false\n * ```\n */\nexport function satisfiesVersion(version: string, requirement: string): boolean {\n const versionParts = version.split(\".\").map((p) => parseInt(p, 10));\n const requirementParts = requirement.split(\".\");\n\n for (let i = 0; i < requirementParts.length; i++) {\n const req = requirementParts[i];\n if (req === \"x\" || req === \"*\") {\n continue;\n }\n\n const reqNum = parseInt(req ?? \"0\", 10);\n const verNum = versionParts[i] ?? 0;\n\n if (verNum !== reqNum) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if a method is deprecated in the service definition\n */\nexport function isMethodDeprecated(\n definition: ServiceDefinition,\n methodName: string,\n type: \"query\" | \"mutation\"\n): { deprecated: boolean; since?: string; replacement?: string } {\n const methods = type === \"query\" ? definition.queries : definition.mutations;\n const method = methods?.[methodName];\n\n if (!method?.deprecated) {\n return { deprecated: false };\n }\n\n const result: { deprecated: boolean; since?: string; replacement?: string } = {\n deprecated: true,\n since: method.deprecated,\n };\n\n if (method.replacement) {\n result.replacement = method.replacement;\n }\n\n return result;\n}\n\n/**\n * Get method timeout (use method-specific or fall back to default)\n */\nexport function getMethodTimeout(\n definition: ServiceDefinition,\n methodName: string,\n type: \"query\" | \"mutation\",\n defaultTimeout: number\n): number {\n const methods = type === \"query\" ? definition.queries : definition.mutations;\n const method = methods?.[methodName];\n\n return method?.timeout ?? defaultTimeout;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/define.ts"],"sourcesContent":["/**\n * @parsrun/service - Service Definition\n * Factory function for defining services\n */\n\nimport type {\n ServiceDefinition,\n QueryDefinition,\n MutationDefinition,\n EventDefinition,\n} from \"./types.js\";\n\n// ============================================================================\n// SERVICE DEFINITION FACTORY\n// ============================================================================\n\n/**\n * Define a service with type-safe queries, mutations, and events\n *\n * @example\n * ```typescript\n * const paymentsService = defineService({\n * name: 'payments',\n * version: '1.0.0',\n *\n * queries: {\n * getSubscription: {\n * input: { subscriptionId: 'string' },\n * output: { status: 'string', plan: 'string' },\n * },\n * },\n *\n * mutations: {\n * subscribe: {\n * input: { email: 'string', planId: 'string' },\n * output: { checkoutUrl: 'string' },\n * },\n * },\n *\n * events: {\n * emits: {\n * 'subscription.created': {\n * data: { customerId: 'string', planId: 'string' },\n * delivery: 'at-least-once',\n * },\n * },\n * handles: ['user.deleted', 'tenant.suspended'],\n * },\n * });\n * ```\n */\nexport function defineService<\n TQueries extends Record<string, QueryDefinition> = Record<string, QueryDefinition>,\n TMutations extends Record<string, MutationDefinition> = Record<string, MutationDefinition>,\n TEmits extends Record<string, EventDefinition> = Record<string, EventDefinition>,\n THandles extends string[] = string[],\n>(\n definition: ServiceDefinition<TQueries, TMutations, TEmits, THandles>\n): ServiceDefinition<TQueries, TMutations, TEmits, THandles> {\n // Validate service definition\n validateServiceDefinition(definition);\n\n // Freeze the definition to prevent mutation\n return Object.freeze({\n ...definition,\n queries: definition.queries ? Object.freeze({ ...definition.queries }) : undefined,\n mutations: definition.mutations ? Object.freeze({ ...definition.mutations }) : undefined,\n events: definition.events\n ? Object.freeze({\n emits: definition.events.emits\n ? Object.freeze({ ...definition.events.emits })\n : undefined,\n handles: definition.events.handles\n ? Object.freeze([...definition.events.handles])\n : undefined,\n })\n : undefined,\n }) as ServiceDefinition<TQueries, TMutations, TEmits, THandles>;\n}\n\n/**\n * Validate service definition\n */\nfunction validateServiceDefinition(definition: ServiceDefinition): void {\n if (!definition.name) {\n throw new Error(\"Service name is required\");\n }\n\n if (!definition.version) {\n throw new Error(\"Service version is required\");\n }\n\n // Validate version format (semver-like)\n const versionRegex = /^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?$/;\n if (!versionRegex.test(definition.version)) {\n throw new Error(`Invalid version format: ${definition.version}. Expected semver (e.g., 1.0.0)`);\n }\n\n // Validate query/mutation names (no dots or special chars)\n const nameRegex = /^[a-zA-Z][a-zA-Z0-9_]*$/;\n\n if (definition.queries) {\n for (const name of Object.keys(definition.queries)) {\n if (!nameRegex.test(name)) {\n throw new Error(\n `Invalid query name: ${name}. Must start with letter and contain only alphanumeric and underscore`\n );\n }\n }\n }\n\n if (definition.mutations) {\n for (const name of Object.keys(definition.mutations)) {\n if (!nameRegex.test(name)) {\n throw new Error(\n `Invalid mutation name: ${name}. Must start with letter and contain only alphanumeric and underscore`\n );\n }\n }\n }\n\n // Validate event names (dot notation allowed)\n const eventNameRegex = /^[a-zA-Z][a-zA-Z0-9_.]*$/;\n\n if (definition.events?.emits) {\n for (const name of Object.keys(definition.events.emits)) {\n if (!eventNameRegex.test(name)) {\n throw new Error(\n `Invalid event name: ${name}. Must start with letter and contain only alphanumeric, underscore, and dot`\n );\n }\n }\n }\n\n if (definition.events?.handles) {\n for (const name of definition.events.handles) {\n if (!eventNameRegex.test(name)) {\n throw new Error(\n `Invalid handled event name: ${name}. Must start with letter and contain only alphanumeric, underscore, and dot`\n );\n }\n }\n }\n}\n\n// ============================================================================\n// SERVICE DEFINITION UTILITIES\n// ============================================================================\n\n/**\n * Get all method names from a service definition.\n *\n * @param definition - The service definition\n * @returns Object containing arrays of query and mutation names\n */\nexport function getServiceMethods(definition: ServiceDefinition): {\n queries: string[];\n mutations: string[];\n} {\n return {\n queries: definition.queries ? Object.keys(definition.queries) : [],\n mutations: definition.mutations ? Object.keys(definition.mutations) : [],\n };\n}\n\n/**\n * Get all event types from a service definition.\n *\n * @param definition - The service definition\n * @returns Object containing arrays of emitted and handled event types\n */\nexport function getServiceEvents(definition: ServiceDefinition): {\n emits: string[];\n handles: string[];\n} {\n return {\n emits: definition.events?.emits ? Object.keys(definition.events.emits) : [],\n handles: definition.events?.handles ?? [],\n };\n}\n\n/**\n * Check if a service version satisfies a version requirement.\n * Supports wildcards (x or *) in version requirements.\n *\n * @param version - The actual version to check\n * @param requirement - The version requirement with optional wildcards\n * @returns True if the version satisfies the requirement\n *\n * @example\n * ```typescript\n * satisfiesVersion('1.2.3', '1.x') // true\n * satisfiesVersion('1.2.3', '1.2.x') // true\n * satisfiesVersion('2.0.0', '1.x') // false\n * ```\n */\nexport function satisfiesVersion(version: string, requirement: string): boolean {\n const versionParts = version.split(\".\").map((p) => parseInt(p, 10));\n const requirementParts = requirement.split(\".\");\n\n for (let i = 0; i < requirementParts.length; i++) {\n const req = requirementParts[i];\n if (req === \"x\" || req === \"*\") {\n continue;\n }\n\n const reqNum = parseInt(req ?? \"0\", 10);\n const verNum = versionParts[i] ?? 0;\n\n if (verNum !== reqNum) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Check if a method is deprecated in the service definition.\n *\n * @param definition - The service definition\n * @param methodName - Name of the method to check\n * @param type - Type of method (\"query\" or \"mutation\")\n * @returns Object with deprecation status and optional metadata\n */\nexport function isMethodDeprecated(\n definition: ServiceDefinition,\n methodName: string,\n type: \"query\" | \"mutation\"\n): { deprecated: boolean; since?: string; replacement?: string } {\n const methods = type === \"query\" ? definition.queries : definition.mutations;\n const method = methods?.[methodName];\n\n if (!method?.deprecated) {\n return { deprecated: false };\n }\n\n const result: { deprecated: boolean; since?: string; replacement?: string } = {\n deprecated: true,\n since: method.deprecated,\n };\n\n if (method.replacement) {\n result.replacement = method.replacement;\n }\n\n return result;\n}\n\n/**\n * Get method timeout from the service definition.\n * Uses method-specific timeout if defined, otherwise falls back to default.\n *\n * @param definition - The service definition\n * @param methodName - Name of the method\n * @param type - Type of method (\"query\" or \"mutation\")\n * @param defaultTimeout - Default timeout to use if not specified\n * @returns Timeout value in milliseconds\n */\nexport function getMethodTimeout(\n definition: ServiceDefinition,\n methodName: string,\n type: \"query\" | \"mutation\",\n defaultTimeout: number\n): number {\n const methods = type === \"query\" ? definition.queries : definition.mutations;\n const method = methods?.[methodName];\n\n return method?.timeout ?? defaultTimeout;\n}\n"],"mappings":"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","names":[]}
|
package/dist/events/index.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { m as TraceContext, P as ParsEvent, C as CompactEvent, b as ServiceDefinition, t as EventTransport, e as EventHandlerOptions, j as EventHandler, U as Unsubscribe } from '../types-
|
|
1
|
+
import { m as TraceContext, P as ParsEvent, C as CompactEvent, b as ServiceDefinition, t as EventTransport, e as EventHandlerOptions, j as EventHandler, U as Unsubscribe } from '../types-DHZaZwAt.js';
|
|
2
2
|
import { Logger } from '@parsrun/core';
|
|
3
|
-
export { A as AddEntryOptions, d as DeadLetterEntry, D as DeadLetterQueue, e as DeadLetterQueueOptions, E as EventHandlerRegistry, a as EventHandlerRegistryOptions, H as HandlerRegistration, b as createDeadLetterQueue, c as createEventHandlerRegistry } from '../handler-
|
|
3
|
+
export { A as AddEntryOptions, d as DeadLetterEntry, D as DeadLetterQueue, e as DeadLetterQueueOptions, E as EventHandlerRegistry, a as EventHandlerRegistryOptions, H as HandlerRegistration, b as createDeadLetterQueue, c as createEventHandlerRegistry } from '../handler-eCIZLODd.js';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @parsrun/service - Event Format
|
|
7
7
|
* CloudEvents and compact event format utilities
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Options for creating a CloudEvents-compatible event.
|
|
12
|
+
*/
|
|
10
13
|
interface CreateEventOptions<T = unknown> {
|
|
11
14
|
/** Event type (e.g., "subscription.created") */
|
|
12
15
|
type: string;
|
|
@@ -28,56 +31,92 @@ interface CreateEventOptions<T = unknown> {
|
|
|
28
31
|
delivery?: "at-most-once" | "at-least-once";
|
|
29
32
|
}
|
|
30
33
|
/**
|
|
31
|
-
* Create a CloudEvents-compatible event
|
|
34
|
+
* Create a CloudEvents-compatible event.
|
|
35
|
+
*
|
|
36
|
+
* @param options - Event creation options
|
|
37
|
+
* @returns A new ParsEvent conforming to CloudEvents spec
|
|
32
38
|
*/
|
|
33
39
|
declare function createEvent<T = unknown>(options: CreateEventOptions<T>): ParsEvent<T>;
|
|
34
40
|
/**
|
|
35
|
-
* Convert to full CloudEvents format
|
|
41
|
+
* Convert to full CloudEvents format (creates a copy).
|
|
42
|
+
*
|
|
43
|
+
* @param event - The event to convert
|
|
44
|
+
* @returns A copy of the event in CloudEvents format
|
|
36
45
|
*/
|
|
37
46
|
declare function toCloudEvent<T>(event: ParsEvent<T>): ParsEvent<T>;
|
|
38
47
|
/**
|
|
39
|
-
* Convert to compact internal format
|
|
48
|
+
* Convert to compact internal format for efficient transport.
|
|
49
|
+
*
|
|
50
|
+
* @param event - The CloudEvents event to convert
|
|
51
|
+
* @returns A compact representation of the event
|
|
40
52
|
*/
|
|
41
53
|
declare function toCompactEvent<T>(event: ParsEvent<T>): CompactEvent<T>;
|
|
42
54
|
/**
|
|
43
|
-
* Convert from compact format to CloudEvents
|
|
55
|
+
* Convert from compact format to CloudEvents format.
|
|
56
|
+
*
|
|
57
|
+
* @param compact - The compact event to convert
|
|
58
|
+
* @param source - Optional source override
|
|
59
|
+
* @returns A full CloudEvents event
|
|
44
60
|
*/
|
|
45
61
|
declare function fromCompactEvent<T>(compact: CompactEvent<T>, source?: string): ParsEvent<T>;
|
|
46
62
|
/**
|
|
47
|
-
* Format full event type with source prefix
|
|
63
|
+
* Format full event type with source prefix.
|
|
64
|
+
*
|
|
65
|
+
* @param source - The source service name
|
|
66
|
+
* @param type - The event type
|
|
67
|
+
* @returns Fully qualified event type
|
|
48
68
|
*
|
|
49
69
|
* @example
|
|
70
|
+
* ```typescript
|
|
50
71
|
* formatEventType('payments', 'subscription.created')
|
|
51
72
|
* // Returns: 'com.pars.payments.subscription.created'
|
|
73
|
+
* ```
|
|
52
74
|
*/
|
|
53
75
|
declare function formatEventType(source: string, type: string): string;
|
|
54
76
|
/**
|
|
55
|
-
* Parse event type to extract source and type
|
|
77
|
+
* Parse event type to extract source and type.
|
|
78
|
+
*
|
|
79
|
+
* @param fullType - The fully qualified event type
|
|
80
|
+
* @returns Parsed source and type, or null if invalid
|
|
56
81
|
*
|
|
57
82
|
* @example
|
|
83
|
+
* ```typescript
|
|
58
84
|
* parseEventType('com.pars.payments.subscription.created')
|
|
59
85
|
* // Returns: { source: 'payments', type: 'subscription.created' }
|
|
86
|
+
* ```
|
|
60
87
|
*/
|
|
61
88
|
declare function parseEventType(fullType: string): {
|
|
62
89
|
source: string;
|
|
63
90
|
type: string;
|
|
64
91
|
} | null;
|
|
65
92
|
/**
|
|
66
|
-
* Check if event type matches a pattern
|
|
67
|
-
* Supports wildcards: * matches one segment, ** matches multiple segments
|
|
93
|
+
* Check if event type matches a pattern.
|
|
94
|
+
* Supports wildcards: * matches one segment, ** matches multiple segments.
|
|
95
|
+
*
|
|
96
|
+
* @param type - The event type to check
|
|
97
|
+
* @param pattern - The pattern to match against
|
|
98
|
+
* @returns True if the type matches the pattern
|
|
68
99
|
*
|
|
69
100
|
* @example
|
|
101
|
+
* ```typescript
|
|
70
102
|
* matchEventType('subscription.created', 'subscription.*') // true
|
|
71
103
|
* matchEventType('payment.invoice.paid', 'payment.**') // true
|
|
72
104
|
* matchEventType('subscription.created', 'payment.*') // false
|
|
105
|
+
* ```
|
|
73
106
|
*/
|
|
74
107
|
declare function matchEventType(type: string, pattern: string): boolean;
|
|
75
108
|
/**
|
|
76
|
-
* Validate CloudEvents structure
|
|
109
|
+
* Validate that an object conforms to CloudEvents structure.
|
|
110
|
+
*
|
|
111
|
+
* @param event - The object to validate
|
|
112
|
+
* @returns True if the object is a valid ParsEvent
|
|
77
113
|
*/
|
|
78
114
|
declare function validateEvent(event: unknown): event is ParsEvent;
|
|
79
115
|
/**
|
|
80
|
-
* Validate compact event structure
|
|
116
|
+
* Validate that an object conforms to compact event structure.
|
|
117
|
+
*
|
|
118
|
+
* @param event - The object to validate
|
|
119
|
+
* @returns True if the object is a valid CompactEvent
|
|
81
120
|
*/
|
|
82
121
|
declare function validateCompactEvent(event: unknown): event is CompactEvent;
|
|
83
122
|
|
|
@@ -86,6 +125,9 @@ declare function validateCompactEvent(event: unknown): event is CompactEvent;
|
|
|
86
125
|
* Service-level event emission
|
|
87
126
|
*/
|
|
88
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Options for creating an event emitter.
|
|
130
|
+
*/
|
|
89
131
|
interface EventEmitterOptions {
|
|
90
132
|
/** Service name (source) */
|
|
91
133
|
service: string;
|
|
@@ -159,7 +201,19 @@ declare class ScopedEmitter {
|
|
|
159
201
|
emit<T = unknown>(type: string, data: T, options?: EmitOptions): Promise<string>;
|
|
160
202
|
}
|
|
161
203
|
/**
|
|
162
|
-
* Create an event emitter
|
|
204
|
+
* Create an event emitter for publishing service events.
|
|
205
|
+
*
|
|
206
|
+
* @param options - Emitter configuration options
|
|
207
|
+
* @returns A new event emitter instance
|
|
208
|
+
*
|
|
209
|
+
* @example
|
|
210
|
+
* ```typescript
|
|
211
|
+
* const emitter = createEventEmitter({
|
|
212
|
+
* service: 'payments',
|
|
213
|
+
* transport: memoryTransport,
|
|
214
|
+
* });
|
|
215
|
+
* await emitter.emit('subscription.created', { customerId: '123' });
|
|
216
|
+
* ```
|
|
163
217
|
*/
|
|
164
218
|
declare function createEventEmitter(options: EventEmitterOptions): EventEmitter;
|
|
165
219
|
/**
|
|
@@ -182,6 +236,9 @@ type TypedEventEmitter<TDef extends ServiceDefinition> = EventEmitter & {
|
|
|
182
236
|
* In-memory event transport for embedded mode and testing
|
|
183
237
|
*/
|
|
184
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Options for creating a memory event transport.
|
|
241
|
+
*/
|
|
185
242
|
interface MemoryEventTransportOptions {
|
|
186
243
|
/** Logger */
|
|
187
244
|
logger?: Logger;
|
|
@@ -236,7 +293,20 @@ declare class MemoryEventTransport implements EventTransport {
|
|
|
236
293
|
close(): Promise<void>;
|
|
237
294
|
}
|
|
238
295
|
/**
|
|
239
|
-
* Create a memory event transport
|
|
296
|
+
* Create a memory event transport for in-process event handling.
|
|
297
|
+
* Suitable for testing and embedded mode.
|
|
298
|
+
*
|
|
299
|
+
* @param options - Transport configuration options
|
|
300
|
+
* @returns A new memory event transport instance
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```typescript
|
|
304
|
+
* const transport = createMemoryEventTransport({ sync: true });
|
|
305
|
+
* transport.subscribe('user.created', async (event) => {
|
|
306
|
+
* console.log('User created:', event.data);
|
|
307
|
+
* });
|
|
308
|
+
* await transport.emit({ type: 'user.created', data: { id: '123' } });
|
|
309
|
+
* ```
|
|
240
310
|
*/
|
|
241
311
|
declare function createMemoryEventTransport(options?: MemoryEventTransportOptions): MemoryEventTransport;
|
|
242
312
|
/**
|
|
@@ -278,7 +348,17 @@ declare class GlobalEventBus {
|
|
|
278
348
|
static reset(): void;
|
|
279
349
|
}
|
|
280
350
|
/**
|
|
281
|
-
* Get the global event bus
|
|
351
|
+
* Get the global event bus singleton.
|
|
352
|
+
* Provides a shared event bus for communication between embedded services.
|
|
353
|
+
*
|
|
354
|
+
* @returns The global event bus instance
|
|
355
|
+
*
|
|
356
|
+
* @example
|
|
357
|
+
* ```typescript
|
|
358
|
+
* const bus = getGlobalEventBus();
|
|
359
|
+
* bus.register('payments', paymentsTransport);
|
|
360
|
+
* await bus.broadcast(event, 'payments'); // Exclude payments
|
|
361
|
+
* ```
|
|
282
362
|
*/
|
|
283
363
|
declare function getGlobalEventBus(): GlobalEventBus;
|
|
284
364
|
|
package/dist/events/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/events/format.ts","../../src/events/emitter.ts","../../src/events/handler.ts","../../src/events/transports/memory.ts","../../src/events/dead-letter.ts"],"sourcesContent":["/**\n * @parsrun/service - Event Format\n * CloudEvents and compact event format utilities\n */\n\nimport { generateId } from \"@parsrun/core\";\nimport type { ParsEvent, CompactEvent, TraceContext } from \"../types.js\";\n\n// ============================================================================\n// EVENT CREATION\n// ============================================================================\n\nexport interface CreateEventOptions<T = unknown> {\n /** Event type (e.g., \"subscription.created\") */\n type: string;\n /** Source service */\n source: string;\n /** Event data */\n data: T;\n /** Optional event ID (auto-generated if not provided) */\n id?: string;\n /** Optional subject */\n subject?: string;\n /** Tenant ID */\n tenantId?: string;\n /** Request ID for correlation */\n requestId?: string;\n /** Trace context */\n traceContext?: TraceContext;\n /** Delivery guarantee */\n delivery?: \"at-most-once\" | \"at-least-once\";\n}\n\n/**\n * Create a CloudEvents-compatible event\n */\nexport function createEvent<T = unknown>(options: CreateEventOptions<T>): ParsEvent<T> {\n const event: ParsEvent<T> = {\n specversion: \"1.0\",\n type: options.type,\n source: options.source,\n id: options.id ?? generateId(),\n time: new Date().toISOString(),\n datacontenttype: \"application/json\",\n data: options.data,\n };\n\n if (options.subject) event.subject = options.subject;\n if (options.tenantId) event.parstenantid = options.tenantId;\n if (options.requestId) event.parsrequestid = options.requestId;\n if (options.traceContext) event.parstracecontext = formatTraceContext(options.traceContext);\n if (options.delivery) event.parsdelivery = options.delivery;\n\n return event;\n}\n\n// ============================================================================\n// FORMAT CONVERSION\n// ============================================================================\n\n/**\n * Convert to full CloudEvents format\n */\nexport function toCloudEvent<T>(event: ParsEvent<T>): ParsEvent<T> {\n return { ...event };\n}\n\n/**\n * Convert to compact internal format\n */\nexport function toCompactEvent<T>(event: ParsEvent<T>): CompactEvent<T> {\n const compact: CompactEvent<T> = {\n e: event.type,\n s: event.source,\n i: event.id,\n t: new Date(event.time).getTime(),\n d: event.data,\n };\n\n if (event.parstracecontext) compact.ctx = event.parstracecontext;\n if (event.parstenantid) compact.tid = event.parstenantid;\n\n return compact;\n}\n\n/**\n * Convert from compact format to CloudEvents\n */\nexport function fromCompactEvent<T>(compact: CompactEvent<T>, source?: string): ParsEvent<T> {\n const event: ParsEvent<T> = {\n specversion: \"1.0\",\n type: compact.e,\n source: source ?? compact.s,\n id: compact.i,\n time: new Date(compact.t).toISOString(),\n datacontenttype: \"application/json\",\n data: compact.d,\n };\n\n if (compact.ctx) event.parstracecontext = compact.ctx;\n if (compact.tid) event.parstenantid = compact.tid;\n\n return event;\n}\n\n// ============================================================================\n// EVENT TYPE UTILITIES\n// ============================================================================\n\n/**\n * Format full event type with source prefix\n *\n * @example\n * formatEventType('payments', 'subscription.created')\n * // Returns: 'com.pars.payments.subscription.created'\n */\nexport function formatEventType(source: string, type: string): string {\n return `com.pars.${source}.${type}`;\n}\n\n/**\n * Parse event type to extract source and type\n *\n * @example\n * parseEventType('com.pars.payments.subscription.created')\n * // Returns: { source: 'payments', type: 'subscription.created' }\n */\nexport function parseEventType(fullType: string): { source: string; type: string } | null {\n const prefix = \"com.pars.\";\n if (!fullType.startsWith(prefix)) {\n // Try to parse as simple type (source.type)\n const parts = fullType.split(\".\");\n if (parts.length >= 2) {\n const [source, ...rest] = parts;\n return { source: source!, type: rest.join(\".\") };\n }\n return null;\n }\n\n const withoutPrefix = fullType.slice(prefix.length);\n const dotIndex = withoutPrefix.indexOf(\".\");\n if (dotIndex === -1) {\n return null;\n }\n\n return {\n source: withoutPrefix.slice(0, dotIndex),\n type: withoutPrefix.slice(dotIndex + 1),\n };\n}\n\n/**\n * Check if event type matches a pattern\n * Supports wildcards: * matches one segment, ** matches multiple segments\n *\n * @example\n * matchEventType('subscription.created', 'subscription.*') // true\n * matchEventType('payment.invoice.paid', 'payment.**') // true\n * matchEventType('subscription.created', 'payment.*') // false\n */\nexport function matchEventType(type: string, pattern: string): boolean {\n if (pattern === \"*\" || pattern === \"**\") {\n return true;\n }\n\n const typeParts = type.split(\".\");\n const patternParts = pattern.split(\".\");\n\n let ti = 0;\n let pi = 0;\n\n while (ti < typeParts.length && pi < patternParts.length) {\n const pp = patternParts[pi];\n\n if (pp === \"**\") {\n // ** matches rest of type\n if (pi === patternParts.length - 1) {\n return true;\n }\n // Try to match remaining pattern\n for (let i = ti; i <= typeParts.length; i++) {\n const remaining = typeParts.slice(i).join(\".\");\n const remainingPattern = patternParts.slice(pi + 1).join(\".\");\n if (matchEventType(remaining, remainingPattern)) {\n return true;\n }\n }\n return false;\n }\n\n if (pp === \"*\") {\n // * matches single segment\n ti++;\n pi++;\n continue;\n }\n\n if (pp !== typeParts[ti]) {\n return false;\n }\n\n ti++;\n pi++;\n }\n\n return ti === typeParts.length && pi === patternParts.length;\n}\n\n// ============================================================================\n// TRACE CONTEXT HELPERS\n// ============================================================================\n\n/**\n * Format trace context to W3C traceparent string\n */\nfunction formatTraceContext(ctx: TraceContext): string {\n const flags = ctx.traceFlags.toString(16).padStart(2, \"0\");\n return `00-${ctx.traceId}-${ctx.spanId}-${flags}`;\n}\n\n/**\n * Parse W3C traceparent string to trace context\n */\nexport function parseTraceContext(traceparent: string): TraceContext | null {\n const parts = traceparent.split(\"-\");\n if (parts.length !== 4) {\n return null;\n }\n\n const [version, traceId, spanId, flags] = parts;\n if (version !== \"00\" || !traceId || !spanId || !flags) {\n return null;\n }\n\n return {\n traceId,\n spanId,\n traceFlags: parseInt(flags, 16),\n };\n}\n\n// ============================================================================\n// VALIDATION\n// ============================================================================\n\n/**\n * Validate CloudEvents structure\n */\nexport function validateEvent(event: unknown): event is ParsEvent {\n if (!event || typeof event !== \"object\") {\n return false;\n }\n\n const e = event as Record<string, unknown>;\n\n // Required fields\n if (e[\"specversion\"] !== \"1.0\") return false;\n if (typeof e[\"type\"] !== \"string\" || (e[\"type\"] as string).length === 0) return false;\n if (typeof e[\"source\"] !== \"string\" || (e[\"source\"] as string).length === 0) return false;\n if (typeof e[\"id\"] !== \"string\" || (e[\"id\"] as string).length === 0) return false;\n if (typeof e[\"time\"] !== \"string\") return false;\n\n return true;\n}\n\n/**\n * Validate compact event structure\n */\nexport function validateCompactEvent(event: unknown): event is CompactEvent {\n if (!event || typeof event !== \"object\") {\n return false;\n }\n\n const e = event as Record<string, unknown>;\n\n if (typeof e[\"e\"] !== \"string\" || (e[\"e\"] as string).length === 0) return false;\n if (typeof e[\"s\"] !== \"string\" || (e[\"s\"] as string).length === 0) return false;\n if (typeof e[\"i\"] !== \"string\" || (e[\"i\"] as string).length === 0) return false;\n if (typeof e[\"t\"] !== \"number\") return false;\n\n return true;\n}\n","/**\n * @parsrun/service - Event Emitter\n * Service-level event emission\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger } from \"@parsrun/core\";\nimport type {\n EventTransport,\n TraceContext,\n ServiceDefinition,\n} from \"../types.js\";\nimport { createEvent, type CreateEventOptions } from \"./format.js\";\n\n// ============================================================================\n// EVENT EMITTER\n// ============================================================================\n\nexport interface EventEmitterOptions {\n /** Service name (source) */\n service: string;\n /** Service definition (for validation) */\n definition?: ServiceDefinition;\n /** Event transport */\n transport: EventTransport;\n /** Logger */\n logger?: Logger;\n /** Default tenant ID */\n defaultTenantId?: string;\n /** Validate events against definition */\n validateEvents?: boolean;\n}\n\n/**\n * Event emitter for service events\n */\nexport class EventEmitter {\n private readonly service: string;\n private readonly definition?: ServiceDefinition;\n private readonly transport: EventTransport;\n private readonly logger: Logger;\n private readonly defaultTenantId?: string;\n private readonly validateEvents: boolean;\n\n constructor(options: EventEmitterOptions) {\n this.service = options.service;\n if (options.definition) {\n this.definition = options.definition;\n }\n this.transport = options.transport;\n this.logger = options.logger ?? createLogger({ name: `events:${options.service}` });\n if (options.defaultTenantId) {\n this.defaultTenantId = options.defaultTenantId;\n }\n this.validateEvents = options.validateEvents ?? true;\n }\n\n /**\n * Emit an event\n */\n async emit<T = unknown>(\n type: string,\n data: T,\n options?: EmitOptions\n ): Promise<string> {\n // Validate event type if definition provided\n if (this.validateEvents && this.definition?.events?.emits) {\n const emits = this.definition.events.emits;\n if (!(type in emits)) {\n this.logger.warn(`Event type not declared in service definition: ${type}`);\n }\n }\n\n // Get delivery guarantee from definition\n let delivery: \"at-most-once\" | \"at-least-once\" | undefined;\n if (this.definition?.events?.emits?.[type]) {\n delivery = this.definition.events.emits[type].delivery;\n }\n\n // Create event options\n const eventOptions: CreateEventOptions<T> = {\n type,\n source: this.service,\n data,\n };\n\n if (options?.eventId) eventOptions.id = options.eventId;\n if (options?.subject) eventOptions.subject = options.subject;\n\n const tenantId = options?.tenantId ?? this.defaultTenantId;\n if (tenantId) eventOptions.tenantId = tenantId;\n\n if (options?.requestId) eventOptions.requestId = options.requestId;\n if (options?.traceContext) eventOptions.traceContext = options.traceContext;\n\n const eventDelivery = options?.delivery ?? delivery;\n if (eventDelivery) eventOptions.delivery = eventDelivery;\n\n // Create event\n const event = createEvent(eventOptions);\n\n // Emit via transport\n try {\n await this.transport.emit(event);\n this.logger.debug(`Event emitted: ${type}`, {\n eventId: event.id,\n tenantId: event.parstenantid,\n });\n return event.id;\n } catch (error) {\n this.logger.error(`Failed to emit event: ${type}`, error as Error, {\n eventId: event.id,\n });\n throw error;\n }\n }\n\n /**\n * Emit multiple events\n */\n async emitBatch<T = unknown>(\n events: Array<{ type: string; data: T; options?: EmitOptions }>\n ): Promise<string[]> {\n const results: string[] = [];\n\n for (const { type, data, options } of events) {\n const eventId = await this.emit(type, data, options);\n results.push(eventId);\n }\n\n return results;\n }\n\n /**\n * Create a scoped emitter with preset options\n */\n scoped(options: Partial<EmitOptions>): ScopedEmitter {\n return new ScopedEmitter(this, options);\n }\n\n /**\n * Get service name\n */\n get serviceName(): string {\n return this.service;\n }\n}\n\n/**\n * Emit options\n */\nexport interface EmitOptions {\n /** Custom event ID */\n eventId?: string;\n /** Event subject */\n subject?: string;\n /** Tenant ID */\n tenantId?: string;\n /** Request ID for correlation */\n requestId?: string;\n /** Trace context */\n traceContext?: TraceContext;\n /** Override delivery guarantee */\n delivery?: \"at-most-once\" | \"at-least-once\";\n}\n\n/**\n * Scoped emitter with preset options\n */\nexport class ScopedEmitter {\n private readonly emitter: EventEmitter;\n private readonly defaultOptions: Partial<EmitOptions>;\n\n constructor(emitter: EventEmitter, defaultOptions: Partial<EmitOptions>) {\n this.emitter = emitter;\n this.defaultOptions = defaultOptions;\n }\n\n async emit<T = unknown>(\n type: string,\n data: T,\n options?: EmitOptions\n ): Promise<string> {\n return this.emitter.emit(type, data, {\n ...this.defaultOptions,\n ...options,\n });\n }\n}\n\n/**\n * Create an event emitter\n */\nexport function createEventEmitter(options: EventEmitterOptions): EventEmitter {\n return new EventEmitter(options);\n}\n\n// ============================================================================\n// TYPED EVENT EMITTER\n// ============================================================================\n\n/**\n * Create a typed event emitter from service definition\n * Provides type-safe event emission\n */\nexport function createTypedEmitter<TDef extends ServiceDefinition>(\n definition: TDef,\n options: Omit<EventEmitterOptions, \"service\" | \"definition\">\n): TypedEventEmitter<TDef> {\n const emitter = new EventEmitter({\n ...options,\n service: definition.name,\n definition,\n });\n\n return emitter as TypedEventEmitter<TDef>;\n}\n\n/**\n * Typed event emitter type\n * Provides type-safe event emission with specific event types\n */\nexport type TypedEventEmitter<TDef extends ServiceDefinition> = EventEmitter & {\n emit<K extends keyof NonNullable<TDef[\"events\"]>[\"emits\"]>(\n type: K,\n data: NonNullable<TDef[\"events\"]>[\"emits\"][K] extends { data?: infer D } ? D : unknown,\n options?: EmitOptions\n ): Promise<string>;\n};\n","/**\n * @parsrun/service - Event Handler\n * Event handler registration and execution\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger } from \"@parsrun/core\";\nimport type {\n ParsEvent,\n EventHandler,\n EventHandlerContext,\n EventHandlerOptions,\n Unsubscribe,\n} from \"../types.js\";\nimport { matchEventType } from \"./format.js\";\nimport type { DeadLetterQueue } from \"./dead-letter.js\";\n\n// ============================================================================\n// EVENT HANDLER REGISTRY\n// ============================================================================\n\n/**\n * Resolved handler options with required fields\n */\nexport interface ResolvedHandlerOptions {\n retries: number;\n backoff: \"linear\" | \"exponential\";\n maxDelay: number;\n onExhausted: \"alert\" | \"log\" | \"discard\";\n deadLetter?: string;\n}\n\nexport interface HandlerRegistration {\n /** Event type pattern (supports wildcards) */\n pattern: string;\n /** Handler function */\n handler: EventHandler;\n /** Handler options */\n options: ResolvedHandlerOptions;\n}\n\nexport interface EventHandlerRegistryOptions {\n /** Logger */\n logger?: Logger;\n /** Dead letter queue */\n deadLetterQueue?: DeadLetterQueue;\n /** Default handler options */\n defaultOptions?: Partial<EventHandlerOptions>;\n}\n\n/**\n * Registry for event handlers\n */\nexport class EventHandlerRegistry {\n private readonly handlers: Map<string, HandlerRegistration[]> = new Map();\n private readonly logger: Logger;\n private readonly deadLetterQueue?: DeadLetterQueue;\n private readonly defaultOptions: ResolvedHandlerOptions;\n\n constructor(options: EventHandlerRegistryOptions = {}) {\n this.logger = options.logger ?? createLogger({ name: \"event-handler\" });\n if (options.deadLetterQueue) {\n this.deadLetterQueue = options.deadLetterQueue;\n }\n const defaultOpts: ResolvedHandlerOptions = {\n retries: options.defaultOptions?.retries ?? 3,\n backoff: options.defaultOptions?.backoff ?? \"exponential\",\n maxDelay: options.defaultOptions?.maxDelay ?? 30_000,\n onExhausted: options.defaultOptions?.onExhausted ?? \"log\",\n };\n if (options.defaultOptions?.deadLetter) {\n defaultOpts.deadLetter = options.defaultOptions.deadLetter;\n }\n this.defaultOptions = defaultOpts;\n }\n\n /**\n * Register an event handler\n */\n register(\n pattern: string,\n handler: EventHandler,\n options?: EventHandlerOptions\n ): Unsubscribe {\n const registration: HandlerRegistration = {\n pattern,\n handler,\n options: {\n ...this.defaultOptions,\n ...options,\n },\n };\n\n const handlers = this.handlers.get(pattern) ?? [];\n handlers.push(registration);\n this.handlers.set(pattern, handlers);\n\n this.logger.debug(`Handler registered for pattern: ${pattern}`);\n\n // Return unsubscribe function\n return () => {\n const currentHandlers = this.handlers.get(pattern);\n if (currentHandlers) {\n const index = currentHandlers.indexOf(registration);\n if (index !== -1) {\n currentHandlers.splice(index, 1);\n if (currentHandlers.length === 0) {\n this.handlers.delete(pattern);\n }\n this.logger.debug(`Handler unregistered for pattern: ${pattern}`);\n }\n }\n };\n }\n\n /**\n * Handle an event\n */\n async handle(event: ParsEvent): Promise<void> {\n const matchingHandlers = this.getMatchingHandlers(event.type);\n\n if (matchingHandlers.length === 0) {\n this.logger.debug(`No handlers for event type: ${event.type}`, {\n eventId: event.id,\n });\n return;\n }\n\n this.logger.debug(`Handling event: ${event.type}`, {\n eventId: event.id,\n handlerCount: matchingHandlers.length,\n });\n\n // Execute handlers in parallel\n const results = await Promise.allSettled(\n matchingHandlers.map((reg) => this.executeHandler(event, reg))\n );\n\n // Log failures\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n if (result?.status === \"rejected\") {\n this.logger.error(\n `Handler failed for ${event.type}`,\n result.reason as Error,\n { eventId: event.id, pattern: matchingHandlers[i]?.pattern }\n );\n }\n }\n }\n\n /**\n * Execute a single handler with retry logic\n */\n private async executeHandler(\n event: ParsEvent,\n registration: HandlerRegistration\n ): Promise<void> {\n const { handler, options } = registration;\n const maxAttempts = options.retries + 1;\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const context: EventHandlerContext = {\n logger: this.logger.child({\n eventId: event.id,\n pattern: registration.pattern,\n attempt,\n }),\n attempt,\n maxAttempts,\n isRetry: attempt > 1,\n };\n\n // Add trace context if available\n if (event.parstracecontext) {\n const traceCtx = parseTraceContext(event.parstracecontext);\n if (traceCtx) {\n context.traceContext = traceCtx;\n }\n }\n\n await handler(event, context);\n return; // Success\n } catch (error) {\n lastError = error as Error;\n\n if (attempt < maxAttempts) {\n const delay = this.calculateBackoff(attempt, options);\n this.logger.warn(\n `Handler failed, retrying in ${delay}ms`,\n { eventId: event.id, attempt, maxAttempts }\n );\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted\n await this.handleExhausted(event, registration, lastError!);\n }\n\n /**\n * Calculate backoff delay\n */\n private calculateBackoff(\n attempt: number,\n options: ResolvedHandlerOptions\n ): number {\n const baseDelay = 100;\n\n if (options.backoff === \"exponential\") {\n return Math.min(baseDelay * Math.pow(2, attempt - 1), options.maxDelay);\n }\n\n // Linear\n return Math.min(baseDelay * attempt, options.maxDelay);\n }\n\n /**\n * Handle exhausted retries\n */\n private async handleExhausted(\n event: ParsEvent,\n registration: HandlerRegistration,\n error: Error\n ): Promise<void> {\n const { options } = registration;\n\n // Send to dead letter queue\n if (options.deadLetter && this.deadLetterQueue) {\n await this.deadLetterQueue.add({\n event,\n error: error.message,\n pattern: registration.pattern,\n attempts: options.retries + 1,\n });\n }\n\n // Handle based on onExhausted option\n switch (options.onExhausted) {\n case \"alert\":\n this.logger.error(\n `[ALERT] Event handler exhausted all retries`,\n error,\n {\n eventId: event.id,\n eventType: event.type,\n pattern: registration.pattern,\n }\n );\n break;\n case \"discard\":\n this.logger.debug(`Event discarded after exhausted retries`, {\n eventId: event.id,\n });\n break;\n case \"log\":\n default:\n this.logger.warn(`Event handler exhausted all retries`, {\n eventId: event.id,\n error: error.message,\n });\n }\n }\n\n /**\n * Get handlers matching an event type\n */\n private getMatchingHandlers(eventType: string): HandlerRegistration[] {\n const matching: HandlerRegistration[] = [];\n\n for (const [pattern, handlers] of this.handlers) {\n if (matchEventType(eventType, pattern)) {\n matching.push(...handlers);\n }\n }\n\n return matching;\n }\n\n /**\n * Get all registered patterns\n */\n getPatterns(): string[] {\n return Array.from(this.handlers.keys());\n }\n\n /**\n * Check if a pattern has handlers\n */\n hasHandlers(pattern: string): boolean {\n return this.handlers.has(pattern);\n }\n\n /**\n * Clear all handlers\n */\n clear(): void {\n this.handlers.clear();\n }\n}\n\n/**\n * Create an event handler registry\n */\nexport function createEventHandlerRegistry(\n options?: EventHandlerRegistryOptions\n): EventHandlerRegistry {\n return new EventHandlerRegistry(options);\n}\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseTraceContext(traceparent: string): {\n traceId: string;\n spanId: string;\n traceFlags: number;\n} | undefined {\n const parts = traceparent.split(\"-\");\n if (parts.length !== 4) return undefined;\n\n const [, traceId, spanId, flags] = parts;\n if (!traceId || !spanId || !flags) return undefined;\n\n return {\n traceId,\n spanId,\n traceFlags: parseInt(flags, 16),\n };\n}\n","/**\n * @parsrun/service - Memory Event Transport\n * In-memory event transport for embedded mode and testing\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger } from \"@parsrun/core\";\nimport type {\n ParsEvent,\n EventTransport,\n EventHandler,\n EventHandlerOptions,\n Unsubscribe,\n} from \"../../types.js\";\nimport { EventHandlerRegistry, type EventHandlerRegistryOptions } from \"../handler.js\";\n\n// ============================================================================\n// MEMORY EVENT TRANSPORT\n// ============================================================================\n\nexport interface MemoryEventTransportOptions {\n /** Logger */\n logger?: Logger;\n /** Process events synchronously (default: false) */\n sync?: boolean;\n /** Default handler options */\n defaultHandlerOptions?: EventHandlerOptions;\n}\n\n/**\n * In-memory event transport\n * Events are processed immediately without persistence\n */\nexport class MemoryEventTransport implements EventTransport {\n readonly name = \"memory\";\n private readonly registry: EventHandlerRegistry;\n private readonly logger: Logger;\n private readonly sync: boolean;\n private readonly pendingEvents: ParsEvent[] = [];\n private processing = false;\n\n constructor(options: MemoryEventTransportOptions = {}) {\n this.logger = options.logger ?? createLogger({ name: \"memory-transport\" });\n this.sync = options.sync ?? false;\n\n const registryOptions: EventHandlerRegistryOptions = {\n logger: this.logger,\n };\n if (options.defaultHandlerOptions) {\n registryOptions.defaultOptions = options.defaultHandlerOptions;\n }\n this.registry = new EventHandlerRegistry(registryOptions);\n }\n\n /**\n * Emit an event\n */\n async emit<T>(event: ParsEvent<T>): Promise<void> {\n this.logger.debug(`Event emitted: ${event.type}`, {\n eventId: event.id,\n tenantId: event.parstenantid,\n });\n\n if (this.sync) {\n // Process synchronously\n await this.registry.handle(event);\n } else {\n // Queue for async processing\n this.pendingEvents.push(event);\n this.processQueue();\n }\n }\n\n /**\n * Subscribe to events\n */\n subscribe(\n eventType: string,\n handler: EventHandler,\n options?: EventHandlerOptions\n ): Unsubscribe {\n return this.registry.register(eventType, handler, options);\n }\n\n /**\n * Process pending events asynchronously\n */\n private async processQueue(): Promise<void> {\n if (this.processing) return;\n this.processing = true;\n\n try {\n while (this.pendingEvents.length > 0) {\n const event = this.pendingEvents.shift();\n if (event) {\n await this.registry.handle(event);\n }\n }\n } finally {\n this.processing = false;\n }\n }\n\n /**\n * Wait for all pending events to be processed\n */\n async flush(): Promise<void> {\n while (this.pendingEvents.length > 0 || this.processing) {\n await new Promise((resolve) => setTimeout(resolve, 10));\n }\n }\n\n /**\n * Get pending event count\n */\n get pendingCount(): number {\n return this.pendingEvents.length;\n }\n\n /**\n * Get registered patterns\n */\n getPatterns(): string[] {\n return this.registry.getPatterns();\n }\n\n /**\n * Clear all subscriptions\n */\n clear(): void {\n this.registry.clear();\n this.pendingEvents.length = 0;\n }\n\n /**\n * Close the transport\n */\n async close(): Promise<void> {\n await this.flush();\n this.clear();\n }\n}\n\n/**\n * Create a memory event transport\n */\nexport function createMemoryEventTransport(\n options?: MemoryEventTransportOptions\n): MemoryEventTransport {\n return new MemoryEventTransport(options);\n}\n\n// ============================================================================\n// GLOBAL EVENT BUS (for embedded multi-service)\n// ============================================================================\n\n/**\n * Global event bus for communication between embedded services\n */\nexport class GlobalEventBus {\n private static instance: GlobalEventBus | null = null;\n private readonly transports: Map<string, MemoryEventTransport> = new Map();\n private readonly logger: Logger;\n\n private constructor() {\n this.logger = createLogger({ name: \"global-event-bus\" });\n }\n\n static getInstance(): GlobalEventBus {\n if (!GlobalEventBus.instance) {\n GlobalEventBus.instance = new GlobalEventBus();\n }\n return GlobalEventBus.instance;\n }\n\n /**\n * Register a service's event transport\n */\n register(serviceName: string, transport: MemoryEventTransport): void {\n if (this.transports.has(serviceName)) {\n throw new Error(`Service already registered: ${serviceName}`);\n }\n this.transports.set(serviceName, transport);\n this.logger.debug(`Service registered: ${serviceName}`);\n }\n\n /**\n * Unregister a service\n */\n unregister(serviceName: string): boolean {\n const deleted = this.transports.delete(serviceName);\n if (deleted) {\n this.logger.debug(`Service unregistered: ${serviceName}`);\n }\n return deleted;\n }\n\n /**\n * Broadcast an event to all services (except source)\n */\n async broadcast(event: ParsEvent, excludeSource?: string): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const [name, transport] of this.transports) {\n if (name !== excludeSource) {\n promises.push(transport.emit(event));\n }\n }\n\n await Promise.allSettled(promises);\n }\n\n /**\n * Send an event to a specific service\n */\n async send(serviceName: string, event: ParsEvent): Promise<void> {\n const transport = this.transports.get(serviceName);\n if (!transport) {\n this.logger.warn(`Target service not found: ${serviceName}`, {\n eventId: event.id,\n });\n return;\n }\n\n await transport.emit(event);\n }\n\n /**\n * Get all registered service names\n */\n getServices(): string[] {\n return Array.from(this.transports.keys());\n }\n\n /**\n * Clear all registrations\n */\n clear(): void {\n this.transports.clear();\n }\n\n /**\n * Reset singleton (for testing)\n */\n static reset(): void {\n GlobalEventBus.instance = null;\n }\n}\n\n/**\n * Get the global event bus\n */\nexport function getGlobalEventBus(): GlobalEventBus {\n return GlobalEventBus.getInstance();\n}\n","/**\n * @parsrun/service - Dead Letter Queue\n * Storage for failed events\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger, generateId } from \"@parsrun/core\";\nimport type { ParsEvent } from \"../types.js\";\n\n// ============================================================================\n// DEAD LETTER QUEUE\n// ============================================================================\n\nexport interface DeadLetterEntry {\n /** Unique ID */\n id: string;\n /** Original event */\n event: ParsEvent;\n /** Error message */\n error: string;\n /** Handler pattern that failed */\n pattern: string;\n /** Number of attempts made */\n attempts: number;\n /** Timestamp when added */\n addedAt: Date;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\nexport interface DeadLetterQueueOptions {\n /** Maximum entries to keep */\n maxSize?: number;\n /** Retention period in ms */\n retentionMs?: number;\n /** Callback when entry is added */\n onAdd?: (entry: DeadLetterEntry) => void;\n /** Callback when threshold is reached */\n onThreshold?: (count: number) => void;\n /** Alert threshold */\n alertThreshold?: number;\n /** Logger */\n logger?: Logger;\n}\n\nexport interface AddEntryOptions {\n /** Original event */\n event: ParsEvent;\n /** Error message */\n error: string;\n /** Handler pattern */\n pattern: string;\n /** Number of attempts */\n attempts: number;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Resolved DLQ options\n */\ninterface ResolvedDlqOptions {\n maxSize: number;\n retentionMs: number;\n alertThreshold: number;\n onAdd?: (entry: DeadLetterEntry) => void;\n onThreshold?: (count: number) => void;\n logger?: Logger;\n}\n\n/**\n * In-memory Dead Letter Queue\n */\nexport class DeadLetterQueue {\n private readonly entries: Map<string, DeadLetterEntry> = new Map();\n private readonly resolvedOptions: ResolvedDlqOptions;\n private readonly logger: Logger;\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(options: DeadLetterQueueOptions = {}) {\n this.resolvedOptions = {\n maxSize: options.maxSize ?? 1000,\n retentionMs: options.retentionMs ?? 30 * 24 * 60 * 60 * 1000, // 30 days\n alertThreshold: options.alertThreshold ?? 10,\n };\n\n if (options.onAdd) this.resolvedOptions.onAdd = options.onAdd;\n if (options.onThreshold) this.resolvedOptions.onThreshold = options.onThreshold;\n if (options.logger) this.resolvedOptions.logger = options.logger;\n\n this.logger = options.logger ?? createLogger({ name: \"dlq\" });\n\n // Start cleanup timer\n this.cleanupTimer = setInterval(() => this.cleanup(), 60 * 60 * 1000); // Every hour\n }\n\n /**\n * Add an entry to the DLQ\n */\n async add(options: AddEntryOptions): Promise<string> {\n const entry: DeadLetterEntry = {\n id: generateId(),\n event: options.event,\n error: options.error,\n pattern: options.pattern,\n attempts: options.attempts,\n addedAt: new Date(),\n };\n\n if (options.metadata) {\n entry.metadata = options.metadata;\n }\n\n // Check max size\n if (this.entries.size >= this.resolvedOptions.maxSize) {\n // Remove oldest entry\n const oldest = this.getOldest();\n if (oldest) {\n this.entries.delete(oldest.id);\n this.logger.debug(`DLQ: Removed oldest entry to make room`, {\n removedId: oldest.id,\n });\n }\n }\n\n this.entries.set(entry.id, entry);\n\n this.logger.warn(`DLQ: Entry added`, {\n id: entry.id,\n eventId: entry.event.id,\n eventType: entry.event.type,\n error: entry.error,\n });\n\n // Callbacks\n this.resolvedOptions.onAdd?.(entry);\n\n // Check threshold\n if (this.entries.size >= this.resolvedOptions.alertThreshold) {\n this.resolvedOptions.onThreshold?.(this.entries.size);\n }\n\n return entry.id;\n }\n\n /**\n * Get an entry by ID\n */\n get(id: string): DeadLetterEntry | undefined {\n return this.entries.get(id);\n }\n\n /**\n * Get all entries\n */\n getAll(): DeadLetterEntry[] {\n return Array.from(this.entries.values());\n }\n\n /**\n * Get entries by event type\n */\n getByEventType(eventType: string): DeadLetterEntry[] {\n return Array.from(this.entries.values()).filter(\n (e) => e.event.type === eventType\n );\n }\n\n /**\n * Get entries by pattern\n */\n getByPattern(pattern: string): DeadLetterEntry[] {\n return Array.from(this.entries.values()).filter(\n (e) => e.pattern === pattern\n );\n }\n\n /**\n * Remove an entry\n */\n remove(id: string): boolean {\n const deleted = this.entries.delete(id);\n if (deleted) {\n this.logger.debug(`DLQ: Entry removed`, { id });\n }\n return deleted;\n }\n\n /**\n * Retry an entry (remove from DLQ and return event)\n */\n retry(id: string): ParsEvent | undefined {\n const entry = this.entries.get(id);\n if (!entry) return undefined;\n\n this.entries.delete(id);\n this.logger.info(`DLQ: Entry removed for retry`, {\n id,\n eventId: entry.event.id,\n });\n\n return entry.event;\n }\n\n /**\n * Get count\n */\n get size(): number {\n return this.entries.size;\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.entries.clear();\n this.logger.info(`DLQ: Cleared all entries`);\n }\n\n /**\n * Cleanup expired entries\n */\n private cleanup(): void {\n const now = Date.now();\n let removed = 0;\n\n for (const [id, entry] of this.entries) {\n const age = now - entry.addedAt.getTime();\n if (age > this.resolvedOptions.retentionMs) {\n this.entries.delete(id);\n removed++;\n }\n }\n\n if (removed > 0) {\n this.logger.debug(`DLQ: Cleaned up ${removed} expired entries`);\n }\n }\n\n /**\n * Get oldest entry\n */\n private getOldest(): DeadLetterEntry | undefined {\n let oldest: DeadLetterEntry | undefined;\n\n for (const entry of this.entries.values()) {\n if (!oldest || entry.addedAt < oldest.addedAt) {\n oldest = entry;\n }\n }\n\n return oldest;\n }\n\n /**\n * Stop cleanup timer\n */\n close(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n /**\n * Export entries for persistence\n */\n export(): DeadLetterEntry[] {\n return Array.from(this.entries.values()).map((e) => ({\n ...e,\n addedAt: e.addedAt,\n }));\n }\n\n /**\n * Import entries from persistence\n */\n import(entries: DeadLetterEntry[]): void {\n for (const entry of entries) {\n this.entries.set(entry.id, {\n ...entry,\n addedAt: new Date(entry.addedAt),\n });\n }\n this.logger.info(`DLQ: Imported ${entries.length} entries`);\n }\n}\n\n/**\n * Create a dead letter queue\n */\nexport function createDeadLetterQueue(\n options?: DeadLetterQueueOptions\n): DeadLetterQueue {\n return new DeadLetterQueue(options);\n}\n"],"mappings":"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","names":["createLogger","createLogger","createLogger","createLogger","createLogger","generateId"]}
|
|
1
|
+
{"version":3,"sources":["../../src/events/format.ts","../../src/events/emitter.ts","../../src/events/handler.ts","../../src/events/transports/memory.ts","../../src/events/dead-letter.ts"],"sourcesContent":["/**\n * @parsrun/service - Event Format\n * CloudEvents and compact event format utilities\n */\n\nimport { generateId } from \"@parsrun/core\";\nimport type { ParsEvent, CompactEvent, TraceContext } from \"../types.js\";\n\n// ============================================================================\n// EVENT CREATION\n// ============================================================================\n\n/**\n * Options for creating a CloudEvents-compatible event.\n */\nexport interface CreateEventOptions<T = unknown> {\n /** Event type (e.g., \"subscription.created\") */\n type: string;\n /** Source service */\n source: string;\n /** Event data */\n data: T;\n /** Optional event ID (auto-generated if not provided) */\n id?: string;\n /** Optional subject */\n subject?: string;\n /** Tenant ID */\n tenantId?: string;\n /** Request ID for correlation */\n requestId?: string;\n /** Trace context */\n traceContext?: TraceContext;\n /** Delivery guarantee */\n delivery?: \"at-most-once\" | \"at-least-once\";\n}\n\n/**\n * Create a CloudEvents-compatible event.\n *\n * @param options - Event creation options\n * @returns A new ParsEvent conforming to CloudEvents spec\n */\nexport function createEvent<T = unknown>(options: CreateEventOptions<T>): ParsEvent<T> {\n const event: ParsEvent<T> = {\n specversion: \"1.0\",\n type: options.type,\n source: options.source,\n id: options.id ?? generateId(),\n time: new Date().toISOString(),\n datacontenttype: \"application/json\",\n data: options.data,\n };\n\n if (options.subject) event.subject = options.subject;\n if (options.tenantId) event.parstenantid = options.tenantId;\n if (options.requestId) event.parsrequestid = options.requestId;\n if (options.traceContext) event.parstracecontext = formatTraceContext(options.traceContext);\n if (options.delivery) event.parsdelivery = options.delivery;\n\n return event;\n}\n\n// ============================================================================\n// FORMAT CONVERSION\n// ============================================================================\n\n/**\n * Convert to full CloudEvents format (creates a copy).\n *\n * @param event - The event to convert\n * @returns A copy of the event in CloudEvents format\n */\nexport function toCloudEvent<T>(event: ParsEvent<T>): ParsEvent<T> {\n return { ...event };\n}\n\n/**\n * Convert to compact internal format for efficient transport.\n *\n * @param event - The CloudEvents event to convert\n * @returns A compact representation of the event\n */\nexport function toCompactEvent<T>(event: ParsEvent<T>): CompactEvent<T> {\n const compact: CompactEvent<T> = {\n e: event.type,\n s: event.source,\n i: event.id,\n t: new Date(event.time).getTime(),\n d: event.data,\n };\n\n if (event.parstracecontext) compact.ctx = event.parstracecontext;\n if (event.parstenantid) compact.tid = event.parstenantid;\n\n return compact;\n}\n\n/**\n * Convert from compact format to CloudEvents format.\n *\n * @param compact - The compact event to convert\n * @param source - Optional source override\n * @returns A full CloudEvents event\n */\nexport function fromCompactEvent<T>(compact: CompactEvent<T>, source?: string): ParsEvent<T> {\n const event: ParsEvent<T> = {\n specversion: \"1.0\",\n type: compact.e,\n source: source ?? compact.s,\n id: compact.i,\n time: new Date(compact.t).toISOString(),\n datacontenttype: \"application/json\",\n data: compact.d,\n };\n\n if (compact.ctx) event.parstracecontext = compact.ctx;\n if (compact.tid) event.parstenantid = compact.tid;\n\n return event;\n}\n\n// ============================================================================\n// EVENT TYPE UTILITIES\n// ============================================================================\n\n/**\n * Format full event type with source prefix.\n *\n * @param source - The source service name\n * @param type - The event type\n * @returns Fully qualified event type\n *\n * @example\n * ```typescript\n * formatEventType('payments', 'subscription.created')\n * // Returns: 'com.pars.payments.subscription.created'\n * ```\n */\nexport function formatEventType(source: string, type: string): string {\n return `com.pars.${source}.${type}`;\n}\n\n/**\n * Parse event type to extract source and type.\n *\n * @param fullType - The fully qualified event type\n * @returns Parsed source and type, or null if invalid\n *\n * @example\n * ```typescript\n * parseEventType('com.pars.payments.subscription.created')\n * // Returns: { source: 'payments', type: 'subscription.created' }\n * ```\n */\nexport function parseEventType(fullType: string): { source: string; type: string } | null {\n const prefix = \"com.pars.\";\n if (!fullType.startsWith(prefix)) {\n // Try to parse as simple type (source.type)\n const parts = fullType.split(\".\");\n if (parts.length >= 2) {\n const [source, ...rest] = parts;\n return { source: source!, type: rest.join(\".\") };\n }\n return null;\n }\n\n const withoutPrefix = fullType.slice(prefix.length);\n const dotIndex = withoutPrefix.indexOf(\".\");\n if (dotIndex === -1) {\n return null;\n }\n\n return {\n source: withoutPrefix.slice(0, dotIndex),\n type: withoutPrefix.slice(dotIndex + 1),\n };\n}\n\n/**\n * Check if event type matches a pattern.\n * Supports wildcards: * matches one segment, ** matches multiple segments.\n *\n * @param type - The event type to check\n * @param pattern - The pattern to match against\n * @returns True if the type matches the pattern\n *\n * @example\n * ```typescript\n * matchEventType('subscription.created', 'subscription.*') // true\n * matchEventType('payment.invoice.paid', 'payment.**') // true\n * matchEventType('subscription.created', 'payment.*') // false\n * ```\n */\nexport function matchEventType(type: string, pattern: string): boolean {\n if (pattern === \"*\" || pattern === \"**\") {\n return true;\n }\n\n const typeParts = type.split(\".\");\n const patternParts = pattern.split(\".\");\n\n let ti = 0;\n let pi = 0;\n\n while (ti < typeParts.length && pi < patternParts.length) {\n const pp = patternParts[pi];\n\n if (pp === \"**\") {\n // ** matches rest of type\n if (pi === patternParts.length - 1) {\n return true;\n }\n // Try to match remaining pattern\n for (let i = ti; i <= typeParts.length; i++) {\n const remaining = typeParts.slice(i).join(\".\");\n const remainingPattern = patternParts.slice(pi + 1).join(\".\");\n if (matchEventType(remaining, remainingPattern)) {\n return true;\n }\n }\n return false;\n }\n\n if (pp === \"*\") {\n // * matches single segment\n ti++;\n pi++;\n continue;\n }\n\n if (pp !== typeParts[ti]) {\n return false;\n }\n\n ti++;\n pi++;\n }\n\n return ti === typeParts.length && pi === patternParts.length;\n}\n\n// ============================================================================\n// TRACE CONTEXT HELPERS\n// ============================================================================\n\n/**\n * Format trace context to W3C traceparent string\n */\nfunction formatTraceContext(ctx: TraceContext): string {\n const flags = ctx.traceFlags.toString(16).padStart(2, \"0\");\n return `00-${ctx.traceId}-${ctx.spanId}-${flags}`;\n}\n\n/**\n * Parse W3C traceparent string to trace context.\n *\n * @param traceparent - The traceparent header value\n * @returns Parsed trace context, or null if invalid\n */\nexport function parseTraceContext(traceparent: string): TraceContext | null {\n const parts = traceparent.split(\"-\");\n if (parts.length !== 4) {\n return null;\n }\n\n const [version, traceId, spanId, flags] = parts;\n if (version !== \"00\" || !traceId || !spanId || !flags) {\n return null;\n }\n\n return {\n traceId,\n spanId,\n traceFlags: parseInt(flags, 16),\n };\n}\n\n// ============================================================================\n// VALIDATION\n// ============================================================================\n\n/**\n * Validate that an object conforms to CloudEvents structure.\n *\n * @param event - The object to validate\n * @returns True if the object is a valid ParsEvent\n */\nexport function validateEvent(event: unknown): event is ParsEvent {\n if (!event || typeof event !== \"object\") {\n return false;\n }\n\n const e = event as Record<string, unknown>;\n\n // Required fields\n if (e[\"specversion\"] !== \"1.0\") return false;\n if (typeof e[\"type\"] !== \"string\" || (e[\"type\"] as string).length === 0) return false;\n if (typeof e[\"source\"] !== \"string\" || (e[\"source\"] as string).length === 0) return false;\n if (typeof e[\"id\"] !== \"string\" || (e[\"id\"] as string).length === 0) return false;\n if (typeof e[\"time\"] !== \"string\") return false;\n\n return true;\n}\n\n/**\n * Validate that an object conforms to compact event structure.\n *\n * @param event - The object to validate\n * @returns True if the object is a valid CompactEvent\n */\nexport function validateCompactEvent(event: unknown): event is CompactEvent {\n if (!event || typeof event !== \"object\") {\n return false;\n }\n\n const e = event as Record<string, unknown>;\n\n if (typeof e[\"e\"] !== \"string\" || (e[\"e\"] as string).length === 0) return false;\n if (typeof e[\"s\"] !== \"string\" || (e[\"s\"] as string).length === 0) return false;\n if (typeof e[\"i\"] !== \"string\" || (e[\"i\"] as string).length === 0) return false;\n if (typeof e[\"t\"] !== \"number\") return false;\n\n return true;\n}\n","/**\n * @parsrun/service - Event Emitter\n * Service-level event emission\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger } from \"@parsrun/core\";\nimport type {\n EventTransport,\n TraceContext,\n ServiceDefinition,\n} from \"../types.js\";\nimport { createEvent, type CreateEventOptions } from \"./format.js\";\n\n// ============================================================================\n// EVENT EMITTER\n// ============================================================================\n\n/**\n * Options for creating an event emitter.\n */\nexport interface EventEmitterOptions {\n /** Service name (source) */\n service: string;\n /** Service definition (for validation) */\n definition?: ServiceDefinition;\n /** Event transport */\n transport: EventTransport;\n /** Logger */\n logger?: Logger;\n /** Default tenant ID */\n defaultTenantId?: string;\n /** Validate events against definition */\n validateEvents?: boolean;\n}\n\n/**\n * Event emitter for service events\n */\nexport class EventEmitter {\n private readonly service: string;\n private readonly definition?: ServiceDefinition;\n private readonly transport: EventTransport;\n private readonly logger: Logger;\n private readonly defaultTenantId?: string;\n private readonly validateEvents: boolean;\n\n constructor(options: EventEmitterOptions) {\n this.service = options.service;\n if (options.definition) {\n this.definition = options.definition;\n }\n this.transport = options.transport;\n this.logger = options.logger ?? createLogger({ name: `events:${options.service}` });\n if (options.defaultTenantId) {\n this.defaultTenantId = options.defaultTenantId;\n }\n this.validateEvents = options.validateEvents ?? true;\n }\n\n /**\n * Emit an event\n */\n async emit<T = unknown>(\n type: string,\n data: T,\n options?: EmitOptions\n ): Promise<string> {\n // Validate event type if definition provided\n if (this.validateEvents && this.definition?.events?.emits) {\n const emits = this.definition.events.emits;\n if (!(type in emits)) {\n this.logger.warn(`Event type not declared in service definition: ${type}`);\n }\n }\n\n // Get delivery guarantee from definition\n let delivery: \"at-most-once\" | \"at-least-once\" | undefined;\n if (this.definition?.events?.emits?.[type]) {\n delivery = this.definition.events.emits[type].delivery;\n }\n\n // Create event options\n const eventOptions: CreateEventOptions<T> = {\n type,\n source: this.service,\n data,\n };\n\n if (options?.eventId) eventOptions.id = options.eventId;\n if (options?.subject) eventOptions.subject = options.subject;\n\n const tenantId = options?.tenantId ?? this.defaultTenantId;\n if (tenantId) eventOptions.tenantId = tenantId;\n\n if (options?.requestId) eventOptions.requestId = options.requestId;\n if (options?.traceContext) eventOptions.traceContext = options.traceContext;\n\n const eventDelivery = options?.delivery ?? delivery;\n if (eventDelivery) eventOptions.delivery = eventDelivery;\n\n // Create event\n const event = createEvent(eventOptions);\n\n // Emit via transport\n try {\n await this.transport.emit(event);\n this.logger.debug(`Event emitted: ${type}`, {\n eventId: event.id,\n tenantId: event.parstenantid,\n });\n return event.id;\n } catch (error) {\n this.logger.error(`Failed to emit event: ${type}`, error as Error, {\n eventId: event.id,\n });\n throw error;\n }\n }\n\n /**\n * Emit multiple events\n */\n async emitBatch<T = unknown>(\n events: Array<{ type: string; data: T; options?: EmitOptions }>\n ): Promise<string[]> {\n const results: string[] = [];\n\n for (const { type, data, options } of events) {\n const eventId = await this.emit(type, data, options);\n results.push(eventId);\n }\n\n return results;\n }\n\n /**\n * Create a scoped emitter with preset options\n */\n scoped(options: Partial<EmitOptions>): ScopedEmitter {\n return new ScopedEmitter(this, options);\n }\n\n /**\n * Get service name\n */\n get serviceName(): string {\n return this.service;\n }\n}\n\n/**\n * Emit options\n */\nexport interface EmitOptions {\n /** Custom event ID */\n eventId?: string;\n /** Event subject */\n subject?: string;\n /** Tenant ID */\n tenantId?: string;\n /** Request ID for correlation */\n requestId?: string;\n /** Trace context */\n traceContext?: TraceContext;\n /** Override delivery guarantee */\n delivery?: \"at-most-once\" | \"at-least-once\";\n}\n\n/**\n * Scoped emitter with preset options\n */\nexport class ScopedEmitter {\n private readonly emitter: EventEmitter;\n private readonly defaultOptions: Partial<EmitOptions>;\n\n constructor(emitter: EventEmitter, defaultOptions: Partial<EmitOptions>) {\n this.emitter = emitter;\n this.defaultOptions = defaultOptions;\n }\n\n async emit<T = unknown>(\n type: string,\n data: T,\n options?: EmitOptions\n ): Promise<string> {\n return this.emitter.emit(type, data, {\n ...this.defaultOptions,\n ...options,\n });\n }\n}\n\n/**\n * Create an event emitter for publishing service events.\n *\n * @param options - Emitter configuration options\n * @returns A new event emitter instance\n *\n * @example\n * ```typescript\n * const emitter = createEventEmitter({\n * service: 'payments',\n * transport: memoryTransport,\n * });\n * await emitter.emit('subscription.created', { customerId: '123' });\n * ```\n */\nexport function createEventEmitter(options: EventEmitterOptions): EventEmitter {\n return new EventEmitter(options);\n}\n\n// ============================================================================\n// TYPED EVENT EMITTER\n// ============================================================================\n\n/**\n * Create a typed event emitter from service definition\n * Provides type-safe event emission\n */\nexport function createTypedEmitter<TDef extends ServiceDefinition>(\n definition: TDef,\n options: Omit<EventEmitterOptions, \"service\" | \"definition\">\n): TypedEventEmitter<TDef> {\n const emitter = new EventEmitter({\n ...options,\n service: definition.name,\n definition,\n });\n\n return emitter as TypedEventEmitter<TDef>;\n}\n\n/**\n * Typed event emitter type\n * Provides type-safe event emission with specific event types\n */\nexport type TypedEventEmitter<TDef extends ServiceDefinition> = EventEmitter & {\n emit<K extends keyof NonNullable<TDef[\"events\"]>[\"emits\"]>(\n type: K,\n data: NonNullable<TDef[\"events\"]>[\"emits\"][K] extends { data?: infer D } ? D : unknown,\n options?: EmitOptions\n ): Promise<string>;\n};\n","/**\n * @parsrun/service - Event Handler\n * Event handler registration and execution\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger } from \"@parsrun/core\";\nimport type {\n ParsEvent,\n EventHandler,\n EventHandlerContext,\n EventHandlerOptions,\n Unsubscribe,\n} from \"../types.js\";\nimport { matchEventType } from \"./format.js\";\nimport type { DeadLetterQueue } from \"./dead-letter.js\";\n\n// ============================================================================\n// EVENT HANDLER REGISTRY\n// ============================================================================\n\n/**\n * Resolved handler options with required fields\n */\nexport interface ResolvedHandlerOptions {\n retries: number;\n backoff: \"linear\" | \"exponential\";\n maxDelay: number;\n onExhausted: \"alert\" | \"log\" | \"discard\";\n deadLetter?: string;\n}\n\n/**\n * Registration entry for an event handler.\n */\nexport interface HandlerRegistration {\n /** Event type pattern (supports wildcards) */\n pattern: string;\n /** Handler function */\n handler: EventHandler;\n /** Handler options */\n options: ResolvedHandlerOptions;\n}\n\n/**\n * Options for creating an event handler registry.\n */\nexport interface EventHandlerRegistryOptions {\n /** Logger */\n logger?: Logger;\n /** Dead letter queue */\n deadLetterQueue?: DeadLetterQueue;\n /** Default handler options */\n defaultOptions?: Partial<EventHandlerOptions>;\n}\n\n/**\n * Registry for event handlers\n */\nexport class EventHandlerRegistry {\n private readonly handlers: Map<string, HandlerRegistration[]> = new Map();\n private readonly logger: Logger;\n private readonly deadLetterQueue?: DeadLetterQueue;\n private readonly defaultOptions: ResolvedHandlerOptions;\n\n constructor(options: EventHandlerRegistryOptions = {}) {\n this.logger = options.logger ?? createLogger({ name: \"event-handler\" });\n if (options.deadLetterQueue) {\n this.deadLetterQueue = options.deadLetterQueue;\n }\n const defaultOpts: ResolvedHandlerOptions = {\n retries: options.defaultOptions?.retries ?? 3,\n backoff: options.defaultOptions?.backoff ?? \"exponential\",\n maxDelay: options.defaultOptions?.maxDelay ?? 30_000,\n onExhausted: options.defaultOptions?.onExhausted ?? \"log\",\n };\n if (options.defaultOptions?.deadLetter) {\n defaultOpts.deadLetter = options.defaultOptions.deadLetter;\n }\n this.defaultOptions = defaultOpts;\n }\n\n /**\n * Register an event handler\n */\n register(\n pattern: string,\n handler: EventHandler,\n options?: EventHandlerOptions\n ): Unsubscribe {\n const registration: HandlerRegistration = {\n pattern,\n handler,\n options: {\n ...this.defaultOptions,\n ...options,\n },\n };\n\n const handlers = this.handlers.get(pattern) ?? [];\n handlers.push(registration);\n this.handlers.set(pattern, handlers);\n\n this.logger.debug(`Handler registered for pattern: ${pattern}`);\n\n // Return unsubscribe function\n return () => {\n const currentHandlers = this.handlers.get(pattern);\n if (currentHandlers) {\n const index = currentHandlers.indexOf(registration);\n if (index !== -1) {\n currentHandlers.splice(index, 1);\n if (currentHandlers.length === 0) {\n this.handlers.delete(pattern);\n }\n this.logger.debug(`Handler unregistered for pattern: ${pattern}`);\n }\n }\n };\n }\n\n /**\n * Handle an event\n */\n async handle(event: ParsEvent): Promise<void> {\n const matchingHandlers = this.getMatchingHandlers(event.type);\n\n if (matchingHandlers.length === 0) {\n this.logger.debug(`No handlers for event type: ${event.type}`, {\n eventId: event.id,\n });\n return;\n }\n\n this.logger.debug(`Handling event: ${event.type}`, {\n eventId: event.id,\n handlerCount: matchingHandlers.length,\n });\n\n // Execute handlers in parallel\n const results = await Promise.allSettled(\n matchingHandlers.map((reg) => this.executeHandler(event, reg))\n );\n\n // Log failures\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n if (result?.status === \"rejected\") {\n this.logger.error(\n `Handler failed for ${event.type}`,\n result.reason as Error,\n { eventId: event.id, pattern: matchingHandlers[i]?.pattern }\n );\n }\n }\n }\n\n /**\n * Execute a single handler with retry logic\n */\n private async executeHandler(\n event: ParsEvent,\n registration: HandlerRegistration\n ): Promise<void> {\n const { handler, options } = registration;\n const maxAttempts = options.retries + 1;\n let lastError: Error | undefined;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const context: EventHandlerContext = {\n logger: this.logger.child({\n eventId: event.id,\n pattern: registration.pattern,\n attempt,\n }),\n attempt,\n maxAttempts,\n isRetry: attempt > 1,\n };\n\n // Add trace context if available\n if (event.parstracecontext) {\n const traceCtx = parseTraceContext(event.parstracecontext);\n if (traceCtx) {\n context.traceContext = traceCtx;\n }\n }\n\n await handler(event, context);\n return; // Success\n } catch (error) {\n lastError = error as Error;\n\n if (attempt < maxAttempts) {\n const delay = this.calculateBackoff(attempt, options);\n this.logger.warn(\n `Handler failed, retrying in ${delay}ms`,\n { eventId: event.id, attempt, maxAttempts }\n );\n await sleep(delay);\n }\n }\n }\n\n // All retries exhausted\n await this.handleExhausted(event, registration, lastError!);\n }\n\n /**\n * Calculate backoff delay\n */\n private calculateBackoff(\n attempt: number,\n options: ResolvedHandlerOptions\n ): number {\n const baseDelay = 100;\n\n if (options.backoff === \"exponential\") {\n return Math.min(baseDelay * Math.pow(2, attempt - 1), options.maxDelay);\n }\n\n // Linear\n return Math.min(baseDelay * attempt, options.maxDelay);\n }\n\n /**\n * Handle exhausted retries\n */\n private async handleExhausted(\n event: ParsEvent,\n registration: HandlerRegistration,\n error: Error\n ): Promise<void> {\n const { options } = registration;\n\n // Send to dead letter queue\n if (options.deadLetter && this.deadLetterQueue) {\n await this.deadLetterQueue.add({\n event,\n error: error.message,\n pattern: registration.pattern,\n attempts: options.retries + 1,\n });\n }\n\n // Handle based on onExhausted option\n switch (options.onExhausted) {\n case \"alert\":\n this.logger.error(\n `[ALERT] Event handler exhausted all retries`,\n error,\n {\n eventId: event.id,\n eventType: event.type,\n pattern: registration.pattern,\n }\n );\n break;\n case \"discard\":\n this.logger.debug(`Event discarded after exhausted retries`, {\n eventId: event.id,\n });\n break;\n case \"log\":\n default:\n this.logger.warn(`Event handler exhausted all retries`, {\n eventId: event.id,\n error: error.message,\n });\n }\n }\n\n /**\n * Get handlers matching an event type\n */\n private getMatchingHandlers(eventType: string): HandlerRegistration[] {\n const matching: HandlerRegistration[] = [];\n\n for (const [pattern, handlers] of this.handlers) {\n if (matchEventType(eventType, pattern)) {\n matching.push(...handlers);\n }\n }\n\n return matching;\n }\n\n /**\n * Get all registered patterns\n */\n getPatterns(): string[] {\n return Array.from(this.handlers.keys());\n }\n\n /**\n * Check if a pattern has handlers\n */\n hasHandlers(pattern: string): boolean {\n return this.handlers.has(pattern);\n }\n\n /**\n * Clear all handlers\n */\n clear(): void {\n this.handlers.clear();\n }\n}\n\n/**\n * Create an event handler registry for managing event subscriptions.\n *\n * @param options - Registry configuration options\n * @returns A new event handler registry instance\n *\n * @example\n * ```typescript\n * const registry = createEventHandlerRegistry({\n * deadLetterQueue: dlq,\n * defaultOptions: { retries: 3 },\n * });\n * registry.register('subscription.*', async (event, ctx) => {\n * console.log('Received event:', event.type);\n * });\n * ```\n */\nexport function createEventHandlerRegistry(\n options?: EventHandlerRegistryOptions\n): EventHandlerRegistry {\n return new EventHandlerRegistry(options);\n}\n\n// ============================================================================\n// HELPERS\n// ============================================================================\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction parseTraceContext(traceparent: string): {\n traceId: string;\n spanId: string;\n traceFlags: number;\n} | undefined {\n const parts = traceparent.split(\"-\");\n if (parts.length !== 4) return undefined;\n\n const [, traceId, spanId, flags] = parts;\n if (!traceId || !spanId || !flags) return undefined;\n\n return {\n traceId,\n spanId,\n traceFlags: parseInt(flags, 16),\n };\n}\n","/**\n * @parsrun/service - Memory Event Transport\n * In-memory event transport for embedded mode and testing\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger } from \"@parsrun/core\";\nimport type {\n ParsEvent,\n EventTransport,\n EventHandler,\n EventHandlerOptions,\n Unsubscribe,\n} from \"../../types.js\";\nimport { EventHandlerRegistry, type EventHandlerRegistryOptions } from \"../handler.js\";\n\n// ============================================================================\n// MEMORY EVENT TRANSPORT\n// ============================================================================\n\n/**\n * Options for creating a memory event transport.\n */\nexport interface MemoryEventTransportOptions {\n /** Logger */\n logger?: Logger;\n /** Process events synchronously (default: false) */\n sync?: boolean;\n /** Default handler options */\n defaultHandlerOptions?: EventHandlerOptions;\n}\n\n/**\n * In-memory event transport\n * Events are processed immediately without persistence\n */\nexport class MemoryEventTransport implements EventTransport {\n readonly name = \"memory\";\n private readonly registry: EventHandlerRegistry;\n private readonly logger: Logger;\n private readonly sync: boolean;\n private readonly pendingEvents: ParsEvent[] = [];\n private processing = false;\n\n constructor(options: MemoryEventTransportOptions = {}) {\n this.logger = options.logger ?? createLogger({ name: \"memory-transport\" });\n this.sync = options.sync ?? false;\n\n const registryOptions: EventHandlerRegistryOptions = {\n logger: this.logger,\n };\n if (options.defaultHandlerOptions) {\n registryOptions.defaultOptions = options.defaultHandlerOptions;\n }\n this.registry = new EventHandlerRegistry(registryOptions);\n }\n\n /**\n * Emit an event\n */\n async emit<T>(event: ParsEvent<T>): Promise<void> {\n this.logger.debug(`Event emitted: ${event.type}`, {\n eventId: event.id,\n tenantId: event.parstenantid,\n });\n\n if (this.sync) {\n // Process synchronously\n await this.registry.handle(event);\n } else {\n // Queue for async processing\n this.pendingEvents.push(event);\n this.processQueue();\n }\n }\n\n /**\n * Subscribe to events\n */\n subscribe(\n eventType: string,\n handler: EventHandler,\n options?: EventHandlerOptions\n ): Unsubscribe {\n return this.registry.register(eventType, handler, options);\n }\n\n /**\n * Process pending events asynchronously\n */\n private async processQueue(): Promise<void> {\n if (this.processing) return;\n this.processing = true;\n\n try {\n while (this.pendingEvents.length > 0) {\n const event = this.pendingEvents.shift();\n if (event) {\n await this.registry.handle(event);\n }\n }\n } finally {\n this.processing = false;\n }\n }\n\n /**\n * Wait for all pending events to be processed\n */\n async flush(): Promise<void> {\n while (this.pendingEvents.length > 0 || this.processing) {\n await new Promise((resolve) => setTimeout(resolve, 10));\n }\n }\n\n /**\n * Get pending event count\n */\n get pendingCount(): number {\n return this.pendingEvents.length;\n }\n\n /**\n * Get registered patterns\n */\n getPatterns(): string[] {\n return this.registry.getPatterns();\n }\n\n /**\n * Clear all subscriptions\n */\n clear(): void {\n this.registry.clear();\n this.pendingEvents.length = 0;\n }\n\n /**\n * Close the transport\n */\n async close(): Promise<void> {\n await this.flush();\n this.clear();\n }\n}\n\n/**\n * Create a memory event transport for in-process event handling.\n * Suitable for testing and embedded mode.\n *\n * @param options - Transport configuration options\n * @returns A new memory event transport instance\n *\n * @example\n * ```typescript\n * const transport = createMemoryEventTransport({ sync: true });\n * transport.subscribe('user.created', async (event) => {\n * console.log('User created:', event.data);\n * });\n * await transport.emit({ type: 'user.created', data: { id: '123' } });\n * ```\n */\nexport function createMemoryEventTransport(\n options?: MemoryEventTransportOptions\n): MemoryEventTransport {\n return new MemoryEventTransport(options);\n}\n\n// ============================================================================\n// GLOBAL EVENT BUS (for embedded multi-service)\n// ============================================================================\n\n/**\n * Global event bus for communication between embedded services\n */\nexport class GlobalEventBus {\n private static instance: GlobalEventBus | null = null;\n private readonly transports: Map<string, MemoryEventTransport> = new Map();\n private readonly logger: Logger;\n\n private constructor() {\n this.logger = createLogger({ name: \"global-event-bus\" });\n }\n\n static getInstance(): GlobalEventBus {\n if (!GlobalEventBus.instance) {\n GlobalEventBus.instance = new GlobalEventBus();\n }\n return GlobalEventBus.instance;\n }\n\n /**\n * Register a service's event transport\n */\n register(serviceName: string, transport: MemoryEventTransport): void {\n if (this.transports.has(serviceName)) {\n throw new Error(`Service already registered: ${serviceName}`);\n }\n this.transports.set(serviceName, transport);\n this.logger.debug(`Service registered: ${serviceName}`);\n }\n\n /**\n * Unregister a service\n */\n unregister(serviceName: string): boolean {\n const deleted = this.transports.delete(serviceName);\n if (deleted) {\n this.logger.debug(`Service unregistered: ${serviceName}`);\n }\n return deleted;\n }\n\n /**\n * Broadcast an event to all services (except source)\n */\n async broadcast(event: ParsEvent, excludeSource?: string): Promise<void> {\n const promises: Promise<void>[] = [];\n\n for (const [name, transport] of this.transports) {\n if (name !== excludeSource) {\n promises.push(transport.emit(event));\n }\n }\n\n await Promise.allSettled(promises);\n }\n\n /**\n * Send an event to a specific service\n */\n async send(serviceName: string, event: ParsEvent): Promise<void> {\n const transport = this.transports.get(serviceName);\n if (!transport) {\n this.logger.warn(`Target service not found: ${serviceName}`, {\n eventId: event.id,\n });\n return;\n }\n\n await transport.emit(event);\n }\n\n /**\n * Get all registered service names\n */\n getServices(): string[] {\n return Array.from(this.transports.keys());\n }\n\n /**\n * Clear all registrations\n */\n clear(): void {\n this.transports.clear();\n }\n\n /**\n * Reset singleton (for testing)\n */\n static reset(): void {\n GlobalEventBus.instance = null;\n }\n}\n\n/**\n * Get the global event bus singleton.\n * Provides a shared event bus for communication between embedded services.\n *\n * @returns The global event bus instance\n *\n * @example\n * ```typescript\n * const bus = getGlobalEventBus();\n * bus.register('payments', paymentsTransport);\n * await bus.broadcast(event, 'payments'); // Exclude payments\n * ```\n */\nexport function getGlobalEventBus(): GlobalEventBus {\n return GlobalEventBus.getInstance();\n}\n","/**\n * @parsrun/service - Dead Letter Queue\n * Storage for failed events\n */\n\nimport type { Logger } from \"@parsrun/core\";\nimport { createLogger, generateId } from \"@parsrun/core\";\nimport type { ParsEvent } from \"../types.js\";\n\n// ============================================================================\n// DEAD LETTER QUEUE\n// ============================================================================\n\n/**\n * Entry stored in the dead letter queue.\n * Contains the failed event and metadata about the failure.\n */\nexport interface DeadLetterEntry {\n /** Unique ID */\n id: string;\n /** Original event */\n event: ParsEvent;\n /** Error message */\n error: string;\n /** Handler pattern that failed */\n pattern: string;\n /** Number of attempts made */\n attempts: number;\n /** Timestamp when added */\n addedAt: Date;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Options for creating a dead letter queue.\n */\nexport interface DeadLetterQueueOptions {\n /** Maximum entries to keep */\n maxSize?: number;\n /** Retention period in ms */\n retentionMs?: number;\n /** Callback when entry is added */\n onAdd?: (entry: DeadLetterEntry) => void;\n /** Callback when threshold is reached */\n onThreshold?: (count: number) => void;\n /** Alert threshold */\n alertThreshold?: number;\n /** Logger */\n logger?: Logger;\n}\n\n/**\n * Options for adding an entry to the dead letter queue.\n */\nexport interface AddEntryOptions {\n /** Original event */\n event: ParsEvent;\n /** Error message */\n error: string;\n /** Handler pattern */\n pattern: string;\n /** Number of attempts */\n attempts: number;\n /** Optional metadata */\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Resolved DLQ options\n */\ninterface ResolvedDlqOptions {\n maxSize: number;\n retentionMs: number;\n alertThreshold: number;\n onAdd?: (entry: DeadLetterEntry) => void;\n onThreshold?: (count: number) => void;\n logger?: Logger;\n}\n\n/**\n * In-memory Dead Letter Queue\n */\nexport class DeadLetterQueue {\n private readonly entries: Map<string, DeadLetterEntry> = new Map();\n private readonly resolvedOptions: ResolvedDlqOptions;\n private readonly logger: Logger;\n private cleanupTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(options: DeadLetterQueueOptions = {}) {\n this.resolvedOptions = {\n maxSize: options.maxSize ?? 1000,\n retentionMs: options.retentionMs ?? 30 * 24 * 60 * 60 * 1000, // 30 days\n alertThreshold: options.alertThreshold ?? 10,\n };\n\n if (options.onAdd) this.resolvedOptions.onAdd = options.onAdd;\n if (options.onThreshold) this.resolvedOptions.onThreshold = options.onThreshold;\n if (options.logger) this.resolvedOptions.logger = options.logger;\n\n this.logger = options.logger ?? createLogger({ name: \"dlq\" });\n\n // Start cleanup timer\n this.cleanupTimer = setInterval(() => this.cleanup(), 60 * 60 * 1000); // Every hour\n }\n\n /**\n * Add an entry to the DLQ\n */\n async add(options: AddEntryOptions): Promise<string> {\n const entry: DeadLetterEntry = {\n id: generateId(),\n event: options.event,\n error: options.error,\n pattern: options.pattern,\n attempts: options.attempts,\n addedAt: new Date(),\n };\n\n if (options.metadata) {\n entry.metadata = options.metadata;\n }\n\n // Check max size\n if (this.entries.size >= this.resolvedOptions.maxSize) {\n // Remove oldest entry\n const oldest = this.getOldest();\n if (oldest) {\n this.entries.delete(oldest.id);\n this.logger.debug(`DLQ: Removed oldest entry to make room`, {\n removedId: oldest.id,\n });\n }\n }\n\n this.entries.set(entry.id, entry);\n\n this.logger.warn(`DLQ: Entry added`, {\n id: entry.id,\n eventId: entry.event.id,\n eventType: entry.event.type,\n error: entry.error,\n });\n\n // Callbacks\n this.resolvedOptions.onAdd?.(entry);\n\n // Check threshold\n if (this.entries.size >= this.resolvedOptions.alertThreshold) {\n this.resolvedOptions.onThreshold?.(this.entries.size);\n }\n\n return entry.id;\n }\n\n /**\n * Get an entry by ID\n */\n get(id: string): DeadLetterEntry | undefined {\n return this.entries.get(id);\n }\n\n /**\n * Get all entries\n */\n getAll(): DeadLetterEntry[] {\n return Array.from(this.entries.values());\n }\n\n /**\n * Get entries by event type\n */\n getByEventType(eventType: string): DeadLetterEntry[] {\n return Array.from(this.entries.values()).filter(\n (e) => e.event.type === eventType\n );\n }\n\n /**\n * Get entries by pattern\n */\n getByPattern(pattern: string): DeadLetterEntry[] {\n return Array.from(this.entries.values()).filter(\n (e) => e.pattern === pattern\n );\n }\n\n /**\n * Remove an entry\n */\n remove(id: string): boolean {\n const deleted = this.entries.delete(id);\n if (deleted) {\n this.logger.debug(`DLQ: Entry removed`, { id });\n }\n return deleted;\n }\n\n /**\n * Retry an entry (remove from DLQ and return event)\n */\n retry(id: string): ParsEvent | undefined {\n const entry = this.entries.get(id);\n if (!entry) return undefined;\n\n this.entries.delete(id);\n this.logger.info(`DLQ: Entry removed for retry`, {\n id,\n eventId: entry.event.id,\n });\n\n return entry.event;\n }\n\n /**\n * Get count\n */\n get size(): number {\n return this.entries.size;\n }\n\n /**\n * Clear all entries\n */\n clear(): void {\n this.entries.clear();\n this.logger.info(`DLQ: Cleared all entries`);\n }\n\n /**\n * Cleanup expired entries\n */\n private cleanup(): void {\n const now = Date.now();\n let removed = 0;\n\n for (const [id, entry] of this.entries) {\n const age = now - entry.addedAt.getTime();\n if (age > this.resolvedOptions.retentionMs) {\n this.entries.delete(id);\n removed++;\n }\n }\n\n if (removed > 0) {\n this.logger.debug(`DLQ: Cleaned up ${removed} expired entries`);\n }\n }\n\n /**\n * Get oldest entry\n */\n private getOldest(): DeadLetterEntry | undefined {\n let oldest: DeadLetterEntry | undefined;\n\n for (const entry of this.entries.values()) {\n if (!oldest || entry.addedAt < oldest.addedAt) {\n oldest = entry;\n }\n }\n\n return oldest;\n }\n\n /**\n * Stop cleanup timer\n */\n close(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = null;\n }\n }\n\n /**\n * Export entries for persistence\n */\n export(): DeadLetterEntry[] {\n return Array.from(this.entries.values()).map((e) => ({\n ...e,\n addedAt: e.addedAt,\n }));\n }\n\n /**\n * Import entries from persistence\n */\n import(entries: DeadLetterEntry[]): void {\n for (const entry of entries) {\n this.entries.set(entry.id, {\n ...entry,\n addedAt: new Date(entry.addedAt),\n });\n }\n this.logger.info(`DLQ: Imported ${entries.length} entries`);\n }\n}\n\n/**\n * Create a dead letter queue for storing failed events.\n *\n * @param options - DLQ configuration options\n * @returns A new dead letter queue instance\n *\n * @example\n * ```typescript\n * const dlq = createDeadLetterQueue({\n * maxSize: 1000,\n * alertThreshold: 50,\n * onThreshold: (count) => alert(`DLQ has ${count} entries`),\n * });\n * ```\n */\nexport function createDeadLetterQueue(\n options?: DeadLetterQueueOptions\n): DeadLetterQueue {\n return new DeadLetterQueue(options);\n}\n"],"mappings":"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","names":["createLogger","createLogger","createLogger","createLogger","createLogger","generateId"]}
|