@fabricorg/platform 0.1.1 → 0.2.0
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/dist/actions/index.cjs +48 -0
- package/dist/actions/index.cjs.map +1 -0
- package/dist/actions/index.d.cts +116 -0
- package/dist/actions/index.js +1 -57
- package/dist/actions/index.js.map +1 -1
- package/dist/adapters/index.cjs +28 -0
- package/dist/adapters/index.cjs.map +1 -0
- package/dist/adapters/index.d.cts +83 -0
- package/dist/adapters/index.js +1 -99
- package/dist/adapters/index.js.map +1 -1
- package/dist/chunk-3A6FU3KV.js +67 -0
- package/dist/chunk-3A6FU3KV.js.map +1 -0
- package/dist/chunk-3F6FKQZA.js +89 -0
- package/dist/chunk-3F6FKQZA.js.map +1 -0
- package/dist/chunk-3ZW5USXF.js +101 -0
- package/dist/chunk-3ZW5USXF.js.map +1 -0
- package/dist/chunk-4YQOGV7H.js +55 -0
- package/dist/chunk-4YQOGV7H.js.map +1 -0
- package/dist/chunk-6FMW4NF6.js +59 -0
- package/dist/chunk-6FMW4NF6.js.map +1 -0
- package/dist/chunk-7KJHGAZY.cjs +99 -0
- package/dist/chunk-7KJHGAZY.cjs.map +1 -0
- package/dist/chunk-GB2PSZ33.cjs +74 -0
- package/dist/chunk-GB2PSZ33.cjs.map +1 -0
- package/dist/chunk-I35B576X.js +30 -0
- package/dist/chunk-I35B576X.js.map +1 -0
- package/dist/chunk-IFMZPLM4.js +27 -0
- package/dist/chunk-IFMZPLM4.js.map +1 -0
- package/dist/chunk-JAXDEK5Z.cjs +63 -0
- package/dist/chunk-JAXDEK5Z.cjs.map +1 -0
- package/dist/chunk-JSTGOT6P.js +181 -0
- package/dist/chunk-JSTGOT6P.js.map +1 -0
- package/dist/chunk-KOC4A7A4.js +544 -0
- package/dist/chunk-KOC4A7A4.js.map +1 -0
- package/dist/chunk-KQEBNUZI.cjs +70 -0
- package/dist/chunk-KQEBNUZI.cjs.map +1 -0
- package/dist/chunk-LHCSVEFT.cjs +8 -0
- package/dist/chunk-LHCSVEFT.cjs.map +1 -0
- package/dist/chunk-LYX73U3P.cjs +195 -0
- package/dist/chunk-LYX73U3P.cjs.map +1 -0
- package/dist/chunk-LZSE6QGQ.cjs +60 -0
- package/dist/chunk-LZSE6QGQ.cjs.map +1 -0
- package/dist/chunk-N24NLCZ6.js +6 -0
- package/dist/chunk-N24NLCZ6.js.map +1 -0
- package/dist/chunk-NPVIFZQV.cjs +107 -0
- package/dist/chunk-NPVIFZQV.cjs.map +1 -0
- package/dist/chunk-OZLZHISS.js +3 -0
- package/dist/chunk-OZLZHISS.js.map +1 -0
- package/dist/chunk-PG5LYTUX.cjs +4 -0
- package/dist/chunk-PG5LYTUX.cjs.map +1 -0
- package/dist/chunk-PXMKCAQI.js +187 -0
- package/dist/chunk-PXMKCAQI.js.map +1 -0
- package/dist/chunk-Q3WYIWCN.cjs +183 -0
- package/dist/chunk-Q3WYIWCN.cjs.map +1 -0
- package/dist/chunk-QETQGAXJ.cjs +35 -0
- package/dist/chunk-QETQGAXJ.cjs.map +1 -0
- package/dist/chunk-RALMUSOX.js +55 -0
- package/dist/chunk-RALMUSOX.js.map +1 -0
- package/dist/chunk-SDXDHVTV.cjs +555 -0
- package/dist/chunk-SDXDHVTV.cjs.map +1 -0
- package/dist/chunk-YZKUEC2J.cjs +31 -0
- package/dist/chunk-YZKUEC2J.cjs.map +1 -0
- package/dist/displays/index.cjs +24 -0
- package/dist/displays/index.cjs.map +1 -0
- package/dist/displays/index.d.cts +34 -0
- package/dist/displays/index.js +1 -87
- package/dist/displays/index.js.map +1 -1
- package/dist/events/index.cjs +36 -0
- package/dist/events/index.cjs.map +1 -0
- package/dist/events/index.d.cts +35 -0
- package/dist/events/index.js +1 -53
- package/dist/events/index.js.map +1 -1
- package/dist/evidence/index.cjs +6 -0
- package/dist/evidence/index.cjs.map +1 -0
- package/dist/evidence/index.d.cts +43 -0
- package/dist/evidence/index.js +1 -1
- package/dist/ids/index.cjs +24 -0
- package/dist/ids/index.cjs.map +1 -0
- package/dist/ids/index.d.cts +19 -0
- package/dist/ids/index.js +1 -53
- package/dist/ids/index.js.map +1 -1
- package/dist/index.cjs +268 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +13 -0
- package/dist/index.js +13 -1355
- package/dist/index.js.map +1 -1
- package/dist/modules/index.cjs +42 -0
- package/dist/modules/index.cjs.map +1 -0
- package/dist/modules/index.d.cts +73 -0
- package/dist/modules/index.js +7 -373
- package/dist/modules/index.js.map +1 -1
- package/dist/objects/index.cjs +24 -0
- package/dist/objects/index.cjs.map +1 -0
- package/dist/objects/index.d.cts +7 -0
- package/dist/objects/index.js +1 -28
- package/dist/objects/index.js.map +1 -1
- package/dist/policies/index.cjs +48 -0
- package/dist/policies/index.cjs.map +1 -0
- package/dist/policies/index.d.cts +143 -0
- package/dist/policies/index.js +1 -542
- package/dist/policies/index.js.map +1 -1
- package/dist/privacy/index.cjs +12 -0
- package/dist/privacy/index.cjs.map +1 -0
- package/dist/privacy/index.d.cts +77 -0
- package/dist/privacy/index.js +1 -4
- package/dist/privacy/index.js.map +1 -1
- package/dist/projections/index.cjs +12 -0
- package/dist/projections/index.cjs.map +1 -0
- package/dist/projections/index.d.cts +52 -0
- package/dist/projections/index.js +1 -179
- package/dist/projections/index.js.map +1 -1
- package/dist/state-machines/index.cjs +32 -0
- package/dist/state-machines/index.cjs.map +1 -0
- package/dist/state-machines/index.d.cts +60 -0
- package/dist/state-machines/index.js +1 -65
- package/dist/state-machines/index.js.map +1 -1
- package/dist/testing/index.cjs +21 -0
- package/dist/testing/index.cjs.map +1 -0
- package/dist/testing/index.d.cts +19 -0
- package/dist/testing/index.js +2 -56
- package/dist/testing/index.js.map +1 -1
- package/package.json +196 -111
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
declare const PLATFORM_PRIVACY_POLICY_VERSION = "fabric-platform-privacy-v1";
|
|
2
|
+
type RedactionMethod = "nullify" | "mask" | "hash" | "tokenize" | "generalize" | "drop";
|
|
3
|
+
type PlatformDataClass = "asset_event" | "read_model" | "raw_payload" | "evidence_packet" | "action_evidence" | "access_event";
|
|
4
|
+
interface RedactionRule {
|
|
5
|
+
fieldPath: string;
|
|
6
|
+
method: RedactionMethod;
|
|
7
|
+
reason: string;
|
|
8
|
+
dataClass?: PlatformDataClass;
|
|
9
|
+
}
|
|
10
|
+
interface DataClassificationRule {
|
|
11
|
+
fieldPath: string;
|
|
12
|
+
classification: string;
|
|
13
|
+
containsDirectIdentifier?: boolean;
|
|
14
|
+
containsSensitiveData?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface AnonymizationContext {
|
|
17
|
+
tenantId: string;
|
|
18
|
+
spaceId?: string | null;
|
|
19
|
+
jobId: string;
|
|
20
|
+
reason: string;
|
|
21
|
+
redactedAt?: Date;
|
|
22
|
+
policyVersion?: string;
|
|
23
|
+
}
|
|
24
|
+
interface AnonymizationFieldMetadata {
|
|
25
|
+
fieldPath: string;
|
|
26
|
+
method: RedactionMethod;
|
|
27
|
+
policyVersion: string;
|
|
28
|
+
jobId: string;
|
|
29
|
+
redactedAt: string;
|
|
30
|
+
reason: string;
|
|
31
|
+
dataClass: PlatformDataClass;
|
|
32
|
+
beforeChecksum: string;
|
|
33
|
+
}
|
|
34
|
+
interface AnonymizationMetadata {
|
|
35
|
+
redactionState: "anonymized";
|
|
36
|
+
policyVersion: string;
|
|
37
|
+
jobId: string;
|
|
38
|
+
redactedAt: string;
|
|
39
|
+
reason: string;
|
|
40
|
+
dataClass: PlatformDataClass;
|
|
41
|
+
redactedFields: AnonymizationFieldMetadata[];
|
|
42
|
+
preservedSemantics: string[];
|
|
43
|
+
}
|
|
44
|
+
interface AnonymizationResult<TValue> {
|
|
45
|
+
value: TValue;
|
|
46
|
+
metadata: AnonymizationMetadata;
|
|
47
|
+
}
|
|
48
|
+
interface AnalyticsDataContractSource {
|
|
49
|
+
name: string;
|
|
50
|
+
privacyClass: "raw" | "operational_pii" | "tenant_scoped_tokenized" | "anonymized" | "aggregated" | "differentially_minimized";
|
|
51
|
+
containsDirectIdentifiers?: boolean;
|
|
52
|
+
containsGloballyStablePersonTokens?: boolean;
|
|
53
|
+
anonymizationPolicyVersion?: string;
|
|
54
|
+
minimumGroupSize?: number;
|
|
55
|
+
}
|
|
56
|
+
interface AnalyticsDataContract {
|
|
57
|
+
contractId: string;
|
|
58
|
+
status: "draft" | "accepted" | "deprecated";
|
|
59
|
+
crossTenant: boolean;
|
|
60
|
+
acceptedBy?: string;
|
|
61
|
+
acceptedAt?: string;
|
|
62
|
+
adrReference?: string;
|
|
63
|
+
sources: AnalyticsDataContractSource[];
|
|
64
|
+
}
|
|
65
|
+
interface AnalyticsEligibilityDecision {
|
|
66
|
+
eligible: boolean;
|
|
67
|
+
policyVersion: string;
|
|
68
|
+
reasons: string[];
|
|
69
|
+
}
|
|
70
|
+
interface RetentionRule {
|
|
71
|
+
dataClass: PlatformDataClass;
|
|
72
|
+
retainForDays: number;
|
|
73
|
+
afterRetention: "delete" | "anonymize" | "archive";
|
|
74
|
+
legalHoldExempt?: boolean;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export { type AnalyticsDataContract, type AnalyticsDataContractSource, type AnalyticsEligibilityDecision, type AnonymizationContext, type AnonymizationFieldMetadata, type AnonymizationMetadata, type AnonymizationResult, type DataClassificationRule, PLATFORM_PRIVACY_POLICY_VERSION, type PlatformDataClass, type RedactionMethod, type RedactionRule, type RetentionRule };
|
package/dist/privacy/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
var PLATFORM_PRIVACY_POLICY_VERSION = "fabric-platform-privacy-v1";
|
|
3
|
-
|
|
4
|
-
export { PLATFORM_PRIVACY_POLICY_VERSION };
|
|
1
|
+
export { PLATFORM_PRIVACY_POLICY_VERSION } from '../chunk-N24NLCZ6.js';
|
|
5
2
|
//# sourceMappingURL=index.js.map
|
|
6
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkQ3WYIWCN_cjs = require('../chunk-Q3WYIWCN.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "replayEvents", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkQ3WYIWCN_cjs.replayEvents; }
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=index.cjs.map
|
|
12
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
interface ReplayableAssetEvent<Payload = unknown> {
|
|
2
|
+
id: string;
|
|
3
|
+
tenantId: string;
|
|
4
|
+
spaceId: string;
|
|
5
|
+
eventType: string;
|
|
6
|
+
subjectType: string;
|
|
7
|
+
subjectId: string;
|
|
8
|
+
payload: Payload;
|
|
9
|
+
sequence: number;
|
|
10
|
+
occurredAt: Date | string;
|
|
11
|
+
recordedAt: Date | string;
|
|
12
|
+
actionInvocationId: string;
|
|
13
|
+
correlationId: string;
|
|
14
|
+
}
|
|
15
|
+
interface ReplayScope {
|
|
16
|
+
tenantId: string;
|
|
17
|
+
spaceId: string;
|
|
18
|
+
subjectType?: string;
|
|
19
|
+
subjectId?: string;
|
|
20
|
+
}
|
|
21
|
+
interface ReplaySnapshot<State = unknown> {
|
|
22
|
+
snapshotData: State;
|
|
23
|
+
eventCursor?: string | null;
|
|
24
|
+
eventSequence?: number | null;
|
|
25
|
+
}
|
|
26
|
+
type ReplayWarningCode = "cursor_not_found" | "duplicate_event" | "missing_sequence" | "subject_scope_incomplete";
|
|
27
|
+
interface ReplayWarning {
|
|
28
|
+
code: ReplayWarningCode;
|
|
29
|
+
message: string;
|
|
30
|
+
eventId?: string;
|
|
31
|
+
subjectType?: string;
|
|
32
|
+
subjectId?: string;
|
|
33
|
+
expectedSequence?: number;
|
|
34
|
+
actualSequence?: number;
|
|
35
|
+
}
|
|
36
|
+
interface ReplayEventsOptions<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent> {
|
|
37
|
+
events: Iterable<Event> | AsyncIterable<Event>;
|
|
38
|
+
scope: ReplayScope;
|
|
39
|
+
initialState: State;
|
|
40
|
+
snapshot?: ReplaySnapshot<State> | null;
|
|
41
|
+
applyEvent: (state: State, event: Event) => State | Promise<State>;
|
|
42
|
+
}
|
|
43
|
+
interface ReplayEventsResult<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent> {
|
|
44
|
+
state: State;
|
|
45
|
+
appliedEvents: Event[];
|
|
46
|
+
warnings: ReplayWarning[];
|
|
47
|
+
eventCursor: string | null;
|
|
48
|
+
eventSequence: number;
|
|
49
|
+
}
|
|
50
|
+
declare function replayEvents<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent>({ events, scope, initialState, snapshot, applyEvent, }: ReplayEventsOptions<State, Event>): Promise<ReplayEventsResult<State, Event>>;
|
|
51
|
+
|
|
52
|
+
export { type ReplayEventsOptions, type ReplayEventsResult, type ReplayScope, type ReplaySnapshot, type ReplayWarning, type ReplayWarningCode, type ReplayableAssetEvent, replayEvents };
|
|
@@ -1,181 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
async function replayEvents({
|
|
3
|
-
events,
|
|
4
|
-
scope,
|
|
5
|
-
initialState,
|
|
6
|
-
snapshot,
|
|
7
|
-
applyEvent
|
|
8
|
-
}) {
|
|
9
|
-
const warnings = [];
|
|
10
|
-
const scopedEvents = filterEventsByScope(await collectEvents(events), scope, warnings);
|
|
11
|
-
const orderedEvents = sortEvents(scopedEvents, isSubjectScoped(scope));
|
|
12
|
-
const uniqueEvents = removeDuplicateEvents(orderedEvents, warnings);
|
|
13
|
-
const resumableEvents = applyCursor(uniqueEvents, snapshot, isSubjectScoped(scope), warnings);
|
|
14
|
-
let state = snapshot?.snapshotData ?? initialState;
|
|
15
|
-
const appliedEvents = [];
|
|
16
|
-
let eventCursor = snapshot?.eventCursor ?? null;
|
|
17
|
-
let eventSequence = snapshot?.eventSequence ?? 0;
|
|
18
|
-
for (const event of resumableEvents) {
|
|
19
|
-
state = await applyEvent(state, event);
|
|
20
|
-
appliedEvents.push(event);
|
|
21
|
-
eventCursor = event.id;
|
|
22
|
-
eventSequence = event.sequence;
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
state,
|
|
26
|
-
appliedEvents,
|
|
27
|
-
warnings,
|
|
28
|
-
eventCursor,
|
|
29
|
-
eventSequence
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
async function collectEvents(events) {
|
|
33
|
-
const collected = [];
|
|
34
|
-
if (Symbol.asyncIterator in events) {
|
|
35
|
-
for await (const event of events) {
|
|
36
|
-
collected.push(event);
|
|
37
|
-
}
|
|
38
|
-
return collected;
|
|
39
|
-
}
|
|
40
|
-
for (const event of events) {
|
|
41
|
-
collected.push(event);
|
|
42
|
-
}
|
|
43
|
-
return collected;
|
|
44
|
-
}
|
|
45
|
-
function filterEventsByScope(events, scope, warnings) {
|
|
46
|
-
if (scope.subjectType && !scope.subjectId || !scope.subjectType && scope.subjectId) {
|
|
47
|
-
warnings.push({
|
|
48
|
-
code: "subject_scope_incomplete",
|
|
49
|
-
message: "Both subjectType and subjectId are required for subject-scoped replay.",
|
|
50
|
-
subjectType: scope.subjectType,
|
|
51
|
-
subjectId: scope.subjectId
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
return events.filter((event) => {
|
|
55
|
-
if (event.tenantId !== scope.tenantId || event.spaceId !== scope.spaceId) {
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
if (scope.subjectType && event.subjectType !== scope.subjectType) {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
if (scope.subjectId && event.subjectId !== scope.subjectId) {
|
|
62
|
-
return false;
|
|
63
|
-
}
|
|
64
|
-
return true;
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
function removeDuplicateEvents(events, warnings) {
|
|
68
|
-
const seenEventIds = /* @__PURE__ */ new Set();
|
|
69
|
-
const uniqueEvents = [];
|
|
70
|
-
for (const event of events) {
|
|
71
|
-
if (seenEventIds.has(event.id)) {
|
|
72
|
-
warnings.push({
|
|
73
|
-
code: "duplicate_event",
|
|
74
|
-
message: `Duplicate event ${event.id} ignored during replay.`,
|
|
75
|
-
eventId: event.id,
|
|
76
|
-
subjectType: event.subjectType,
|
|
77
|
-
subjectId: event.subjectId
|
|
78
|
-
});
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
seenEventIds.add(event.id);
|
|
82
|
-
uniqueEvents.push(event);
|
|
83
|
-
}
|
|
84
|
-
recordMissingSequenceWarnings(uniqueEvents, warnings);
|
|
85
|
-
return uniqueEvents;
|
|
86
|
-
}
|
|
87
|
-
function recordMissingSequenceWarnings(events, warnings) {
|
|
88
|
-
const lastSequenceBySubject = /* @__PURE__ */ new Map();
|
|
89
|
-
for (const event of events) {
|
|
90
|
-
const subjectKey = `${event.subjectType}:${event.subjectId}`;
|
|
91
|
-
const previousSequence = lastSequenceBySubject.get(subjectKey);
|
|
92
|
-
const expectedSequence = previousSequence === void 0 ? event.sequence : previousSequence + 1;
|
|
93
|
-
if (previousSequence !== void 0 && event.sequence > expectedSequence) {
|
|
94
|
-
warnings.push({
|
|
95
|
-
code: "missing_sequence",
|
|
96
|
-
message: `Missing event sequence for ${subjectKey}: expected ${expectedSequence}, received ${event.sequence}.`,
|
|
97
|
-
eventId: event.id,
|
|
98
|
-
subjectType: event.subjectType,
|
|
99
|
-
subjectId: event.subjectId,
|
|
100
|
-
expectedSequence,
|
|
101
|
-
actualSequence: event.sequence
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
lastSequenceBySubject.set(subjectKey, Math.max(previousSequence ?? event.sequence, event.sequence));
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
function applyCursor(events, snapshot, subjectScoped, warnings) {
|
|
108
|
-
const eventCursor = snapshot?.eventCursor;
|
|
109
|
-
if (eventCursor) {
|
|
110
|
-
const cursorIndex = events.findIndex((event) => event.id === eventCursor);
|
|
111
|
-
if (cursorIndex >= 0) {
|
|
112
|
-
return events.slice(cursorIndex + 1);
|
|
113
|
-
}
|
|
114
|
-
warnings.push({
|
|
115
|
-
code: "cursor_not_found",
|
|
116
|
-
message: `Snapshot cursor ${eventCursor} was not found in the scoped event stream.`,
|
|
117
|
-
eventId: eventCursor
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
if (subjectScoped && snapshot?.eventSequence !== void 0 && snapshot.eventSequence !== null) {
|
|
121
|
-
return events.filter((event) => event.sequence > snapshot.eventSequence);
|
|
122
|
-
}
|
|
123
|
-
return events;
|
|
124
|
-
}
|
|
125
|
-
function sortEvents(events, subjectScoped) {
|
|
126
|
-
return [...events].sort(
|
|
127
|
-
(first, second) => subjectScoped ? compareSubjectEvents(first, second) : compareGlobalEvents(first, second)
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
function compareSubjectEvents(first, second) {
|
|
131
|
-
return compareValues(
|
|
132
|
-
[first.sequence, toTimestamp(first.recordedAt), toTimestamp(first.occurredAt), first.id],
|
|
133
|
-
[second.sequence, toTimestamp(second.recordedAt), toTimestamp(second.occurredAt), second.id]
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
function compareGlobalEvents(first, second) {
|
|
137
|
-
return compareValues(
|
|
138
|
-
[
|
|
139
|
-
toTimestamp(first.recordedAt),
|
|
140
|
-
toTimestamp(first.occurredAt),
|
|
141
|
-
first.actionInvocationId,
|
|
142
|
-
first.correlationId,
|
|
143
|
-
first.subjectType,
|
|
144
|
-
first.subjectId,
|
|
145
|
-
first.sequence,
|
|
146
|
-
first.id
|
|
147
|
-
],
|
|
148
|
-
[
|
|
149
|
-
toTimestamp(second.recordedAt),
|
|
150
|
-
toTimestamp(second.occurredAt),
|
|
151
|
-
second.actionInvocationId,
|
|
152
|
-
second.correlationId,
|
|
153
|
-
second.subjectType,
|
|
154
|
-
second.subjectId,
|
|
155
|
-
second.sequence,
|
|
156
|
-
second.id
|
|
157
|
-
]
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
function compareValues(firstValues, secondValues) {
|
|
161
|
-
for (const [index, firstValue] of firstValues.entries()) {
|
|
162
|
-
const secondValue = secondValues[index];
|
|
163
|
-
if (firstValue < secondValue) {
|
|
164
|
-
return -1;
|
|
165
|
-
}
|
|
166
|
-
if (firstValue > secondValue) {
|
|
167
|
-
return 1;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return 0;
|
|
171
|
-
}
|
|
172
|
-
function isSubjectScoped(scope) {
|
|
173
|
-
return Boolean(scope.subjectType && scope.subjectId);
|
|
174
|
-
}
|
|
175
|
-
function toTimestamp(value) {
|
|
176
|
-
return value instanceof Date ? value.getTime() : new Date(value).getTime();
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
export { replayEvents };
|
|
1
|
+
export { replayEvents } from '../chunk-JSTGOT6P.js';
|
|
180
2
|
//# sourceMappingURL=index.js.map
|
|
181
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../projections/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export interface ReplayableAssetEvent<Payload = unknown> {\n\tid: string;\n\ttenantId: string;\n\tspaceId: string;\n\teventType: string;\n\tsubjectType: string;\n\tsubjectId: string;\n\tpayload: Payload;\n\tsequence: number;\n\toccurredAt: Date | string;\n\trecordedAt: Date | string;\n\tactionInvocationId: string;\n\tcorrelationId: string;\n}\n\nexport interface ReplayScope {\n\ttenantId: string;\n\tspaceId: string;\n\tsubjectType?: string;\n\tsubjectId?: string;\n}\n\nexport interface ReplaySnapshot<State = unknown> {\n\tsnapshotData: State;\n\teventCursor?: string | null;\n\teventSequence?: number | null;\n}\n\nexport type ReplayWarningCode =\n\t| \"cursor_not_found\"\n\t| \"duplicate_event\"\n\t| \"missing_sequence\"\n\t| \"subject_scope_incomplete\";\n\nexport interface ReplayWarning {\n\tcode: ReplayWarningCode;\n\tmessage: string;\n\teventId?: string;\n\tsubjectType?: string;\n\tsubjectId?: string;\n\texpectedSequence?: number;\n\tactualSequence?: number;\n}\n\nexport interface ReplayEventsOptions<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent> {\n\tevents: Iterable<Event> | AsyncIterable<Event>;\n\tscope: ReplayScope;\n\tinitialState: State;\n\tsnapshot?: ReplaySnapshot<State> | null;\n\tapplyEvent: (state: State, event: Event) => State | Promise<State>;\n}\n\nexport interface ReplayEventsResult<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent> {\n\tstate: State;\n\tappliedEvents: Event[];\n\twarnings: ReplayWarning[];\n\teventCursor: string | null;\n\teventSequence: number;\n}\n\nexport async function replayEvents<State, Event extends ReplayableAssetEvent = ReplayableAssetEvent>({\n\tevents,\n\tscope,\n\tinitialState,\n\tsnapshot,\n\tapplyEvent,\n}: ReplayEventsOptions<State, Event>): Promise<ReplayEventsResult<State, Event>> {\n\tconst warnings: ReplayWarning[] = [];\n\tconst scopedEvents = filterEventsByScope(await collectEvents(events), scope, warnings);\n\tconst orderedEvents = sortEvents(scopedEvents, isSubjectScoped(scope));\n\tconst uniqueEvents = removeDuplicateEvents(orderedEvents, warnings);\n\tconst resumableEvents = applyCursor(uniqueEvents, snapshot, isSubjectScoped(scope), warnings);\n\n\tlet state = snapshot?.snapshotData ?? initialState;\n\tconst appliedEvents: Event[] = [];\n\tlet eventCursor = snapshot?.eventCursor ?? null;\n\tlet eventSequence = snapshot?.eventSequence ?? 0;\n\n\tfor (const event of resumableEvents) {\n\t\tstate = await applyEvent(state, event);\n\t\tappliedEvents.push(event);\n\t\teventCursor = event.id;\n\t\teventSequence = event.sequence;\n\t}\n\n\treturn {\n\t\tstate,\n\t\tappliedEvents,\n\t\twarnings,\n\t\teventCursor,\n\t\teventSequence,\n\t};\n}\n\nasync function collectEvents<Event extends ReplayableAssetEvent>(\n\tevents: Iterable<Event> | AsyncIterable<Event>,\n): Promise<Event[]> {\n\tconst collected: Event[] = [];\n\n\tif (Symbol.asyncIterator in events) {\n\t\tfor await (const event of events) {\n\t\t\tcollected.push(event);\n\t\t}\n\n\t\treturn collected;\n\t}\n\n\tfor (const event of events) {\n\t\tcollected.push(event);\n\t}\n\n\treturn collected;\n}\n\nfunction filterEventsByScope<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\tscope: ReplayScope,\n\twarnings: ReplayWarning[],\n): Event[] {\n\tif ((scope.subjectType && !scope.subjectId) || (!scope.subjectType && scope.subjectId)) {\n\t\twarnings.push({\n\t\t\tcode: \"subject_scope_incomplete\",\n\t\t\tmessage: \"Both subjectType and subjectId are required for subject-scoped replay.\",\n\t\t\tsubjectType: scope.subjectType,\n\t\t\tsubjectId: scope.subjectId,\n\t\t});\n\t}\n\n\treturn events.filter((event) => {\n\t\tif (event.tenantId !== scope.tenantId || event.spaceId !== scope.spaceId) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (scope.subjectType && event.subjectType !== scope.subjectType) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif (scope.subjectId && event.subjectId !== scope.subjectId) {\n\t\t\treturn false;\n\t\t}\n\n\t\treturn true;\n\t});\n}\n\nfunction removeDuplicateEvents<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\twarnings: ReplayWarning[],\n): Event[] {\n\tconst seenEventIds = new Set<string>();\n\tconst uniqueEvents: Event[] = [];\n\n\tfor (const event of events) {\n\t\tif (seenEventIds.has(event.id)) {\n\t\t\twarnings.push({\n\t\t\t\tcode: \"duplicate_event\",\n\t\t\t\tmessage: `Duplicate event ${event.id} ignored during replay.`,\n\t\t\t\teventId: event.id,\n\t\t\t\tsubjectType: event.subjectType,\n\t\t\t\tsubjectId: event.subjectId,\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\n\t\tseenEventIds.add(event.id);\n\t\tuniqueEvents.push(event);\n\t}\n\n\trecordMissingSequenceWarnings(uniqueEvents, warnings);\n\n\treturn uniqueEvents;\n}\n\nfunction recordMissingSequenceWarnings<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\twarnings: ReplayWarning[],\n): void {\n\tconst lastSequenceBySubject = new Map<string, number>();\n\n\tfor (const event of events) {\n\t\tconst subjectKey = `${event.subjectType}:${event.subjectId}`;\n\t\tconst previousSequence = lastSequenceBySubject.get(subjectKey);\n\t\tconst expectedSequence = previousSequence === undefined ? event.sequence : previousSequence + 1;\n\n\t\tif (previousSequence !== undefined && event.sequence > expectedSequence) {\n\t\t\twarnings.push({\n\t\t\t\tcode: \"missing_sequence\",\n\t\t\t\tmessage: `Missing event sequence for ${subjectKey}: expected ${expectedSequence}, received ${event.sequence}.`,\n\t\t\t\teventId: event.id,\n\t\t\t\tsubjectType: event.subjectType,\n\t\t\t\tsubjectId: event.subjectId,\n\t\t\t\texpectedSequence,\n\t\t\t\tactualSequence: event.sequence,\n\t\t\t});\n\t\t}\n\n\t\tlastSequenceBySubject.set(subjectKey, Math.max(previousSequence ?? event.sequence, event.sequence));\n\t}\n}\n\nfunction applyCursor<Event extends ReplayableAssetEvent>(\n\tevents: Event[],\n\tsnapshot: ReplaySnapshot | null | undefined,\n\tsubjectScoped: boolean,\n\twarnings: ReplayWarning[],\n): Event[] {\n\tconst eventCursor = snapshot?.eventCursor;\n\n\tif (eventCursor) {\n\t\tconst cursorIndex = events.findIndex((event) => event.id === eventCursor);\n\n\t\tif (cursorIndex >= 0) {\n\t\t\treturn events.slice(cursorIndex + 1);\n\t\t}\n\n\t\twarnings.push({\n\t\t\tcode: \"cursor_not_found\",\n\t\t\tmessage: `Snapshot cursor ${eventCursor} was not found in the scoped event stream.`,\n\t\t\teventId: eventCursor,\n\t\t});\n\t}\n\n\tif (subjectScoped && snapshot?.eventSequence !== undefined && snapshot.eventSequence !== null) {\n\t\treturn events.filter((event) => event.sequence > snapshot.eventSequence!);\n\t}\n\n\treturn events;\n}\n\nfunction sortEvents<Event extends ReplayableAssetEvent>(events: Event[], subjectScoped: boolean): Event[] {\n\treturn [...events].sort((first, second) =>\n\t\tsubjectScoped ? compareSubjectEvents(first, second) : compareGlobalEvents(first, second),\n\t);\n}\n\nfunction compareSubjectEvents(first: ReplayableAssetEvent, second: ReplayableAssetEvent): number {\n\treturn compareValues(\n\t\t[first.sequence, toTimestamp(first.recordedAt), toTimestamp(first.occurredAt), first.id],\n\t\t[second.sequence, toTimestamp(second.recordedAt), toTimestamp(second.occurredAt), second.id],\n\t);\n}\n\nfunction compareGlobalEvents(first: ReplayableAssetEvent, second: ReplayableAssetEvent): number {\n\treturn compareValues(\n\t\t[\n\t\t\ttoTimestamp(first.recordedAt),\n\t\t\ttoTimestamp(first.occurredAt),\n\t\t\tfirst.actionInvocationId,\n\t\t\tfirst.correlationId,\n\t\t\tfirst.subjectType,\n\t\t\tfirst.subjectId,\n\t\t\tfirst.sequence,\n\t\t\tfirst.id,\n\t\t],\n\t\t[\n\t\t\ttoTimestamp(second.recordedAt),\n\t\t\ttoTimestamp(second.occurredAt),\n\t\t\tsecond.actionInvocationId,\n\t\t\tsecond.correlationId,\n\t\t\tsecond.subjectType,\n\t\t\tsecond.subjectId,\n\t\t\tsecond.sequence,\n\t\t\tsecond.id,\n\t\t],\n\t);\n}\n\nfunction compareValues(firstValues: Array<number | string>, secondValues: Array<number | string>): number {\n\tfor (const [index, firstValue] of firstValues.entries()) {\n\t\tconst secondValue = secondValues[index];\n\n\t\tif (firstValue < secondValue) {\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (firstValue > secondValue) {\n\t\t\treturn 1;\n\t\t}\n\t}\n\n\treturn 0;\n}\n\nfunction isSubjectScoped(scope: ReplayScope): boolean {\n\treturn Boolean(scope.subjectType && scope.subjectId);\n}\n\nfunction toTimestamp(value: Date | string): number {\n\treturn value instanceof Date ? value.getTime() : new Date(value).getTime();\n}\n"]}
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkGB2PSZ33_cjs = require('../chunk-GB2PSZ33.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "getAllowedTransitions", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkGB2PSZ33_cjs.getAllowedTransitions; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, "getEntityStateClass", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkGB2PSZ33_cjs.getEntityStateClass; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "registerStateMachine", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkGB2PSZ33_cjs.registerStateMachine; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, "registerStateMachineIfMissing", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return chunkGB2PSZ33_cjs.registerStateMachineIfMissing; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, "resolveStateMachine", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return chunkGB2PSZ33_cjs.resolveStateMachine; }
|
|
26
|
+
});
|
|
27
|
+
Object.defineProperty(exports, "validateTransition", {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () { return chunkGB2PSZ33_cjs.validateTransition; }
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=index.cjs.map
|
|
32
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
interface StateMachineDefinition {
|
|
2
|
+
entityType: string;
|
|
3
|
+
states: Record<string, StateDefinition>;
|
|
4
|
+
transitions: Array<{
|
|
5
|
+
from: string;
|
|
6
|
+
to: string;
|
|
7
|
+
causedByAction: string;
|
|
8
|
+
guard?: (ctx: TransitionContext) => boolean | Promise<boolean>;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
type StateMachineDatabaseClient = any;
|
|
12
|
+
interface TransitionContext<TDb = StateMachineDatabaseClient> {
|
|
13
|
+
entity: Record<string, unknown>;
|
|
14
|
+
actionInvocationId: string;
|
|
15
|
+
actorId: string;
|
|
16
|
+
parameters: unknown;
|
|
17
|
+
db: TDb;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Register a state-machine definition for an entity type.
|
|
21
|
+
* Throws if a definition for this entity type is already registered.
|
|
22
|
+
*/
|
|
23
|
+
declare function registerStateMachine(def: StateMachineDefinition): void;
|
|
24
|
+
/**
|
|
25
|
+
* Register a state-machine definition only if one for this entity type
|
|
26
|
+
* is not already registered. Idempotent — safe to call multiple times.
|
|
27
|
+
*/
|
|
28
|
+
declare function registerStateMachineIfMissing(def: StateMachineDefinition): void;
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a previously registered state-machine definition by entity type.
|
|
31
|
+
*/
|
|
32
|
+
declare function resolveStateMachine(entityType: string): StateMachineDefinition | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Validate whether a transition is allowed for the given entity type,
|
|
35
|
+
* from state, to state, and action ID.
|
|
36
|
+
*/
|
|
37
|
+
declare function validateTransition(entityType: string, from: string, to: string, actionId: string): {
|
|
38
|
+
valid: boolean;
|
|
39
|
+
error?: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Get all allowed transitions from a given state for an entity type.
|
|
43
|
+
*/
|
|
44
|
+
declare function getAllowedTransitions(entityType: string, from: string): Array<{
|
|
45
|
+
to: string;
|
|
46
|
+
causedByAction: string;
|
|
47
|
+
}>;
|
|
48
|
+
/**
|
|
49
|
+
* Get the StateClass of a given state for an entity type.
|
|
50
|
+
*/
|
|
51
|
+
declare function getEntityStateClass(entityType: string, state: string): StateClass | undefined;
|
|
52
|
+
|
|
53
|
+
type StateClass = "initial" | "active" | "action_required" | "waiting" | "terminal" | "exception";
|
|
54
|
+
interface StateDefinition {
|
|
55
|
+
id: string;
|
|
56
|
+
label: string;
|
|
57
|
+
stateClass: StateClass;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export { type StateClass, type StateDefinition, type StateMachineDatabaseClient, type StateMachineDefinition, type TransitionContext, getAllowedTransitions, getEntityStateClass, registerStateMachine, registerStateMachineIfMissing, resolveStateMachine, validateTransition };
|
|
@@ -1,67 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
var registry = /* @__PURE__ */ new Map();
|
|
3
|
-
function registerStateMachine(def) {
|
|
4
|
-
if (registry.has(def.entityType)) {
|
|
5
|
-
throw new Error(`State machine for entity type "${def.entityType}" is already registered.`);
|
|
6
|
-
}
|
|
7
|
-
registry.set(def.entityType, def);
|
|
8
|
-
}
|
|
9
|
-
function registerStateMachineIfMissing(def) {
|
|
10
|
-
if (!registry.has(def.entityType)) {
|
|
11
|
-
registerStateMachine(def);
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
function resolveStateMachine(entityType) {
|
|
15
|
-
return registry.get(entityType);
|
|
16
|
-
}
|
|
17
|
-
function validateTransition(entityType, from, to, actionId) {
|
|
18
|
-
const sm = registry.get(entityType);
|
|
19
|
-
if (!sm) {
|
|
20
|
-
return {
|
|
21
|
-
valid: false,
|
|
22
|
-
error: `No state machine registered for entity type "${entityType}".`
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
const fromDef = sm.states[from];
|
|
26
|
-
if (!fromDef) {
|
|
27
|
-
return {
|
|
28
|
-
valid: false,
|
|
29
|
-
error: `State "${from}" does not exist in state machine for entity type "${entityType}".`
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
const toDef = sm.states[to];
|
|
33
|
-
if (!toDef) {
|
|
34
|
-
return {
|
|
35
|
-
valid: false,
|
|
36
|
-
error: `State "${to}" does not exist in state machine for entity type "${entityType}".`
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
const transitionExists = sm.transitions.some(
|
|
40
|
-
(t) => t.from === from && t.to === to && t.causedByAction === actionId
|
|
41
|
-
);
|
|
42
|
-
if (!transitionExists) {
|
|
43
|
-
return {
|
|
44
|
-
valid: false,
|
|
45
|
-
error: `Transition from "${from}" to "${to}" via action "${actionId}" is not defined for entity type "${entityType}".`
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
return { valid: true };
|
|
49
|
-
}
|
|
50
|
-
function getAllowedTransitions(entityType, from) {
|
|
51
|
-
const sm = registry.get(entityType);
|
|
52
|
-
if (!sm) {
|
|
53
|
-
return [];
|
|
54
|
-
}
|
|
55
|
-
return sm.transitions.filter((t) => t.from === from).map((t) => ({ to: t.to, causedByAction: t.causedByAction }));
|
|
56
|
-
}
|
|
57
|
-
function getEntityStateClass(entityType, state) {
|
|
58
|
-
const sm = registry.get(entityType);
|
|
59
|
-
if (!sm) {
|
|
60
|
-
return void 0;
|
|
61
|
-
}
|
|
62
|
-
return sm.states[state]?.stateClass;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export { getAllowedTransitions, getEntityStateClass, registerStateMachine, registerStateMachineIfMissing, resolveStateMachine, validateTransition };
|
|
1
|
+
export { getAllowedTransitions, getEntityStateClass, registerStateMachine, registerStateMachineIfMissing, resolveStateMachine, validateTransition } from '../chunk-3A6FU3KV.js';
|
|
66
2
|
//# sourceMappingURL=index.js.map
|
|
67
3
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkYZKUEC2J_cjs = require('../chunk-YZKUEC2J.cjs');
|
|
4
|
+
require('../chunk-NPVIFZQV.cjs');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Object.defineProperty(exports, "createDeterministicIdFactory", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
get: function () { return chunkYZKUEC2J_cjs.createDeterministicIdFactory; }
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "createFakeActionContext", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () { return chunkYZKUEC2J_cjs.createFakeActionContext; }
|
|
15
|
+
});
|
|
16
|
+
Object.defineProperty(exports, "createInMemoryAdapterRegistry", {
|
|
17
|
+
enumerable: true,
|
|
18
|
+
get: function () { return chunkYZKUEC2J_cjs.createInMemoryAdapterRegistry; }
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=index.cjs.map
|
|
21
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AdapterRegistry } from '../adapters/index.cjs';
|
|
2
|
+
import { ActorType, ActionContext } from '../actions/index.cjs';
|
|
3
|
+
|
|
4
|
+
interface FakeActionContextOptions<TDb = Record<string, never>> {
|
|
5
|
+
actionInvocationId?: string;
|
|
6
|
+
tenantId?: string;
|
|
7
|
+
spaceId?: string;
|
|
8
|
+
actorId?: string;
|
|
9
|
+
actorType?: ActorType;
|
|
10
|
+
correlationId?: string;
|
|
11
|
+
causationId?: string;
|
|
12
|
+
db?: TDb;
|
|
13
|
+
services?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
declare function createFakeActionContext<TDb = Record<string, never>>(options?: FakeActionContextOptions<TDb>): ActionContext<TDb>;
|
|
16
|
+
declare function createInMemoryAdapterRegistry(): AdapterRegistry;
|
|
17
|
+
declare function createDeterministicIdFactory(prefix?: string): () => string;
|
|
18
|
+
|
|
19
|
+
export { type FakeActionContextOptions, createDeterministicIdFactory, createFakeActionContext, createInMemoryAdapterRegistry };
|