@voidhash/mimic-effect 1.0.0-beta.16 → 1.0.0-beta.18
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/ColdStorage.cjs +1 -1
- package/dist/ColdStorage.d.cts +2 -2
- package/dist/ColdStorage.d.cts.map +1 -1
- package/dist/ColdStorage.d.mts +2 -2
- package/dist/ColdStorage.d.mts.map +1 -1
- package/dist/ColdStorage.mjs +2 -2
- package/dist/ColdStorage.mjs.map +1 -1
- package/dist/DocumentInstance.cjs +13 -13
- package/dist/DocumentInstance.mjs +13 -13
- package/dist/DocumentInstance.mjs.map +1 -1
- package/dist/Errors.d.cts +8 -8
- package/dist/Errors.d.cts.map +1 -1
- package/dist/Errors.d.mts +8 -8
- package/dist/Errors.d.mts.map +1 -1
- package/dist/HotStorage.cjs +1 -1
- package/dist/HotStorage.d.cts +2 -2
- package/dist/HotStorage.d.mts +2 -2
- package/dist/HotStorage.mjs +2 -2
- package/dist/HotStorage.mjs.map +1 -1
- package/dist/Metrics.cjs +6 -6
- package/dist/Metrics.d.cts +21 -23
- package/dist/Metrics.d.cts.map +1 -1
- package/dist/Metrics.d.mts +21 -23
- package/dist/Metrics.d.mts.map +1 -1
- package/dist/Metrics.mjs +7 -7
- package/dist/Metrics.mjs.map +1 -1
- package/dist/MimicAuthService.cjs +1 -1
- package/dist/MimicAuthService.d.cts +2 -2
- package/dist/MimicAuthService.d.cts.map +1 -1
- package/dist/MimicAuthService.d.mts +2 -2
- package/dist/MimicAuthService.d.mts.map +1 -1
- package/dist/MimicAuthService.mjs +2 -2
- package/dist/MimicAuthService.mjs.map +1 -1
- package/dist/MimicClusterServerEngine.cjs +38 -41
- package/dist/MimicClusterServerEngine.d.cts +1 -1
- package/dist/MimicClusterServerEngine.d.mts +1 -1
- package/dist/MimicClusterServerEngine.mjs +31 -34
- package/dist/MimicClusterServerEngine.mjs.map +1 -1
- package/dist/MimicServer.cjs +23 -23
- package/dist/MimicServer.d.cts +3 -3
- package/dist/MimicServer.d.cts.map +1 -1
- package/dist/MimicServer.d.mts +3 -3
- package/dist/MimicServer.d.mts.map +1 -1
- package/dist/MimicServer.mjs +22 -22
- package/dist/MimicServer.mjs.map +1 -1
- package/dist/MimicServerEngine.cjs +13 -13
- package/dist/MimicServerEngine.d.cts +2 -2
- package/dist/MimicServerEngine.d.mts +2 -2
- package/dist/MimicServerEngine.mjs +14 -14
- package/dist/MimicServerEngine.mjs.map +1 -1
- package/dist/PresenceManager.cjs +4 -4
- package/dist/PresenceManager.d.cts +2 -2
- package/dist/PresenceManager.d.mts +2 -2
- package/dist/PresenceManager.mjs +5 -5
- package/dist/PresenceManager.mjs.map +1 -1
- package/dist/Types.d.cts +1 -1
- package/dist/Types.d.mts +1 -1
- package/dist/testing/ColdStorageTestSuite.cjs +3 -3
- package/dist/testing/ColdStorageTestSuite.mjs +3 -3
- package/dist/testing/ColdStorageTestSuite.mjs.map +1 -1
- package/dist/testing/HotStorageTestSuite.cjs +13 -13
- package/dist/testing/HotStorageTestSuite.mjs +13 -13
- package/dist/testing/HotStorageTestSuite.mjs.map +1 -1
- package/dist/testing/StorageIntegrationTestSuite.cjs +3 -3
- package/dist/testing/StorageIntegrationTestSuite.mjs +3 -3
- package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -1
- package/dist/testing/types.d.cts +3 -3
- package/dist/testing/types.d.cts.map +1 -1
- package/dist/testing/types.d.mts +1 -1
- package/dist/testing/types.d.mts.map +1 -1
- package/package.json +17 -21
- package/src/ColdStorage.ts +4 -5
- package/src/DocumentInstance.ts +13 -13
- package/src/HotStorage.ts +3 -3
- package/src/Metrics.ts +22 -16
- package/src/MimicAuthService.ts +3 -3
- package/src/MimicClusterServerEngine.ts +35 -35
- package/src/MimicServer.ts +26 -30
- package/src/MimicServerEngine.ts +15 -15
- package/src/PresenceManager.ts +6 -6
- package/src/Types.ts +1 -1
- package/src/testing/ColdStorageTestSuite.ts +3 -3
- package/src/testing/HotStorageTestSuite.ts +17 -17
- package/src/testing/StorageIntegrationTestSuite.ts +3 -3
- package/.turbo/turbo-build.log +0 -154
- package/tests/ColdStorage.test.ts +0 -24
- package/tests/DocumentInstance.test.ts +0 -669
- package/tests/HotStorage.test.ts +0 -24
- package/tests/MimicAuthService.test.ts +0 -153
- package/tests/MimicClusterServerEngine.test.ts +0 -587
- package/tests/MimicServer.test.ts +0 -142
- package/tests/MimicServerEngine.test.ts +0 -547
- package/tests/PresenceManager.test.ts +0 -380
- package/tests/Protocol.test.ts +0 -190
- package/tests/StorageIntegration.test.ts +0 -259
- package/tsconfig.build.json +0 -24
- package/tsconfig.json +0 -8
- package/tsdown.config.ts +0 -18
- package/vitest.mts +0 -11
|
@@ -1,587 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { Effect, Layer, Schema } from "effect";
|
|
3
|
-
import { Primitive, Presence, Document, Transaction } from "@voidhash/mimic";
|
|
4
|
-
import { TestRunner } from "@effect/cluster";
|
|
5
|
-
import {
|
|
6
|
-
MimicClusterServerEngine,
|
|
7
|
-
} from "../src/MimicClusterServerEngine";
|
|
8
|
-
import { MimicServerEngineTag } from "../src/MimicServerEngine";
|
|
9
|
-
import { ColdStorage } from "../src/ColdStorage";
|
|
10
|
-
import { HotStorage } from "../src/HotStorage";
|
|
11
|
-
import { MimicAuthService } from "../src/MimicAuthService";
|
|
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
|
-
const CursorPresence = Presence.make({
|
|
23
|
-
schema: Schema.Struct({
|
|
24
|
-
x: Schema.Number,
|
|
25
|
-
y: Schema.Number,
|
|
26
|
-
name: Schema.optional(Schema.String),
|
|
27
|
-
}),
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// =============================================================================
|
|
31
|
-
// Helper Functions
|
|
32
|
-
// =============================================================================
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Create a valid transaction using the Document API
|
|
36
|
-
*/
|
|
37
|
-
const createValidTransaction = (title: string): Transaction.Transaction => {
|
|
38
|
-
const doc = Document.make(TestSchema);
|
|
39
|
-
doc.transaction((root) => {
|
|
40
|
-
root.title.set(title);
|
|
41
|
-
});
|
|
42
|
-
return doc.flush();
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
// =============================================================================
|
|
46
|
-
// Test Layer Factory
|
|
47
|
-
// =============================================================================
|
|
48
|
-
|
|
49
|
-
const makeTestLayer = (options?: {
|
|
50
|
-
withPresence?: boolean;
|
|
51
|
-
authPermissions?: Record<string, "read" | "write">;
|
|
52
|
-
initial?: { title: string; count?: number };
|
|
53
|
-
shardGroup?: string;
|
|
54
|
-
}) => {
|
|
55
|
-
const Engine = MimicClusterServerEngine.make({
|
|
56
|
-
schema: TestSchema,
|
|
57
|
-
initial: options?.initial,
|
|
58
|
-
presence: options?.withPresence ? CursorPresence : undefined,
|
|
59
|
-
shardGroup: options?.shardGroup ?? "test-documents",
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const authLayer = options?.authPermissions
|
|
63
|
-
? MimicAuthService.Static.make({
|
|
64
|
-
permissions: options.authPermissions,
|
|
65
|
-
defaultPermission: undefined,
|
|
66
|
-
})
|
|
67
|
-
: MimicAuthService.NoAuth.make();
|
|
68
|
-
|
|
69
|
-
return Engine.pipe(
|
|
70
|
-
Layer.provide(ColdStorage.InMemory.make()),
|
|
71
|
-
Layer.provide(HotStorage.InMemory.make()),
|
|
72
|
-
Layer.provide(authLayer),
|
|
73
|
-
Layer.provide(TestRunner.layer)
|
|
74
|
-
);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// =============================================================================
|
|
78
|
-
// MimicClusterServerEngine Tests
|
|
79
|
-
// =============================================================================
|
|
80
|
-
|
|
81
|
-
describe("MimicClusterServerEngine", () => {
|
|
82
|
-
describe("make", () => {
|
|
83
|
-
it("should create engine with minimal config", async () => {
|
|
84
|
-
const Engine = MimicClusterServerEngine.make({
|
|
85
|
-
schema: TestSchema,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const layer = Engine.pipe(
|
|
89
|
-
Layer.provide(ColdStorage.InMemory.make()),
|
|
90
|
-
Layer.provide(HotStorage.InMemory.make()),
|
|
91
|
-
Layer.provide(MimicAuthService.NoAuth.make()),
|
|
92
|
-
Layer.provide(TestRunner.layer)
|
|
93
|
-
);
|
|
94
|
-
|
|
95
|
-
const result = await Effect.runPromise(
|
|
96
|
-
Effect.scoped(
|
|
97
|
-
Effect.gen(function* () {
|
|
98
|
-
const engine = yield* MimicServerEngineTag;
|
|
99
|
-
// Engine should have document management methods
|
|
100
|
-
return (
|
|
101
|
-
typeof engine.submit === "function" &&
|
|
102
|
-
typeof engine.getSnapshot === "function" &&
|
|
103
|
-
typeof engine.subscribe === "function" &&
|
|
104
|
-
typeof engine.touch === "function" &&
|
|
105
|
-
engine.config !== undefined
|
|
106
|
-
);
|
|
107
|
-
})
|
|
108
|
-
).pipe(Effect.provide(layer))
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
expect(result).toBe(true);
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
it("should create engine with full config", async () => {
|
|
115
|
-
const Engine = MimicClusterServerEngine.make({
|
|
116
|
-
schema: TestSchema,
|
|
117
|
-
initial: { title: "Default Title" },
|
|
118
|
-
maxIdleTime: "10 minutes",
|
|
119
|
-
maxTransactionHistory: 500,
|
|
120
|
-
snapshot: {
|
|
121
|
-
interval: "1 minute",
|
|
122
|
-
transactionThreshold: 50,
|
|
123
|
-
},
|
|
124
|
-
shardGroup: "custom-shard-group",
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
const layer = Engine.pipe(
|
|
128
|
-
Layer.provide(ColdStorage.InMemory.make()),
|
|
129
|
-
Layer.provide(HotStorage.InMemory.make()),
|
|
130
|
-
Layer.provide(MimicAuthService.NoAuth.make()),
|
|
131
|
-
Layer.provide(TestRunner.layer)
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
const result = await Effect.runPromise(
|
|
135
|
-
Effect.scoped(
|
|
136
|
-
Effect.gen(function* () {
|
|
137
|
-
const engine = yield* MimicServerEngineTag;
|
|
138
|
-
return engine.config !== undefined;
|
|
139
|
-
})
|
|
140
|
-
).pipe(Effect.provide(layer))
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
expect(result).toBe(true);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
it("should work with static auth", async () => {
|
|
147
|
-
const Engine = MimicClusterServerEngine.make({
|
|
148
|
-
schema: TestSchema,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
const layer = Engine.pipe(
|
|
152
|
-
Layer.provide(ColdStorage.InMemory.make()),
|
|
153
|
-
Layer.provide(HotStorage.InMemory.make()),
|
|
154
|
-
Layer.provide(
|
|
155
|
-
MimicAuthService.Static.make({
|
|
156
|
-
permissions: { admin: "write", user: "read" },
|
|
157
|
-
})
|
|
158
|
-
),
|
|
159
|
-
Layer.provide(TestRunner.layer)
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
const result = await Effect.runPromise(
|
|
163
|
-
Effect.scoped(
|
|
164
|
-
Effect.gen(function* () {
|
|
165
|
-
const engine = yield* MimicServerEngineTag;
|
|
166
|
-
return engine.config !== undefined;
|
|
167
|
-
})
|
|
168
|
-
).pipe(Effect.provide(layer))
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
expect(result).toBe(true);
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
describe("document management", () => {
|
|
176
|
-
it("should get snapshot for new document", async () => {
|
|
177
|
-
const result = await Effect.runPromise(
|
|
178
|
-
Effect.scoped(
|
|
179
|
-
Effect.gen(function* () {
|
|
180
|
-
const engine = yield* MimicServerEngineTag;
|
|
181
|
-
const snapshot = yield* engine.getSnapshot("cluster-doc-1");
|
|
182
|
-
return snapshot;
|
|
183
|
-
})
|
|
184
|
-
).pipe(Effect.provide(makeTestLayer({ initial: { title: "Initial" } })))
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
// Note: state only includes properties that were explicitly set (not defaults)
|
|
188
|
-
expect(result.state).toEqual({ title: "Initial" });
|
|
189
|
-
expect(result.version).toBe(0);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
it("should submit transaction and update state", async () => {
|
|
193
|
-
const tx = createValidTransaction("Updated Title");
|
|
194
|
-
|
|
195
|
-
const result = await Effect.runPromise(
|
|
196
|
-
Effect.scoped(
|
|
197
|
-
Effect.gen(function* () {
|
|
198
|
-
const engine = yield* MimicServerEngineTag;
|
|
199
|
-
|
|
200
|
-
// Submit transaction
|
|
201
|
-
const submitResult = yield* engine.submit("cluster-doc-2", tx);
|
|
202
|
-
|
|
203
|
-
// Get snapshot
|
|
204
|
-
const snapshot = yield* engine.getSnapshot("cluster-doc-2");
|
|
205
|
-
|
|
206
|
-
return { submitResult, snapshot };
|
|
207
|
-
})
|
|
208
|
-
).pipe(Effect.provide(makeTestLayer({ initial: { title: "Initial" } })))
|
|
209
|
-
);
|
|
210
|
-
|
|
211
|
-
expect(result.submitResult.success).toBe(true);
|
|
212
|
-
if (result.submitResult.success) {
|
|
213
|
-
expect(result.submitResult.version).toBe(1);
|
|
214
|
-
}
|
|
215
|
-
// Note: state only includes properties that were explicitly set
|
|
216
|
-
expect(result.snapshot.state).toEqual({ title: "Updated Title" });
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
it("should touch document without error", async () => {
|
|
220
|
-
const result = await Effect.runPromise(
|
|
221
|
-
Effect.scoped(
|
|
222
|
-
Effect.gen(function* () {
|
|
223
|
-
const engine = yield* MimicServerEngineTag;
|
|
224
|
-
|
|
225
|
-
// Get document first (creates it)
|
|
226
|
-
yield* engine.getSnapshot("cluster-doc-3");
|
|
227
|
-
|
|
228
|
-
// Touch should not throw
|
|
229
|
-
yield* engine.touch("cluster-doc-3");
|
|
230
|
-
|
|
231
|
-
return true;
|
|
232
|
-
})
|
|
233
|
-
).pipe(Effect.provide(makeTestLayer()))
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
expect(result).toBe(true);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it("should handle multiple sequential transactions", async () => {
|
|
240
|
-
const tx1 = createValidTransaction("First");
|
|
241
|
-
const tx2 = createValidTransaction("Second");
|
|
242
|
-
const tx3 = createValidTransaction("Third");
|
|
243
|
-
|
|
244
|
-
const result = await Effect.runPromise(
|
|
245
|
-
Effect.scoped(
|
|
246
|
-
Effect.gen(function* () {
|
|
247
|
-
const engine = yield* MimicServerEngineTag;
|
|
248
|
-
|
|
249
|
-
const r1 = yield* engine.submit("cluster-doc-seq", tx1);
|
|
250
|
-
const r2 = yield* engine.submit("cluster-doc-seq", tx2);
|
|
251
|
-
const r3 = yield* engine.submit("cluster-doc-seq", tx3);
|
|
252
|
-
|
|
253
|
-
const snapshot = yield* engine.getSnapshot("cluster-doc-seq");
|
|
254
|
-
|
|
255
|
-
return { r1, r2, r3, snapshot };
|
|
256
|
-
})
|
|
257
|
-
).pipe(Effect.provide(makeTestLayer({ initial: { title: "Initial" } })))
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
expect(result.r1.success).toBe(true);
|
|
261
|
-
expect(result.r2.success).toBe(true);
|
|
262
|
-
expect(result.r3.success).toBe(true);
|
|
263
|
-
|
|
264
|
-
if (result.r1.success && result.r2.success && result.r3.success) {
|
|
265
|
-
expect(result.r1.version).toBe(1);
|
|
266
|
-
expect(result.r2.version).toBe(2);
|
|
267
|
-
expect(result.r3.version).toBe(3);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
expect(result.snapshot.version).toBe(3);
|
|
271
|
-
expect(result.snapshot.state).toEqual({ title: "Third" });
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
it("should handle documents with different IDs independently", async () => {
|
|
275
|
-
const tx1 = createValidTransaction("Doc A Title");
|
|
276
|
-
const tx2 = createValidTransaction("Doc B Title");
|
|
277
|
-
|
|
278
|
-
const result = await Effect.runPromise(
|
|
279
|
-
Effect.scoped(
|
|
280
|
-
Effect.gen(function* () {
|
|
281
|
-
const engine = yield* MimicServerEngineTag;
|
|
282
|
-
|
|
283
|
-
yield* engine.submit("doc-a", tx1);
|
|
284
|
-
yield* engine.submit("doc-b", tx2);
|
|
285
|
-
|
|
286
|
-
const snapshotA = yield* engine.getSnapshot("doc-a");
|
|
287
|
-
const snapshotB = yield* engine.getSnapshot("doc-b");
|
|
288
|
-
|
|
289
|
-
return { snapshotA, snapshotB };
|
|
290
|
-
})
|
|
291
|
-
).pipe(Effect.provide(makeTestLayer({ initial: { title: "Initial" } })))
|
|
292
|
-
);
|
|
293
|
-
|
|
294
|
-
expect(result.snapshotA.state).toEqual({ title: "Doc A Title" });
|
|
295
|
-
expect(result.snapshotB.state).toEqual({ title: "Doc B Title" });
|
|
296
|
-
});
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
describe("presence management", () => {
|
|
300
|
-
it("should set and get presence", async () => {
|
|
301
|
-
const result = await Effect.runPromise(
|
|
302
|
-
Effect.scoped(
|
|
303
|
-
Effect.gen(function* () {
|
|
304
|
-
const engine = yield* MimicServerEngineTag;
|
|
305
|
-
|
|
306
|
-
// Set presence
|
|
307
|
-
yield* engine.setPresence("cluster-presence-1", "conn-1", {
|
|
308
|
-
data: { x: 10, y: 20 },
|
|
309
|
-
userId: "user-1",
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
// Get snapshot
|
|
313
|
-
const snapshot = yield* engine.getPresenceSnapshot(
|
|
314
|
-
"cluster-presence-1"
|
|
315
|
-
);
|
|
316
|
-
|
|
317
|
-
return snapshot;
|
|
318
|
-
})
|
|
319
|
-
).pipe(Effect.provide(makeTestLayer({ withPresence: true })))
|
|
320
|
-
);
|
|
321
|
-
|
|
322
|
-
expect(result.presences["conn-1"]).toEqual({
|
|
323
|
-
data: { x: 10, y: 20 },
|
|
324
|
-
userId: "user-1",
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
it("should remove presence", async () => {
|
|
329
|
-
const result = await Effect.runPromise(
|
|
330
|
-
Effect.scoped(
|
|
331
|
-
Effect.gen(function* () {
|
|
332
|
-
const engine = yield* MimicServerEngineTag;
|
|
333
|
-
|
|
334
|
-
// Set presence
|
|
335
|
-
yield* engine.setPresence("cluster-presence-2", "conn-2", {
|
|
336
|
-
data: { x: 10, y: 20 },
|
|
337
|
-
userId: "user-1",
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
// Remove presence
|
|
341
|
-
yield* engine.removePresence("cluster-presence-2", "conn-2");
|
|
342
|
-
|
|
343
|
-
// Get snapshot
|
|
344
|
-
const snapshot = yield* engine.getPresenceSnapshot(
|
|
345
|
-
"cluster-presence-2"
|
|
346
|
-
);
|
|
347
|
-
|
|
348
|
-
return snapshot;
|
|
349
|
-
})
|
|
350
|
-
).pipe(Effect.provide(makeTestLayer({ withPresence: true })))
|
|
351
|
-
);
|
|
352
|
-
|
|
353
|
-
expect(result.presences["conn-2"]).toBeUndefined();
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
it("should handle multiple presence entries", async () => {
|
|
357
|
-
const result = await Effect.runPromise(
|
|
358
|
-
Effect.scoped(
|
|
359
|
-
Effect.gen(function* () {
|
|
360
|
-
const engine = yield* MimicServerEngineTag;
|
|
361
|
-
|
|
362
|
-
yield* engine.setPresence("cluster-presence-multi", "conn-a", {
|
|
363
|
-
data: { x: 0, y: 0 },
|
|
364
|
-
userId: "user-a",
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
yield* engine.setPresence("cluster-presence-multi", "conn-b", {
|
|
368
|
-
data: { x: 100, y: 100 },
|
|
369
|
-
userId: "user-b",
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
yield* engine.setPresence("cluster-presence-multi", "conn-c", {
|
|
373
|
-
data: { x: 50, y: 50 },
|
|
374
|
-
userId: "user-c",
|
|
375
|
-
});
|
|
376
|
-
|
|
377
|
-
const snapshot = yield* engine.getPresenceSnapshot(
|
|
378
|
-
"cluster-presence-multi"
|
|
379
|
-
);
|
|
380
|
-
|
|
381
|
-
return snapshot;
|
|
382
|
-
})
|
|
383
|
-
).pipe(Effect.provide(makeTestLayer({ withPresence: true })))
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
expect(Object.keys(result.presences)).toHaveLength(3);
|
|
387
|
-
expect(result.presences["conn-a"]).toEqual({
|
|
388
|
-
data: { x: 0, y: 0 },
|
|
389
|
-
userId: "user-a",
|
|
390
|
-
});
|
|
391
|
-
expect(result.presences["conn-b"]).toEqual({
|
|
392
|
-
data: { x: 100, y: 100 },
|
|
393
|
-
userId: "user-b",
|
|
394
|
-
});
|
|
395
|
-
expect(result.presences["conn-c"]).toEqual({
|
|
396
|
-
data: { x: 50, y: 50 },
|
|
397
|
-
userId: "user-c",
|
|
398
|
-
});
|
|
399
|
-
});
|
|
400
|
-
|
|
401
|
-
it("should update existing presence entry", async () => {
|
|
402
|
-
const result = await Effect.runPromise(
|
|
403
|
-
Effect.scoped(
|
|
404
|
-
Effect.gen(function* () {
|
|
405
|
-
const engine = yield* MimicServerEngineTag;
|
|
406
|
-
|
|
407
|
-
// Set initial presence
|
|
408
|
-
yield* engine.setPresence("cluster-presence-update", "conn-1", {
|
|
409
|
-
data: { x: 10, y: 20 },
|
|
410
|
-
userId: "user-1",
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
// Update presence
|
|
414
|
-
yield* engine.setPresence("cluster-presence-update", "conn-1", {
|
|
415
|
-
data: { x: 100, y: 200 },
|
|
416
|
-
userId: "user-1",
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
const snapshot = yield* engine.getPresenceSnapshot(
|
|
420
|
-
"cluster-presence-update"
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
return snapshot;
|
|
424
|
-
})
|
|
425
|
-
).pipe(Effect.provide(makeTestLayer({ withPresence: true })))
|
|
426
|
-
);
|
|
427
|
-
|
|
428
|
-
expect(result.presences["conn-1"]).toEqual({
|
|
429
|
-
data: { x: 100, y: 200 },
|
|
430
|
-
userId: "user-1",
|
|
431
|
-
});
|
|
432
|
-
});
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
describe("config resolution", () => {
|
|
436
|
-
it("should use default shardGroup when not specified", async () => {
|
|
437
|
-
const Engine = MimicClusterServerEngine.make({
|
|
438
|
-
schema: TestSchema,
|
|
439
|
-
});
|
|
440
|
-
|
|
441
|
-
const layer = Engine.pipe(
|
|
442
|
-
Layer.provide(ColdStorage.InMemory.make()),
|
|
443
|
-
Layer.provide(HotStorage.InMemory.make()),
|
|
444
|
-
Layer.provide(MimicAuthService.NoAuth.make()),
|
|
445
|
-
Layer.provide(TestRunner.layer)
|
|
446
|
-
);
|
|
447
|
-
|
|
448
|
-
const result = await Effect.runPromise(
|
|
449
|
-
Effect.scoped(
|
|
450
|
-
Effect.gen(function* () {
|
|
451
|
-
const engine = yield* MimicServerEngineTag;
|
|
452
|
-
// Config should have shardGroup
|
|
453
|
-
return (engine.config as { shardGroup?: string }).shardGroup;
|
|
454
|
-
})
|
|
455
|
-
).pipe(Effect.provide(layer))
|
|
456
|
-
);
|
|
457
|
-
|
|
458
|
-
expect(result).toBe("mimic-documents");
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
it("should use custom shardGroup when specified", async () => {
|
|
462
|
-
const Engine = MimicClusterServerEngine.make({
|
|
463
|
-
schema: TestSchema,
|
|
464
|
-
shardGroup: "custom-documents",
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
const layer = Engine.pipe(
|
|
468
|
-
Layer.provide(ColdStorage.InMemory.make()),
|
|
469
|
-
Layer.provide(HotStorage.InMemory.make()),
|
|
470
|
-
Layer.provide(MimicAuthService.NoAuth.make()),
|
|
471
|
-
Layer.provide(TestRunner.layer)
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
const result = await Effect.runPromise(
|
|
475
|
-
Effect.scoped(
|
|
476
|
-
Effect.gen(function* () {
|
|
477
|
-
const engine = yield* MimicServerEngineTag;
|
|
478
|
-
return (engine.config as { shardGroup?: string }).shardGroup;
|
|
479
|
-
})
|
|
480
|
-
).pipe(Effect.provide(layer))
|
|
481
|
-
);
|
|
482
|
-
|
|
483
|
-
expect(result).toBe("custom-documents");
|
|
484
|
-
});
|
|
485
|
-
|
|
486
|
-
it("should create engine with presence enabled", async () => {
|
|
487
|
-
const result = await Effect.runPromise(
|
|
488
|
-
Effect.scoped(
|
|
489
|
-
Effect.gen(function* () {
|
|
490
|
-
const engine = yield* MimicServerEngineTag;
|
|
491
|
-
return engine.config.presence !== undefined;
|
|
492
|
-
})
|
|
493
|
-
).pipe(Effect.provide(makeTestLayer({ withPresence: true })))
|
|
494
|
-
);
|
|
495
|
-
|
|
496
|
-
expect(result).toBe(true);
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
it("should create engine with initial state function", async () => {
|
|
500
|
-
const Engine = MimicClusterServerEngine.make({
|
|
501
|
-
schema: TestSchema,
|
|
502
|
-
initial: (ctx) =>
|
|
503
|
-
Effect.succeed({
|
|
504
|
-
title: `Document: ${ctx.documentId}`,
|
|
505
|
-
}),
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
const layer = Engine.pipe(
|
|
509
|
-
Layer.provide(ColdStorage.InMemory.make()),
|
|
510
|
-
Layer.provide(HotStorage.InMemory.make()),
|
|
511
|
-
Layer.provide(MimicAuthService.NoAuth.make()),
|
|
512
|
-
Layer.provide(TestRunner.layer)
|
|
513
|
-
);
|
|
514
|
-
|
|
515
|
-
const result = await Effect.runPromise(
|
|
516
|
-
Effect.scoped(
|
|
517
|
-
Effect.gen(function* () {
|
|
518
|
-
const engine = yield* MimicServerEngineTag;
|
|
519
|
-
const snapshot = yield* engine.getSnapshot("my-special-doc");
|
|
520
|
-
return snapshot;
|
|
521
|
-
})
|
|
522
|
-
).pipe(Effect.provide(layer))
|
|
523
|
-
);
|
|
524
|
-
|
|
525
|
-
expect(result.state).toEqual({ title: "Document: my-special-doc" });
|
|
526
|
-
});
|
|
527
|
-
});
|
|
528
|
-
|
|
529
|
-
describe("subscription", () => {
|
|
530
|
-
it("should provide subscribe method that returns stream", async () => {
|
|
531
|
-
const result = await Effect.runPromise(
|
|
532
|
-
Effect.scoped(
|
|
533
|
-
Effect.gen(function* () {
|
|
534
|
-
const engine = yield* MimicServerEngineTag;
|
|
535
|
-
const stream = yield* engine.subscribe("cluster-sub-doc");
|
|
536
|
-
// Verify we get a stream (has pipe method)
|
|
537
|
-
return typeof stream.pipe === "function";
|
|
538
|
-
})
|
|
539
|
-
).pipe(Effect.provide(makeTestLayer()))
|
|
540
|
-
);
|
|
541
|
-
|
|
542
|
-
expect(result).toBe(true);
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
it("should provide subscribePresence method that returns stream", async () => {
|
|
546
|
-
const result = await Effect.runPromise(
|
|
547
|
-
Effect.scoped(
|
|
548
|
-
Effect.gen(function* () {
|
|
549
|
-
const engine = yield* MimicServerEngineTag;
|
|
550
|
-
const stream = yield* engine.subscribePresence(
|
|
551
|
-
"cluster-sub-presence"
|
|
552
|
-
);
|
|
553
|
-
// Verify we get a stream (has pipe method)
|
|
554
|
-
return typeof stream.pipe === "function";
|
|
555
|
-
})
|
|
556
|
-
).pipe(Effect.provide(makeTestLayer({ withPresence: true })))
|
|
557
|
-
);
|
|
558
|
-
|
|
559
|
-
expect(result).toBe(true);
|
|
560
|
-
});
|
|
561
|
-
});
|
|
562
|
-
|
|
563
|
-
describe("error handling", () => {
|
|
564
|
-
it("should handle duplicate transaction gracefully", async () => {
|
|
565
|
-
const tx = createValidTransaction("Test");
|
|
566
|
-
|
|
567
|
-
const result = await Effect.runPromise(
|
|
568
|
-
Effect.scoped(
|
|
569
|
-
Effect.gen(function* () {
|
|
570
|
-
const engine = yield* MimicServerEngineTag;
|
|
571
|
-
|
|
572
|
-
// Submit first time - should succeed
|
|
573
|
-
const first = yield* engine.submit("cluster-dup-doc", tx);
|
|
574
|
-
|
|
575
|
-
// Submit same transaction again - should fail
|
|
576
|
-
const second = yield* engine.submit("cluster-dup-doc", tx);
|
|
577
|
-
|
|
578
|
-
return { first, second };
|
|
579
|
-
})
|
|
580
|
-
).pipe(Effect.provide(makeTestLayer({ initial: { title: "Initial" } })))
|
|
581
|
-
);
|
|
582
|
-
|
|
583
|
-
expect(result.first.success).toBe(true);
|
|
584
|
-
expect(result.second.success).toBe(false);
|
|
585
|
-
});
|
|
586
|
-
});
|
|
587
|
-
});
|