@actor-system/ask 0.0.16 → 0.0.18

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.
@@ -9,7 +9,12 @@ interface AskSyncOptions<out Req, in Res> {
9
9
  * If an actor's mailbox uses a synchronous processing strategy,
10
10
  * this function can be used to perform an ask operation synchronously.
11
11
  *
12
- * This method will throw an error if the actor does not respond synchronously.
12
+ * This method will throw an error if:
13
+ * - The target actor is not a local actor reference.
14
+ * - The target actor's mailbox does not support synchronous processing.
15
+ * - The actor is currently busy processing another message (reentrancy).
16
+ * - The actor is dead/stopped (and no tombstone response is available).
17
+ * - The ask operation does not receive a response immediately.
13
18
  */
14
19
  declare const askSync: <const Req, Res>(options: AskSyncOptions<Req, Res>) => Res;
15
20
 
@@ -9,7 +9,12 @@ interface AskSyncOptions<out Req, in Res> {
9
9
  * If an actor's mailbox uses a synchronous processing strategy,
10
10
  * this function can be used to perform an ask operation synchronously.
11
11
  *
12
- * This method will throw an error if the actor does not respond synchronously.
12
+ * This method will throw an error if:
13
+ * - The target actor is not a local actor reference.
14
+ * - The target actor's mailbox does not support synchronous processing.
15
+ * - The actor is currently busy processing another message (reentrancy).
16
+ * - The actor is dead/stopped (and no tombstone response is available).
17
+ * - The ask operation does not receive a response immediately.
13
18
  */
14
19
  declare const askSync: <const Req, Res>(options: AskSyncOptions<Req, Res>) => Res;
15
20
 
package/dist/ask-sync.js CHANGED
@@ -1,15 +1,21 @@
1
- import { PriorityScheduler } from '@actor-system/core';
1
+ import { PriorityScheduler, LocalActorRef, SchedulerType } from '@actor-system/core';
2
2
  import { _askWithCallback } from './ask-with-callback.js';
3
- import { AskTimeoutError } from './timeout.js';
3
+ import { UnsupportedSyncOperationError, ReentryError, DisconnectedError, NoSynchronousResponseError, AskTimeoutError } from './errors.js';
4
4
 
5
5
  /**
6
6
  * If an actor's mailbox uses a synchronous processing strategy,
7
7
  * this function can be used to perform an ask operation synchronously.
8
8
  *
9
- * This method will throw an error if the actor does not respond synchronously.
9
+ * This method will throw an error if:
10
+ * - The target actor is not a local actor reference.
11
+ * - The target actor's mailbox does not support synchronous processing.
12
+ * - The actor is currently busy processing another message (reentrancy).
13
+ * - The actor is dead/stopped (and no tombstone response is available).
14
+ * - The ask operation does not receive a response immediately.
10
15
  */
11
16
  const askSync = (options) => {
12
- const { to } = options;
17
+ assertsActorSupportsSync(options.to);
18
+ assertsActorIsIdle(options.to);
13
19
  let msgRef = null;
14
20
  let error;
15
21
  _askWithCallback({
@@ -29,13 +35,31 @@ const askSync = (options) => {
29
35
  },
30
36
  },
31
37
  });
32
- if (error) {
38
+ if (error)
33
39
  throw error;
40
+ assertsSynchronousResponse(options.to, msgRef);
41
+ return msgRef.msg;
42
+ };
43
+ const assertsSynchronousResponse = (to, response) => {
44
+ if (response === null) {
45
+ throw new NoSynchronousResponseError(`Synchronous ask received no response.`, to);
34
46
  }
35
- if (!msgRef) {
36
- throw new AskTimeoutError(`Ask to '${to.path}' did not respond synchronously. Ensure the actor's mailbox is set to synchronous processing.`, to, NaN, undefined);
47
+ };
48
+ const assertsActorSupportsSync = (to) => {
49
+ if (!(to instanceof LocalActorRef)) {
50
+ throw new UnsupportedSyncOperationError(`Synchronous ask operations are only supported for local actors. Actor '${to.path}' is not a local actor reference.`, to);
51
+ }
52
+ if (to._mailbox.schedulerType !== SchedulerType.Sync) {
53
+ throw new UnsupportedSyncOperationError(`Actor '${to.path}' does not support synchronous processing. Ensure the actor's mailbox is configured with a synchronous scheduler.`, to);
54
+ }
55
+ };
56
+ const assertsActorIsIdle = (to) => {
57
+ if (to._mailbox.ongoingProcess !== undefined) {
58
+ throw new ReentryError(`Synchronous ask cannot be performed because actor '${to.path}' is currently processing another message (reentrancy).`, to);
59
+ }
60
+ if (to._mailbox.state !== "connected") {
61
+ throw new DisconnectedError(`Synchronous ask cannot be performed because actor '${to.path}' is not in a connected state.`, to);
37
62
  }
38
- return msgRef.msg;
39
63
  };
40
64
 
41
65
  export { askSync };
@@ -1,5 +1,5 @@
1
1
  import { ActorRef } from '@actor-system/core';
2
- import { AskTimeoutError } from './timeout.js';
2
+ import { AskTimeoutError } from './errors.js';
3
3
 
4
4
  type CreateRequest<out Req, in Res> = (replyTo: ActorRef<Res | AskTimeoutError>) => Req;
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { ActorRef } from '@actor-system/core/internal';
2
- import { AskTimeoutError } from './timeout.internal.js';
2
+ import { AskTimeoutError } from './errors.internal.js';
3
3
 
4
4
  type CreateRequest<out Req, in Res> = (replyTo: ActorRef<Res | AskTimeoutError>) => Req;
5
5
 
@@ -1,7 +1,7 @@
1
1
  import { receiveMessage, stopped } from '@actor-system/behaviors';
2
2
  import { $system, signal } from '@actor-system/core';
3
3
  import { generateMonotonicULID } from './__bundle__/shared/dist/monotonicULID.js';
4
- import { AskTimeoutError } from './timeout.js';
4
+ import { AskTimeoutError } from './errors.js';
5
5
 
6
6
  /**
7
7
  * @internal
@@ -19,7 +19,7 @@ const _askWithCallback = (options) => {
19
19
  if (done)
20
20
  return; // If already done, do not proceed
21
21
  replyTo.tell(new AskTimeoutError(`Ask to '${to.path}' timed out after ${timeout}ms`, to, timeout));
22
- }, timeout);
22
+ }, Math.max(0, timeout));
23
23
  }
24
24
  const replyTo = to[$system].systemActorOf(receiveMessage((msg) => {
25
25
  if (!(msg instanceof AskTimeoutError) && !done) {
package/dist/ask.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { _askWithCallback } from './ask-with-callback.js';
2
- import { AskTimeoutError } from './timeout.js';
2
+ import { AskTimeoutError } from './errors.js';
3
3
 
4
4
  const ask = (options) => new Promise((resolve, reject) => _askWithCallback({
5
5
  timeout: 1000,
@@ -0,0 +1,51 @@
1
+ import { ActorRef } from '@actor-system/core';
2
+ import { Letter } from '@actor-system/mail';
3
+
4
+ declare const $timeoutError = "@@ask.timeout-error";
5
+ declare const $unsupportedSyncOperationError = "@@ask.unsupported-sync-operation-error";
6
+ declare const $noSynchronousResponseError = "@@ask.no-synchronous-response-error";
7
+ declare const $reentryError = "@@ask.reentry-error";
8
+ declare const $disconnectedError = "@@ask.disconnected-error";
9
+ declare class AskTimeoutError extends Error implements Letter<typeof $timeoutError> {
10
+ readonly label: typeof $timeoutError;
11
+ readonly from?: ActorRef;
12
+ readonly to: ActorRef;
13
+ readonly timeout: number;
14
+ constructor(message: string, to: ActorRef, timeout: number, from?: ActorRef);
15
+ }
16
+ /**
17
+ * Error thrown when attempting a synchronous ask operation on an actor
18
+ * that does not support synchronous processing (e.g., actor with async-only mailbox).
19
+ */
20
+ declare class UnsupportedSyncOperationError extends Error implements Letter<typeof $unsupportedSyncOperationError> {
21
+ readonly label: typeof $unsupportedSyncOperationError;
22
+ readonly from?: ActorRef;
23
+ readonly to: ActorRef;
24
+ constructor(message: string, to: ActorRef, from?: ActorRef);
25
+ }
26
+ /**
27
+ * Thrown when a synchronous ask operation receives no response. This can occur
28
+ * in several scenarios: the actor is busy processing another message (reentrancy),
29
+ * the actor is dead/stopped, or the actor has some other condition preventing
30
+ * immediate synchronous response.
31
+ */
32
+ declare class NoSynchronousResponseError extends Error implements Letter<typeof $noSynchronousResponseError> {
33
+ readonly label: typeof $noSynchronousResponseError;
34
+ readonly from?: ActorRef;
35
+ readonly to: ActorRef;
36
+ constructor(message: string, to: ActorRef, from?: ActorRef);
37
+ }
38
+ declare class ReentryError extends Error implements Letter<typeof $reentryError> {
39
+ readonly label: typeof $reentryError;
40
+ readonly from?: ActorRef;
41
+ readonly to: ActorRef;
42
+ constructor(message: string, to: ActorRef, from?: ActorRef);
43
+ }
44
+ declare class DisconnectedError extends Error implements Letter<typeof $disconnectedError> {
45
+ readonly label: typeof $disconnectedError;
46
+ readonly from?: ActorRef;
47
+ readonly to: ActorRef;
48
+ constructor(message: string, to: ActorRef, from?: ActorRef);
49
+ }
50
+
51
+ export { $disconnectedError, $noSynchronousResponseError, $reentryError, $timeoutError, $unsupportedSyncOperationError, AskTimeoutError, DisconnectedError, NoSynchronousResponseError, ReentryError, UnsupportedSyncOperationError };
@@ -0,0 +1,51 @@
1
+ import { ActorRef } from '@actor-system/core/internal';
2
+ import { Letter } from '@actor-system/mail/internal';
3
+
4
+ declare const $timeoutError = "@@ask.timeout-error";
5
+ declare const $unsupportedSyncOperationError = "@@ask.unsupported-sync-operation-error";
6
+ declare const $noSynchronousResponseError = "@@ask.no-synchronous-response-error";
7
+ declare const $reentryError = "@@ask.reentry-error";
8
+ declare const $disconnectedError = "@@ask.disconnected-error";
9
+ declare class AskTimeoutError extends Error implements Letter<typeof $timeoutError> {
10
+ readonly label: typeof $timeoutError;
11
+ readonly from?: ActorRef;
12
+ readonly to: ActorRef;
13
+ readonly timeout: number;
14
+ constructor(message: string, to: ActorRef, timeout: number, from?: ActorRef);
15
+ }
16
+ /**
17
+ * Error thrown when attempting a synchronous ask operation on an actor
18
+ * that does not support synchronous processing (e.g., actor with async-only mailbox).
19
+ */
20
+ declare class UnsupportedSyncOperationError extends Error implements Letter<typeof $unsupportedSyncOperationError> {
21
+ readonly label: typeof $unsupportedSyncOperationError;
22
+ readonly from?: ActorRef;
23
+ readonly to: ActorRef;
24
+ constructor(message: string, to: ActorRef, from?: ActorRef);
25
+ }
26
+ /**
27
+ * Thrown when a synchronous ask operation receives no response. This can occur
28
+ * in several scenarios: the actor is busy processing another message (reentrancy),
29
+ * the actor is dead/stopped, or the actor has some other condition preventing
30
+ * immediate synchronous response.
31
+ */
32
+ declare class NoSynchronousResponseError extends Error implements Letter<typeof $noSynchronousResponseError> {
33
+ readonly label: typeof $noSynchronousResponseError;
34
+ readonly from?: ActorRef;
35
+ readonly to: ActorRef;
36
+ constructor(message: string, to: ActorRef, from?: ActorRef);
37
+ }
38
+ declare class ReentryError extends Error implements Letter<typeof $reentryError> {
39
+ readonly label: typeof $reentryError;
40
+ readonly from?: ActorRef;
41
+ readonly to: ActorRef;
42
+ constructor(message: string, to: ActorRef, from?: ActorRef);
43
+ }
44
+ declare class DisconnectedError extends Error implements Letter<typeof $disconnectedError> {
45
+ readonly label: typeof $disconnectedError;
46
+ readonly from?: ActorRef;
47
+ readonly to: ActorRef;
48
+ constructor(message: string, to: ActorRef, from?: ActorRef);
49
+ }
50
+
51
+ export { $disconnectedError, $noSynchronousResponseError, $reentryError, $timeoutError, $unsupportedSyncOperationError, AskTimeoutError, DisconnectedError, NoSynchronousResponseError, ReentryError, UnsupportedSyncOperationError };
package/dist/errors.js ADDED
@@ -0,0 +1,74 @@
1
+ const $timeoutError = "@@ask.timeout-error";
2
+ const $unsupportedSyncOperationError = "@@ask.unsupported-sync-operation-error";
3
+ const $noSynchronousResponseError = "@@ask.no-synchronous-response-error";
4
+ const $reentryError = "@@ask.reentry-error";
5
+ const $disconnectedError = "@@ask.disconnected-error";
6
+ class AskTimeoutError extends Error {
7
+ label = $timeoutError;
8
+ from;
9
+ to;
10
+ timeout;
11
+ constructor(message, to, timeout, from) {
12
+ super(message);
13
+ this.name = "AskTimeoutError";
14
+ this.from = from;
15
+ this.to = to;
16
+ this.timeout = timeout;
17
+ }
18
+ }
19
+ /**
20
+ * Error thrown when attempting a synchronous ask operation on an actor
21
+ * that does not support synchronous processing (e.g., actor with async-only mailbox).
22
+ */
23
+ class UnsupportedSyncOperationError extends Error {
24
+ label = $unsupportedSyncOperationError;
25
+ from;
26
+ to;
27
+ constructor(message, to, from) {
28
+ super(message);
29
+ this.name = "UnsupportedSyncOperationError";
30
+ this.from = from;
31
+ this.to = to;
32
+ }
33
+ }
34
+ /**
35
+ * Thrown when a synchronous ask operation receives no response. This can occur
36
+ * in several scenarios: the actor is busy processing another message (reentrancy),
37
+ * the actor is dead/stopped, or the actor has some other condition preventing
38
+ * immediate synchronous response.
39
+ */
40
+ class NoSynchronousResponseError extends Error {
41
+ label = $noSynchronousResponseError;
42
+ from;
43
+ to;
44
+ constructor(message, to, from) {
45
+ super(message);
46
+ this.name = "NoSynchronousResponseError";
47
+ this.from = from;
48
+ this.to = to;
49
+ }
50
+ }
51
+ class ReentryError extends Error {
52
+ label = $reentryError;
53
+ from;
54
+ to;
55
+ constructor(message, to, from) {
56
+ super(message);
57
+ this.name = "ReentryError";
58
+ this.from = from;
59
+ this.to = to;
60
+ }
61
+ }
62
+ class DisconnectedError extends Error {
63
+ label = $disconnectedError;
64
+ from;
65
+ to;
66
+ constructor(message, to, from) {
67
+ super(message);
68
+ this.name = "DisconnectedError";
69
+ this.from = from;
70
+ this.to = to;
71
+ }
72
+ }
73
+
74
+ export { $disconnectedError, $noSynchronousResponseError, $reentryError, $timeoutError, $unsupportedSyncOperationError, AskTimeoutError, DisconnectedError, NoSynchronousResponseError, ReentryError, UnsupportedSyncOperationError };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { AskSyncOptions, askSync } from './ask-sync.js';
2
2
  export { AskOptions, ask } from './ask.js';
3
- export { $timeoutError, AskTimeoutError } from './timeout.js';
3
+ export { $disconnectedError, $noSynchronousResponseError, $reentryError, $timeoutError, $unsupportedSyncOperationError, AskTimeoutError, DisconnectedError, NoSynchronousResponseError, ReentryError, UnsupportedSyncOperationError } from './errors.js';
4
4
  export { Ask, MapResponse, WithAskOptions, withAsk } from './use-ask.js';
@@ -1,4 +1,4 @@
1
1
  export { AskSyncOptions, askSync } from './ask-sync.internal.js';
2
2
  export { AskOptions, ask } from './ask.internal.js';
3
- export { $timeoutError, AskTimeoutError } from './timeout.internal.js';
3
+ export { $disconnectedError, $noSynchronousResponseError, $reentryError, $timeoutError, $unsupportedSyncOperationError, AskTimeoutError, DisconnectedError, NoSynchronousResponseError, ReentryError, UnsupportedSyncOperationError } from './errors.internal.js';
4
4
  export { Ask, MapResponse, WithAskOptions, withAsk } from './use-ask.internal.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  export { askSync } from './ask-sync.js';
2
2
  export { ask } from './ask.js';
3
- export { $timeoutError, AskTimeoutError } from './timeout.js';
3
+ export { $disconnectedError, $noSynchronousResponseError, $reentryError, $timeoutError, $unsupportedSyncOperationError, AskTimeoutError, DisconnectedError, NoSynchronousResponseError, ReentryError, UnsupportedSyncOperationError } from './errors.js';
4
4
  export { withAsk } from './use-ask.js';
package/dist/use-ask.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ActorRef, ActorContext, behavior } from '@actor-system/core';
2
- import { AskTimeoutError } from './timeout.js';
2
+ import { AskTimeoutError } from './errors.js';
3
3
  import { CreateRequest } from './ask-with-callback.js';
4
4
 
5
5
  type MapResponse<in Res, out T> = (response: Res | AskTimeoutError) => T;
@@ -1,5 +1,5 @@
1
1
  import { ActorRef, ActorContext, behavior } from '@actor-system/core/internal';
2
- import { AskTimeoutError } from './timeout.internal.js';
2
+ import { AskTimeoutError } from './errors.internal.js';
3
3
  import { CreateRequest } from './ask-with-callback.internal.js';
4
4
 
5
5
  type MapResponse<in Res, out T> = (response: Res | AskTimeoutError) => T;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@actor-system/ask",
3
- "version": "0.0.16",
3
+ "version": "0.0.18",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "type-check": "tsc -b src",
@@ -9,7 +9,13 @@
9
9
  "publint": "publint",
10
10
  "build:tsc:internal": "tsc -b src/tsconfig.lib.json",
11
11
  "build:tsc:trimmed": "tsc -b src/tsconfig.lib.trimmed.json",
12
- "build:rollup": "rollup -c node:config/rollup-config"
12
+ "build:rollup": "rollup -c node:config/rollup-config",
13
+ "test": "NODE_OPTIONS=\"--expose-gc\" vitest run",
14
+ "test:browser": "vitest run --browser.enabled",
15
+ "test:browser:watch": "vitest --browser.enabled",
16
+ "test:browser:coverage": "vitest run --coverage --browser.enabled",
17
+ "test:extensive": "npm run test && npm run test -- --mode sync && npm run test:browser && npm run test:browser -- --mode sync",
18
+ "test:coverage": "vitest run --coverage"
13
19
  },
14
20
  "module": "./dist/index.js",
15
21
  "main": "./dist/index.js",
@@ -28,13 +34,13 @@
28
34
  "@actor-system/shared"
29
35
  ],
