@holo-js/events 0.3.28 → 0.4.1
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/LICENSE +21 -0
- package/dist/.holo-build-fingerprint +1 -0
- package/dist/index.d.ts +18 -25
- package/dist/index.mjs +100 -120
- package/package.json +16 -10
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Holo-JS contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3fc9dd4981443d3306e60b3ff6271a7d1d56721340f20c03d22c91df21ae7fe9
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { QueueJobDefinition, QueueJsonValue, QueueRegisteredJob } from '@holo-js/queue';
|
|
1
|
+
import { QueueJobDefinition, QueueJsonValue, QueueRegisteredJob, QueueJobContext } from '@holo-js/queue';
|
|
2
2
|
|
|
3
3
|
type EventDelayValue = number | Date;
|
|
4
4
|
type EventDefinitionDispatcher = <TPayload>(event: EventDefinition<TPayload, string | undefined>, payload: TPayload) => EventPendingDispatch<TPayload>;
|
|
@@ -50,6 +50,8 @@ interface ListenerDefinition<TInput extends EventReferenceInput = EventReference
|
|
|
50
50
|
readonly queueName?: string;
|
|
51
51
|
readonly delay?: EventDelayValue;
|
|
52
52
|
readonly afterCommit?: boolean;
|
|
53
|
+
readonly tries?: number;
|
|
54
|
+
readonly backoff?: number | readonly number[];
|
|
53
55
|
handle(event: ListenerHandledEvent<TInput>): TResult | Promise<TResult>;
|
|
54
56
|
}
|
|
55
57
|
type ListenerDefinitionInput<TInput extends EventReferenceInput = EventReferenceInput, TResult = unknown> = Omit<ListenerDefinition<TInput, TResult>, 'listensTo'> & {
|
|
@@ -94,6 +96,7 @@ interface EventQueuedListenerDispatch {
|
|
|
94
96
|
readonly connection?: string;
|
|
95
97
|
readonly queueName?: string;
|
|
96
98
|
readonly delay?: EventDelayValue;
|
|
99
|
+
readonly tries?: number;
|
|
97
100
|
}
|
|
98
101
|
interface EventDeferredDispatchContext {
|
|
99
102
|
readonly eventName: string;
|
|
@@ -196,7 +199,9 @@ declare module '@holo-js/queue' {
|
|
|
196
199
|
}
|
|
197
200
|
type QueueModule = {
|
|
198
201
|
defineJob(definition: QueueJobDefinition<EventsInvokeListenerPayload, void>): QueueJobDefinition<EventsInvokeListenerPayload, void>;
|
|
199
|
-
dispatch(jobName: string, payload: EventsInvokeListenerPayload
|
|
202
|
+
dispatch(jobName: string, payload: EventsInvokeListenerPayload, options?: {
|
|
203
|
+
readonly tries?: number;
|
|
204
|
+
}): QueuePendingDispatchChain;
|
|
200
205
|
getRegisteredQueueJob(name: string): QueueRegisteredJob | undefined;
|
|
201
206
|
registerQueueJob(definition: QueueJobDefinition<EventsInvokeListenerPayload, void>, options: {
|
|
202
207
|
name: string;
|
|
@@ -212,7 +217,7 @@ declare function loadQueueModule(): Promise<QueueModule>;
|
|
|
212
217
|
declare function createQueuedListenerEventEnvelope(payload: EventsInvokeListenerPayload): EventEnvelope<string, QueueJsonValue>;
|
|
213
218
|
declare function requireQueuedListener(listenerId: string): RegisteredListener;
|
|
214
219
|
declare function assertQueuedListenerMatchesEvent(listener: RegisteredListener, eventName: string): void;
|
|
215
|
-
declare function runQueuedListenerInvocation(payload: EventsInvokeListenerPayload): Promise<void>;
|
|
220
|
+
declare function runQueuedListenerInvocation(payload: EventsInvokeListenerPayload, context?: QueueJobContext): Promise<void>;
|
|
216
221
|
declare function ensureEventsQueueJobRegistered(): void;
|
|
217
222
|
declare function ensureEventsQueueJobRegisteredAsync(): Promise<void>;
|
|
218
223
|
declare const eventQueueInternals: {
|
|
@@ -234,12 +239,6 @@ type EventPayloadValidationState = {
|
|
|
234
239
|
type RuntimeState = {
|
|
235
240
|
hooks: EventRuntimeHooks;
|
|
236
241
|
};
|
|
237
|
-
type ListenerExecutionGroups = {
|
|
238
|
-
readonly immediateSyncListeners: readonly RegisteredListener[];
|
|
239
|
-
readonly immediateQueuedListeners: readonly RegisteredListener[];
|
|
240
|
-
readonly deferredSyncListeners: readonly RegisteredListener[];
|
|
241
|
-
readonly deferredQueuedListeners: readonly RegisteredListener[];
|
|
242
|
-
};
|
|
243
242
|
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
244
243
|
declare function assertEventJsonValue(value: unknown, path: string, state: EventPayloadValidationState): void;
|
|
245
244
|
declare function validateQueuedEventPayload<TPayload>(payload: TPayload): void;
|
|
@@ -249,19 +248,14 @@ declare function normalizeEventName(name: string): string;
|
|
|
249
248
|
declare function resolveDispatchedEventName<TPayload>(event: string | EventDefinition<TPayload, string | undefined>): string;
|
|
250
249
|
declare function requireRegisteredEvent(name: string): RegisteredEvent;
|
|
251
250
|
declare function createEventEnvelope<TPayload>(eventName: string, payload: TPayload, occurredAt?: number): EventEnvelope<string, TPayload>;
|
|
252
|
-
declare function
|
|
253
|
-
readonly
|
|
254
|
-
readonly
|
|
251
|
+
declare function splitListenersByCommitTiming(listeners: readonly RegisteredListener[], shouldDeferAll: boolean): {
|
|
252
|
+
readonly immediateListeners: readonly RegisteredListener[];
|
|
253
|
+
readonly deferredListeners: readonly RegisteredListener[];
|
|
255
254
|
};
|
|
256
|
-
declare function executeSyncListeners<TPayload>(listeners: readonly RegisteredListener[], event: EventEnvelope<string, TPayload>): Promise<number>;
|
|
257
|
-
declare function executeListenerGroups<TPayload>(syncListeners: readonly RegisteredListener[], queuedListeners: readonly RegisteredListener[], event: EventEnvelope<string, TPayload>, options: PendingOptions): Promise<{
|
|
258
|
-
readonly syncCount: number;
|
|
259
|
-
readonly queuedCount: number;
|
|
260
|
-
}>;
|
|
261
255
|
declare function executeListener<TPayload>(listener: RegisteredListener, event: EventEnvelope<string, TPayload>): Promise<void>;
|
|
262
256
|
declare function createQueuedListenerDispatch(listener: RegisteredListener, event: EventEnvelope, options: PendingOptions): EventQueuedListenerDispatch;
|
|
263
|
-
declare function
|
|
264
|
-
declare function
|
|
257
|
+
declare function dispatchQueuedListener<TPayload>(listener: RegisteredListener, event: EventEnvelope<string, TPayload>, options: PendingOptions): Promise<void>;
|
|
258
|
+
declare function runListenersInOrder<TPayload>(listeners: readonly RegisteredListener[], event: EventEnvelope<string, TPayload>, options: PendingOptions): Promise<void>;
|
|
265
259
|
declare function scheduleDeferredDispatch(callback: () => Promise<void>, eventName: string): boolean;
|
|
266
260
|
declare function executeDispatch<TPayload>(event: string | EventDefinition<TPayload, string | undefined>, payload: TPayload, options?: PendingOptions): Promise<EventDispatchResult>;
|
|
267
261
|
declare function configureEventsRuntime(hooks?: EventRuntimeHooks): void;
|
|
@@ -276,20 +270,19 @@ declare const eventRuntimeInternals: {
|
|
|
276
270
|
createEventEnvelope: typeof createEventEnvelope;
|
|
277
271
|
createQueuedListenerDispatch: typeof createQueuedListenerDispatch;
|
|
278
272
|
createRuntimeBinding: typeof createRuntimeBinding;
|
|
279
|
-
|
|
280
|
-
executeListenerGroups: typeof executeListenerGroups;
|
|
273
|
+
dispatchQueuedListener: typeof dispatchQueuedListener;
|
|
281
274
|
executeDispatch: typeof executeDispatch;
|
|
282
275
|
executeListener: typeof executeListener;
|
|
283
|
-
|
|
276
|
+
runListenersInOrder: typeof runListenersInOrder;
|
|
284
277
|
getRuntimeState: typeof getRuntimeState;
|
|
285
278
|
isPlainObject: typeof isPlainObject;
|
|
286
279
|
normalizeEventName: typeof normalizeEventName;
|
|
287
280
|
requireRegisteredEvent: typeof requireRegisteredEvent;
|
|
288
281
|
resolveDispatchedEventName: typeof resolveDispatchedEventName;
|
|
289
282
|
scheduleDeferredDispatch: typeof scheduleDeferredDispatch;
|
|
290
|
-
|
|
291
|
-
splitListenersForExecution: typeof splitListenersForExecution;
|
|
283
|
+
splitListenersByCommitTiming: typeof splitListenersByCommitTiming;
|
|
292
284
|
validateQueuedEventPayload: typeof validateQueuedEventPayload;
|
|
293
285
|
};
|
|
294
286
|
|
|
295
|
-
export {
|
|
287
|
+
export { EVENTS_INVOKE_LISTENER_JOB, Event, configureEventsRuntime, deferEventDispatchToDatabaseCommit, defineEvent, defineListener, dispatchEvent, ensureEventsQueueJobRegistered, ensureEventsQueueJobRegisteredAsync, eventInternals, eventQueueInternals, eventRegistryInternals, eventRuntimeInternals, getEventsRuntime, getRegisteredEvent, getRegisteredListener, isEventDefinition, isListenerDefinition, listRegisteredEvents, listRegisteredListeners, listRegisteredListenersForEvent, normalizeEventDefinition, normalizeListenerDefinition, registerEvent, registerEvents, registerListener, registerListeners, resetEventRegistry, resetEventsRegistry, resetEventsRuntime, resetListenerRegistry, runQueuedListenerInvocation, unregisterEvent, unregisterListener };
|
|
288
|
+
export type { DefinedEventDefinition, EventDeferredDispatchContext, EventDefinition, EventDelayValue, EventDispatchResult, EventEnvelope, EventEnvelopeFor, EventFacade, EventPayloadFor, EventPendingDispatch, EventQueuedListenerDispatch, EventReference, EventReferenceInput, EventRuntimeBinding, EventRuntimeHooks, EventsInvokeListenerPayload, ExportedEventDefinition, HoloEventRegistry, HoloListenerRegistry, ListenerDefinition, ListenerDefinitionInput, ListenerHandledEvent, RegisterEventOptions, RegisterListenerOptions, RegisteredEvent, RegisteredListener };
|
package/dist/index.mjs
CHANGED
|
@@ -37,6 +37,30 @@ function normalizeOptionalBoolean(value, label) {
|
|
|
37
37
|
}
|
|
38
38
|
return value;
|
|
39
39
|
}
|
|
40
|
+
function normalizeOptionalTries(value) {
|
|
41
|
+
if (typeof value === "undefined") {
|
|
42
|
+
return void 0;
|
|
43
|
+
}
|
|
44
|
+
if (!Number.isInteger(value) || value < 1) {
|
|
45
|
+
throw new Error("[Holo Events] Listener tries must be an integer greater than or equal to 1.");
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
function normalizeOptionalBackoff(value) {
|
|
50
|
+
if (typeof value === "undefined") {
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
53
|
+
if (typeof value === "number") {
|
|
54
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
55
|
+
throw new Error("[Holo Events] Listener backoff must be an integer greater than or equal to 0 or a non-empty array of them.");
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((entry) => !Number.isInteger(entry) || entry < 0)) {
|
|
60
|
+
throw new Error("[Holo Events] Listener backoff must be an integer greater than or equal to 0 or a non-empty array of them.");
|
|
61
|
+
}
|
|
62
|
+
return Object.freeze([...value]);
|
|
63
|
+
}
|
|
40
64
|
function normalizeOptionalDelay(value) {
|
|
41
65
|
if (typeof value === "undefined") {
|
|
42
66
|
return void 0;
|
|
@@ -139,7 +163,9 @@ function normalizeListenerDefinition(listener) {
|
|
|
139
163
|
const queueName = normalizeOptionalString(listener.queueName, "Listener queue name");
|
|
140
164
|
const delay = normalizeOptionalDelay(listener.delay);
|
|
141
165
|
const afterCommit = normalizeOptionalBoolean(listener.afterCommit, "Listener afterCommit");
|
|
142
|
-
|
|
166
|
+
const tries = normalizeOptionalTries(listener.tries);
|
|
167
|
+
const backoff = normalizeOptionalBackoff(listener.backoff);
|
|
168
|
+
if (queue !== true && (connection || queueName || typeof delay !== "undefined" || typeof tries !== "undefined" || typeof backoff !== "undefined")) {
|
|
143
169
|
throw new Error("[Holo Events] Listener queue metadata requires queue: true.");
|
|
144
170
|
}
|
|
145
171
|
return {
|
|
@@ -150,7 +176,9 @@ function normalizeListenerDefinition(listener) {
|
|
|
150
176
|
...typeof connection === "undefined" ? {} : { connection },
|
|
151
177
|
...typeof queueName === "undefined" ? {} : { queueName },
|
|
152
178
|
...typeof delay === "undefined" ? {} : { delay },
|
|
153
|
-
...typeof afterCommit === "undefined" ? {} : { afterCommit }
|
|
179
|
+
...typeof afterCommit === "undefined" ? {} : { afterCommit },
|
|
180
|
+
...typeof tries === "undefined" ? {} : { tries },
|
|
181
|
+
...typeof backoff === "undefined" ? {} : { backoff }
|
|
154
182
|
};
|
|
155
183
|
}
|
|
156
184
|
function defineListener(listener) {
|
|
@@ -411,6 +439,7 @@ function deferEventDispatchToDatabaseCommit(callback, _context) {
|
|
|
411
439
|
|
|
412
440
|
// src/queue.ts
|
|
413
441
|
import { createRequire } from "module";
|
|
442
|
+
import { holoRuntimeInternals } from "@holo-js/db";
|
|
414
443
|
var EVENTS_INVOKE_LISTENER_JOB = "holo.events.invoke-listener";
|
|
415
444
|
var require2 = createRequire(import.meta.url);
|
|
416
445
|
var queueSpecifier = "@holo-js/queue";
|
|
@@ -455,10 +484,29 @@ function assertQueuedListenerMatchesEvent(listener, eventName) {
|
|
|
455
484
|
);
|
|
456
485
|
}
|
|
457
486
|
}
|
|
458
|
-
|
|
487
|
+
function resolveListenerRetryDelaySeconds(backoff, attempt) {
|
|
488
|
+
if (typeof backoff === "number") {
|
|
489
|
+
return backoff;
|
|
490
|
+
}
|
|
491
|
+
return backoff[Math.min(Math.max(attempt - 1, 0), backoff.length - 1)] ?? 0;
|
|
492
|
+
}
|
|
493
|
+
async function runQueuedListenerInvocation(payload, context) {
|
|
459
494
|
const listener = requireQueuedListener(payload.listenerId);
|
|
460
495
|
assertQueuedListenerMatchesEvent(listener, payload.eventName);
|
|
461
|
-
|
|
496
|
+
try {
|
|
497
|
+
await listener.definition.handle(createQueuedListenerEventEnvelope(payload));
|
|
498
|
+
} catch (error) {
|
|
499
|
+
const { backoff } = listener.definition;
|
|
500
|
+
if (!context || typeof backoff === "undefined" || context.attempt >= context.maxAttempts) {
|
|
501
|
+
throw error;
|
|
502
|
+
}
|
|
503
|
+
try {
|
|
504
|
+
await context.release(resolveListenerRetryDelaySeconds(backoff, context.attempt));
|
|
505
|
+
} catch (releaseError) {
|
|
506
|
+
holoRuntimeInternals.reportError(releaseError, { capability: "events", operation: "listener.releaseRetry" });
|
|
507
|
+
throw error;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
462
510
|
}
|
|
463
511
|
function registerEventsQueueJob(queue) {
|
|
464
512
|
if (queue.getRegisteredQueueJob(EVENTS_INVOKE_LISTENER_JOB)) {
|
|
@@ -482,7 +530,7 @@ async function dispatchQueuedListenerViaQueue(dispatch) {
|
|
|
482
530
|
eventName: dispatch.event.name,
|
|
483
531
|
occurredAt: dispatch.event.occurredAt,
|
|
484
532
|
payload: dispatch.event.payload
|
|
485
|
-
});
|
|
533
|
+
}, typeof dispatch.tries === "undefined" ? {} : { tries: dispatch.tries });
|
|
486
534
|
if (typeof dispatch.connection !== "undefined") {
|
|
487
535
|
pending = pending.onConnection(dispatch.connection);
|
|
488
536
|
}
|
|
@@ -599,33 +647,19 @@ function createEventEnvelope(eventName, payload, occurredAt = Date.now()) {
|
|
|
599
647
|
occurredAt
|
|
600
648
|
});
|
|
601
649
|
}
|
|
602
|
-
function
|
|
603
|
-
const
|
|
604
|
-
const
|
|
650
|
+
function splitListenersByCommitTiming(listeners, shouldDeferAll) {
|
|
651
|
+
const immediateListeners = [];
|
|
652
|
+
const deferredListeners = [];
|
|
605
653
|
for (const listener of listeners) {
|
|
606
|
-
if (listener.definition.
|
|
607
|
-
|
|
654
|
+
if (shouldDeferAll || listener.definition.afterCommit === true) {
|
|
655
|
+
deferredListeners.push(listener);
|
|
608
656
|
continue;
|
|
609
657
|
}
|
|
610
|
-
|
|
611
|
-
}
|
|
612
|
-
return Object.freeze({
|
|
613
|
-
syncListeners: Object.freeze(syncListeners),
|
|
614
|
-
queuedListeners: Object.freeze(queuedListeners)
|
|
615
|
-
});
|
|
616
|
-
}
|
|
617
|
-
async function executeSyncListeners(listeners, event) {
|
|
618
|
-
for (const listener of listeners) {
|
|
619
|
-
await executeListener(listener, event);
|
|
658
|
+
immediateListeners.push(listener);
|
|
620
659
|
}
|
|
621
|
-
return listeners.length;
|
|
622
|
-
}
|
|
623
|
-
async function executeListenerGroups(syncListeners, queuedListeners, event, options) {
|
|
624
|
-
const syncCount = await executeSyncListeners(syncListeners, event);
|
|
625
|
-
const queuedCount = await dispatchQueuedListeners(queuedListeners, event, options);
|
|
626
660
|
return Object.freeze({
|
|
627
|
-
|
|
628
|
-
|
|
661
|
+
immediateListeners: Object.freeze(immediateListeners),
|
|
662
|
+
deferredListeners: Object.freeze(deferredListeners)
|
|
629
663
|
});
|
|
630
664
|
}
|
|
631
665
|
async function executeListener(listener, event) {
|
|
@@ -637,53 +671,22 @@ function createQueuedListenerDispatch(listener, event, options) {
|
|
|
637
671
|
event,
|
|
638
672
|
...typeof (options.connection ?? listener.definition.connection) === "undefined" ? {} : { connection: options.connection ?? listener.definition.connection },
|
|
639
673
|
...typeof (options.queueName ?? listener.definition.queueName) === "undefined" ? {} : { queueName: options.queueName ?? listener.definition.queueName },
|
|
640
|
-
...typeof (options.delay ?? listener.definition.delay) === "undefined" ? {} : { delay: options.delay ?? listener.definition.delay }
|
|
674
|
+
...typeof (options.delay ?? listener.definition.delay) === "undefined" ? {} : { delay: options.delay ?? listener.definition.delay },
|
|
675
|
+
...typeof listener.definition.tries === "undefined" ? {} : { tries: listener.definition.tries }
|
|
641
676
|
});
|
|
642
677
|
}
|
|
643
|
-
async function
|
|
644
|
-
if (listeners.length === 0) {
|
|
645
|
-
return 0;
|
|
646
|
-
}
|
|
647
|
-
validateQueuedEventPayload(event.payload);
|
|
678
|
+
async function dispatchQueuedListener(listener, event, options) {
|
|
648
679
|
const dispatcher = getRuntimeState().hooks.dispatchQueuedListener ?? dispatchQueuedListenerViaQueue;
|
|
649
|
-
|
|
650
|
-
await dispatcher(createQueuedListenerDispatch(listener, event, options));
|
|
651
|
-
}
|
|
652
|
-
return listeners.length;
|
|
680
|
+
await dispatcher(createQueuedListenerDispatch(listener, event, options));
|
|
653
681
|
}
|
|
654
|
-
function
|
|
655
|
-
const immediateSyncListeners = [];
|
|
656
|
-
const immediateQueuedListeners = [];
|
|
657
|
-
const deferredSyncListeners = [];
|
|
658
|
-
const deferredQueuedListeners = [];
|
|
682
|
+
async function runListenersInOrder(listeners, event, options) {
|
|
659
683
|
for (const listener of listeners) {
|
|
660
|
-
const shouldDefer = forceAfterCommit || listener.definition.afterCommit === true;
|
|
661
|
-
if (shouldDefer) {
|
|
662
|
-
if (listener.definition.queue === true) {
|
|
663
|
-
deferredQueuedListeners.push(listener);
|
|
664
|
-
continue;
|
|
665
|
-
}
|
|
666
|
-
deferredSyncListeners.push(listener);
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
684
|
if (listener.definition.queue === true) {
|
|
670
|
-
|
|
685
|
+
await dispatchQueuedListener(listener, event, options);
|
|
671
686
|
continue;
|
|
672
687
|
}
|
|
673
|
-
|
|
674
|
-
}
|
|
675
|
-
return Object.freeze({
|
|
676
|
-
immediateSyncListeners: Object.freeze(immediateSyncListeners),
|
|
677
|
-
immediateQueuedListeners: Object.freeze(immediateQueuedListeners),
|
|
678
|
-
deferredSyncListeners: Object.freeze(deferredSyncListeners),
|
|
679
|
-
deferredQueuedListeners: Object.freeze(deferredQueuedListeners)
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
function validateQueuedPayloadForExecutionGroups(groups, payload) {
|
|
683
|
-
if (groups.immediateQueuedListeners.length === 0 && groups.deferredQueuedListeners.length === 0) {
|
|
684
|
-
return;
|
|
688
|
+
await executeListener(listener, event);
|
|
685
689
|
}
|
|
686
|
-
validateQueuedEventPayload(payload);
|
|
687
690
|
}
|
|
688
691
|
function scheduleDeferredDispatch(callback, eventName) {
|
|
689
692
|
const defer = getRuntimeState().hooks.defer ?? deferEventDispatchToDatabaseCommit;
|
|
@@ -697,61 +700,38 @@ async function executeDispatch(event, payload, options = {}) {
|
|
|
697
700
|
requireRegisteredEvent(eventName);
|
|
698
701
|
const envelope = createEventEnvelope(eventName, payload);
|
|
699
702
|
const listeners = listRegisteredListenersForEvent(eventName);
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
const scheduled = scheduleDeferredDispatch(async () => {
|
|
704
|
-
await executeListenerGroups(
|
|
705
|
-
[...groups.immediateSyncListeners, ...groups.deferredSyncListeners],
|
|
706
|
-
[...groups.immediateQueuedListeners, ...groups.deferredQueuedListeners],
|
|
707
|
-
envelope,
|
|
708
|
-
options
|
|
709
|
-
);
|
|
710
|
-
}, eventName);
|
|
711
|
-
if (scheduled) {
|
|
712
|
-
return Object.freeze({
|
|
713
|
-
eventName,
|
|
714
|
-
occurredAt: envelope.occurredAt,
|
|
715
|
-
deferred: true,
|
|
716
|
-
syncListeners: groups.immediateSyncListeners.length + groups.deferredSyncListeners.length,
|
|
717
|
-
queuedListeners: groups.immediateQueuedListeners.length + groups.deferredQueuedListeners.length
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
const immediate = await executeListenerGroups(
|
|
722
|
-
groups.immediateSyncListeners,
|
|
723
|
-
groups.immediateQueuedListeners,
|
|
724
|
-
envelope,
|
|
725
|
-
options
|
|
726
|
-
);
|
|
727
|
-
let deferred = false;
|
|
728
|
-
if (groups.deferredSyncListeners.length > 0 || groups.deferredQueuedListeners.length > 0) {
|
|
729
|
-
const scheduled = scheduleDeferredDispatch(async () => {
|
|
730
|
-
await executeListenerGroups(
|
|
731
|
-
groups.deferredSyncListeners,
|
|
732
|
-
groups.deferredQueuedListeners,
|
|
733
|
-
envelope,
|
|
734
|
-
options
|
|
735
|
-
);
|
|
736
|
-
}, eventName);
|
|
737
|
-
if (scheduled) {
|
|
738
|
-
deferred = true;
|
|
739
|
-
} else {
|
|
740
|
-
await executeListenerGroups(
|
|
741
|
-
groups.deferredSyncListeners,
|
|
742
|
-
groups.deferredQueuedListeners,
|
|
743
|
-
envelope,
|
|
744
|
-
options
|
|
745
|
-
);
|
|
746
|
-
}
|
|
703
|
+
const queuedListeners = listeners.filter((listener) => listener.definition.queue === true).length;
|
|
704
|
+
if (queuedListeners > 0) {
|
|
705
|
+
validateQueuedEventPayload(envelope.payload);
|
|
747
706
|
}
|
|
748
|
-
|
|
707
|
+
const createResult = (deferred) => Object.freeze({
|
|
749
708
|
eventName,
|
|
750
709
|
occurredAt: envelope.occurredAt,
|
|
751
710
|
deferred,
|
|
752
|
-
syncListeners:
|
|
753
|
-
queuedListeners
|
|
711
|
+
syncListeners: listeners.length - queuedListeners,
|
|
712
|
+
queuedListeners
|
|
754
713
|
});
|
|
714
|
+
const { immediateListeners, deferredListeners } = splitListenersByCommitTiming(
|
|
715
|
+
listeners,
|
|
716
|
+
options.afterCommit === true
|
|
717
|
+
);
|
|
718
|
+
if (deferredListeners.length === 0) {
|
|
719
|
+
await runListenersInOrder(listeners, envelope, options);
|
|
720
|
+
return createResult(false);
|
|
721
|
+
}
|
|
722
|
+
let immediatePhaseCompleted = false;
|
|
723
|
+
const scheduled = scheduleDeferredDispatch(async () => {
|
|
724
|
+
if (immediatePhaseCompleted) {
|
|
725
|
+
await runListenersInOrder(deferredListeners, envelope, options);
|
|
726
|
+
}
|
|
727
|
+
}, eventName);
|
|
728
|
+
if (!scheduled) {
|
|
729
|
+
await runListenersInOrder(listeners, envelope, options);
|
|
730
|
+
return createResult(false);
|
|
731
|
+
}
|
|
732
|
+
await runListenersInOrder(immediateListeners, envelope, options);
|
|
733
|
+
immediatePhaseCompleted = true;
|
|
734
|
+
return createResult(true);
|
|
755
735
|
}
|
|
756
736
|
var PendingEventDispatch = class _PendingEventDispatch {
|
|
757
737
|
constructor(event, payload, options = {}) {
|
|
@@ -759,6 +739,8 @@ var PendingEventDispatch = class _PendingEventDispatch {
|
|
|
759
739
|
this.payload = payload;
|
|
760
740
|
this.options = options;
|
|
761
741
|
}
|
|
742
|
+
event;
|
|
743
|
+
payload;
|
|
762
744
|
options;
|
|
763
745
|
executionPromise;
|
|
764
746
|
afterCommit() {
|
|
@@ -826,19 +808,17 @@ var eventRuntimeInternals = {
|
|
|
826
808
|
createEventEnvelope,
|
|
827
809
|
createQueuedListenerDispatch,
|
|
828
810
|
createRuntimeBinding,
|
|
829
|
-
|
|
830
|
-
executeListenerGroups,
|
|
811
|
+
dispatchQueuedListener,
|
|
831
812
|
executeDispatch,
|
|
832
813
|
executeListener,
|
|
833
|
-
|
|
814
|
+
runListenersInOrder,
|
|
834
815
|
getRuntimeState,
|
|
835
816
|
isPlainObject: isPlainObject2,
|
|
836
817
|
normalizeEventName,
|
|
837
818
|
requireRegisteredEvent,
|
|
838
819
|
resolveDispatchedEventName,
|
|
839
820
|
scheduleDeferredDispatch,
|
|
840
|
-
|
|
841
|
-
splitListenersForExecution,
|
|
821
|
+
splitListenersByCommitTiming,
|
|
842
822
|
validateQueuedEventPayload
|
|
843
823
|
};
|
|
844
824
|
export {
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/events",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Holo-JS Framework - event contracts and runtime surface",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/cobraprojects/holo-js.git",
|
|
10
|
+
"directory": "packages/events"
|
|
11
|
+
},
|
|
7
12
|
"exports": {
|
|
8
13
|
".": {
|
|
9
14
|
"types": "./dist/index.d.ts",
|
|
@@ -14,7 +19,8 @@
|
|
|
14
19
|
"main": "./dist/index.mjs",
|
|
15
20
|
"types": "./dist/index.d.ts",
|
|
16
21
|
"files": [
|
|
17
|
-
"dist"
|
|
22
|
+
"dist",
|
|
23
|
+
"LICENSE"
|
|
18
24
|
],
|
|
19
25
|
"scripts": {
|
|
20
26
|
"build": "tsup",
|
|
@@ -23,10 +29,10 @@
|
|
|
23
29
|
"test": "vitest --run"
|
|
24
30
|
},
|
|
25
31
|
"dependencies": {
|
|
26
|
-
"@holo-js/db": "^0.
|
|
32
|
+
"@holo-js/db": "^0.4.1"
|
|
27
33
|
},
|
|
28
34
|
"peerDependencies": {
|
|
29
|
-
"@holo-js/queue": "^0.
|
|
35
|
+
"@holo-js/queue": "^0.4.1"
|
|
30
36
|
},
|
|
31
37
|
"peerDependenciesMeta": {
|
|
32
38
|
"@holo-js/queue": {
|
|
@@ -34,13 +40,13 @@
|
|
|
34
40
|
}
|
|
35
41
|
},
|
|
36
42
|
"devDependencies": {
|
|
37
|
-
"@holo-js/queue": "^0.
|
|
38
|
-
"@types/node": "^22.
|
|
39
|
-
"tsup": "^
|
|
40
|
-
"typescript": "^
|
|
41
|
-
"vitest": "^
|
|
43
|
+
"@holo-js/queue": "^0.4.1",
|
|
44
|
+
"@types/node": "^22.20.5",
|
|
45
|
+
"tsup": "^9.0.0",
|
|
46
|
+
"typescript": "^6.0.3",
|
|
47
|
+
"vitest": "^5.0.5"
|
|
42
48
|
},
|
|
43
49
|
"engines": {
|
|
44
|
-
"node": "^22.
|
|
50
|
+
"node": "^22.18.0 || ^24.0.0 || ^26.0.0"
|
|
45
51
|
}
|
|
46
52
|
}
|