@rotorsoft/act 0.33.0 → 0.33.2
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/README.md +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/@types/act.d.ts +25 -31
- package/dist/@types/act.d.ts.map +1 -1
- package/dist/@types/adapters/console-logger.d.ts +2 -0
- package/dist/@types/adapters/console-logger.d.ts.map +1 -1
- package/dist/@types/adapters/in-memory-cache.d.ts +7 -1
- package/dist/@types/adapters/in-memory-cache.d.ts.map +1 -1
- package/dist/@types/builders/state-builder.d.ts +2 -2
- package/dist/@types/builders/state-builder.d.ts.map +1 -1
- package/dist/@types/config.d.ts +2 -1
- package/dist/@types/config.d.ts.map +1 -1
- package/dist/@types/internal/drain-cycle.d.ts.map +1 -1
- package/dist/@types/internal/event-sourcing.d.ts.map +1 -1
- package/dist/@types/internal/index.d.ts +2 -2
- package/dist/@types/internal/index.d.ts.map +1 -1
- package/dist/@types/ports.d.ts +6 -1
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +6 -6
- package/dist/@types/types/action.d.ts.map +1 -1
- package/dist/@types/types/errors.d.ts +19 -19
- package/dist/@types/types/errors.d.ts.map +1 -1
- package/dist/@types/types/ports.d.ts +11 -10
- package/dist/@types/types/ports.d.ts.map +1 -1
- package/dist/@types/types/registry.d.ts +13 -4
- package/dist/@types/types/registry.d.ts.map +1 -1
- package/dist/@types/types/schemas.d.ts +19 -19
- package/dist/@types/types/schemas.d.ts.map +1 -1
- package/dist/@types/utils.d.ts.map +1 -1
- package/dist/{chunk-IDEYGKT4.js → chunk-AWT7TU22.js} +9 -9
- package/dist/{chunk-IDEYGKT4.js.map → chunk-AWT7TU22.js.map} +1 -1
- package/dist/index.cjs +66 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +54 -41
- package/dist/index.js.map +1 -1
- package/dist/types/index.cjs +7 -7
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.js +1 -1
- package/package.json +7 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ZodObject, ZodRawShape, z } from "zod";
|
|
2
2
|
/**
|
|
3
3
|
* @packageDocumentation
|
|
4
4
|
* @module act/types
|
|
@@ -12,16 +12,16 @@ export declare const ZodEmpty: z.ZodRecord<z.ZodString, z.ZodNever>;
|
|
|
12
12
|
/**
|
|
13
13
|
* Zod schema for an actor (user, system, etc.).
|
|
14
14
|
*/
|
|
15
|
-
export declare const ActorSchema: z.ZodReadonly<
|
|
15
|
+
export declare const ActorSchema: z.ZodReadonly<ZodObject<{
|
|
16
16
|
id: z.ZodString;
|
|
17
17
|
name: z.ZodString;
|
|
18
18
|
}, z.core.$loose>>;
|
|
19
19
|
/**
|
|
20
20
|
* Zod schema for a target (stream and actor info).
|
|
21
21
|
*/
|
|
22
|
-
export declare const TargetSchema: z.ZodReadonly<
|
|
22
|
+
export declare const TargetSchema: z.ZodReadonly<ZodObject<{
|
|
23
23
|
stream: z.ZodString;
|
|
24
|
-
actor: z.ZodReadonly<
|
|
24
|
+
actor: z.ZodReadonly<ZodObject<{
|
|
25
25
|
id: z.ZodString;
|
|
26
26
|
name: z.ZodString;
|
|
27
27
|
}, z.core.$loose>>;
|
|
@@ -30,7 +30,7 @@ export declare const TargetSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
30
30
|
/**
|
|
31
31
|
* Zod schema for causation event metadata.
|
|
32
32
|
*/
|
|
33
|
-
export declare const CausationEventSchema:
|
|
33
|
+
export declare const CausationEventSchema: ZodObject<{
|
|
34
34
|
id: z.ZodNumber;
|
|
35
35
|
name: z.ZodString;
|
|
36
36
|
stream: z.ZodString;
|
|
@@ -38,20 +38,20 @@ export declare const CausationEventSchema: z.ZodObject<{
|
|
|
38
38
|
/**
|
|
39
39
|
* Zod schema for event metadata (correlation and causation).
|
|
40
40
|
*/
|
|
41
|
-
export declare const EventMetaSchema: z.ZodReadonly<
|
|
41
|
+
export declare const EventMetaSchema: z.ZodReadonly<ZodObject<{
|
|
42
42
|
correlation: z.ZodString;
|
|
43
|
-
causation:
|
|
44
|
-
action: z.ZodOptional<z.ZodIntersection<z.ZodReadonly<
|
|
43
|
+
causation: ZodObject<{
|
|
44
|
+
action: z.ZodOptional<z.ZodIntersection<z.ZodReadonly<ZodObject<{
|
|
45
45
|
stream: z.ZodString;
|
|
46
|
-
actor: z.ZodReadonly<
|
|
46
|
+
actor: z.ZodReadonly<ZodObject<{
|
|
47
47
|
id: z.ZodString;
|
|
48
48
|
name: z.ZodString;
|
|
49
49
|
}, z.core.$loose>>;
|
|
50
50
|
expectedVersion: z.ZodOptional<z.ZodNumber>;
|
|
51
|
-
}, z.core.$loose>>,
|
|
51
|
+
}, z.core.$loose>>, ZodObject<{
|
|
52
52
|
name: z.ZodString;
|
|
53
53
|
}, z.core.$strip>>>;
|
|
54
|
-
event: z.ZodOptional<
|
|
54
|
+
event: z.ZodOptional<ZodObject<{
|
|
55
55
|
id: z.ZodNumber;
|
|
56
56
|
name: z.ZodString;
|
|
57
57
|
stream: z.ZodString;
|
|
@@ -61,25 +61,25 @@ export declare const EventMetaSchema: z.ZodReadonly<z.ZodObject<{
|
|
|
61
61
|
/**
|
|
62
62
|
* Zod schema for committed event metadata (id, stream, version, created, meta).
|
|
63
63
|
*/
|
|
64
|
-
export declare const CommittedMetaSchema: z.ZodReadonly<
|
|
64
|
+
export declare const CommittedMetaSchema: z.ZodReadonly<ZodObject<{
|
|
65
65
|
id: z.ZodNumber;
|
|
66
66
|
stream: z.ZodString;
|
|
67
67
|
version: z.ZodNumber;
|
|
68
68
|
created: z.ZodDate;
|
|
69
|
-
meta: z.ZodReadonly<
|
|
69
|
+
meta: z.ZodReadonly<ZodObject<{
|
|
70
70
|
correlation: z.ZodString;
|
|
71
|
-
causation:
|
|
72
|
-
action: z.ZodOptional<z.ZodIntersection<z.ZodReadonly<
|
|
71
|
+
causation: ZodObject<{
|
|
72
|
+
action: z.ZodOptional<z.ZodIntersection<z.ZodReadonly<ZodObject<{
|
|
73
73
|
stream: z.ZodString;
|
|
74
|
-
actor: z.ZodReadonly<
|
|
74
|
+
actor: z.ZodReadonly<ZodObject<{
|
|
75
75
|
id: z.ZodString;
|
|
76
76
|
name: z.ZodString;
|
|
77
77
|
}, z.core.$loose>>;
|
|
78
78
|
expectedVersion: z.ZodOptional<z.ZodNumber>;
|
|
79
|
-
}, z.core.$loose>>,
|
|
79
|
+
}, z.core.$loose>>, ZodObject<{
|
|
80
80
|
name: z.ZodString;
|
|
81
81
|
}, z.core.$strip>>>;
|
|
82
|
-
event: z.ZodOptional<
|
|
82
|
+
event: z.ZodOptional<ZodObject<{
|
|
83
83
|
id: z.ZodNumber;
|
|
84
84
|
name: z.ZodString;
|
|
85
85
|
stream: z.ZodString;
|
|
@@ -101,7 +101,7 @@ export type StateSchema = Readonly<{
|
|
|
101
101
|
/**
|
|
102
102
|
* Query options for event store queries.
|
|
103
103
|
*/
|
|
104
|
-
export declare const QuerySchema: z.ZodReadonly<
|
|
104
|
+
export declare const QuerySchema: z.ZodReadonly<ZodObject<{
|
|
105
105
|
stream: z.ZodOptional<z.ZodString>;
|
|
106
106
|
names: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
107
107
|
before: z.ZodOptional<z.ZodNumber>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/types/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../../src/types/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAEhD;;;;;GAKG;AAEH;;GAEG;AACH,eAAO,MAAM,QAAQ,sCAAkC,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,WAAW;;;kBAMX,CAAC;AAEd;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;;;kBAOZ,CAAC;AAEd;;GAEG;AACH,eAAO,MAAM,oBAAoB;;;;iBAI/B,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;kBAQf,CAAC;AAEd;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;kBAQnB,CAAC;AAEd;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,WAAW,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC;IACjE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,WAAW,CAAC,GAAG,OAAO,QAAQ,CAAC,CAAC;IAClE,KAAK,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;CAC/B,CAAC,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;kBAcX,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAA2B,KAAK,OAAO,EAAE,MAAM,KAAK,CAAC;AAI5D;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,QAAQ,GAAI,CAAC,EACxB,QAAQ,MAAM,EACd,SAAS,QAAQ,CAAC,CAAC,CAAC,EACpB,SAAS,OAAO,CAAC,CAAC,CAAC,KAClB,QAAQ,CAAC,CAAC,CASZ,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,MAAM,GACjB,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAEjC,QAAQ,QAAQ,CAAC,CAAC,CAAC,EACnB,QAAQ,OAAO,CAAC,CAAC,CAAC,EAClB,SAAS,QAAQ,CAAC,CAAC,CAAC,KACnB,QAAQ,CAAC,CAAC,GAAG,CAAC,CAGhB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CAAC,EAAE,CAAC,EAAE,MAAM,oBAEtC"}
|
|
@@ -25,13 +25,6 @@ var InvariantError = class extends Error {
|
|
|
25
25
|
this.name = Errors.InvariantError;
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
|
-
var StreamClosedError = class extends Error {
|
|
29
|
-
constructor(stream) {
|
|
30
|
-
super(`Stream "${stream}" is closed (tombstoned)`);
|
|
31
|
-
this.stream = stream;
|
|
32
|
-
this.name = Errors.StreamClosedError;
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
28
|
var ConcurrencyError = class extends Error {
|
|
36
29
|
constructor(stream, lastVersion, events, expectedVersion) {
|
|
37
30
|
super(
|
|
@@ -46,6 +39,13 @@ var ConcurrencyError = class extends Error {
|
|
|
46
39
|
this.name = Errors.ConcurrencyError;
|
|
47
40
|
}
|
|
48
41
|
};
|
|
42
|
+
var StreamClosedError = class extends Error {
|
|
43
|
+
constructor(stream) {
|
|
44
|
+
super(`Stream "${stream}" is closed (tombstoned)`);
|
|
45
|
+
this.stream = stream;
|
|
46
|
+
this.name = Errors.StreamClosedError;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
49
|
|
|
50
50
|
// src/types/schemas.ts
|
|
51
51
|
import { z } from "zod";
|
|
@@ -112,8 +112,8 @@ export {
|
|
|
112
112
|
Errors,
|
|
113
113
|
ValidationError,
|
|
114
114
|
InvariantError,
|
|
115
|
-
StreamClosedError,
|
|
116
115
|
ConcurrencyError,
|
|
116
|
+
StreamClosedError,
|
|
117
117
|
ZodEmpty,
|
|
118
118
|
ActorSchema,
|
|
119
119
|
TargetSchema,
|
|
@@ -124,4 +124,4 @@ export {
|
|
|
124
124
|
Environments,
|
|
125
125
|
LogLevels
|
|
126
126
|
};
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
127
|
+
//# sourceMappingURL=chunk-AWT7TU22.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/errors.ts","../src/types/schemas.ts","../src/types/index.ts"],"sourcesContent":["import type {\n Actor,\n Message,\n Schema,\n Schemas,\n Snapshot,\n Target,\n} from \"./action.js\";\n\n/**\n * @packageDocumentation\n * @module act/types\n * @category Types\n * Application error type constants and error classes for the Act Framework.\n *\n * - `ERR_VALIDATION`: Schema validation error\n * - `ERR_INVARIANT`: Invariant validation error\n * - `ERR_CONCURRENCY`: Optimistic concurrency validation error on commits\n */\nexport const Errors = {\n ValidationError: \"ERR_VALIDATION\",\n InvariantError: \"ERR_INVARIANT\",\n ConcurrencyError: \"ERR_CONCURRENCY\",\n StreamClosedError: \"ERR_STREAM_CLOSED\",\n} as const;\n\n/**\n * Thrown when an action or event payload fails Zod schema validation.\n *\n * This error indicates that data doesn't match the expected schema defined\n * for an action or event. The `details` property contains the Zod validation\n * error with specific information about what failed.\n *\n * @example Catching validation errors\n * ```typescript\n * import { ValidationError } from \"@rotorsoft/act\";\n *\n * try {\n * await app.do(\"createUser\", target, {\n * email: \"invalid-email\", // Missing @ symbol\n * age: -5 // Negative age\n * });\n * } catch (error) {\n * if (error instanceof ValidationError) {\n * console.error(\"Validation failed for:\", error.target);\n * console.error(\"Invalid payload:\", error.payload);\n * console.error(\"Validation details:\", error.details);\n * // details contains Zod error with field-level info\n * }\n * }\n * ```\n *\n * @example Logging validation details\n * ```typescript\n * try {\n * await app.do(\"updateProfile\", target, payload);\n * } catch (error) {\n * if (error instanceof ValidationError) {\n * error.details.errors.forEach((err) => {\n * console.error(`Field ${err.path.join(\".\")}: ${err.message}`);\n * });\n * }\n * }\n * ```\n *\n * @see {@link https://zod.dev | Zod documentation} for validation details\n */\nexport class ValidationError extends Error {\n constructor(\n /** The type of target being validated (e.g., \"action\", \"event\") */\n public readonly target: string,\n /** The invalid payload that failed validation */\n public readonly payload: any,\n /** Zod validation error details */\n public readonly details: any\n ) {\n super(`Invalid ${target} payload`);\n this.name = Errors.ValidationError;\n }\n}\n\n/**\n * Thrown when a business rule (invariant) is violated during action execution.\n *\n * Invariants are conditions that must hold true for an action to succeed.\n * They're checked after loading the current state but before emitting events.\n * This error provides complete context about what action was attempted and\n * why it was rejected.\n *\n * @template TState - State schema type\n * @template TEvents - Event schemas type\n * @template TActions - Action schemas type\n * @template TKey - Action name\n * @template TActor - Actor type extending base Actor\n *\n * @example Catching invariant violations\n * ```typescript\n * import { InvariantError } from \"@rotorsoft/act\";\n *\n * try {\n * await app.do(\"withdraw\",\n * { stream: \"account-123\", actor: { id: \"user1\", name: \"Alice\" } },\n * { amount: 1000 }\n * );\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * console.error(\"Action:\", error.action);\n * console.error(\"Reason:\", error.description);\n * console.error(\"Current state:\", error.snapshot.state);\n * console.error(\"Attempted payload:\", error.payload);\n * }\n * }\n * ```\n *\n * @example User-friendly error messages\n * ```typescript\n * try {\n * await app.do(\"closeTicket\", target, payload);\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * // Present friendly message to user\n * if (error.description === \"Ticket must be open\") {\n * return { error: \"This ticket is already closed\" };\n * } else if (error.description === \"Not authorized\") {\n * return { error: \"You don't have permission to close this ticket\" };\n * }\n * }\n * }\n * ```\n *\n * @example Logging with context\n * ```typescript\n * try {\n * await app.do(\"transfer\", target, { to: \"account2\", amount: 500 });\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * logger.error({\n * action: error.action,\n * stream: error.target.stream,\n * actor: error.target.actor,\n * reason: error.description,\n * balance: error.snapshot.state.balance,\n * attempted: error.payload.amount\n * }, \"Invariant violation\");\n * }\n * }\n * ```\n *\n * @see {@link Invariant} for defining business rules\n */\nexport class InvariantError<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TKey extends keyof TActions,\n TActor extends Actor = Actor,\n> extends Error {\n constructor(\n /** The action that was attempted */\n readonly action: TKey,\n /** The action payload that was provided */\n readonly payload: Readonly<TActions[TKey]>,\n /** The target stream and actor context */\n readonly target: Target<TActor>,\n /** The current state snapshot when invariant was checked */\n readonly snapshot: Snapshot<TState, TEvents>,\n /** Human-readable description of why the invariant failed */\n readonly description: string\n ) {\n super(`${action as string} failed invariant: ${description}`);\n this.name = Errors.InvariantError;\n }\n}\n\n/**\n * Thrown when optimistic concurrency control detects a conflict.\n *\n * This error occurs when trying to commit events to a stream that has been\n * modified by another process since it was last loaded. The version number\n * doesn't match expectations, indicating a concurrent modification.\n *\n * This is a normal occurrence in distributed systems and should be handled\n * by reloading the current state and retrying the action.\n *\n * @example Handling concurrency conflicts with retry\n * ```typescript\n * import { ConcurrencyError } from \"@rotorsoft/act\";\n *\n * async function transferWithRetry(from, to, amount, maxRetries = 3) {\n * for (let attempt = 0; attempt < maxRetries; attempt++) {\n * try {\n * await app.do(\"transfer\",\n * { stream: from, actor: currentUser },\n * { to, amount }\n * );\n * return { success: true };\n * } catch (error) {\n * if (error instanceof ConcurrencyError) {\n * if (attempt < maxRetries - 1) {\n * console.log(`Concurrent modification detected, retrying... (${attempt + 1}/${maxRetries})`);\n * await sleep(100 * Math.pow(2, attempt)); // Exponential backoff\n * continue;\n * }\n * }\n * throw error;\n * }\n * }\n * return { success: false, reason: \"Too many concurrent modifications\" };\n * }\n * ```\n *\n * @example Logging concurrency conflicts\n * ```typescript\n * try {\n * await app.do(\"updateInventory\", target, payload);\n * } catch (error) {\n * if (error instanceof ConcurrencyError) {\n * logger.warn({\n * stream: error.stream,\n * expectedVersion: error.expectedVersion,\n * actualVersion: error.lastVersion,\n * events: error.events.map(e => e.name)\n * }, \"Concurrent modification detected\");\n * }\n * }\n * ```\n *\n * @example User feedback for conflicts\n * ```typescript\n * try {\n * await app.do(\"editDocument\", target, { content: newContent });\n * } catch (error) {\n * if (error instanceof ConcurrencyError) {\n * return {\n * error: \"This document was modified by another user. Please refresh and try again.\",\n * code: \"CONCURRENT_MODIFICATION\"\n * };\n * }\n * }\n * ```\n *\n * @see {@link Store.commit} for version checking details\n */\n/**\n * Thrown when attempting to write to a stream that has been closed\n * with a tombstone event.\n *\n * A tombstoned stream is permanently closed — no further actions can\n * be executed against it. The only way to reopen a tombstoned stream\n * is through `Act.close()` with a `restart` callback.\n *\n * @example\n * ```typescript\n * import { StreamClosedError } from \"@rotorsoft/act\";\n *\n * try {\n * await app.do(\"updateTicket\", target, payload);\n * } catch (error) {\n * if (error instanceof StreamClosedError) {\n * console.error(`Stream ${error.stream} is closed`);\n * }\n * }\n * ```\n *\n * @see {@link Act.close} for closing streams\n */\nexport class StreamClosedError extends Error {\n constructor(\n /** The stream that is closed */\n public readonly stream: string\n ) {\n super(`Stream \"${stream}\" is closed (tombstoned)`);\n this.name = Errors.StreamClosedError;\n }\n}\n\nexport class ConcurrencyError extends Error {\n constructor(\n /** The stream that had the concurrent modification */\n public readonly stream: string,\n /** The actual current version in the store */\n public readonly lastVersion: number,\n /** The events that were being committed */\n public readonly events: Message<Schemas, keyof Schemas>[],\n /** The version number that was expected */\n public readonly expectedVersion: number\n ) {\n // Message lists stream + event names only. Payloads remain accessible\n // via `error.events` for callers who need them — keeping them out of\n // the message avoids MB-scale strings on contended writes and keeps\n // potentially-sensitive data out of log streams.\n super(\n `Concurrency error committing \"${events\n .map((e) => `${stream}.${e.name}`)\n .join(\n \", \"\n )}\". Expected version ${expectedVersion} but found version ${lastVersion}.`\n );\n this.name = Errors.ConcurrencyError;\n }\n}\n","import { z, ZodObject, ZodRawShape } from \"zod\";\n\n/**\n * @packageDocumentation\n * @module act/types\n * @category Types\n * Zod schemas and helpers for the Act Framework.\n */\n\n/**\n * An empty Zod schema (no properties).\n */\nexport const ZodEmpty = z.record(z.string(), z.never());\n\n/**\n * Zod schema for an actor (user, system, etc.).\n */\nexport const ActorSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n })\n .loose()\n .readonly();\n\n/**\n * Zod schema for a target (stream and actor info).\n */\nexport const TargetSchema = z\n .object({\n stream: z.string(),\n actor: ActorSchema,\n expectedVersion: z.number().optional(),\n })\n .loose()\n .readonly();\n\n/**\n * Zod schema for causation event metadata.\n */\nexport const CausationEventSchema = z.object({\n id: z.number(),\n name: z.string(),\n stream: z.string(),\n});\n\n/**\n * Zod schema for event metadata (correlation and causation).\n */\nexport const EventMetaSchema = z\n .object({\n correlation: z.string(),\n causation: z.object({\n action: TargetSchema.and(z.object({ name: z.string() })).optional(),\n event: CausationEventSchema.optional(),\n }),\n })\n .readonly();\n\n/**\n * Zod schema for committed event metadata (id, stream, version, created, meta).\n */\nexport const CommittedMetaSchema = z\n .object({\n id: z.number(),\n stream: z.string(),\n version: z.number(),\n created: z.date(),\n meta: EventMetaSchema,\n })\n .readonly();\n\n/**\n * Type representing the full state schema for a domain.\n * @property events - Map of event names to Zod schemas.\n * @property actions - Map of action names to Zod schemas.\n * @property state - Zod schema for the state object.\n */\nexport type StateSchema = Readonly<{\n events: Record<string, ZodObject<ZodRawShape> | typeof ZodEmpty>;\n actions: Record<string, ZodObject<ZodRawShape> | typeof ZodEmpty>;\n state: ZodObject<ZodRawShape>;\n}>;\n\n/**\n * Query options for event store queries.\n */\nexport const QuerySchema = z\n .object({\n stream: z.string().optional(),\n names: z.string().array().optional(),\n before: z.number().optional(),\n after: z.number().optional(),\n limit: z.number().optional(),\n created_before: z.date().optional(),\n created_after: z.date().optional(),\n backward: z.boolean().optional(),\n correlation: z.string().optional(),\n with_snaps: z.boolean().optional(),\n stream_exact: z.boolean().optional(),\n })\n .readonly();\n","/**\n * @packageDocumentation\n * @module act/types\n * Barrel file for Act Framework core types.\n *\n * Re-exports all major type definitions for actions, errors, ports, reactions, registries, and schemas.\n * Also defines common environment and log level types/constants for configuration and logging.\n *\n * @remarks\n * Import from this module to access all core framework types in one place.\n */\nexport type * from \"./action.js\";\nexport * from \"./errors.js\";\nexport type * from \"./ports.js\";\nexport type * from \"./reaction.js\";\nexport type * from \"./registry.js\";\nexport * from \"./schemas.js\";\n\n/**\n * Supported runtime environments for the framework.\n * - `development`: Local development\n * - `test`: Automated testing\n * - `staging`: Pre-production\n * - `production`: Live/production\n */\nexport const Environments = [\n \"development\",\n \"test\",\n \"staging\",\n \"production\",\n] as const;\n\n/**\n * Type representing a valid environment string.\n */\nexport type Environment = (typeof Environments)[number];\n\n/**\n * Supported log levels for framework logging.\n * - `fatal`, `error`, `warn`, `info`, `debug`, `trace`\n */\nexport const LogLevels = [\n \"fatal\",\n \"error\",\n \"warn\",\n \"info\",\n \"debug\",\n \"trace\",\n] as const;\n\n/**\n * Type representing a valid log level string.\n */\nexport type LogLevel = (typeof LogLevels)[number];\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/types/errors.ts","../src/types/schemas.ts","../src/types/index.ts"],"sourcesContent":["import type {\n Actor,\n Message,\n Schema,\n Schemas,\n Snapshot,\n Target,\n} from \"./action.js\";\n\n/**\n * @packageDocumentation\n * @module act/types\n * @category Types\n * Application error type constants and error classes for the Act Framework.\n *\n * - `ERR_VALIDATION`: Schema validation error\n * - `ERR_INVARIANT`: Invariant validation error\n * - `ERR_CONCURRENCY`: Optimistic concurrency validation error on commits\n */\nexport const Errors = {\n ValidationError: \"ERR_VALIDATION\",\n InvariantError: \"ERR_INVARIANT\",\n ConcurrencyError: \"ERR_CONCURRENCY\",\n StreamClosedError: \"ERR_STREAM_CLOSED\",\n} as const;\n\n/**\n * Thrown when an action or event payload fails Zod schema validation.\n *\n * This error indicates that data doesn't match the expected schema defined\n * for an action or event. The `details` property contains the Zod validation\n * error with specific information about what failed.\n *\n * @example Catching validation errors\n * ```typescript\n * import { ValidationError } from \"@rotorsoft/act\";\n *\n * try {\n * await app.do(\"createUser\", target, {\n * email: \"invalid-email\", // Missing @ symbol\n * age: -5 // Negative age\n * });\n * } catch (error) {\n * if (error instanceof ValidationError) {\n * console.error(\"Validation failed for:\", error.target);\n * console.error(\"Invalid payload:\", error.payload);\n * console.error(\"Validation details:\", error.details);\n * // details contains Zod error with field-level info\n * }\n * }\n * ```\n *\n * @example Logging validation details\n * ```typescript\n * try {\n * await app.do(\"updateProfile\", target, payload);\n * } catch (error) {\n * if (error instanceof ValidationError) {\n * error.details.errors.forEach((err) => {\n * console.error(`Field ${err.path.join(\".\")}: ${err.message}`);\n * });\n * }\n * }\n * ```\n *\n * @see {@link https://zod.dev | Zod documentation} for validation details\n */\nexport class ValidationError extends Error {\n constructor(\n /** The type of target being validated (e.g., \"action\", \"event\") */\n public readonly target: string,\n /** The invalid payload that failed validation */\n public readonly payload: any,\n /** Zod validation error details */\n public readonly details: any\n ) {\n super(`Invalid ${target} payload`);\n this.name = Errors.ValidationError;\n }\n}\n\n/**\n * Thrown when a business rule (invariant) is violated during action execution.\n *\n * Invariants are conditions that must hold true for an action to succeed.\n * They're checked after loading the current state but before emitting events.\n * This error provides complete context about what action was attempted and\n * why it was rejected.\n *\n * @template TState - State schema type\n * @template TEvents - Event schemas type\n * @template TActions - Action schemas type\n * @template TKey - Action name\n * @template TActor - Actor type extending base Actor\n *\n * @example Catching invariant violations\n * ```typescript\n * import { InvariantError } from \"@rotorsoft/act\";\n *\n * try {\n * await app.do(\"withdraw\",\n * { stream: \"account-123\", actor: { id: \"user1\", name: \"Alice\" } },\n * { amount: 1000 }\n * );\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * console.error(\"Action:\", error.action);\n * console.error(\"Reason:\", error.description);\n * console.error(\"Current state:\", error.snapshot.state);\n * console.error(\"Attempted payload:\", error.payload);\n * }\n * }\n * ```\n *\n * @example User-friendly error messages\n * ```typescript\n * try {\n * await app.do(\"closeTicket\", target, payload);\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * // Present friendly message to user\n * if (error.description === \"Ticket must be open\") {\n * return { error: \"This ticket is already closed\" };\n * } else if (error.description === \"Not authorized\") {\n * return { error: \"You don't have permission to close this ticket\" };\n * }\n * }\n * }\n * ```\n *\n * @example Logging with context\n * ```typescript\n * try {\n * await app.do(\"transfer\", target, { to: \"account2\", amount: 500 });\n * } catch (error) {\n * if (error instanceof InvariantError) {\n * logger.error({\n * action: error.action,\n * stream: error.target.stream,\n * actor: error.target.actor,\n * reason: error.description,\n * balance: error.snapshot.state.balance,\n * attempted: error.payload.amount\n * }, \"Invariant violation\");\n * }\n * }\n * ```\n *\n * @see {@link Invariant} for defining business rules\n */\nexport class InvariantError<\n TState extends Schema,\n TEvents extends Schemas,\n TActions extends Schemas,\n TKey extends keyof TActions,\n TActor extends Actor = Actor,\n> extends Error {\n constructor(\n /** The action that was attempted */\n readonly action: TKey,\n /** The action payload that was provided */\n readonly payload: Readonly<TActions[TKey]>,\n /** The target stream and actor context */\n readonly target: Target<TActor>,\n /** The current state snapshot when invariant was checked */\n readonly snapshot: Snapshot<TState, TEvents>,\n /** Human-readable description of why the invariant failed */\n readonly description: string\n ) {\n super(`${action as string} failed invariant: ${description}`);\n this.name = Errors.InvariantError;\n }\n}\n\n/**\n * Thrown when optimistic concurrency control detects a conflict.\n *\n * This error occurs when trying to commit events to a stream that has been\n * modified by another process since it was last loaded. The version number\n * doesn't match expectations, indicating a concurrent modification.\n *\n * This is a normal occurrence in distributed systems and should be handled\n * by reloading the current state and retrying the action.\n *\n * @example Handling concurrency conflicts with retry\n * ```typescript\n * import { ConcurrencyError } from \"@rotorsoft/act\";\n *\n * async function transferWithRetry(from, to, amount, maxRetries = 3) {\n * for (let attempt = 0; attempt < maxRetries; attempt++) {\n * try {\n * await app.do(\"transfer\",\n * { stream: from, actor: currentUser },\n * { to, amount }\n * );\n * return { success: true };\n * } catch (error) {\n * if (error instanceof ConcurrencyError) {\n * if (attempt < maxRetries - 1) {\n * console.log(`Concurrent modification detected, retrying... (${attempt + 1}/${maxRetries})`);\n * await sleep(100 * Math.pow(2, attempt)); // Exponential backoff\n * continue;\n * }\n * }\n * throw error;\n * }\n * }\n * return { success: false, reason: \"Too many concurrent modifications\" };\n * }\n * ```\n *\n * @example Logging concurrency conflicts\n * ```typescript\n * try {\n * await app.do(\"updateInventory\", target, payload);\n * } catch (error) {\n * if (error instanceof ConcurrencyError) {\n * logger.warn({\n * stream: error.stream,\n * expectedVersion: error.expectedVersion,\n * actualVersion: error.lastVersion,\n * events: error.events.map(e => e.name)\n * }, \"Concurrent modification detected\");\n * }\n * }\n * ```\n *\n * @example User feedback for conflicts\n * ```typescript\n * try {\n * await app.do(\"editDocument\", target, { content: newContent });\n * } catch (error) {\n * if (error instanceof ConcurrencyError) {\n * return {\n * error: \"This document was modified by another user. Please refresh and try again.\",\n * code: \"CONCURRENT_MODIFICATION\"\n * };\n * }\n * }\n * ```\n *\n * @see {@link Store.commit} for version checking details\n */\nexport class ConcurrencyError extends Error {\n constructor(\n /** The stream that had the concurrent modification */\n public readonly stream: string,\n /** The actual current version in the store */\n public readonly lastVersion: number,\n /** The events that were being committed */\n public readonly events: Message<Schemas, keyof Schemas>[],\n /** The version number that was expected */\n public readonly expectedVersion: number\n ) {\n // Message lists stream + event names only. Payloads remain accessible\n // via `error.events` for callers who need them — keeping them out of\n // the message avoids MB-scale strings on contended writes and keeps\n // potentially-sensitive data out of log streams.\n super(\n `Concurrency error committing \"${events\n .map((e) => `${stream}.${e.name}`)\n .join(\n \", \"\n )}\". Expected version ${expectedVersion} but found version ${lastVersion}.`\n );\n this.name = Errors.ConcurrencyError;\n }\n}\n\n/**\n * Thrown when attempting to write to a stream that has been closed\n * with a tombstone event.\n *\n * A tombstoned stream is permanently closed — no further actions can\n * be executed against it. The only way to reopen a tombstoned stream\n * is through `Act.close()` with a `restart` callback.\n *\n * @example\n * ```typescript\n * import { StreamClosedError } from \"@rotorsoft/act\";\n *\n * try {\n * await app.do(\"updateTicket\", target, payload);\n * } catch (error) {\n * if (error instanceof StreamClosedError) {\n * console.error(`Stream ${error.stream} is closed`);\n * }\n * }\n * ```\n *\n * @see {@link Act.close} for closing streams\n */\nexport class StreamClosedError extends Error {\n constructor(\n /** The stream that is closed */\n public readonly stream: string\n ) {\n super(`Stream \"${stream}\" is closed (tombstoned)`);\n this.name = Errors.StreamClosedError;\n }\n}\n","import { ZodObject, ZodRawShape, z } from \"zod\";\n\n/**\n * @packageDocumentation\n * @module act/types\n * @category Types\n * Zod schemas and helpers for the Act Framework.\n */\n\n/**\n * An empty Zod schema (no properties).\n */\nexport const ZodEmpty = z.record(z.string(), z.never());\n\n/**\n * Zod schema for an actor (user, system, etc.).\n */\nexport const ActorSchema = z\n .object({\n id: z.string(),\n name: z.string(),\n })\n .loose()\n .readonly();\n\n/**\n * Zod schema for a target (stream and actor info).\n */\nexport const TargetSchema = z\n .object({\n stream: z.string(),\n actor: ActorSchema,\n expectedVersion: z.number().optional(),\n })\n .loose()\n .readonly();\n\n/**\n * Zod schema for causation event metadata.\n */\nexport const CausationEventSchema = z.object({\n id: z.number(),\n name: z.string(),\n stream: z.string(),\n});\n\n/**\n * Zod schema for event metadata (correlation and causation).\n */\nexport const EventMetaSchema = z\n .object({\n correlation: z.string(),\n causation: z.object({\n action: TargetSchema.and(z.object({ name: z.string() })).optional(),\n event: CausationEventSchema.optional(),\n }),\n })\n .readonly();\n\n/**\n * Zod schema for committed event metadata (id, stream, version, created, meta).\n */\nexport const CommittedMetaSchema = z\n .object({\n id: z.number(),\n stream: z.string(),\n version: z.number(),\n created: z.date(),\n meta: EventMetaSchema,\n })\n .readonly();\n\n/**\n * Type representing the full state schema for a domain.\n * @property events - Map of event names to Zod schemas.\n * @property actions - Map of action names to Zod schemas.\n * @property state - Zod schema for the state object.\n */\nexport type StateSchema = Readonly<{\n events: Record<string, ZodObject<ZodRawShape> | typeof ZodEmpty>;\n actions: Record<string, ZodObject<ZodRawShape> | typeof ZodEmpty>;\n state: ZodObject<ZodRawShape>;\n}>;\n\n/**\n * Query options for event store queries.\n */\nexport const QuerySchema = z\n .object({\n stream: z.string().optional(),\n names: z.string().array().optional(),\n before: z.number().optional(),\n after: z.number().optional(),\n limit: z.number().optional(),\n created_before: z.date().optional(),\n created_after: z.date().optional(),\n backward: z.boolean().optional(),\n correlation: z.string().optional(),\n with_snaps: z.boolean().optional(),\n stream_exact: z.boolean().optional(),\n })\n .readonly();\n","/**\n * @packageDocumentation\n * @module act/types\n * Barrel file for Act Framework core types.\n *\n * Re-exports all major type definitions for actions, errors, ports, reactions, registries, and schemas.\n * Also defines common environment and log level types/constants for configuration and logging.\n *\n * @remarks\n * Import from this module to access all core framework types in one place.\n */\nexport type * from \"./action.js\";\nexport * from \"./errors.js\";\nexport type * from \"./ports.js\";\nexport type * from \"./reaction.js\";\nexport type * from \"./registry.js\";\nexport * from \"./schemas.js\";\n\n/**\n * Supported runtime environments for the framework.\n * - `development`: Local development\n * - `test`: Automated testing\n * - `staging`: Pre-production\n * - `production`: Live/production\n */\nexport const Environments = [\n \"development\",\n \"test\",\n \"staging\",\n \"production\",\n] as const;\n\n/**\n * Type representing a valid environment string.\n */\nexport type Environment = (typeof Environments)[number];\n\n/**\n * Supported log levels for framework logging.\n * - `fatal`, `error`, `warn`, `info`, `debug`, `trace`\n */\nexport const LogLevels = [\n \"fatal\",\n \"error\",\n \"warn\",\n \"info\",\n \"debug\",\n \"trace\",\n] as const;\n\n/**\n * Type representing a valid log level string.\n */\nexport type LogLevel = (typeof LogLevels)[number];\n"],"mappings":"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","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -123,8 +123,10 @@ var ConsoleLogger = class _ConsoleLogger {
|
|
|
123
123
|
this.debug = threshold <= 20 ? write.bind(this, "debug", 20) : noop;
|
|
124
124
|
this.trace = threshold <= 10 ? write.bind(this, "trace", 10) : noop;
|
|
125
125
|
}
|
|
126
|
+
/** No-op — `console.log` has no resources to release. */
|
|
126
127
|
async dispose() {
|
|
127
128
|
}
|
|
129
|
+
/** @inheritDoc */
|
|
128
130
|
child(bindings) {
|
|
129
131
|
return new _ConsoleLogger({
|
|
130
132
|
level: this.level,
|
|
@@ -249,21 +251,27 @@ var InMemoryCache = class {
|
|
|
249
251
|
constructor(options) {
|
|
250
252
|
this._entries = new LruMap(options?.maxSize ?? 1e3);
|
|
251
253
|
}
|
|
254
|
+
/** @inheritDoc */
|
|
252
255
|
async get(stream) {
|
|
253
256
|
return this._entries.get(stream);
|
|
254
257
|
}
|
|
258
|
+
/** @inheritDoc */
|
|
255
259
|
async set(stream, entry) {
|
|
256
260
|
this._entries.set(stream, entry);
|
|
257
261
|
}
|
|
262
|
+
/** @inheritDoc */
|
|
258
263
|
async invalidate(stream) {
|
|
259
264
|
this._entries.delete(stream);
|
|
260
265
|
}
|
|
266
|
+
/** @inheritDoc */
|
|
261
267
|
async clear() {
|
|
262
268
|
this._entries.clear();
|
|
263
269
|
}
|
|
270
|
+
/** @inheritDoc */
|
|
264
271
|
async dispose() {
|
|
265
272
|
this._entries.clear();
|
|
266
273
|
}
|
|
274
|
+
/** Current number of entries held by the LRU. */
|
|
267
275
|
get size() {
|
|
268
276
|
return this._entries.size;
|
|
269
277
|
}
|
|
@@ -296,13 +304,6 @@ var InvariantError = class extends Error {
|
|
|
296
304
|
this.name = Errors.InvariantError;
|
|
297
305
|
}
|
|
298
306
|
};
|
|
299
|
-
var StreamClosedError = class extends Error {
|
|
300
|
-
constructor(stream) {
|
|
301
|
-
super(`Stream "${stream}" is closed (tombstoned)`);
|
|
302
|
-
this.stream = stream;
|
|
303
|
-
this.name = Errors.StreamClosedError;
|
|
304
|
-
}
|
|
305
|
-
};
|
|
306
307
|
var ConcurrencyError = class extends Error {
|
|
307
308
|
constructor(stream, lastVersion, events, expectedVersion) {
|
|
308
309
|
super(
|
|
@@ -317,6 +318,13 @@ var ConcurrencyError = class extends Error {
|
|
|
317
318
|
this.name = Errors.ConcurrencyError;
|
|
318
319
|
}
|
|
319
320
|
};
|
|
321
|
+
var StreamClosedError = class extends Error {
|
|
322
|
+
constructor(stream) {
|
|
323
|
+
super(`Stream "${stream}" is closed (tombstoned)`);
|
|
324
|
+
this.stream = stream;
|
|
325
|
+
this.name = Errors.StreamClosedError;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
320
328
|
|
|
321
329
|
// src/utils.ts
|
|
322
330
|
var import_zod3 = require("zod");
|
|
@@ -906,7 +914,7 @@ var InMemoryStore = class {
|
|
|
906
914
|
var ExitCodes = ["ERROR", "EXIT"];
|
|
907
915
|
var adapters = /* @__PURE__ */ new Map();
|
|
908
916
|
function port(injector) {
|
|
909
|
-
return
|
|
917
|
+
return (adapter) => {
|
|
910
918
|
if (!adapters.has(injector.name)) {
|
|
911
919
|
const injected = injector(adapter);
|
|
912
920
|
adapters.set(injector.name, injected);
|
|
@@ -972,7 +980,7 @@ process.once("unhandledRejection", async (arg) => {
|
|
|
972
980
|
});
|
|
973
981
|
|
|
974
982
|
// src/act.ts
|
|
975
|
-
var
|
|
983
|
+
var import_node_events = __toESM(require("events"), 1);
|
|
976
984
|
|
|
977
985
|
// src/internal/build-classify.ts
|
|
978
986
|
function classifyRegistry(registry, states) {
|
|
@@ -1006,7 +1014,7 @@ function classifyRegistry(registry, states) {
|
|
|
1006
1014
|
}
|
|
1007
1015
|
|
|
1008
1016
|
// src/internal/close-cycle.ts
|
|
1009
|
-
var
|
|
1017
|
+
var import_node_crypto = require("crypto");
|
|
1010
1018
|
async function runCloseCycle(targets, deps) {
|
|
1011
1019
|
const targetMap = new Map(targets.map((t) => [t.stream, t]));
|
|
1012
1020
|
const streams = [...targetMap.keys()];
|
|
@@ -1018,7 +1026,7 @@ async function runCloseCycle(targets, deps) {
|
|
|
1018
1026
|
skipped
|
|
1019
1027
|
);
|
|
1020
1028
|
if (!safe.length) return { truncated: /* @__PURE__ */ new Map(), skipped };
|
|
1021
|
-
const correlation = (0,
|
|
1029
|
+
const correlation = (0, import_node_crypto.randomUUID)();
|
|
1022
1030
|
const { guarded, guardEvents } = await guardWithTombstones(
|
|
1023
1031
|
safe,
|
|
1024
1032
|
streamInfo,
|
|
@@ -1275,7 +1283,7 @@ var CorrelateCycle = class {
|
|
|
1275
1283
|
};
|
|
1276
1284
|
|
|
1277
1285
|
// src/internal/drain-cycle.ts
|
|
1278
|
-
var
|
|
1286
|
+
var import_node_crypto2 = require("crypto");
|
|
1279
1287
|
|
|
1280
1288
|
// src/internal/drain-ratio.ts
|
|
1281
1289
|
var RATIO_MIN = 0.2;
|
|
@@ -1297,7 +1305,7 @@ function computeLagLeadRatio(handled, lagging, leading) {
|
|
|
1297
1305
|
|
|
1298
1306
|
// src/internal/drain-cycle.ts
|
|
1299
1307
|
async function runDrainCycle(ops, registry, batchHandlers, handle, handleBatch, lagging, leading, eventLimit, leaseMillis) {
|
|
1300
|
-
const leased = await ops.claim(lagging, leading, (0,
|
|
1308
|
+
const leased = await ops.claim(lagging, leading, (0, import_node_crypto2.randomUUID)(), leaseMillis);
|
|
1301
1309
|
if (!leased.length) return void 0;
|
|
1302
1310
|
const fetched = await ops.fetch(leased, eventLimit);
|
|
1303
1311
|
const fetchMap = /* @__PURE__ */ new Map();
|
|
@@ -1698,8 +1706,8 @@ var block = (leases) => store().block(leases);
|
|
|
1698
1706
|
var subscribe = (streams) => store().subscribe(streams);
|
|
1699
1707
|
|
|
1700
1708
|
// src/internal/event-sourcing.ts
|
|
1709
|
+
var import_node_crypto3 = require("crypto");
|
|
1701
1710
|
var import_act_patch = require("@rotorsoft/act-patch");
|
|
1702
|
-
var import_crypto3 = require("crypto");
|
|
1703
1711
|
async function snap(snapshot) {
|
|
1704
1712
|
try {
|
|
1705
1713
|
const { id, stream, name, meta, version } = snapshot.event;
|
|
@@ -1759,7 +1767,7 @@ async function load(me, stream, callback, asOf) {
|
|
|
1759
1767
|
`Skipping unknown event "${String(e.name)}" on stream "${stream}" (id=${e.id}) \u2014 no reducer in state "${me.name}"`
|
|
1760
1768
|
);
|
|
1761
1769
|
}
|
|
1762
|
-
callback
|
|
1770
|
+
callback?.({
|
|
1763
1771
|
event,
|
|
1764
1772
|
state: state2,
|
|
1765
1773
|
version,
|
|
@@ -1775,6 +1783,15 @@ async function load(me, stream, callback, asOf) {
|
|
|
1775
1783
|
...cached ? { after: cached.event_id } : { with_snaps: true, ...asOf }
|
|
1776
1784
|
}
|
|
1777
1785
|
);
|
|
1786
|
+
if (replayed > 0 && !timeTravel && event) {
|
|
1787
|
+
await cache().set(stream, {
|
|
1788
|
+
state: state2,
|
|
1789
|
+
version,
|
|
1790
|
+
event_id: event.id,
|
|
1791
|
+
patches,
|
|
1792
|
+
snaps
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1778
1795
|
return { event, state: state2, version, patches, snaps, cache_hit, replayed };
|
|
1779
1796
|
}
|
|
1780
1797
|
async function action(me, action2, target, payload, reactingTo, skipValidation = false) {
|
|
@@ -1809,7 +1826,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1809
1826
|
data: skipValidation ? data : validate(name, data, me.events[name])
|
|
1810
1827
|
}));
|
|
1811
1828
|
const meta = {
|
|
1812
|
-
correlation: reactingTo?.meta.correlation || (0,
|
|
1829
|
+
correlation: reactingTo?.meta.correlation || (0, import_node_crypto3.randomUUID)(),
|
|
1813
1830
|
causation: {
|
|
1814
1831
|
action: {
|
|
1815
1832
|
name: action2,
|
|
@@ -1859,7 +1876,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1859
1876
|
};
|
|
1860
1877
|
});
|
|
1861
1878
|
const last = snapshots.at(-1);
|
|
1862
|
-
const snapped = me.snap
|
|
1879
|
+
const snapped = me.snap?.(last);
|
|
1863
1880
|
cache().set(stream, {
|
|
1864
1881
|
state: last.state,
|
|
1865
1882
|
version: last.event.version,
|
|
@@ -2040,6 +2057,17 @@ function buildDrain(logger) {
|
|
|
2040
2057
|
var DEFAULT_MAX_SUBSCRIBED_STREAMS = 1e3;
|
|
2041
2058
|
var DEFAULT_SETTLE_DEBOUNCE_MS = 10;
|
|
2042
2059
|
var Act = class {
|
|
2060
|
+
/**
|
|
2061
|
+
* Create a new Act orchestrator. Prefer the {@link act} builder over
|
|
2062
|
+
* direct construction — `act()...build()` wires the registry, merges
|
|
2063
|
+
* partial states, and collects batch handlers from registered slices
|
|
2064
|
+
* and projections in one pass.
|
|
2065
|
+
*
|
|
2066
|
+
* @param registry Schemas for every event and action across registered states
|
|
2067
|
+
* @param _states Merged map of state name → state definition
|
|
2068
|
+
* @param batchHandlers Static-target projection batch handlers (target → handler)
|
|
2069
|
+
* @param options Tuning knobs — see {@link ActOptions}
|
|
2070
|
+
*/
|
|
2043
2071
|
constructor(registry, _states = /* @__PURE__ */ new Map(), batchHandlers = /* @__PURE__ */ new Map(), options = {}) {
|
|
2044
2072
|
this.registry = registry;
|
|
2045
2073
|
this._states = _states;
|
|
@@ -2096,7 +2124,7 @@ var Act = class {
|
|
|
2096
2124
|
return Promise.resolve();
|
|
2097
2125
|
});
|
|
2098
2126
|
}
|
|
2099
|
-
_emitter = new
|
|
2127
|
+
_emitter = new import_node_events.default();
|
|
2100
2128
|
/** Event names with at least one registered reaction (computed at build time) */
|
|
2101
2129
|
_reactive_events;
|
|
2102
2130
|
/** Drain pipeline driver: armed flag, concurrency lock, adaptive ratio. */
|
|
@@ -2127,12 +2155,6 @@ var Act = class {
|
|
|
2127
2155
|
this._emitter.off(event, listener);
|
|
2128
2156
|
return this;
|
|
2129
2157
|
}
|
|
2130
|
-
/**
|
|
2131
|
-
* Create a new Act orchestrator.
|
|
2132
|
-
*
|
|
2133
|
-
* @param registry The registry of state, event, and action schemas
|
|
2134
|
-
* @param states Map of state names to their (potentially merged) state definitions
|
|
2135
|
-
*/
|
|
2136
2158
|
/** Batch handlers for static-target projections (target → handler) */
|
|
2137
2159
|
_batch_handlers;
|
|
2138
2160
|
/** Event-sourcing handlers, optionally wrapped with trace decorators */
|
|
@@ -2278,14 +2300,9 @@ var Act = class {
|
|
|
2278
2300
|
*
|
|
2279
2301
|
* For small result sets, consider using {@link query_array} instead.
|
|
2280
2302
|
*
|
|
2281
|
-
* @param query -
|
|
2282
|
-
*
|
|
2283
|
-
*
|
|
2284
|
-
* @param query.after - Filter events after this event ID
|
|
2285
|
-
* @param query.before - Filter events before this event ID
|
|
2286
|
-
* @param query.created_after - Filter events after this timestamp
|
|
2287
|
-
* @param query.created_before - Filter events before this timestamp
|
|
2288
|
-
* @param query.limit - Maximum number of events to return
|
|
2303
|
+
* @param query - Filter criteria — see {@link Query} for available fields
|
|
2304
|
+
* (`stream`, `name`, `after`, `before`, `created_after`, `created_before`,
|
|
2305
|
+
* `limit`, `with_snaps`, `stream_exact`)
|
|
2289
2306
|
* @param callback - Optional callback invoked for each matching event
|
|
2290
2307
|
* @returns Object with first event, last event, and total count
|
|
2291
2308
|
*
|
|
@@ -2321,11 +2338,12 @@ var Act = class {
|
|
|
2321
2338
|
* @see {@link query_array} for loading events into memory
|
|
2322
2339
|
*/
|
|
2323
2340
|
async query(query, callback) {
|
|
2324
|
-
let first
|
|
2341
|
+
let first;
|
|
2342
|
+
let last;
|
|
2325
2343
|
const count = await store().query((e) => {
|
|
2326
|
-
!first
|
|
2344
|
+
if (!first) first = e;
|
|
2327
2345
|
last = e;
|
|
2328
|
-
callback
|
|
2346
|
+
callback?.(e);
|
|
2329
2347
|
}, query);
|
|
2330
2348
|
return { first, last, count };
|
|
2331
2349
|
}
|
|
@@ -2376,10 +2394,8 @@ var Act = class {
|
|
|
2376
2394
|
* Call `correlate()` before `drain()` to discover target streams. For a higher-level
|
|
2377
2395
|
* API that handles debouncing, correlation, and signaling automatically, use {@link settle}.
|
|
2378
2396
|
*
|
|
2379
|
-
* @param options - Drain configuration
|
|
2380
|
-
*
|
|
2381
|
-
* @param options.eventLimit - Maximum events to fetch per stream (default: 10)
|
|
2382
|
-
* @param options.leaseMillis - Lease duration in milliseconds (default: 10000)
|
|
2397
|
+
* @param options - Drain configuration — see {@link DrainOptions} for fields
|
|
2398
|
+
* (`streamLimit`, `eventLimit`, `leaseMillis`).
|
|
2383
2399
|
* @returns Drain statistics with fetched, leased, acked, and blocked counts
|
|
2384
2400
|
*
|
|
2385
2401
|
* @example In tests and scripts
|
|
@@ -2414,8 +2430,8 @@ var Act = class {
|
|
|
2414
2430
|
* the next drain cycle.
|
|
2415
2431
|
*
|
|
2416
2432
|
* @param query - Query filter to scan for new correlations
|
|
2417
|
-
* @param query
|
|
2418
|
-
*
|
|
2433
|
+
* @param query - Scan filter — see {@link Query} for fields (typically
|
|
2434
|
+
* `{ after: <event-id>, limit: <count> }`)
|
|
2419
2435
|
* @returns Object with newly leased streams and last scanned event ID
|
|
2420
2436
|
*
|
|
2421
2437
|
* @example Manual correlation
|
|
@@ -2462,9 +2478,8 @@ var Act = class {
|
|
|
2462
2478
|
*
|
|
2463
2479
|
* **Note:** Only one correlation worker can run at a time per Act instance.
|
|
2464
2480
|
*
|
|
2465
|
-
* @param query - Query filter for correlation scans
|
|
2466
|
-
*
|
|
2467
|
-
* @param query.limit - Events to scan per cycle (default: 100)
|
|
2481
|
+
* @param query - Query filter for correlation scans — see {@link Query}
|
|
2482
|
+
* (typically `{ after: -1, limit: 100 }`)
|
|
2468
2483
|
* @param frequency - Correlation frequency in milliseconds (default: 10000)
|
|
2469
2484
|
* @param callback - Optional callback invoked with newly discovered streams
|
|
2470
2485
|
* @returns `true` if worker started, `false` if already running
|
|
@@ -2631,14 +2646,11 @@ var Act = class {
|
|
|
2631
2646
|
* fully catches up paginated streams (e.g. after `reset()` on a long
|
|
2632
2647
|
* projection) without forcing callers to loop.
|
|
2633
2648
|
*
|
|
2634
|
-
* @param options - Settle configuration
|
|
2635
|
-
*
|
|
2636
|
-
*
|
|
2637
|
-
*
|
|
2638
|
-
*
|
|
2639
|
-
* @param options.streamLimit - Maximum streams per drain cycle (default: 10)
|
|
2640
|
-
* @param options.eventLimit - Maximum events per stream (default: 10)
|
|
2641
|
-
* @param options.leaseMillis - Lease duration in milliseconds (default: 10000)
|
|
2649
|
+
* @param options - Settle configuration — see {@link SettleOptions} for fields:
|
|
2650
|
+
* `debounceMs` (default 10), `correlate` (default `{ after: -1, limit: 100 }`),
|
|
2651
|
+
* `maxPasses` (default `Infinity` — kill-switch for runaway loops),
|
|
2652
|
+
* `streamLimit` (default 10), `eventLimit` (default 10),
|
|
2653
|
+
* `leaseMillis` (default 10000).
|
|
2642
2654
|
*
|
|
2643
2655
|
* @example API mutations
|
|
2644
2656
|
* ```typescript
|
|
@@ -2901,7 +2913,8 @@ function action_builder(state2) {
|
|
|
2901
2913
|
throw new Error(`Duplicate action "${action2}"`);
|
|
2902
2914
|
internal.actions[action2] = schema;
|
|
2903
2915
|
function given(rules) {
|
|
2904
|
-
|
|
2916
|
+
internal.given ??= {};
|
|
2917
|
+
internal.given[action2] = rules;
|
|
2905
2918
|
return { emit };
|
|
2906
2919
|
}
|
|
2907
2920
|
function emit(handler) {
|