30
36
  "dependencies": {
31
- "@actor-system/behaviors": "0.0.16",
32
- "@actor-system/core": "0.1.0",
33
- "@actor-system/mail": "0.0.2"
37
+ "@actor-system/behaviors": "0.0.18",
38
+ "@actor-system/core": "0.1.2",
39
+ "@actor-system/mail": "0.0.3"
34
40
  },
35
41
  "devDependencies": {
36
42
  "@actor-system/testing": "0.0.2",
37
- "@actor-system/shared": "0.0.2",
43
+ "@actor-system/shared": "0.0.3",
38
44
  "config": "^1.0.0"
39
45
  }
40
46
  }
package/dist/timeout.d.ts DELETED
@@ -1,13 +0,0 @@
1
- import { ActorRef } from '@actor-system/core';
2
- import { Letter } from '@actor-system/mail';
3
-
4
- declare const $timeoutError = "@@ask.timeout-error";
5
- declare class AskTimeoutError extends Error implements Letter<typeof $timeoutError> {
6
- readonly label: typeof $timeoutError;
7
- readonly from?: ActorRef;
8
- readonly to: ActorRef;
9
- readonly timeout: number;
10
- constructor(message: string, to: ActorRef, timeout: number, from?: ActorRef);
11
- }
12
-
13
- export { $timeoutError, AskTimeoutError };
@@ -1,13 +0,0 @@
1
- import { ActorRef } from '@actor-system/core/internal';
2
- import { Letter } from '@actor-system/mail/internal';
3
-
4
- declare const $timeoutError = "@@ask.timeout-error";
5
- declare class AskTimeoutError extends Error implements Letter<typeof $timeoutError> {
6
- readonly label: typeof $timeoutError;
7
- readonly from?: ActorRef;
8
- readonly to: ActorRef;
9
- readonly timeout: number;
10
- constructor(message: string, to: ActorRef, timeout: number, from?: ActorRef);
11
- }
12
-
13
- export { $timeoutError, AskTimeoutError };
package/dist/timeout.js DELETED
@@ -1,16 +0,0 @@
1
- const $timeoutError = "@@ask.timeout-error";
2
- class AskTimeoutError extends Error {
3
- label = $timeoutError;
4
- from;
5
- to;
6
- timeout;
7
- constructor(message, to, timeout, from) {
8
- super(message);
9
- this.name = "AskTimeoutError";
10
- this.from = from;
11
- this.to = to;
12
- this.timeout = timeout;
13
- }
14
- }
15
-
16
- export { $timeoutError, AskTimeoutError };