@voidhash/mimic-effect 1.0.0-beta.1 → 1.0.0-beta.10

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 (142) hide show
  1. package/.turbo/turbo-build.log +116 -74
  2. package/dist/ColdStorage.cjs +9 -5
  3. package/dist/ColdStorage.d.cts.map +1 -1
  4. package/dist/ColdStorage.d.mts.map +1 -1
  5. package/dist/ColdStorage.mjs +9 -5
  6. package/dist/ColdStorage.mjs.map +1 -1
  7. package/dist/DocumentInstance.cjs +263 -0
  8. package/dist/DocumentInstance.d.cts +78 -0
  9. package/dist/DocumentInstance.d.cts.map +1 -0
  10. package/dist/DocumentInstance.d.mts +78 -0
  11. package/dist/DocumentInstance.d.mts.map +1 -0
  12. package/dist/DocumentInstance.mjs +264 -0
  13. package/dist/DocumentInstance.mjs.map +1 -0
  14. package/dist/Errors.cjs +10 -1
  15. package/dist/Errors.d.cts +18 -3
  16. package/dist/Errors.d.cts.map +1 -1
  17. package/dist/Errors.d.mts +18 -3
  18. package/dist/Errors.d.mts.map +1 -1
  19. package/dist/Errors.mjs +9 -1
  20. package/dist/Errors.mjs.map +1 -1
  21. package/dist/HotStorage.cjs +39 -12
  22. package/dist/HotStorage.d.cts +17 -1
  23. package/dist/HotStorage.d.cts.map +1 -1
  24. package/dist/HotStorage.d.mts +17 -1
  25. package/dist/HotStorage.d.mts.map +1 -1
  26. package/dist/HotStorage.mjs +39 -12
  27. package/dist/HotStorage.mjs.map +1 -1
  28. package/dist/Metrics.cjs +29 -1
  29. package/dist/Metrics.d.cts +5 -0
  30. package/dist/Metrics.d.cts.map +1 -1
  31. package/dist/Metrics.d.mts +5 -0
  32. package/dist/Metrics.d.mts.map +1 -1
  33. package/dist/Metrics.mjs +26 -1
  34. package/dist/Metrics.mjs.map +1 -1
  35. package/dist/MimicClusterServerEngine.cjs +44 -139
  36. package/dist/MimicClusterServerEngine.d.cts.map +1 -1
  37. package/dist/MimicClusterServerEngine.d.mts +1 -1
  38. package/dist/MimicClusterServerEngine.d.mts.map +1 -1
  39. package/dist/MimicClusterServerEngine.mjs +46 -141
  40. package/dist/MimicClusterServerEngine.mjs.map +1 -1
  41. package/dist/MimicServer.cjs +20 -20
  42. package/dist/MimicServer.d.cts.map +1 -1
  43. package/dist/MimicServer.d.mts.map +1 -1
  44. package/dist/MimicServer.mjs +20 -20
  45. package/dist/MimicServer.mjs.map +1 -1
  46. package/dist/MimicServerEngine.cjs +92 -11
  47. package/dist/MimicServerEngine.d.cts +12 -4
  48. package/dist/MimicServerEngine.d.cts.map +1 -1
  49. package/dist/MimicServerEngine.d.mts +12 -4
  50. package/dist/MimicServerEngine.d.mts.map +1 -1
  51. package/dist/MimicServerEngine.mjs +94 -13
  52. package/dist/MimicServerEngine.mjs.map +1 -1
  53. package/dist/PresenceManager.cjs +5 -5
  54. package/dist/PresenceManager.d.cts.map +1 -1
  55. package/dist/PresenceManager.d.mts.map +1 -1
  56. package/dist/PresenceManager.mjs +5 -5
  57. package/dist/PresenceManager.mjs.map +1 -1
  58. package/dist/Protocol.d.cts +1 -1
  59. package/dist/Protocol.d.mts +1 -1
  60. package/dist/Types.d.cts +9 -2
  61. package/dist/Types.d.cts.map +1 -1
  62. package/dist/Types.d.mts +9 -2
  63. package/dist/Types.d.mts.map +1 -1
  64. package/dist/index.cjs +5 -6
  65. package/dist/index.d.cts +3 -3
  66. package/dist/index.d.mts +3 -3
  67. package/dist/index.mjs +3 -3
  68. package/dist/testing/ColdStorageTestSuite.cjs +508 -0
  69. package/dist/testing/ColdStorageTestSuite.d.cts +36 -0
  70. package/dist/testing/ColdStorageTestSuite.d.cts.map +1 -0
  71. package/dist/testing/ColdStorageTestSuite.d.mts +36 -0
  72. package/dist/testing/ColdStorageTestSuite.d.mts.map +1 -0
  73. package/dist/testing/ColdStorageTestSuite.mjs +508 -0
  74. package/dist/testing/ColdStorageTestSuite.mjs.map +1 -0
  75. package/dist/testing/FailingStorage.cjs +162 -0
  76. package/dist/testing/FailingStorage.d.cts +43 -0
  77. package/dist/testing/FailingStorage.d.cts.map +1 -0
  78. package/dist/testing/FailingStorage.d.mts +43 -0
  79. package/dist/testing/FailingStorage.d.mts.map +1 -0
  80. package/dist/testing/FailingStorage.mjs +163 -0
  81. package/dist/testing/FailingStorage.mjs.map +1 -0
  82. package/dist/testing/HotStorageTestSuite.cjs +820 -0
  83. package/dist/testing/HotStorageTestSuite.d.cts +42 -0
  84. package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
  85. package/dist/testing/HotStorageTestSuite.d.mts +42 -0
  86. package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
  87. package/dist/testing/HotStorageTestSuite.mjs +820 -0
  88. package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
  89. package/dist/testing/StorageIntegrationTestSuite.cjs +487 -0
  90. package/dist/testing/StorageIntegrationTestSuite.d.cts +37 -0
  91. package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
  92. package/dist/testing/StorageIntegrationTestSuite.d.mts +37 -0
  93. package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
  94. package/dist/testing/StorageIntegrationTestSuite.mjs +487 -0
  95. package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
  96. package/dist/testing/assertions.cjs +117 -0
  97. package/dist/testing/assertions.mjs +112 -0
  98. package/dist/testing/assertions.mjs.map +1 -0
  99. package/dist/testing/index.cjs +14 -0
  100. package/dist/testing/index.d.cts +6 -0
  101. package/dist/testing/index.d.mts +6 -0
  102. package/dist/testing/index.mjs +7 -0
  103. package/dist/testing/types.cjs +15 -0
  104. package/dist/testing/types.d.cts +90 -0
  105. package/dist/testing/types.d.cts.map +1 -0
  106. package/dist/testing/types.d.mts +90 -0
  107. package/dist/testing/types.d.mts.map +1 -0
  108. package/dist/testing/types.mjs +16 -0
  109. package/dist/testing/types.mjs.map +1 -0
  110. package/package.json +8 -3
  111. package/src/ColdStorage.ts +21 -12
  112. package/src/DocumentInstance.ts +527 -0
  113. package/src/Errors.ts +15 -1
  114. package/src/HotStorage.ts +115 -24
  115. package/src/Metrics.ts +30 -0
  116. package/src/MimicClusterServerEngine.ts +120 -275
  117. package/src/MimicServer.ts +83 -75
  118. package/src/MimicServerEngine.ts +230 -30
  119. package/src/PresenceManager.ts +44 -34
  120. package/src/Types.ts +9 -2
  121. package/src/index.ts +5 -35
  122. package/src/testing/ColdStorageTestSuite.ts +589 -0
  123. package/src/testing/FailingStorage.ts +338 -0
  124. package/src/testing/HotStorageTestSuite.ts +1105 -0
  125. package/src/testing/StorageIntegrationTestSuite.ts +736 -0
  126. package/src/testing/assertions.ts +188 -0
  127. package/src/testing/index.ts +83 -0
  128. package/src/testing/types.ts +100 -0
  129. package/tests/ColdStorage.test.ts +8 -120
  130. package/tests/DocumentInstance.test.ts +669 -0
  131. package/tests/HotStorage.test.ts +7 -126
  132. package/tests/StorageIntegration.test.ts +259 -0
  133. package/tsdown.config.ts +1 -1
  134. package/dist/DocumentManager.cjs +0 -229
  135. package/dist/DocumentManager.d.cts +0 -59
  136. package/dist/DocumentManager.d.cts.map +0 -1
  137. package/dist/DocumentManager.d.mts +0 -59
  138. package/dist/DocumentManager.d.mts.map +0 -1
  139. package/dist/DocumentManager.mjs +0 -227
  140. package/dist/DocumentManager.mjs.map +0 -1
  141. package/src/DocumentManager.ts +0 -506
  142. package/tests/DocumentManager.test.ts +0 -335
