@actor-system/behaviors 0.0.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.
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Bivariance hack for ergonomic action and guard typing in strict TypeScript mode.
3
+ * Allows config-based functions to be less strictly parameterized.
4
+ */
5
+ type Bivariant<Fn extends (...args: any[]) => any> = {
6
+ bivarianceHack(...args: Parameters<Fn>): ReturnType<Fn>;
7
+ }["bivarianceHack"];
8
+
9
+ export type { Bivariant };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Bivariance hack for ergonomic action and guard typing in strict TypeScript mode.
3
+ * Allows config-based functions to be less strictly parameterized.
4
+ */
5
+ type Bivariant<Fn extends (...args: any[]) => any> = {
6
+ bivarianceHack(...args: Parameters<Fn>): ReturnType<Fn>;
7
+ }["bivarianceHack"];
8
+
9
+ export type { Bivariant };
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ declare const empty: behavior.Receive<never>;
4
+
5
+ export { empty };
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core/internal';
2
+
3
+ declare const empty: behavior.Receive<never>;
4
+
5
+ export { empty };
package/dist/empty.js ADDED
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ const empty = behavior._empty;
4
+
5
+ export { empty };
@@ -0,0 +1,11 @@
1
+ export { empty } from './empty.js';
2
+ export { intercept } from './intercept.js';
3
+ export { ReceiveMessage, ReceiveSignal, receive, receiveMessage, receiveSignal } from './receive.js';
4
+ export { restart } from './restart.js';
5
+ export { same } from './same.js';
6
+ export { setup } from './setup.js';
7
+ export { stopped } from './stopped.js';
8
+ export { supervise } from './supervise.js';
9
+ export { Stash, withStash } from './with-stash.js';
10
+ export { Timers, withTimers } from './with-timers.js';
11
+ export { Behavior } from '@actor-system/core';
@@ -0,0 +1,11 @@
1
+ export { empty } from './empty.internal.js';
2
+ export { intercept } from './intercept.internal.js';
3
+ export { ReceiveMessage, ReceiveSignal, receive, receiveMessage, receiveSignal } from './receive.internal.js';
4
+ export { restart } from './restart.internal.js';
5
+ export { same } from './same.internal.js';
6
+ export { setup } from './setup.internal.js';
7
+ export { stopped } from './stopped.internal.js';
8
+ export { supervise } from './supervise.internal.js';
9
+ export { Stash, withStash } from './with-stash.internal.js';
10
+ export { Timers, withTimers } from './with-timers.internal.js';
11
+ export { Behavior } from '@actor-system/core/internal';
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export { empty } from './empty.js';
2
+ export { intercept } from './intercept.js';
3
+ export { receive, receiveMessage, receiveSignal } from './receive.js';
4
+ export { restart } from './restart.js';
5
+ export { same } from './same.js';
6
+ export { setup } from './setup.js';
7
+ export { stopped } from './stopped.js';
8
+ export { supervise } from './supervise.js';
9
+ export { withStash } from './with-stash.js';
10
+ export { withTimers } from './with-timers.js';
@@ -0,0 +1,10 @@
1
+ import { behavior, signal, ActorContext } from '@actor-system/core';
2
+ import { Bivariant } from './__bundle__/shared/dist/types.js';
3
+
4
+ type Interceptor<Input, Output = Input> = Bivariant<(post: Output | signal.Signal, context: ActorContext<Output>) => Input | signal.Signal | behavior.Behavior<Input>>;
5
+ declare function intercept<Input, Output = Input>(inner: behavior.Folded<Input>, interceptor: Interceptor<Input, Output>): behavior.Folded<Output>;
6
+ declare function intercept<Input, Output = Input>(inner: behavior.Control<Input>, interceptor: Interceptor<Input, Output>): behavior.Control<Output>;
7
+ declare function intercept<Input, Output = Input>(inner: behavior.Receive<Input>, interceptor: Interceptor<Input, Output>): behavior.Receive<Output>;
8
+ declare function intercept<Input, Output = Input>(inner: behavior.Behavior<Input>, interceptor: Interceptor<Input, Output>): behavior.Behavior<Output>;
9
+
10
+ export { intercept };
@@ -0,0 +1,10 @@
1
+ import { behavior, signal, ActorContext } from '@actor-system/core/internal';
2
+ import { Bivariant } from './__bundle__/shared/dist/types.internal.js';
3
+
4
+ type Interceptor<Input, Output = Input> = Bivariant<(post: Output | signal.Signal, context: ActorContext<Output>) => Input | signal.Signal | behavior.Behavior<Input>>;
5
+ declare function intercept<Input, Output = Input>(inner: behavior.Folded<Input>, interceptor: Interceptor<Input, Output>): behavior.Folded<Output>;
6
+ declare function intercept<Input, Output = Input>(inner: behavior.Control<Input>, interceptor: Interceptor<Input, Output>): behavior.Control<Output>;
7
+ declare function intercept<Input, Output = Input>(inner: behavior.Receive<Input>, interceptor: Interceptor<Input, Output>): behavior.Receive<Output>;
8
+ declare function intercept<Input, Output = Input>(inner: behavior.Behavior<Input>, interceptor: Interceptor<Input, Output>): behavior.Behavior<Output>;
9
+
10
+ export { intercept };
@@ -0,0 +1,23 @@
1
+ import { behavior } from '@actor-system/core';
2
+ import { receive } from './receive.js';
3
+ import { setup } from './setup.js';
4
+
5
+ function intercept(inner, interceptor) {
6
+ if (behavior.isControl(inner)) {
7
+ return inner;
8
+ }
9
+ if (behavior.isFolded(inner)) {
10
+ return setup((ctx) => intercept(behavior.unfold(inner, ctx), interceptor));
11
+ }
12
+ if (behavior.isReceive(inner)) {
13
+ return receive((message, context) => {
14
+ const intercepted = interceptor(message, context);
15
+ return behavior.isBehavior(intercepted)
16
+ ? intercept(intercepted, interceptor)
17
+ : intercept(behavior.delegate(inner, intercepted, context), interceptor);
18
+ });
19
+ }
20
+ throw new Error(`Cannot intercept behavior of type ${inner} with interceptor`);
21
+ }
22
+
23
+ export { intercept };
@@ -0,0 +1,15 @@
1
+ import { signal, ActorContext, behavior } from '@actor-system/core';
2
+ import { Bivariant } from './__bundle__/shared/dist/types.js';
3
+
4
+ interface ReceiveMessage<T> extends behavior.Receive<T> {
5
+ receiveSignal(handler: Bivariant<(signal: signal.Signal, ctx: ActorContext<T>) => behavior.Behavior<T> | void>): behavior.Receive<T>;
6
+ }
7
+ interface ReceiveSignal<T> extends behavior.Receive<T> {
8
+ receiveMessage(handler: Bivariant<(message: T, ctx: ActorContext<T>) => behavior.Behavior<T> | void>): behavior.Receive<T>;
9
+ }
10
+ declare const receiveMessage: <T>(onMessage: Bivariant<(message: T, context: ActorContext<T>) => behavior.Behavior<T> | void>) => ReceiveMessage<T>;
11
+ declare const receiveSignal: <T>(onSignal: Bivariant<(signal: signal.Signal, context: ActorContext<T>) => behavior.Behavior<T> | void>) => ReceiveSignal<T>;
12
+ declare const receive: <T>(handler: Bivariant<(messageOrSignal: T | signal.Signal, context: ActorContext<T>) => behavior.Behavior<T> | void>) => behavior.Receive<T>;
13
+
14
+ export { receive, receiveMessage, receiveSignal };
15
+ export type { ReceiveMessage, ReceiveSignal };
@@ -0,0 +1,15 @@
1
+ import { signal, ActorContext, behavior } from '@actor-system/core/internal';
2
+ import { Bivariant } from './__bundle__/shared/dist/types.internal.js';
3
+
4
+ interface ReceiveMessage<T> extends behavior.Receive<T> {
5
+ receiveSignal(handler: Bivariant<(signal: signal.Signal, ctx: ActorContext<T>) => behavior.Behavior<T> | void>): behavior.Receive<T>;
6
+ }
7
+ interface ReceiveSignal<T> extends behavior.Receive<T> {
8
+ receiveMessage(handler: Bivariant<(message: T, ctx: ActorContext<T>) => behavior.Behavior<T> | void>): behavior.Receive<T>;
9
+ }
10
+ declare const receiveMessage: <T>(onMessage: Bivariant<(message: T, context: ActorContext<T>) => behavior.Behavior<T> | void>) => ReceiveMessage<T>;
11
+ declare const receiveSignal: <T>(onSignal: Bivariant<(signal: signal.Signal, context: ActorContext<T>) => behavior.Behavior<T> | void>) => ReceiveSignal<T>;
12
+ declare const receive: <T>(handler: Bivariant<(messageOrSignal: T | signal.Signal, context: ActorContext<T>) => behavior.Behavior<T> | void>) => behavior.Receive<T>;
13
+
14
+ export { receive, receiveMessage, receiveSignal };
15
+ export type { ReceiveMessage, ReceiveSignal };
@@ -0,0 +1,18 @@
1
+ import { behavior, signal } from '@actor-system/core';
2
+ import { same } from './same.js';
3
+
4
+ const receiveMessage = (onMessage) => ({
5
+ ...behavior.receive((message, ctx) => !signal.isSignal(message) ? (onMessage(message, ctx) ?? same) : same),
6
+ receiveSignal: (onSignal) => behavior.receive((message, context) => (!signal.isSignal(message)
7
+ ? onMessage(message, context)
8
+ : onSignal(message, context)) ?? same),
9
+ });
10
+ const receiveSignal = (onSignal) => ({
11
+ ...behavior.receive((message, ctx) => signal.isSignal(message) ? (onSignal(message, ctx) ?? same) : same),
12
+ receiveMessage: (onMessage) => behavior.receive((message, context) => (signal.isSignal(message)
13
+ ? onSignal(message, context)
14
+ : onMessage(message, context)) ?? same),
15
+ });
16
+ const receive = (handler) => behavior.receive((message, ctx) => handler(message, ctx) ?? same);
17
+
18
+ export { receive, receiveMessage, receiveSignal };
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ declare const restart: <T>(checkpoint: behavior.Behavior<T>) => behavior.Control<T>;
4
+
5
+ export { restart };
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core/internal';
2
+
3
+ declare const restart: <T>(checkpoint: behavior.Behavior<T>) => behavior.Control<T>;
4
+
5
+ export { restart };
@@ -0,0 +1,7 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ const restart = (checkpoint) => behavior.control((runtime) => {
4
+ runtime.restart(checkpoint);
5
+ });
6
+
7
+ export { restart };
package/dist/same.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ declare const same: behavior.Control<never>;
4
+
5
+ export { same };
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core/internal';
2
+
3
+ declare const same: behavior.Control<never>;
4
+
5
+ export { same };
package/dist/same.js ADDED
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ const same = behavior._same;
4
+
5
+ export { same };
@@ -0,0 +1,8 @@
1
+ import { ActorContext, behavior } from '@actor-system/core';
2
+ import { Bivariant } from './__bundle__/shared/dist/types.js';
3
+
4
+ type SetupFactory<T> = Bivariant<(context: ActorContext<T>) => behavior.Behavior<T> | void>;
5
+ declare const setup: <T>(factory: SetupFactory<T>) => behavior.Folded<T>;
6
+
7
+ export { setup };
8
+ export type { SetupFactory };
@@ -0,0 +1,8 @@
1
+ import { ActorContext, behavior } from '@actor-system/core/internal';
2
+ import { Bivariant } from './__bundle__/shared/dist/types.internal.js';
3
+
4
+ type SetupFactory<T> = Bivariant<(context: ActorContext<T>) => behavior.Behavior<T> | void>;
5
+ declare const setup: <T>(factory: SetupFactory<T>) => behavior.Folded<T>;
6
+
7
+ export { setup };
8
+ export type { SetupFactory };
package/dist/setup.js ADDED
@@ -0,0 +1,6 @@
1
+ import { behavior } from '@actor-system/core';
2
+ import { empty } from './empty.js';
3
+
4
+ const setup = (factory) => behavior.folded((ctx) => factory(ctx) ?? empty);
5
+
6
+ export { setup };
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ declare const stopped: behavior.Control<never>;
4
+
5
+ export { stopped };
@@ -0,0 +1,5 @@
1
+ import { behavior } from '@actor-system/core/internal';
2
+
3
+ declare const stopped: behavior.Control<never>;
4
+
5
+ export { stopped };
@@ -0,0 +1,7 @@
1
+ import { behavior } from '@actor-system/core';
2
+
3
+ const stopped = behavior.control((runtime) => {
4
+ runtime.stopSelf();
5
+ });
6
+
7
+ export { stopped };
@@ -0,0 +1,14 @@
1
+ import { behavior, ActorContext } from '@actor-system/core';
2
+
3
+ /**
4
+ * Supervision Decision Types
5
+ */
6
+ type SupervisionDecision = "restart" | "resume" | "stop" | "escalate";
7
+ type SupervisionStrategy<T> = (error: unknown, ctx: ActorContext<T>) => SupervisionDecision;
8
+ declare function supervise<T>(inner: behavior.Control<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Control<T>;
9
+ declare function supervise<T>(inner: behavior.Receive<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Receive<T>;
10
+ declare function supervise<T>(inner: behavior.Folded<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Folded<T>;
11
+ declare function supervise<T>(inner: behavior.Behavior<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Behavior<T>;
12
+
13
+ export { supervise };
14
+ export type { SupervisionDecision, SupervisionStrategy };
@@ -0,0 +1,14 @@
1
+ import { behavior, ActorContext } from '@actor-system/core/internal';
2
+
3
+ /**
4
+ * Supervision Decision Types
5
+ */
6
+ type SupervisionDecision = "restart" | "resume" | "stop" | "escalate";
7
+ type SupervisionStrategy<T> = (error: unknown, ctx: ActorContext<T>) => SupervisionDecision;
8
+ declare function supervise<T>(inner: behavior.Control<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Control<T>;
9
+ declare function supervise<T>(inner: behavior.Receive<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Receive<T>;
10
+ declare function supervise<T>(inner: behavior.Folded<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Folded<T>;
11
+ declare function supervise<T>(inner: behavior.Behavior<T>, strategy: SupervisionStrategy<T> | SupervisionDecision): behavior.Behavior<T>;
12
+
13
+ export { supervise };
14
+ export type { SupervisionDecision, SupervisionStrategy };
@@ -0,0 +1,36 @@
1
+ import { behavior } from '@actor-system/core';
2
+ import { restart } from './restart.js';
3
+ import { stopped } from './stopped.js';
4
+
5
+ function supervise(inner, strategy) {
6
+ if (behavior.isControl(inner)) {
7
+ return inner;
8
+ }
9
+ if (behavior.isFolded(inner)) {
10
+ return behavior.folded((context) => supervise(behavior.unfold(inner, context), strategy));
11
+ }
12
+ if (behavior.isReceive(inner)) {
13
+ return behavior.receive((message, context) => {
14
+ try {
15
+ const nextBehavior = inner._receive(message, context);
16
+ return supervise(nextBehavior, strategy);
17
+ }
18
+ catch (error) {
19
+ const decision = typeof strategy === "string" ? strategy : strategy(error, context);
20
+ switch (decision) {
21
+ case "restart":
22
+ return restart(supervise(inner, strategy));
23
+ case "resume":
24
+ return supervise(inner, strategy);
25
+ case "stop":
26
+ return stopped;
27
+ case "escalate":
28
+ throw error;
29
+ }
30
+ }
31
+ });
32
+ }
33
+ throw new Error(`Unknown behavior type: ${inner}`);
34
+ }
35
+
36
+ export { supervise };
@@ -0,0 +1,12 @@
1
+ import { ActorContext, behavior } from '@actor-system/core';
2
+
3
+ interface Stash<T> {
4
+ push(msg: T): void;
5
+ dropAll(): void;
6
+ popAll(): void;
7
+ readonly size: number;
8
+ }
9
+ declare const withStash: <T>(factory: (stash: Stash<T>, context: ActorContext<T>) => behavior.Behavior<T>) => behavior.Behavior<T>;
10
+
11
+ export { withStash };
12
+ export type { Stash };
@@ -0,0 +1,12 @@
1
+ import { ActorContext, behavior } from '@actor-system/core/internal';
2
+
3
+ interface Stash<T> {
4
+ push(msg: T): void;
5
+ dropAll(): void;
6
+ popAll(): void;
7
+ readonly size: number;
8
+ }
9
+ declare const withStash: <T>(factory: (stash: Stash<T>, context: ActorContext<T>) => behavior.Behavior<T>) => behavior.Behavior<T>;
10
+
11
+ export { withStash };
12
+ export type { Stash };
@@ -0,0 +1,45 @@
1
+ import { signal } from '@actor-system/core';
2
+ import { setup } from './setup.js';
3
+ import { intercept } from './intercept.js';
4
+
5
+ const $stash = Symbol("stash");
6
+ const withStash = (factory) => setup((context) => {
7
+ const stash = useStash(context);
8
+ const innerBehavior = factory(stash, context);
9
+ return intercept(innerBehavior, (post) => {
10
+ if (signal.isPostStop(post)) {
11
+ stash.dropAll();
12
+ }
13
+ return post;
14
+ });
15
+ });
16
+ const useStash = (context, capacity = 100) => {
17
+ if (context[$stash])
18
+ return context[$stash];
19
+ const stack = [];
20
+ const stash = {
21
+ /** Stash a message for later processing */
22
+ push: (msg) => {
23
+ if (stack.length < capacity) {
24
+ stack.push(msg);
25
+ }
26
+ },
27
+ /** Drop all stashed messages */
28
+ dropAll: () => {
29
+ stack.length = 0;
30
+ },
31
+ /** Unstash all messages, sending them to the actor's mailbox */
32
+ popAll: () => {
33
+ stack.forEach((msg) => context.self.tell(msg));
34
+ stack.length = 0;
35
+ },
36
+ /** Get current stash size */
37
+ get size() {
38
+ return stack.length;
39
+ },
40
+ };
41
+ context[$stash] = stash;
42
+ return stash;
43
+ };
44
+
45
+ export { useStash, withStash };
@@ -0,0 +1,11 @@
1
+ import { ActorContext, behavior } from '@actor-system/core';
2
+
3
+ interface Timers<T> {
4
+ startSingleTimer(key: PropertyKey, post: T, delay: number): void;
5
+ cancel(key: PropertyKey): void;
6
+ cancelAll(): void;
7
+ }
8
+ declare const withTimers: <T>(factory: (timers: Timers<T>, context: ActorContext<T>) => behavior.Behavior<T>) => behavior.Folded<T>;
9
+
10
+ export { withTimers };
11
+ export type { Timers };
@@ -0,0 +1,11 @@
1
+ import { ActorContext, behavior } from '@actor-system/core/internal';
2
+
3
+ interface Timers<T> {
4
+ startSingleTimer(key: PropertyKey, post: T, delay: number): void;
5
+ cancel(key: PropertyKey): void;
6
+ cancelAll(): void;
7
+ }
8
+ declare const withTimers: <T>(factory: (timers: Timers<T>, context: ActorContext<T>) => behavior.Behavior<T>) => behavior.Folded<T>;
9
+
10
+ export { withTimers };
11
+ export type { Timers };
@@ -0,0 +1,50 @@
1
+ import { signal } from '@actor-system/core';
2
+ import { intercept } from './intercept.js';
3
+ import { setup } from './setup.js';
4
+
5
+ const $timers = Symbol("timers");
6
+ const withTimers = (factory) => setup((context) => {
7
+ const timers = useTimers(context);
8
+ const innerBehavior = factory(timers, context);
9
+ return intercept(innerBehavior, (post) => {
10
+ if (signal.isPostStop(post)) {
11
+ timers.cancelAll();
12
+ }
13
+ return post;
14
+ });
15
+ });
16
+ const useTimers = (context) => {
17
+ if (context[$timers])
18
+ return context[$timers];
19
+ const buffer = new Map();
20
+ const timers = {
21
+ startSingleTimer: (key, post, delay) => {
22
+ if (buffer.has(key)) {
23
+ clearTimeout(buffer.get(key));
24
+ }
25
+ const timeout = setTimeout(() => {
26
+ context.self.tell(post);
27
+ buffer.delete(key);
28
+ }, delay);
29
+ buffer.set(key, timeout);
30
+ },
31
+ cancel: (key) => {
32
+ const timeout = buffer.get(key);
33
+ if (timeout) {
34
+ clearTimeout(timeout);
35
+ buffer.delete(key);
36
+ }
37
+ },
38
+ cancelAll() {
39
+ for (const timeout of buffer.values()) {
40
+ clearTimeout(timeout);
41
+ }
42
+ buffer.clear();
43
+ return;
44
+ },
45
+ };
46
+ context[$timers] = timers;
47
+ return timers;
48
+ };
49
+
50
+ export { useTimers, withTimers };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@actor-system/behaviors",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "scripts": {
6
+ "type-check": "tsc -b src",
7
+ "lint": "eslint src",
8
+ "lint:fix": "eslint src --fix",
9
+ "publint": "publint",
10
+ "build:tsc:internal": "tsc -b src/tsconfig.lib.json",
11
+ "build:tsc:trimmed": "tsc -b src/tsconfig.lib.trimmed.json",
12
+ "build:rollup": "rollup -c node:config/rollup-config"
13
+ },
14
+ "module": "./dist/index.js",
15
+ "main": "./dist/index.js",
16
+ "types": "./dist/index.d.ts",
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js"
24
+ },
25
+ "./package.json": "./package.json"
26
+ },
27
+ "bundleDependencies": [
28
+ "@actor-system/shared"
29
+ ],
30
+ "dependencies": {
31
+ "@actor-system/core": "0.0.1"
32
+ },
33
+ "devDependencies": {
34
+ "@actor-system/testing": "0.0.1",
35
+ "@actor-system/shared": "0.0.1",
36
+ "config": "^1.0.0"
37
+ }
38
+ }