@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.
Files changed (122) hide show
  1. package/dist/actions/index.cjs +48 -0
  2. package/dist/actions/index.cjs.map +1 -0
  3. package/dist/actions/index.d.cts +116 -0
  4. package/dist/actions/index.js +1 -57
  5. package/dist/actions/index.js.map +1 -1
  6. package/dist/adapters/index.cjs +28 -0
  7. package/dist/adapters/index.cjs.map +1 -0
  8. package/dist/adapters/index.d.cts +83 -0
  9. package/dist/adapters/index.js +1 -99
  10. package/dist/adapters/index.js.map +1 -1
  11. package/dist/chunk-3A6FU3KV.js +67 -0
  12. package/dist/chunk-3A6FU3KV.js.map +1 -0
  13. package/dist/chunk-3F6FKQZA.js +89 -0
  14. package/dist/chunk-3F6FKQZA.js.map +1 -0
  15. package/dist/chunk-3ZW5USXF.js +101 -0
  16. package/dist/chunk-3ZW5USXF.js.map +1 -0
  17. package/dist/chunk-4YQOGV7H.js +55 -0
  18. package/dist/chunk-4YQOGV7H.js.map +1 -0
  19. package/dist/chunk-6FMW4NF6.js +59 -0
  20. package/dist/chunk-6FMW4NF6.js.map +1 -0
  21. package/dist/chunk-7KJHGAZY.cjs +99 -0
  22. package/dist/chunk-7KJHGAZY.cjs.map +1 -0
  23. package/dist/chunk-GB2PSZ33.cjs +74 -0
  24. package/dist/chunk-GB2PSZ33.cjs.map +1 -0
  25. package/dist/chunk-I35B576X.js +30 -0
  26. package/dist/chunk-I35B576X.js.map +1 -0
  27. package/dist/chunk-IFMZPLM4.js +27 -0
  28. package/dist/chunk-IFMZPLM4.js.map +1 -0
  29. package/dist/chunk-JAXDEK5Z.cjs +63 -0
  30. package/dist/chunk-JAXDEK5Z.cjs.map +1 -0
  31. package/dist/chunk-JSTGOT6P.js +181 -0
  32. package/dist/chunk-JSTGOT6P.js.map +1 -0
  33. package/dist/chunk-KOC4A7A4.js +544 -0
  34. package/dist/chunk-KOC4A7A4.js.map +1 -0
  35. package/dist/chunk-KQEBNUZI.cjs +70 -0
  36. package/dist/chunk-KQEBNUZI.cjs.map +1 -0
  37. package/dist/chunk-LHCSVEFT.cjs +8 -0
  38. package/dist/chunk-LHCSVEFT.cjs.map +1 -0
  39. package/dist/chunk-LYX73U3P.cjs +195 -0
  40. package/dist/chunk-LYX73U3P.cjs.map +1 -0
  41. package/dist/chunk-LZSE6QGQ.cjs +60 -0
  42. package/dist/chunk-LZSE6QGQ.cjs.map +1 -0
  43. package/dist/chunk-N24NLCZ6.js +6 -0
  44. package/dist/chunk-N24NLCZ6.js.map +1 -0
  45. package/dist/chunk-NPVIFZQV.cjs +107 -0
  46. package/dist/chunk-NPVIFZQV.cjs.map +1 -0
  47. package/dist/chunk-OZLZHISS.js +3 -0
  48. package/dist/chunk-OZLZHISS.js.map +1 -0
  49. package/dist/chunk-PG5LYTUX.cjs +4 -0
  50. package/dist/chunk-PG5LYTUX.cjs.map +1 -0
  51. package/dist/chunk-PXMKCAQI.js +187 -0
  52. package/dist/chunk-PXMKCAQI.js.map +1 -0
  53. package/dist/chunk-Q3WYIWCN.cjs +183 -0
  54. package/dist/chunk-Q3WYIWCN.cjs.map +1 -0
  55. package/dist/chunk-QETQGAXJ.cjs +35 -0
  56. package/dist/chunk-QETQGAXJ.cjs.map +1 -0
  57. package/dist/chunk-RALMUSOX.js +55 -0
  58. package/dist/chunk-RALMUSOX.js.map +1 -0
  59. package/dist/chunk-SDXDHVTV.cjs +555 -0
  60. package/dist/chunk-SDXDHVTV.cjs.map +1 -0
  61. package/dist/chunk-YZKUEC2J.cjs +31 -0
  62. package/dist/chunk-YZKUEC2J.cjs.map +1 -0
  63. package/dist/displays/index.cjs +24 -0
  64. package/dist/displays/index.cjs.map +1 -0
  65. package/dist/displays/index.d.cts +34 -0
  66. package/dist/displays/index.js +1 -87
  67. package/dist/displays/index.js.map +1 -1
  68. package/dist/events/index.cjs +36 -0
  69. package/dist/events/index.cjs.map +1 -0
  70. package/dist/events/index.d.cts +35 -0
  71. package/dist/events/index.js +1 -53
  72. package/dist/events/index.js.map +1 -1
  73. package/dist/evidence/index.cjs +6 -0
  74. package/dist/evidence/index.cjs.map +1 -0
  75. package/dist/evidence/index.d.cts +43 -0
  76. package/dist/evidence/index.js +1 -1
  77. package/dist/ids/index.cjs +24 -0
  78. package/dist/ids/index.cjs.map +1 -0
  79. package/dist/ids/index.d.cts +19 -0
  80. package/dist/ids/index.js +1 -53
  81. package/dist/ids/index.js.map +1 -1
  82. package/dist/index.cjs +268 -0
  83. package/dist/index.cjs.map +1 -0
  84. package/dist/index.d.cts +13 -0
  85. package/dist/index.js +13 -1355
  86. package/dist/index.js.map +1 -1
  87. package/dist/modules/index.cjs +42 -0
  88. package/dist/modules/index.cjs.map +1 -0
  89. package/dist/modules/index.d.cts +73 -0
  90. package/dist/modules/index.js +7 -373
  91. package/dist/modules/index.js.map +1 -1
  92. package/dist/objects/index.cjs +24 -0
  93. package/dist/objects/index.cjs.map +1 -0
  94. package/dist/objects/index.d.cts +7 -0
  95. package/dist/objects/index.js +1 -28
  96. package/dist/objects/index.js.map +1 -1
  97. package/dist/policies/index.cjs +48 -0
  98. package/dist/policies/index.cjs.map +1 -0
  99. package/dist/policies/index.d.cts +143 -0
  100. package/dist/policies/index.js +1 -542
  101. package/dist/policies/index.js.map +1 -1
  102. package/dist/privacy/index.cjs +12 -0
  103. package/dist/privacy/index.cjs.map +1 -0
  104. package/dist/privacy/index.d.cts +77 -0
  105. package/dist/privacy/index.js +1 -4
  106. package/dist/privacy/index.js.map +1 -1
  107. package/dist/projections/index.cjs +12 -0
  108. package/dist/projections/index.cjs.map +1 -0
  109. package/dist/projections/index.d.cts +52 -0
  110. package/dist/projections/index.js +1 -179
  111. package/dist/projections/index.js.map +1 -1
  112. package/dist/state-machines/index.cjs +32 -0
  113. package/dist/state-machines/index.cjs.map +1 -0
  114. package/dist/state-machines/index.d.cts +60 -0
  115. package/dist/state-machines/index.js +1 -65
  116. package/dist/state-machines/index.js.map +1 -1
  117. package/dist/testing/index.cjs +21 -0
  118. package/dist/testing/index.cjs.map +1 -0
  119. package/dist/testing/index.d.cts +19 -0
  120. package/dist/testing/index.js +2 -56
  121. package/dist/testing/index.js.map +1 -1
  122. package/package.json +196 -111
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../events/index.ts"],"names":[],"mappings":";;;AAmBA,IAAM,mBAAA,uBAA0B,GAAA,CAAY;AAAA,EAC3C,kBAAA;AAAA,EACA,kBAAA;AAAA,EACA;AACD,CAAC,CAAA;AAED,IAAM,iBAAA,uBAAwB,GAAA,CAAY;AAAA,EACzC,mBAAA;AAAA,EACA,mBAAA;AAAA,EACA,0BAAA;AAAA,EACA,4BAAA;AAAA,EACA,yBAAA;AAAA,EACA;AACD,CAAC,CAAA;AAED,IAAM,mBAAA,uBAA0B,GAAA,EAAY;AAC5C,IAAM,iBAAA,uBAAwB,GAAA,EAAY;AAMnC,SAAS,oBAAoB,IAAA,EAAoB;AACvD,EAAA,mBAAA,CAAoB,IAAI,IAAI,CAAA;AAC7B;AAEO,SAAS,mBAAmB,IAAA,EAAuB;AACzD,EAAA,OAAO,oBAAoB,GAAA,CAAI,IAAI,CAAA,IAAK,mBAAA,CAAoB,IAAI,IAAI,CAAA;AACrE;AAEO,SAAS,yBAAA,GAAsC;AACrD,EAAA,OAAO,KAAA,CAAM,IAAA,iBAAK,IAAI,GAAA,CAAI,CAAC,GAAG,mBAAA,EAAqB,GAAG,mBAAmB,CAAC,CAAC,CAAA;AAC5E;AAEO,SAAS,kBAAkB,IAAA,EAAoB;AACrD,EAAA,iBAAA,CAAkB,IAAI,IAAI,CAAA;AAC3B;AAEO,SAAS,iBAAiB,IAAA,EAAuB;AACvD,EAAA,OAAO,kBAAkB,GAAA,CAAI,IAAI,CAAA,IAAK,iBAAA,CAAkB,IAAI,IAAI,CAAA;AACjE;AAEO,SAAS,uBAAA,GAAoC;AACnD,EAAA,OAAO,KAAA,CAAM,IAAA,iBAAK,IAAI,GAAA,CAAI,CAAC,GAAG,iBAAA,EAAmB,GAAG,iBAAiB,CAAC,CAAC,CAAA;AACxE;AAQO,SAAS,uBAAA,CAAwB,iBAAA,GAA8B,EAAC,EAAsB;AAC5F,EAAA,MAAM,UAAA,GAAa,IAAI,GAAA,CAAI,iBAAiB,CAAA;AAC5C,EAAA,OAAO;AAAA,IACN,SAAS,SAAA,EAAW;AACnB,MAAA,IAAI,CAAC,SAAA,EAAW;AACf,QAAA,MAAM,IAAI,MAAM,4BAA4B,CAAA;AAAA,MAC7C;AACA,MAAA,UAAA,CAAW,IAAI,SAAS,CAAA;AAAA,IACzB,CAAA;AAAA,IACA,IAAI,SAAA,EAAW;AACd,MAAA,OAAO,UAAA,CAAW,IAAI,SAAS,CAAA;AAAA,IAChC,CAAA;AAAA,IACA,IAAA,GAAO;AACN,MAAA,OAAO,KAAA,CAAM,IAAA,CAAK,UAAU,CAAA,CAAE,IAAA,EAAK;AAAA,IACpC;AAAA,GACD;AACD","file":"chunk-JAXDEK5Z.cjs","sourcesContent":["export interface AssetEventEnvelope<TPayload = unknown> {\n\tid: string;\n\ttenantId: string;\n\tspaceId: string;\n\teventType: string;\n\teventSchemaVersion: number;\n\tsubjectType: string;\n\tsubjectId: string;\n\tactorId: string;\n\tactorType: string;\n\tactionInvocationId?: string;\n\tpayload: TPayload;\n\tsequence: number;\n\toccurredAt: Date;\n\trecordedAt: Date;\n\tcorrelationId: string;\n\tcausationId?: string;\n}\n\nconst subjectTypeRegistry = new Set<string>([\n\t\"ActionInvocation\",\n\t\"PolicyEvaluation\",\n\t\"AdapterInvocation\",\n]);\n\nconst eventTypeRegistry = new Set<string>([\n\t\"ComplianceBlocked\",\n\t\"StateTransitioned\",\n\t\"AdapterInvocationStarted\",\n\t\"AdapterInvocationSucceeded\",\n\t\"AdapterInvocationFailed\",\n\t\"WebhookReceived\",\n]);\n\nconst dynamicSubjectTypes = new Set<string>();\nconst dynamicEventTypes = new Set<string>();\n\nexport type AssetEventSubjectType = string;\nexport type AssetEventType = string;\nexport type AssetEventActorType = \"natural_person\" | \"agent\" | \"adapter\" | \"system\" | \"service_account\" | \"external_system\" | \"integration\";\n\nexport function registerSubjectType(type: string): void {\n\tdynamicSubjectTypes.add(type);\n}\n\nexport function isValidSubjectType(type: string): boolean {\n\treturn subjectTypeRegistry.has(type) || dynamicSubjectTypes.has(type);\n}\n\nexport function getRegisteredSubjectTypes(): string[] {\n\treturn Array.from(new Set([...subjectTypeRegistry, ...dynamicSubjectTypes]));\n}\n\nexport function registerEventType(type: string): void {\n\tdynamicEventTypes.add(type);\n}\n\nexport function isValidEventType(type: string): boolean {\n\treturn eventTypeRegistry.has(type) || dynamicEventTypes.has(type);\n}\n\nexport function getRegisteredEventTypes(): string[] {\n\treturn Array.from(new Set([...eventTypeRegistry, ...dynamicEventTypes]));\n}\n\nexport interface EventTypeRegistry {\n\tregister(eventType: string): void;\n\thas(eventType: string): boolean;\n\tlist(): string[];\n}\n\nexport function createEventTypeRegistry(initialEventTypes: string[] = []): EventTypeRegistry {\n\tconst eventTypes = new Set(initialEventTypes);\n\treturn {\n\t\tregister(eventType) {\n\t\t\tif (!eventType) {\n\t\t\t\tthrow new Error(\"Event type cannot be empty\");\n\t\t\t}\n\t\t\teventTypes.add(eventType);\n\t\t},\n\t\thas(eventType) {\n\t\t\treturn eventTypes.has(eventType);\n\t\t},\n\t\tlist() {\n\t\t\treturn Array.from(eventTypes).sort();\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,181 @@
1
+ // projections/index.ts
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 };
180
+ //# sourceMappingURL=chunk-JSTGOT6P.js.map
181
+ //# sourceMappingURL=chunk-JSTGOT6P.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../projections/index.ts"],"names":[],"mappings":"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","file":"chunk-JSTGOT6P.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"]}