@rotorsoft/act 0.33.1 → 0.33.3
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 +37 -21
- package/dist/@types/builders/state-builder.d.ts.map +1 -1
- package/dist/@types/config.d.ts +0 -1
- package/dist/@types/config.d.ts.map +1 -1
- package/dist/@types/internal/correlate-cycle.d.ts +2 -2
- 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/internal/tracing.d.ts +2 -2
- package/dist/@types/internal/tracing.d.ts.map +1 -1
- package/dist/@types/ports.d.ts.map +1 -1
- package/dist/@types/types/action.d.ts +7 -7
- 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-AGWZY6YT.js} +9 -9
- package/dist/chunk-AGWZY6YT.js.map +1 -0
- package/dist/index.cjs +63 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +51 -47
- 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 +4 -2
- package/dist/chunk-IDEYGKT4.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ZodType, z } from "zod";
|
|
2
2
|
import type { CommittedMeta, Schema, Schemas, State } from "./action.js";
|
|
3
3
|
import type { Reaction } from "./reaction.js";
|
|
4
4
|
/**
|
|
@@ -8,7 +8,13 @@ import type { Reaction } from "./reaction.js";
|
|
|
8
8
|
* Types for event and action registries in the Act Framework.
|
|
9
9
|
*/
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Per-event registration: the event's schema plus every reaction
|
|
12
|
+
* registered against it. Keyed by reaction name within the inner map so
|
|
13
|
+
* a single event can fan out to multiple handlers (one per slice or
|
|
14
|
+
* top-level `act().on(...)` call).
|
|
15
|
+
*
|
|
16
|
+
* @template TEvents - Event schemas in the domain
|
|
17
|
+
* @template TKey - Specific event name within `TEvents`
|
|
12
18
|
*/
|
|
13
19
|
export type ReactionsRegister<TEvents extends Schemas, TKey extends keyof TEvents> = {
|
|
14
20
|
schema: ZodType<TEvents[TKey]>;
|
|
@@ -22,8 +28,11 @@ export type EventRegister<TEvents extends Schemas> = {
|
|
|
22
28
|
[TKey in keyof TEvents]: ReactionsRegister<TEvents, TKey>;
|
|
23
29
|
};
|
|
24
30
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
31
|
+
* Type-level constraint: every key in the action map must point at a
|
|
32
|
+
* Zod schema. Used as a constraint on the registry's action half so
|
|
33
|
+
* downstream types can `infer` payloads safely.
|
|
34
|
+
*
|
|
35
|
+
* @template TSchemaReg - Schema register for actions
|
|
27
36
|
*/
|
|
28
37
|
export type SchemaRegister<TSchemaReg> = {
|
|
29
38
|
[TKey in keyof TSchemaReg]: Schema;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/types/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/types/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACtC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE9C;;;;;GAKG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,CAC3B,OAAO,SAAS,OAAO,EACvB,IAAI,SAAS,MAAM,OAAO,IACxB;IACF,MAAM,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;CACjD,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,OAAO,SAAS,OAAO,IAAI;KAClD,IAAI,IAAI,MAAM,OAAO,GAAG,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC;CAC1D,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,CAAC,UAAU,IAAI;KACtC,IAAI,IAAI,MAAM,UAAU,GAAG,MAAM;CACnC,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,CAClB,UAAU,SAAS,cAAc,CAAC,QAAQ,CAAC,EAC3C,OAAO,SAAS,OAAO,EACvB,QAAQ,SAAS,OAAO,IACtB;IACF,QAAQ,CAAC,OAAO,EAAE;SACf,IAAI,IAAI,MAAM,QAAQ,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC;KACrE,CAAC;IACF,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;CACzC,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC5E;IACE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;CAC3B,GAAG,aAAa,GACjB,KAAK,CAAC;AAEV;;;;GAIG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,GAClE;IACE,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC9B,GAAG,aAAa,GACjB,KAAK,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type ZodObject, type 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,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAE1D;;;;;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-AGWZY6YT.js.map
|
|
@@ -0,0 +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 */\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 { type ZodObject, type 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,
|
|
@@ -1251,8 +1259,8 @@ var CorrelateCycle = class {
|
|
|
1251
1259
|
}
|
|
1252
1260
|
/**
|
|
1253
1261
|
* Start a periodic correlation worker. Returns false if one is already
|
|
1254
|
-
* running. Errors from `correlate()` are
|
|
1255
|
-
*
|
|
1262
|
+
* running. Errors from `correlate()` are routed through `log()` so they
|
|
1263
|
+
* land in the configured logger (the timer keeps running on failure).
|
|
1256
1264
|
*/
|
|
1257
1265
|
startPolling(query = {}, frequency = 1e4, callback) {
|
|
1258
1266
|
if (this._timer) return false;
|
|
@@ -1260,7 +1268,7 @@ var CorrelateCycle = class {
|
|
|
1260
1268
|
this._timer = setInterval(
|
|
1261
1269
|
() => this.correlate({ ...query, after: this._checkpoint, limit }).then((result) => {
|
|
1262
1270
|
if (callback && result.subscribed) callback(result.subscribed);
|
|
1263
|
-
}).catch(
|
|
1271
|
+
}).catch((err) => log().error(err)),
|
|
1264
1272
|
frequency
|
|
1265
1273
|
);
|
|
1266
1274
|
return true;
|
|
@@ -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,
|
|
@@ -1789,7 +1797,7 @@ async function load(me, stream, callback, asOf) {
|
|
|
1789
1797
|
async function action(me, action2, target, payload, reactingTo, skipValidation = false) {
|
|
1790
1798
|
const { stream, expectedVersion, actor } = target;
|
|
1791
1799
|
if (!stream) throw new Error("Missing target stream");
|
|
1792
|
-
|
|
1800
|
+
const validated = skipValidation ? payload : validate(action2, payload, me.actions[action2]);
|
|
1793
1801
|
const snapshot = await load(me, stream);
|
|
1794
1802
|
if (snapshot.event?.name === TOMBSTONE_EVENT)
|
|
1795
1803
|
throw new StreamClosedError(stream);
|
|
@@ -1800,14 +1808,14 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1800
1808
|
if (!valid(snapshot.state, actor))
|
|
1801
1809
|
throw new InvariantError(
|
|
1802
1810
|
action2,
|
|
1803
|
-
|
|
1811
|
+
validated,
|
|
1804
1812
|
target,
|
|
1805
1813
|
snapshot,
|
|
1806
1814
|
description
|
|
1807
1815
|
);
|
|
1808
1816
|
});
|
|
1809
1817
|
}
|
|
1810
|
-
const result = me.on[action2](
|
|
1818
|
+
const result = me.on[action2](validated, snapshot, target);
|
|
1811
1819
|
if (!result) return [snapshot];
|
|
1812
1820
|
if (Array.isArray(result) && result.length === 0) {
|
|
1813
1821
|
return [snapshot];
|
|
@@ -1818,7 +1826,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1818
1826
|
data: skipValidation ? data : validate(name, data, me.events[name])
|
|
1819
1827
|
}));
|
|
1820
1828
|
const meta = {
|
|
1821
|
-
correlation: reactingTo?.meta.correlation || (0,
|
|
1829
|
+
correlation: reactingTo?.meta.correlation || (0, import_node_crypto3.randomUUID)(),
|
|
1822
1830
|
causation: {
|
|
1823
1831
|
action: {
|
|
1824
1832
|
name: action2,
|
|
@@ -1868,7 +1876,7 @@ async function action(me, action2, target, payload, reactingTo, skipValidation =
|
|
|
1868
1876
|
};
|
|
1869
1877
|
});
|
|
1870
1878
|
const last = snapshots.at(-1);
|
|
1871
|
-
const snapped = me.snap
|
|
1879
|
+
const snapped = me.snap?.(last);
|
|
1872
1880
|
cache().set(stream, {
|
|
1873
1881
|
state: last.state,
|
|
1874
1882
|
version: last.event.version,
|
|
@@ -2049,6 +2057,17 @@ function buildDrain(logger) {
|
|
|
2049
2057
|
var DEFAULT_MAX_SUBSCRIBED_STREAMS = 1e3;
|
|
2050
2058
|
var DEFAULT_SETTLE_DEBOUNCE_MS = 10;
|
|
2051
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
|
+
*/
|
|
2052
2071
|
constructor(registry, _states = /* @__PURE__ */ new Map(), batchHandlers = /* @__PURE__ */ new Map(), options = {}) {
|
|
2053
2072
|
this.registry = registry;
|
|
2054
2073
|
this._states = _states;
|
|
@@ -2105,7 +2124,7 @@ var Act = class {
|
|
|
2105
2124
|
return Promise.resolve();
|
|
2106
2125
|
});
|
|
2107
2126
|
}
|
|
2108
|
-
_emitter = new
|
|
2127
|
+
_emitter = new import_node_events.default();
|
|
2109
2128
|
/** Event names with at least one registered reaction (computed at build time) */
|
|
2110
2129
|
_reactive_events;
|
|
2111
2130
|
/** Drain pipeline driver: armed flag, concurrency lock, adaptive ratio. */
|
|
@@ -2136,12 +2155,6 @@ var Act = class {
|
|
|
2136
2155
|
this._emitter.off(event, listener);
|
|
2137
2156
|
return this;
|
|
2138
2157
|
}
|
|
2139
|
-
/**
|
|
2140
|
-
* Create a new Act orchestrator.
|
|
2141
|
-
*
|
|
2142
|
-
* @param registry The registry of state, event, and action schemas
|
|
2143
|
-
* @param states Map of state names to their (potentially merged) state definitions
|
|
2144
|
-
*/
|
|
2145
2158
|
/** Batch handlers for static-target projections (target → handler) */
|
|
2146
2159
|
_batch_handlers;
|
|
2147
2160
|
/** Event-sourcing handlers, optionally wrapped with trace decorators */
|
|
@@ -2287,14 +2300,9 @@ var Act = class {
|
|
|
2287
2300
|
*
|
|
2288
2301
|
* For small result sets, consider using {@link query_array} instead.
|
|
2289
2302
|
*
|
|
2290
|
-
* @param query -
|
|
2291
|
-
*
|
|
2292
|
-
*
|
|
2293
|
-
* @param query.after - Filter events after this event ID
|
|
2294
|
-
* @param query.before - Filter events before this event ID
|
|
2295
|
-
* @param query.created_after - Filter events after this timestamp
|
|
2296
|
-
* @param query.created_before - Filter events before this timestamp
|
|
2297
|
-
* @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`)
|
|
2298
2306
|
* @param callback - Optional callback invoked for each matching event
|
|
2299
2307
|
* @returns Object with first event, last event, and total count
|
|
2300
2308
|
*
|
|
@@ -2330,11 +2338,12 @@ var Act = class {
|
|
|
2330
2338
|
* @see {@link query_array} for loading events into memory
|
|
2331
2339
|
*/
|
|
2332
2340
|
async query(query, callback) {
|
|
2333
|
-
let first
|
|
2341
|
+
let first;
|
|
2342
|
+
let last;
|
|
2334
2343
|
const count = await store().query((e) => {
|
|
2335
|
-
!first
|
|
2344
|
+
if (!first) first = e;
|
|
2336
2345
|
last = e;
|
|
2337
|
-
callback
|
|
2346
|
+
callback?.(e);
|
|
2338
2347
|
}, query);
|
|
2339
2348
|
return { first, last, count };
|
|
2340
2349
|
}
|
|
@@ -2385,10 +2394,8 @@ var Act = class {
|
|
|
2385
2394
|
* Call `correlate()` before `drain()` to discover target streams. For a higher-level
|
|
2386
2395
|
* API that handles debouncing, correlation, and signaling automatically, use {@link settle}.
|
|
2387
2396
|
*
|
|
2388
|
-
* @param options - Drain configuration
|
|
2389
|
-
*
|
|
2390
|
-
* @param options.eventLimit - Maximum events to fetch per stream (default: 10)
|
|
2391
|
-
* @param options.leaseMillis - Lease duration in milliseconds (default: 10000)
|
|
2397
|
+
* @param options - Drain configuration — see {@link DrainOptions} for fields
|
|
2398
|
+
* (`streamLimit`, `eventLimit`, `leaseMillis`).
|
|
2392
2399
|
* @returns Drain statistics with fetched, leased, acked, and blocked counts
|
|
2393
2400
|
*
|
|
2394
2401
|
* @example In tests and scripts
|
|
@@ -2423,8 +2430,8 @@ var Act = class {
|
|
|
2423
2430
|
* the next drain cycle.
|
|
2424
2431
|
*
|
|
2425
2432
|
* @param query - Query filter to scan for new correlations
|
|
2426
|
-
* @param query
|
|
2427
|
-
*
|
|
2433
|
+
* @param query - Scan filter — see {@link Query} for fields (typically
|
|
2434
|
+
* `{ after: <event-id>, limit: <count> }`)
|
|
2428
2435
|
* @returns Object with newly leased streams and last scanned event ID
|
|
2429
2436
|
*
|
|
2430
2437
|
* @example Manual correlation
|
|
@@ -2471,9 +2478,8 @@ var Act = class {
|
|
|
2471
2478
|
*
|
|
2472
2479
|
* **Note:** Only one correlation worker can run at a time per Act instance.
|
|
2473
2480
|
*
|
|
2474
|
-
* @param query - Query filter for correlation scans
|
|
2475
|
-
*
|
|
2476
|
-
* @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 }`)
|
|
2477
2483
|
* @param frequency - Correlation frequency in milliseconds (default: 10000)
|
|
2478
2484
|
* @param callback - Optional callback invoked with newly discovered streams
|
|
2479
2485
|
* @returns `true` if worker started, `false` if already running
|
|
@@ -2640,14 +2646,11 @@ var Act = class {
|
|
|
2640
2646
|
* fully catches up paginated streams (e.g. after `reset()` on a long
|
|
2641
2647
|
* projection) without forcing callers to loop.
|
|
2642
2648
|
*
|
|
2643
|
-
* @param options - Settle configuration
|
|
2644
|
-
*
|
|
2645
|
-
*
|
|
2646
|
-
*
|
|
2647
|
-
*
|
|
2648
|
-
* @param options.streamLimit - Maximum streams per drain cycle (default: 10)
|
|
2649
|
-
* @param options.eventLimit - Maximum events per stream (default: 10)
|
|
2650
|
-
* @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).
|
|
2651
2654
|
*
|
|
2652
2655
|
* @example API mutations
|
|
2653
2656
|
* ```typescript
|
|
@@ -2910,7 +2913,8 @@ function action_builder(state2) {
|
|
|
2910
2913
|
throw new Error(`Duplicate action "${action2}"`);
|
|
2911
2914
|
internal.actions[action2] = schema;
|
|
2912
2915
|
function given(rules) {
|
|
2913
|
-
|
|
2916
|
+
internal.given ??= {};
|
|
2917
|
+
internal.given[action2] = rules;
|
|
2914
2918
|
return { emit };
|
|
2915
2919
|
}
|
|
2916
2920
|
function emit(handler) {
|