@@ -1,335 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { Effect, Layer, Stream, Fiber, Duration } from "effect";
3
- import { Primitive, Document, Transaction } from "@voidhash/mimic";
4
- import {
5
- DocumentManager,
6
- DocumentManagerTag,
7
- DocumentManagerConfigTag,
8
- } from "../src/DocumentManager";
9
- import { ColdStorage } from "../src/ColdStorage";
10
- import { HotStorage } from "../src/HotStorage";
11
- import type { ResolvedConfig } from "../src/Types";
12
-
13
- // =============================================================================
14
- // Test Schema
15
- // =============================================================================
16
-
17
- const TestSchema = Primitive.Struct({
18
- title: Primitive.String().default(""),
19
- count: Primitive.Number().default(0),
20
- });
21
-
22
- // =============================================================================
23
- // Test Layer
24
- // =============================================================================
25
-
26
- const makeTestLayer = (options?: {
27
- initial?: { title?: string; count?: number };
28
- }) => {
29
- const config: ResolvedConfig<typeof TestSchema> = {
30
- schema: TestSchema,
31
- initial: options?.initial,
32
- presence: undefined,
33
- maxIdleTime: Duration.minutes(5),
34
- maxTransactionHistory: 100,
35
- snapshot: {
36
- interval: Duration.minutes(5),
37
- transactionThreshold: 100,
38
- },
39
- };
40
-
41
- const configLayer = Layer.succeed(
42
- DocumentManagerConfigTag,
43
- config as ResolvedConfig<Primitive.AnyPrimitive>
44
- );
45
-
46
- return DocumentManager.layer.pipe(
47
- Layer.provide(configLayer),
48
- Layer.provide(ColdStorage.InMemory.make()),
49
- Layer.provide(HotStorage.InMemory.make())
50
- );
51
- };
52
-
53
- // =============================================================================
54
- // Helper Functions
55
- // =============================================================================
56
-
57
- const createValidTransaction = (
58
- id: string,
59
- title: string
60
- ): Transaction.Transaction => {
61
- const doc = Document.make(TestSchema);
62
- doc.transaction((root) => {
63
- root.title.set(title);
64
- });
65
- const tx = doc.flush();
66
- return { ...tx, id };
67
- };
68
-
69
- const createEmptyTransaction = (id: string): Transaction.Transaction => ({
70
- id,
71
- ops: [],
72
- timestamp: Date.now(),
73
- });
74
-
75
- // =============================================================================
76
- // DocumentManager Tests
77
- // =============================================================================
78
-
79
- describe("DocumentManager", () => {
80
- describe("submit", () => {
81
- it("should accept valid transactions", async () => {
82
- const result = await Effect.runPromise(
83
- Effect.scoped(
84
- Effect.gen(function* () {
85
- const manager = yield* DocumentManagerTag;
86
- const tx = createValidTransaction("tx-1", "Hello World");
87
- return yield* manager.submit("doc-1", tx);
88
- })
89
- ).pipe(Effect.provide(makeTestLayer()))
90
- );
91
-
92
- expect(result.success).toBe(true);
93
- if (result.success) {
94
- expect(result.version).toBe(1);
95
- }
96
- });
97
-
98
- it("should reject empty transactions", async () => {
99
- const result = await Effect.runPromise(
100
- Effect.scoped(
101
- Effect.gen(function* () {
102
- const manager = yield* DocumentManagerTag;
103
- const tx = createEmptyTransaction("tx-empty");
104
- return yield* manager.submit("doc-1", tx);
105
- })
106
- ).pipe(Effect.provide(makeTestLayer()))
107
- );
108
-
109
- expect(result.success).toBe(false);
110
- if (!result.success) {
111
- expect(result.reason).toBe("Transaction is empty");
112
- }
113
- });
114
-
115
- it("should reject duplicate transactions", async () => {
116
- const result = await Effect.runPromise(
117
- Effect.scoped(
118
- Effect.gen(function* () {
119
- const manager = yield* DocumentManagerTag;
120
- const tx = createValidTransaction("tx-dup", "First");
121
-
122
- const first = yield* manager.submit("doc-1", tx);
123
- const second = yield* manager.submit("doc-1", tx);
124
-
125
- return { first, second };
126
- })
127
- ).pipe(Effect.provide(makeTestLayer()))
128
- );
129
-
130
- expect(result.first.success).toBe(true);
131
- expect(result.second.success).toBe(false);
132
- if (!result.second.success) {
133
- expect(result.second.reason).toBe(
134
- "Transaction has already been processed"
135
- );
136
- }
137
- });
138
-
139
- it("should increment version with each successful transaction", async () => {
140
- const result = await Effect.runPromise(
141
- Effect.scoped(
142
- Effect.gen(function* () {
143
- const manager = yield* DocumentManagerTag;
144
-
145
- const tx1 = createValidTransaction("tx-1", "One");
146
- const tx2 = createValidTransaction("tx-2", "Two");
147
- const tx3 = createValidTransaction("tx-3", "Three");
148
-
149
- const r1 = yield* manager.submit("doc-1", tx1);
150
- const r2 = yield* manager.submit("doc-1", tx2);
151
- const r3 = yield* manager.submit("doc-1", tx3);
152
-
153
- return { r1, r2, r3 };
154
- })
155
- ).pipe(Effect.provide(makeTestLayer()))
156
- );
157
-
158
- expect(result.r1.success).toBe(true);
159
- expect(result.r2.success).toBe(true);
160
- expect(result.r3.success).toBe(true);
161
-
162
- if (result.r1.success && result.r2.success && result.r3.success) {
163
- expect(result.r1.version).toBe(1);
164
- expect(result.r2.version).toBe(2);
165
- expect(result.r3.version).toBe(3);
166
- }
167
- });
168
-
169
- it("should handle different documents independently", async () => {
170
- const result = await Effect.runPromise(
171
- Effect.scoped(
172
- Effect.gen(function* () {
173
- const manager = yield* DocumentManagerTag;
174
-
175
- const txDoc1 = createValidTransaction("tx-doc1", "Doc 1");
176
- const txDoc2 = createValidTransaction("tx-doc2", "Doc 2");
177
-
178
- const r1 = yield* manager.submit("doc-1", txDoc1);
179
- const r2 = yield* manager.submit("doc-2", txDoc2);
180
-
181
- return { r1, r2 };
182
- })
183
- ).pipe(Effect.provide(makeTestLayer()))
184
- );
185
-
186
- expect(result.r1.success).toBe(true);
187
- expect(result.r2.success).toBe(true);
188
-
189
- if (result.r1.success && result.r2.success) {
190
- expect(result.r1.version).toBe(1);
191
- expect(result.r2.version).toBe(1);
192
- }
193
- });
194
- });
195
-
196
- describe("getSnapshot", () => {
197
- it("should return initial snapshot for new document", async () => {
198
- const result = await Effect.runPromise(
199
- Effect.scoped(
200
- Effect.gen(function* () {
201
- const manager = yield* DocumentManagerTag;
202
- return yield* manager.getSnapshot("new-doc");
203
- })
204
- ).pipe(Effect.provide(makeTestLayer()))
205
- );
206
-
207
- expect(result.type).toBe("snapshot");
208
- expect(result.version).toBe(0);
209
- expect(result.state).toEqual({ title: "", count: 0 });
210
- });
211
-
212
- it("should return current state after transactions", async () => {
213
- const result = await Effect.runPromise(
214
- Effect.scoped(
215
- Effect.gen(function* () {
216
- const manager = yield* DocumentManagerTag;
217
-
218
- const tx = createValidTransaction("tx-1", "Updated Title");
219
- yield* manager.submit("doc-1", tx);
220
-
221
- return yield* manager.getSnapshot("doc-1");
222
- })
223
- ).pipe(Effect.provide(makeTestLayer()))
224
- );
225
-
226
- expect(result.type).toBe("snapshot");
227
- expect(result.version).toBe(1);
228
- expect((result.state as { title: string }).title).toBe("Updated Title");
229
- });
230
-
231
- it("should use initial state for new documents", async () => {
232
- const result = await Effect.runPromise(
233
- Effect.scoped(
234
- Effect.gen(function* () {
235
- const manager = yield* DocumentManagerTag;
236
- return yield* manager.getSnapshot("new-doc");
237
- })
238
- ).pipe(
239
- Effect.provide(
240
- makeTestLayer({ initial: { title: "Initial Title", count: 42 } })
241
- )
242
- )
243
- );
244
-
245
- expect(result.type).toBe("snapshot");
246
- expect(result.version).toBe(0);
247
- expect(result.state).toEqual({ title: "Initial Title", count: 42 });
248
- });
249
- });
250
-
251
- describe("subscribe", () => {
252
- it("should receive broadcasts for submitted transactions", async () => {
253
- const result = await Effect.runPromise(
254
- Effect.scoped(
255
- Effect.gen(function* () {
256
- const manager = yield* DocumentManagerTag;
257
-
258
- const broadcastStream = yield* manager.subscribe("doc-1");
259
-
260
- const collectFiber = yield* Effect.fork(
261
- broadcastStream.pipe(Stream.take(1), Stream.runCollect)
262
- );
263
-
264
- yield* Effect.sleep(50);
265
-
266
- const tx = createValidTransaction("tx-broadcast", "Broadcast Test");
267
- yield* manager.submit("doc-1", tx);
268
-
269
- const broadcasts = yield* Fiber.join(collectFiber).pipe(
270
- Effect.timeout(2000)
271
- );
272
-
273
- return broadcasts;
274
- })
275
- ).pipe(Effect.provide(makeTestLayer()))
276
- );
277
-
278
- expect(result).toBeDefined();
279
- if (result) {
280
- const broadcasts = Array.from(result);
281
- expect(broadcasts.length).toBe(1);
282
- expect(broadcasts[0]!.type).toBe("transaction");
283
- }
284
- });
285
-
286
- it("should broadcast to multiple subscribers", async () => {
287
- const result = await Effect.runPromise(
288
- Effect.scoped(
289
- Effect.gen(function* () {
290
- const manager = yield* DocumentManagerTag;
291
-
292
- const stream1 = yield* manager.subscribe("doc-1");
293
- const stream2 = yield* manager.subscribe("doc-1");
294
-
295
- const collectFiber1 = yield* Effect.fork(
296
- stream1.pipe(Stream.take(1), Stream.runCollect)
297
- );
298
- const collectFiber2 = yield* Effect.fork(
299
- stream2.pipe(Stream.take(1), Stream.runCollect)
300
- );
301
-
302
- yield* Effect.sleep(50);
303
-
304
- const tx = createValidTransaction("tx-multi", "Multi Broadcast");
305
- yield* manager.submit("doc-1", tx);
306
-
307
- const broadcasts1 = yield* Fiber.join(collectFiber1).pipe(
308
- Effect.timeout(2000)
309
- );
310
- const broadcasts2 = yield* Fiber.join(collectFiber2).pipe(
311
- Effect.timeout(2000)
312
- );
313
-
314
- return { broadcasts1, broadcasts2 };
315
- })
316
- ).pipe(Effect.provide(makeTestLayer()))
317
- );
318
-
319
- expect(result.broadcasts1).toBeDefined();
320
- expect(result.broadcasts2).toBeDefined();
321
- if (result.broadcasts1 && result.broadcasts2) {
322
- expect(Array.from(result.broadcasts1).length).toBe(1);
323
- expect(Array.from(result.broadcasts2).length).toBe(1);
324
- }
325
- });
326
- });
327
-
328
- describe("Tag", () => {
329
- it("should have correct identifier", () => {
330
- expect(DocumentManagerTag.key).toBe(
331
- "@voidhash/mimic-effect/DocumentManager"
332
- );
333
- });
334
- });
335
- });