@actor-system/core
Advanced tools
@@ -68,3 +68,5 @@ import { Path } from '../__bundle__/shared/dist/path.internal.js'; | ||
| */ | ||
| _lookupMailboxConfig(actorPath: Path.Actor): MailboxConfig; | ||
| _lookupMailboxConfig(actorPath: Path.Actor): { | ||
| scheduler: PriorityScheduler; | ||
| } | MailboxConfig<unknown>; | ||
| /** @internal */ | ||
@@ -71,0 +73,0 @@ _stopActor(actor: Actor): Promise<void>; |
@@ -11,4 +11,4 @@ import { ActorMessagePort, ActorPostPort, MailboxConfig, MailboxState } from './types.js'; | ||
| #private; | ||
| static create<T>(config: MailboxConfig): Mailbox<T>; | ||
| constructor(config: MailboxConfig); | ||
| static create<T>(config: MailboxConfig<T>): Mailbox<T>; | ||
| constructor(config: MailboxConfig<T>); | ||
| set onmessage(handler: Bivariant<(event: T | SystemMessage) => void> | null); | ||
@@ -20,2 +20,19 @@ /** | ||
| get onmessage(): Bivariant<(event: T | SystemMessage) => void> | null; | ||
| /** | ||
| * Posts a message to the mailbox. The message can be either a user-defined event of type `T` | ||
| * or a system message. The method handles different mailbox states: | ||
| * - If the mailbox is shut down, the message is ignored. | ||
| * - If the mailbox is shutting down, only system messages are accepted. | ||
| * - If the mailbox is disconnected, the message is buffered. | ||
| * - Otherwise, the message is enqueued and the mailbox is drained. | ||
| * | ||
| * @param event The message to post, either of type `T` or a `SystemMessage`. | ||
| * @returns A promise that resolves when the message has been processed. | ||
| * | ||
| * @remarks | ||
| * **Performance:** | ||
| * - The time complexity of posting a message is typically **O(1)** for both buffering and enqueuing operations, | ||
| * assuming the underlying queue and buffer implementations are constant time. | ||
| * - The overall performance may depend on the implementation of `#drain()`, which is not detailed here. | ||
| */ | ||
| postMessage(event: T | SystemMessage): Promise<void>; | ||
@@ -22,0 +39,0 @@ get state(): MailboxState; |
@@ -11,4 +11,4 @@ import { ActorMessagePort, ActorPostPort, MailboxConfig, MailboxState } from './types.internal.js'; | ||
| #private; | ||
| static create<T>(config: MailboxConfig): Mailbox<T>; | ||
| constructor(config: MailboxConfig); | ||
| static create<T>(config: MailboxConfig<T>): Mailbox<T>; | ||
| constructor(config: MailboxConfig<T>); | ||
| set onmessage(handler: Bivariant<(event: T | SystemMessage) => void> | null); | ||
@@ -20,2 +20,19 @@ /** | ||
| get onmessage(): Bivariant<(event: T | SystemMessage) => void> | null; | ||
| /** | ||
| * Posts a message to the mailbox. The message can be either a user-defined event of type `T` | ||
| * or a system message. The method handles different mailbox states: | ||
| * - If the mailbox is shut down, the message is ignored. | ||
| * - If the mailbox is shutting down, only system messages are accepted. | ||
| * - If the mailbox is disconnected, the message is buffered. | ||
| * - Otherwise, the message is enqueued and the mailbox is drained. | ||
| * | ||
| * @param event The message to post, either of type `T` or a `SystemMessage`. | ||
| * @returns A promise that resolves when the message has been processed. | ||
| * | ||
| * @remarks | ||
| * **Performance:** | ||
| * - The time complexity of posting a message is typically **O(1)** for both buffering and enqueuing operations, | ||
| * assuming the underlying queue and buffer implementations are constant time. | ||
| * - The overall performance may depend on the implementation of `#drain()`, which is not detailed here. | ||
| */ | ||
| postMessage(event: T | SystemMessage): Promise<void>; | ||
@@ -22,0 +39,0 @@ get state(): MailboxState; |
+97
-20
@@ -12,2 +12,3 @@ import { waitForScheduler } from '../schedulers/waitForScheduler.js'; | ||
| #scheduler; | ||
| #messageComparator; | ||
| #systemQueue = []; | ||
@@ -25,2 +26,3 @@ #queue = []; | ||
| this.#scheduler = config.scheduler; | ||
| this.#messageComparator = config.messageComparator; | ||
| } | ||
@@ -31,3 +33,5 @@ set onmessage(handler) { | ||
| this.#onmessage = null; | ||
| this.#state = this.#state === "shutdown" ? "shutdown" : "disconnected"; | ||
| if (this.#state !== "shutdown") { | ||
| this.#state = "disconnected"; | ||
| } | ||
| return; | ||
@@ -39,3 +43,7 @@ } | ||
| this.#systemQueue.push(...this.#pendingSystemMessages.splice(0)); | ||
| this.#queue.push(...this.#pendingMessages.splice(0)); | ||
| // Insert pending messages in priority order | ||
| const pendingMessages = this.#pendingMessages.splice(0); | ||
| for (const message of pendingMessages) { | ||
| this.#insertSorted(this.#queue, message); | ||
| } | ||
| // Start processing if there are messages | ||
@@ -51,31 +59,57 @@ this.#drain(); | ||
| } | ||
| /** | ||
| * Posts a message to the mailbox. The message can be either a user-defined event of type `T` | ||
| * or a system message. The method handles different mailbox states: | ||
| * - If the mailbox is shut down, the message is ignored. | ||
| * - If the mailbox is shutting down, only system messages are accepted. | ||
| * - If the mailbox is disconnected, the message is buffered. | ||
| * - Otherwise, the message is enqueued and the mailbox is drained. | ||
| * | ||
| * @param event The message to post, either of type `T` or a `SystemMessage`. | ||
| * @returns A promise that resolves when the message has been processed. | ||
| * | ||
| * @remarks | ||
| * **Performance:** | ||
| * - The time complexity of posting a message is typically **O(1)** for both buffering and enqueuing operations, | ||
| * assuming the underlying queue and buffer implementations are constant time. | ||
| * - The overall performance may depend on the implementation of `#drain()`, which is not detailed here. | ||
| */ | ||
| async postMessage(event) { | ||
| if (this.#state === "shutdown") | ||
| return; | ||
| const isSysMsg = isSystemMessage(event); | ||
| // During shutting-down, only accept system messages | ||
| if (this.#state === "shutting-down" && !isSysMsg) | ||
| if (this.#state === "shutting-down" && | ||
| !isSystemMessage(event)) { | ||
| return; | ||
| const promiseWithResolvers = Promise.withResolvers(); | ||
| } | ||
| let queuedItem; | ||
| if (this.#state === "disconnected") { | ||
| // Buffer messages until connected | ||
| if (isSysMsg) { | ||
| this.#pendingSystemMessages.push({ event, ...promiseWithResolvers }); | ||
| } | ||
| else { | ||
| this.#pendingMessages.push({ event, ...promiseWithResolvers }); | ||
| } | ||
| queuedItem = this.#bufferPendingMessage(event); | ||
| } | ||
| else { | ||
| // Add to processing queues | ||
| if (isSysMsg) { | ||
| this.#systemQueue.push({ event, ...promiseWithResolvers }); | ||
| } | ||
| else { | ||
| this.#queue.push({ event, ...promiseWithResolvers }); | ||
| } | ||
| queuedItem = this.#enqueueMessage(event); | ||
| this.#drain(); | ||
| } | ||
| return promiseWithResolvers.promise; | ||
| return queuedItem.promise; | ||
| } | ||
| #bufferPendingMessage(event) { | ||
| if (isSystemMessage(event)) { | ||
| const item = { event, ...Promise.withResolvers() }; | ||
| this.#pendingSystemMessages.push(item); | ||
| return item; | ||
| } | ||
| const item = { event, ...Promise.withResolvers() }; | ||
| this.#insertSorted(this.#pendingMessages, item); | ||
| return item; | ||
| } | ||
| #enqueueMessage(event) { | ||
| if (isSystemMessage(event)) { | ||
| const item = { event, ...Promise.withResolvers() }; | ||
| this.#systemQueue.push(item); | ||
| return item; | ||
| } | ||
| const item = { event, ...Promise.withResolvers() }; | ||
| this.#insertSorted(this.#queue, item); | ||
| return item; | ||
| } | ||
| get state() { | ||
@@ -108,2 +142,28 @@ return this.#state; | ||
| } | ||
| /** | ||
| * Inserts a `QueueItem` into the given queue array, maintaining sorted order according to the | ||
| * configured message comparator. If no comparator is set, the item is appended to the end (FIFO). | ||
| * | ||
| * This method performs a linear search to find the correct insertion index, resulting in a time | ||
| * complexity of O(n), where n is the length of the queue. | ||
| * | ||
| * @param queue - The array of `QueueItem<T>` objects to insert into. | ||
| * @param item - The `QueueItem<T>` to be inserted. | ||
| */ | ||
| #insertSorted(queue, item) { | ||
| if (!this.#messageComparator) { | ||
| // No comparator, just append (FIFO) | ||
| queue.push(item); | ||
| return; | ||
| } | ||
| // Find insertion point to maintain priority order | ||
| let insertIndex = queue.length; | ||
| for (let i = 0; i < queue.length; i++) { | ||
| if (this.#messageComparator(item.event, queue[i].event) < 0) { | ||
| insertIndex = i; | ||
| break; | ||
| } | ||
| } | ||
| queue.splice(insertIndex, 0, item); | ||
| } | ||
| #drain() { | ||
@@ -119,2 +179,19 @@ const isEmpty = this.#queue.length === 0 && this.#systemQueue.length === 0; | ||
| } | ||
| /** | ||
| * Drains the mailbox queues by processing each queued message asynchronously. | ||
| * | ||
| * This method iterates over both the system and regular message queues, invoking the | ||
| * `onmessage` handler for each item until the queues are empty or the mailbox enters | ||
| * a shutdown state. It ensures that messages are processed in order and respects | ||
| * the mailbox's lifecycle states. | ||
| * | ||
| * Performance: | ||
| * - Time Complexity: O(n), where n is the total number of messages in both queues. | ||
| * Each message is processed once per invocation. | ||
| * - Space Complexity: O(1), as no additional space is allocated proportional to the | ||
| * number of messages; only references to the current item and ongoing process are maintained. | ||
| * | ||
| * @returns {Promise<void>} Resolves when all messages have been processed or the mailbox is shut down. | ||
| * @private | ||
| */ | ||
| async #unsafeDrain() { | ||
@@ -121,0 +198,0 @@ const { promise: ongoingProcess, resolve } = Promise.withResolvers(); |
| import { Scheduler } from '../schedulers/types.js'; | ||
| import { Bivariant } from '../__bundle__/shared/dist/types.js'; | ||
| interface MailboxConfig { | ||
| interface MailboxConfig<T = unknown> { | ||
| /** | ||
@@ -9,2 +10,12 @@ * Scheduler to use for processing messages. | ||
| scheduler: Scheduler; | ||
| /** | ||
| * Optional comparator for prioritizing user messages. | ||
| * System messages always take precedence over user messages. | ||
| * Within user messages, this comparator determines ordering. | ||
| * | ||
| * @param a - First message to compare | ||
| * @param b - Second message to compare | ||
| * @returns - Negative if a has higher priority, positive if b has higher priority, 0 if equal | ||
| */ | ||
| messageComparator?: Bivariant<(a: T, b: T) => number>; | ||
| } | ||
@@ -11,0 +22,0 @@ type ActorMessageListener<T> = (message: T) => void; |
| import { Scheduler } from '../schedulers/types.internal.js'; | ||
| import { Bivariant } from '../__bundle__/shared/dist/types.internal.js'; | ||
| interface MailboxConfig { | ||
| interface MailboxConfig<T = unknown> { | ||
| /** | ||
@@ -9,2 +10,12 @@ * Scheduler to use for processing messages. | ||
| scheduler: Scheduler; | ||
| /** | ||
| * Optional comparator for prioritizing user messages. | ||
| * System messages always take precedence over user messages. | ||
| * Within user messages, this comparator determines ordering. | ||
| * | ||
| * @param a - First message to compare | ||
| * @param b - Second message to compare | ||
| * @returns - Negative if a has higher priority, positive if b has higher priority, 0 if equal | ||
| */ | ||
| messageComparator?: Bivariant<(a: T, b: T) => number>; | ||
| } | ||
@@ -11,0 +22,0 @@ type ActorMessageListener<T> = (message: T) => void; |
+8
-2
| { | ||
| "name": "@actor-system/core", | ||
| "version": "0.1.0", | ||
| "version": "0.1.1", | ||
| "type": "module", | ||
@@ -12,3 +12,9 @@ "scripts": { | ||
| "build:tsc:trimmed": "tsc -b src/tsconfig.lib.trimmed.json", | ||
| "build:rollup": "rollup -c node:config/rollup-config" | ||
| "build:rollup": "rollup -c node:config/rollup-config", | ||
| "test": "NODE_OPTIONS=\"--expose-gc\" vitest run", | ||
| "test:browser": "vitest run --browser.enabled", | ||
| "test:browser:watch": "vitest --browser.enabled", | ||
| "test:browser:coverage": "vitest run --coverage --browser.enabled", | ||
| "test:extensive": "npm run test && npm run test -- --mode sync && npm run test:browser && npm run test:browser -- --mode sync", | ||
| "test:coverage": "vitest run --coverage" | ||
| }, | ||
@@ -15,0 +21,0 @@ "module": "./dist/index.js", |
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
102187
7.33%2421
5.91%