@voidhash/mimic-effect 0.0.9 → 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 (236) hide show
  1. package/.turbo/turbo-build.log +136 -90
  2. package/README.md +385 -0
  3. package/dist/ColdStorage.cjs +64 -0
  4. package/dist/ColdStorage.d.cts +53 -0
  5. package/dist/ColdStorage.d.cts.map +1 -0
  6. package/dist/ColdStorage.d.mts +53 -0
  7. package/dist/ColdStorage.d.mts.map +1 -0
  8. package/dist/ColdStorage.mjs +64 -0
  9. package/dist/ColdStorage.mjs.map +1 -0
  10. package/dist/DocumentInstance.cjs +263 -0
  11. package/dist/DocumentInstance.d.cts +78 -0
  12. package/dist/DocumentInstance.d.cts.map +1 -0
  13. package/dist/DocumentInstance.d.mts +78 -0
  14. package/dist/DocumentInstance.d.mts.map +1 -0
  15. package/dist/DocumentInstance.mjs +264 -0
  16. package/dist/DocumentInstance.mjs.map +1 -0
  17. package/dist/Errors.cjs +54 -0
  18. package/dist/Errors.d.cts +96 -0
  19. package/dist/Errors.d.cts.map +1 -0
  20. package/dist/Errors.d.mts +96 -0
  21. package/dist/Errors.d.mts.map +1 -0
  22. package/dist/Errors.mjs +48 -0
  23. package/dist/Errors.mjs.map +1 -0
  24. package/dist/HotStorage.cjs +104 -0
  25. package/dist/HotStorage.d.cts +70 -0
  26. package/dist/HotStorage.d.cts.map +1 -0
  27. package/dist/HotStorage.d.mts +70 -0
  28. package/dist/HotStorage.d.mts.map +1 -0
  29. package/dist/HotStorage.mjs +104 -0
  30. package/dist/HotStorage.mjs.map +1 -0
  31. package/dist/Metrics.cjs +149 -0
  32. package/dist/Metrics.d.cts +32 -0
  33. package/dist/Metrics.d.cts.map +1 -0
  34. package/dist/Metrics.d.mts +32 -0
  35. package/dist/Metrics.d.mts.map +1 -0
  36. package/dist/Metrics.mjs +131 -0
  37. package/dist/Metrics.mjs.map +1 -0
  38. package/dist/MimicAuthService.cjs +61 -45
  39. package/dist/MimicAuthService.d.cts +61 -48
  40. package/dist/MimicAuthService.d.cts.map +1 -1
  41. package/dist/MimicAuthService.d.mts +61 -48
  42. package/dist/MimicAuthService.d.mts.map +1 -1
  43. package/dist/MimicAuthService.mjs +60 -36
  44. package/dist/MimicAuthService.mjs.map +1 -1
  45. package/dist/MimicClusterServerEngine.cjs +348 -0
  46. package/dist/MimicClusterServerEngine.d.cts +17 -0
  47. package/dist/MimicClusterServerEngine.d.cts.map +1 -0
  48. package/dist/MimicClusterServerEngine.d.mts +17 -0
  49. package/dist/MimicClusterServerEngine.d.mts.map +1 -0
  50. package/dist/MimicClusterServerEngine.mjs +350 -0
  51. package/dist/MimicClusterServerEngine.mjs.map +1 -0
  52. package/dist/MimicServer.cjs +205 -96
  53. package/dist/MimicServer.d.cts +9 -110
  54. package/dist/MimicServer.d.cts.map +1 -1
  55. package/dist/MimicServer.d.mts +9 -110
  56. package/dist/MimicServer.d.mts.map +1 -1
  57. package/dist/MimicServer.mjs +206 -90
  58. package/dist/MimicServer.mjs.map +1 -1
  59. package/dist/MimicServerEngine.cjs +178 -0
  60. package/dist/MimicServerEngine.d.cts +83 -0
  61. package/dist/MimicServerEngine.d.cts.map +1 -0
  62. package/dist/MimicServerEngine.d.mts +83 -0
  63. package/dist/MimicServerEngine.d.mts.map +1 -0
  64. package/dist/MimicServerEngine.mjs +178 -0
  65. package/dist/MimicServerEngine.mjs.map +1 -0
  66. package/dist/PresenceManager.cjs +75 -91
  67. package/dist/PresenceManager.d.cts +17 -66
  68. package/dist/PresenceManager.d.cts.map +1 -1
  69. package/dist/PresenceManager.d.mts +17 -66
  70. package/dist/PresenceManager.d.mts.map +1 -1
  71. package/dist/PresenceManager.mjs +74 -78
  72. package/dist/PresenceManager.mjs.map +1 -1
  73. package/dist/Protocol.cjs +146 -0
  74. package/dist/Protocol.d.cts +203 -0
  75. package/dist/Protocol.d.cts.map +1 -0
  76. package/dist/Protocol.d.mts +203 -0
  77. package/dist/Protocol.d.mts.map +1 -0
  78. package/dist/Protocol.mjs +132 -0
  79. package/dist/Protocol.mjs.map +1 -0
  80. package/dist/Types.d.cts +179 -0
  81. package/dist/Types.d.cts.map +1 -0
  82. package/dist/Types.d.mts +179 -0
  83. package/dist/Types.d.mts.map +1 -0
  84. package/dist/_virtual/rolldown_runtime.cjs +1 -25
  85. package/dist/_virtual/rolldown_runtime.mjs +4 -1
  86. package/dist/index.cjs +37 -76
  87. package/dist/index.d.cts +13 -12
  88. package/dist/index.d.mts +13 -12
  89. package/dist/index.mjs +12 -12
  90. package/dist/testing/ColdStorageTestSuite.cjs +508 -0
  91. package/dist/testing/ColdStorageTestSuite.d.cts +36 -0
  92. package/dist/testing/ColdStorageTestSuite.d.cts.map +1 -0
  93. package/dist/testing/ColdStorageTestSuite.d.mts +36 -0
  94. package/dist/testing/ColdStorageTestSuite.d.mts.map +1 -0
  95. package/dist/testing/ColdStorageTestSuite.mjs +508 -0
  96. package/dist/testing/ColdStorageTestSuite.mjs.map +1 -0
  97. package/dist/testing/FailingStorage.cjs +162 -0
  98. package/dist/testing/FailingStorage.d.cts +43 -0
  99. package/dist/testing/FailingStorage.d.cts.map +1 -0
  100. package/dist/testing/FailingStorage.d.mts +43 -0
  101. package/dist/testing/FailingStorage.d.mts.map +1 -0
  102. package/dist/testing/FailingStorage.mjs +163 -0
  103. package/dist/testing/FailingStorage.mjs.map +1 -0
  104. package/dist/testing/HotStorageTestSuite.cjs +820 -0
  105. package/dist/testing/HotStorageTestSuite.d.cts +42 -0
  106. package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
  107. package/dist/testing/HotStorageTestSuite.d.mts +42 -0
  108. package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
  109. package/dist/testing/HotStorageTestSuite.mjs +820 -0
  110. package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
  111. package/dist/testing/StorageIntegrationTestSuite.cjs +487 -0
  112. package/dist/testing/StorageIntegrationTestSuite.d.cts +37 -0
  113. package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
  114. package/dist/testing/StorageIntegrationTestSuite.d.mts +37 -0
  115. package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
  116. package/dist/testing/StorageIntegrationTestSuite.mjs +487 -0
  117. package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
  118. package/dist/testing/assertions.cjs +117 -0
  119. package/dist/testing/assertions.mjs +112 -0
  120. package/dist/testing/assertions.mjs.map +1 -0
  121. package/dist/testing/index.cjs +14 -0
  122. package/dist/testing/index.d.cts +6 -0
  123. package/dist/testing/index.d.mts +6 -0
  124. package/dist/testing/index.mjs +7 -0
  125. package/dist/testing/types.cjs +15 -0
  126. package/dist/testing/types.d.cts +90 -0
  127. package/dist/testing/types.d.cts.map +1 -0
  128. package/dist/testing/types.d.mts +90 -0
  129. package/dist/testing/types.d.mts.map +1 -0
  130. package/dist/testing/types.mjs +16 -0
  131. package/dist/testing/types.mjs.map +1 -0
  132. package/package.json +18 -3
  133. package/src/ColdStorage.ts +145 -0
  134. package/src/DocumentInstance.ts +527 -0
  135. package/src/Errors.ts +114 -0
  136. package/src/HotStorage.ts +256 -0
  137. package/src/Metrics.ts +193 -0
  138. package/src/MimicAuthService.ts +126 -64
  139. package/src/MimicClusterServerEngine.ts +669 -0
  140. package/src/MimicServer.ts +459 -198
  141. package/src/MimicServerEngine.ts +472 -0
  142. package/src/PresenceManager.ts +173 -234
  143. package/src/Protocol.ts +350 -0
  144. package/src/Types.ts +238 -0
  145. package/src/index.ts +27 -23
  146. package/src/testing/ColdStorageTestSuite.ts +589 -0
  147. package/src/testing/FailingStorage.ts +338 -0
  148. package/src/testing/HotStorageTestSuite.ts +1105 -0
  149. package/src/testing/StorageIntegrationTestSuite.ts +736 -0
  150. package/src/testing/assertions.ts +188 -0
  151. package/src/testing/index.ts +83 -0
  152. package/src/testing/types.ts +100 -0
  153. package/tests/ColdStorage.test.ts +24 -0
  154. package/tests/DocumentInstance.test.ts +669 -0
  155. package/tests/HotStorage.test.ts +24 -0
  156. package/tests/MimicAuthService.test.ts +102 -134
  157. package/tests/MimicClusterServerEngine.test.ts +587 -0
  158. package/tests/MimicServer.test.ts +90 -226
  159. package/tests/MimicServerEngine.test.ts +521 -0
  160. package/tests/PresenceManager.test.ts +22 -63
  161. package/tests/Protocol.test.ts +190 -0
  162. package/tests/StorageIntegration.test.ts +259 -0
  163. package/tsconfig.json +1 -1
  164. package/tsdown.config.ts +1 -1
  165. package/dist/DocumentManager.cjs +0 -118
  166. package/dist/DocumentManager.d.cts +0 -45
  167. package/dist/DocumentManager.d.cts.map +0 -1
  168. package/dist/DocumentManager.d.mts +0 -45
  169. package/dist/DocumentManager.d.mts.map +0 -1
  170. package/dist/DocumentManager.mjs +0 -105
  171. package/dist/DocumentManager.mjs.map +0 -1
  172. package/dist/DocumentProtocol.cjs +0 -94
  173. package/dist/DocumentProtocol.d.cts +0 -113
  174. package/dist/DocumentProtocol.d.cts.map +0 -1
  175. package/dist/DocumentProtocol.d.mts +0 -113
  176. package/dist/DocumentProtocol.d.mts.map +0 -1
  177. package/dist/DocumentProtocol.mjs +0 -89
  178. package/dist/DocumentProtocol.mjs.map +0 -1
  179. package/dist/MimicConfig.cjs +0 -60
  180. package/dist/MimicConfig.d.cts +0 -141
  181. package/dist/MimicConfig.d.cts.map +0 -1
  182. package/dist/MimicConfig.d.mts +0 -141
  183. package/dist/MimicConfig.d.mts.map +0 -1
  184. package/dist/MimicConfig.mjs +0 -50
  185. package/dist/MimicConfig.mjs.map +0 -1
  186. package/dist/MimicDataStorage.cjs +0 -83
  187. package/dist/MimicDataStorage.d.cts +0 -113
  188. package/dist/MimicDataStorage.d.cts.map +0 -1
  189. package/dist/MimicDataStorage.d.mts +0 -113
  190. package/dist/MimicDataStorage.d.mts.map +0 -1
  191. package/dist/MimicDataStorage.mjs +0 -74
  192. package/dist/MimicDataStorage.mjs.map +0 -1
  193. package/dist/WebSocketHandler.cjs +0 -365
  194. package/dist/WebSocketHandler.d.cts +0 -34
  195. package/dist/WebSocketHandler.d.cts.map +0 -1
  196. package/dist/WebSocketHandler.d.mts +0 -34
  197. package/dist/WebSocketHandler.d.mts.map +0 -1
  198. package/dist/WebSocketHandler.mjs +0 -355
  199. package/dist/WebSocketHandler.mjs.map +0 -1
  200. package/dist/auth/NoAuth.cjs +0 -43
  201. package/dist/auth/NoAuth.d.cts +0 -22
  202. package/dist/auth/NoAuth.d.cts.map +0 -1
  203. package/dist/auth/NoAuth.d.mts +0 -22
  204. package/dist/auth/NoAuth.d.mts.map +0 -1
  205. package/dist/auth/NoAuth.mjs +0 -36
  206. package/dist/auth/NoAuth.mjs.map +0 -1
  207. package/dist/errors.cjs +0 -74
  208. package/dist/errors.d.cts +0 -89
  209. package/dist/errors.d.cts.map +0 -1
  210. package/dist/errors.d.mts +0 -89
  211. package/dist/errors.d.mts.map +0 -1
  212. package/dist/errors.mjs +0 -67
  213. package/dist/errors.mjs.map +0 -1
  214. package/dist/storage/InMemoryDataStorage.cjs +0 -57
  215. package/dist/storage/InMemoryDataStorage.d.cts +0 -19
  216. package/dist/storage/InMemoryDataStorage.d.cts.map +0 -1
  217. package/dist/storage/InMemoryDataStorage.d.mts +0 -19
  218. package/dist/storage/InMemoryDataStorage.d.mts.map +0 -1
  219. package/dist/storage/InMemoryDataStorage.mjs +0 -48
  220. package/dist/storage/InMemoryDataStorage.mjs.map +0 -1
  221. package/src/DocumentManager.ts +0 -254
  222. package/src/DocumentProtocol.ts +0 -112
  223. package/src/MimicConfig.ts +0 -211
  224. package/src/MimicDataStorage.ts +0 -157
  225. package/src/WebSocketHandler.ts +0 -735
  226. package/src/auth/NoAuth.ts +0 -46
  227. package/src/errors.ts +0 -113
  228. package/src/storage/InMemoryDataStorage.ts +0 -66
  229. package/tests/DocumentManager.test.ts +0 -464
  230. package/tests/DocumentProtocol.test.ts +0 -113
  231. package/tests/InMemoryDataStorage.test.ts +0 -190
  232. package/tests/MimicConfig.test.ts +0 -290
  233. package/tests/MimicDataStorage.test.ts +0 -190
  234. package/tests/NoAuth.test.ts +0 -94
  235. package/tests/WebSocketHandler.test.ts +0 -321
  236. package/tests/errors.test.ts +0 -77
@@ -1,113 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import * as Schema from "effect/Schema";
3
- import * as Protocol from "../src/DocumentProtocol";
4
-
5
- // =============================================================================
6
- // Schema Tests
7
- // =============================================================================
8
-
9
- describe("DocumentProtocol", () => {
10
- describe("TransactionSchema", () => {
11
- it("should validate a valid transaction", () => {
12
- const transaction = {
13
- id: "tx-123",
14
- ops: [
15
- { kind: "string.set", path: { segments: ["title"] }, payload: "Hello" },
16
- ],
17
- timestamp: Date.now(),
18
- };
19
-
20
- const result = Schema.decodeUnknownSync(Protocol.TransactionSchema)(transaction);
21
- expect(result.id).toBe("tx-123");
22
- expect(result.ops).toHaveLength(1);
23
- });
24
-
25
- it("should reject invalid transaction", () => {
26
- const invalid = {
27
- id: 123, // should be string
28
- ops: [],
29
- timestamp: Date.now(),
30
- };
31
-
32
- expect(() =>
33
- Schema.decodeUnknownSync(Protocol.TransactionSchema)(invalid)
34
- ).toThrow();
35
- });
36
- });
37
-
38
- describe("TransactionMessageSchema", () => {
39
- it("should validate a transaction message", () => {
40
- const message = {
41
- type: "transaction",
42
- transaction: {
43
- id: "tx-456",
44
- ops: [],
45
- timestamp: Date.now(),
46
- },
47
- version: 1,
48
- };
49
-
50
- const result = Schema.decodeUnknownSync(Protocol.TransactionMessageSchema)(message);
51
- expect(result.type).toBe("transaction");
52
- expect(result.version).toBe(1);
53
- });
54
- });
55
-
56
- describe("SnapshotMessageSchema", () => {
57
- it("should validate a snapshot message", () => {
58
- const message = {
59
- type: "snapshot",
60
- state: { title: "Test", count: 42 },
61
- version: 5,
62
- };
63
-
64
- const result = Schema.decodeUnknownSync(Protocol.SnapshotMessageSchema)(message);
65
- expect(result.type).toBe("snapshot");
66
- expect(result.state).toEqual({ title: "Test", count: 42 });
67
- expect(result.version).toBe(5);
68
- });
69
- });
70
-
71
- describe("ErrorMessageSchema", () => {
72
- it("should validate an error message", () => {
73
- const message = {
74
- type: "error",
75
- transactionId: "tx-789",
76
- reason: "Transaction is empty",
77
- };
78
-
79
- const result = Schema.decodeUnknownSync(Protocol.ErrorMessageSchema)(message);
80
- expect(result.type).toBe("error");
81
- expect(result.transactionId).toBe("tx-789");
82
- expect(result.reason).toBe("Transaction is empty");
83
- });
84
- });
85
-
86
- describe("SubmitResultSchema", () => {
87
- it("should validate a success result", () => {
88
- const result = {
89
- success: true,
90
- version: 10,
91
- };
92
-
93
- const decoded = Schema.decodeUnknownSync(Protocol.SubmitResultSchema)(result);
94
- expect(decoded.success).toBe(true);
95
- if (decoded.success) {
96
- expect(decoded.version).toBe(10);
97
- }
98
- });
99
-
100
- it("should validate a failure result", () => {
101
- const result = {
102
- success: false,
103
- reason: "Invalid operation",
104
- };
105
-
106
- const decoded = Schema.decodeUnknownSync(Protocol.SubmitResultSchema)(result);
107
- expect(decoded.success).toBe(false);
108
- if (!decoded.success) {
109
- expect(decoded.reason).toBe("Invalid operation");
110
- }
111
- });
112
- });
113
- });
@@ -1,190 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import * as Effect from "effect/Effect";
3
- import * as InMemoryDataStorage from "../src/storage/InMemoryDataStorage";
4
- import { MimicDataStorageTag } from "../src/MimicDataStorage";
5
-
6
- // =============================================================================
7
- // InMemoryDataStorage Tests
8
- // =============================================================================
9
-
10
- describe("InMemoryDataStorage", () => {
11
- describe("load", () => {
12
- it("should return undefined for non-existent documents", async () => {
13
- const result = await Effect.runPromise(
14
- Effect.gen(function* () {
15
- const storage = yield* MimicDataStorageTag;
16
- return yield* storage.load("non-existent-doc");
17
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
18
- );
19
-
20
- expect(result).toBeUndefined();
21
- });
22
- });
23
-
24
- describe("save and load", () => {
25
- it("should save and load document state", async () => {
26
- const testState = { title: "Test Document", count: 42 };
27
-
28
- const result = await Effect.runPromise(
29
- Effect.gen(function* () {
30
- const storage = yield* MimicDataStorageTag;
31
- yield* storage.save("doc-1", testState);
32
- return yield* storage.load("doc-1");
33
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
34
- );
35
-
36
- expect(result).toEqual(testState);
37
- });
38
-
39
- it("should update existing document", async () => {
40
- const initialState = { title: "Initial", count: 0 };
41
- const updatedState = { title: "Updated", count: 100 };
42
-
43
- const result = await Effect.runPromise(
44
- Effect.gen(function* () {
45
- const storage = yield* MimicDataStorageTag;
46
- yield* storage.save("doc-1", initialState);
47
- yield* storage.save("doc-1", updatedState);
48
- return yield* storage.load("doc-1");
49
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
50
- );
51
-
52
- expect(result).toEqual(updatedState);
53
- });
54
-
55
- it("should store multiple documents independently", async () => {
56
- const state1 = { title: "Doc 1" };
57
- const state2 = { title: "Doc 2" };
58
- const state3 = { title: "Doc 3" };
59
-
60
- const result = await Effect.runPromise(
61
- Effect.gen(function* () {
62
- const storage = yield* MimicDataStorageTag;
63
- yield* storage.save("doc-1", state1);
64
- yield* storage.save("doc-2", state2);
65
- yield* storage.save("doc-3", state3);
66
- return {
67
- doc1: yield* storage.load("doc-1"),
68
- doc2: yield* storage.load("doc-2"),
69
- doc3: yield* storage.load("doc-3"),
70
- };
71
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
72
- );
73
-
74
- expect(result.doc1).toEqual(state1);
75
- expect(result.doc2).toEqual(state2);
76
- expect(result.doc3).toEqual(state3);
77
- });
78
- });
79
-
80
- describe("delete", () => {
81
- it("should delete existing document", async () => {
82
- const testState = { title: "To be deleted" };
83
-
84
- const result = await Effect.runPromise(
85
- Effect.gen(function* () {
86
- const storage = yield* MimicDataStorageTag;
87
- yield* storage.save("doc-1", testState);
88
- const beforeDelete = yield* storage.load("doc-1");
89
- yield* storage.delete("doc-1");
90
- const afterDelete = yield* storage.load("doc-1");
91
- return { beforeDelete, afterDelete };
92
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
93
- );
94
-
95
- expect(result.beforeDelete).toEqual(testState);
96
- expect(result.afterDelete).toBeUndefined();
97
- });
98
-
99
- it("should handle deleting non-existent document gracefully", async () => {
100
- await Effect.runPromise(
101
- Effect.gen(function* () {
102
- const storage = yield* MimicDataStorageTag;
103
- yield* storage.delete("non-existent-doc");
104
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
105
- );
106
- // Should not throw
107
- });
108
-
109
- it("should not affect other documents when deleting", async () => {
110
- const state1 = { title: "Doc 1" };
111
- const state2 = { title: "Doc 2" };
112
-
113
- const result = await Effect.runPromise(
114
- Effect.gen(function* () {
115
- const storage = yield* MimicDataStorageTag;
116
- yield* storage.save("doc-1", state1);
117
- yield* storage.save("doc-2", state2);
118
- yield* storage.delete("doc-1");
119
- return {
120
- doc1: yield* storage.load("doc-1"),
121
- doc2: yield* storage.load("doc-2"),
122
- };
123
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
124
- );
125
-
126
- expect(result.doc1).toBeUndefined();
127
- expect(result.doc2).toEqual(state2);
128
- });
129
- });
130
-
131
- describe("onLoad", () => {
132
- it("should pass through state unchanged", async () => {
133
- const testState = { title: "Test", nested: { value: 123 } };
134
-
135
- const result = await Effect.runPromise(
136
- Effect.gen(function* () {
137
- const storage = yield* MimicDataStorageTag;
138
- return yield* storage.onLoad(testState);
139
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
140
- );
141
-
142
- expect(result).toBe(testState);
143
- });
144
- });
145
-
146
- describe("onSave", () => {
147
- it("should pass through state unchanged", async () => {
148
- const testState = { title: "Test", nested: { value: 456 } };
149
-
150
- const result = await Effect.runPromise(
151
- Effect.gen(function* () {
152
- const storage = yield* MimicDataStorageTag;
153
- return yield* storage.onSave(testState);
154
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
155
- );
156
-
157
- expect(result).toBe(testState);
158
- });
159
- });
160
-
161
- describe("layer aliases", () => {
162
- it("should have layerDefault as an alias for layer", () => {
163
- expect(InMemoryDataStorage.layerDefault).toBe(InMemoryDataStorage.layer);
164
- });
165
- });
166
-
167
- describe("isolation", () => {
168
- it("should have independent storage per layer instance", async () => {
169
- const testState = { title: "Isolated" };
170
-
171
- // Save in one layer
172
- await Effect.runPromise(
173
- Effect.gen(function* () {
174
- const storage = yield* MimicDataStorageTag;
175
- yield* storage.save("doc-1", testState);
176
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
177
- );
178
-
179
- // Load in a new layer instance - should not find the document
180
- const result = await Effect.runPromise(
181
- Effect.gen(function* () {
182
- const storage = yield* MimicDataStorageTag;
183
- return yield* storage.load("doc-1");
184
- }).pipe(Effect.provide(InMemoryDataStorage.layer))
185
- );
186
-
187
- expect(result).toBeUndefined();
188
- });
189
- });
190
- });
@@ -1,290 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import * as Effect from "effect/Effect";
3
- import * as Duration from "effect/Duration";
4
- import * as Schema from "effect/Schema";
5
- import { Primitive, Presence } from "@voidhash/mimic";
6
- import * as MimicConfig from "../src/MimicConfig";
7
-
8
- // =============================================================================
9
- // Test Schema
10
- // =============================================================================
11
-
12
- const TestSchema = Primitive.Struct({
13
- title: Primitive.String().default(""),
14
- count: Primitive.Number().default(0),
15
- });
16
-
17
- // =============================================================================
18
- // MimicConfig Tests
19
- // =============================================================================
20
-
21
- describe("MimicConfig", () => {
22
- describe("make", () => {
23
- it("should create config with default values", () => {
24
- const config = MimicConfig.make({
25
- schema: TestSchema,
26
- });
27
-
28
- expect(config.schema).toBe(TestSchema);
29
- expect(Duration.toMillis(config.maxIdleTime)).toBe(5 * 60 * 1000); // 5 minutes
30
- expect(config.maxTransactionHistory).toBe(1000);
31
- expect(Duration.toMillis(config.heartbeatInterval)).toBe(30 * 1000); // 30 seconds
32
- expect(Duration.toMillis(config.heartbeatTimeout)).toBe(10 * 1000); // 10 seconds
33
- });
34
-
35
- it("should accept custom maxIdleTime", () => {
36
- const config = MimicConfig.make({
37
- schema: TestSchema,
38
- maxIdleTime: "10 minutes",
39
- });
40
-
41
- expect(Duration.toMillis(config.maxIdleTime)).toBe(10 * 60 * 1000);
42
- });
43
-
44
- it("should accept custom maxTransactionHistory", () => {
45
- const config = MimicConfig.make({
46
- schema: TestSchema,
47
- maxTransactionHistory: 500,
48
- });
49
-
50
- expect(config.maxTransactionHistory).toBe(500);
51
- });
52
-
53
- it("should accept custom heartbeatInterval", () => {
54
- const config = MimicConfig.make({
55
- schema: TestSchema,
56
- heartbeatInterval: "1 minute",
57
- });
58
-
59
- expect(Duration.toMillis(config.heartbeatInterval)).toBe(60 * 1000);
60
- });
61
-
62
- it("should accept custom heartbeatTimeout", () => {
63
- const config = MimicConfig.make({
64
- schema: TestSchema,
65
- heartbeatTimeout: "30 seconds",
66
- });
67
-
68
- expect(Duration.toMillis(config.heartbeatTimeout)).toBe(30 * 1000);
69
- });
70
-
71
- it("should accept all custom values", () => {
72
- const config = MimicConfig.make({
73
- schema: TestSchema,
74
- maxIdleTime: "15 minutes",
75
- maxTransactionHistory: 2000,
76
- heartbeatInterval: "45 seconds",
77
- heartbeatTimeout: "15 seconds",
78
- });
79
-
80
- expect(config.schema).toBe(TestSchema);
81
- expect(Duration.toMillis(config.maxIdleTime)).toBe(15 * 60 * 1000);
82
- expect(config.maxTransactionHistory).toBe(2000);
83
- expect(Duration.toMillis(config.heartbeatInterval)).toBe(45 * 1000);
84
- expect(Duration.toMillis(config.heartbeatTimeout)).toBe(15 * 1000);
85
- });
86
- });
87
-
88
- describe("layer", () => {
89
- it("should create a layer that provides MimicServerConfigTag", async () => {
90
- const testLayer = MimicConfig.layer({
91
- schema: TestSchema,
92
- maxTransactionHistory: 100,
93
- });
94
-
95
- const result = await Effect.runPromise(
96
- Effect.gen(function* () {
97
- const config = yield* MimicConfig.MimicServerConfigTag;
98
- return config;
99
- }).pipe(Effect.provide(testLayer))
100
- );
101
-
102
- expect(result.schema).toBe(TestSchema);
103
- expect(result.maxTransactionHistory).toBe(100);
104
- });
105
- });
106
-
107
- describe("MimicServerConfigTag", () => {
108
- it("should have the correct tag identifier", () => {
109
- expect(MimicConfig.MimicServerConfigTag.key).toBe(
110
- "@voidhash/mimic-server-effect/MimicServerConfig"
111
- );
112
- });
113
- });
114
-
115
- describe("presence configuration", () => {
116
- const CursorPresence = Presence.make({
117
- schema: Schema.Struct({
118
- x: Schema.Number,
119
- y: Schema.Number,
120
- name: Schema.optional(Schema.String),
121
- }),
122
- });
123
-
124
- it("should have undefined presence by default", () => {
125
- const config = MimicConfig.make({
126
- schema: TestSchema,
127
- });
128
-
129
- expect(config.presence).toBeUndefined();
130
- });
131
-
132
- it("should accept presence schema option", () => {
133
- const config = MimicConfig.make({
134
- schema: TestSchema,
135
- presence: CursorPresence,
136
- });
137
-
138
- expect(config.presence).toBe(CursorPresence);
139
- });
140
-
141
- it("should provide presence through layer", async () => {
142
- const testLayer = MimicConfig.layer({
143
- schema: TestSchema,
144
- presence: CursorPresence,
145
- });
146
-
147
- const result = await Effect.runPromise(
148
- Effect.gen(function* () {
149
- const config = yield* MimicConfig.MimicServerConfigTag;
150
- return config.presence;
151
- }).pipe(Effect.provide(testLayer))
152
- );
153
-
154
- expect(result).toBe(CursorPresence);
155
- });
156
-
157
- it("should work with all options including presence", () => {
158
- const config = MimicConfig.make({
159
- schema: TestSchema,
160
- maxIdleTime: "10 minutes",
161
- maxTransactionHistory: 500,
162
- heartbeatInterval: "1 minute",
163
- heartbeatTimeout: "20 seconds",
164
- presence: CursorPresence,
165
- });
166
-
167
- expect(config.schema).toBe(TestSchema);
168
- expect(Duration.toMillis(config.maxIdleTime)).toBe(10 * 60 * 1000);
169
- expect(config.maxTransactionHistory).toBe(500);
170
- expect(Duration.toMillis(config.heartbeatInterval)).toBe(60 * 1000);
171
- expect(Duration.toMillis(config.heartbeatTimeout)).toBe(20 * 1000);
172
- expect(config.presence).toBe(CursorPresence);
173
- });
174
- });
175
-
176
- describe("initial state configuration", () => {
177
- it("should have undefined initial state by default", () => {
178
- const config = MimicConfig.make({
179
- schema: TestSchema,
180
- });
181
-
182
- expect(config.initial).toBeUndefined();
183
- });
184
-
185
- it("should accept initial state object and convert to function", async () => {
186
- const config = MimicConfig.make({
187
- schema: TestSchema,
188
- initial: { title: "My Document", count: 42 },
189
- });
190
-
191
- expect(typeof config.initial).toBe("function");
192
- // The function should return the initial state when called
193
- const result = await Effect.runPromise(config.initial!({ documentId: "test-doc" }));
194
- expect(result).toEqual({ title: "My Document", count: 42 });
195
- });
196
-
197
- it("should apply defaults for omitted fields in initial state object", async () => {
198
- const config = MimicConfig.make({
199
- schema: TestSchema,
200
- initial: { title: "My Document" }, // count has default of 0
201
- });
202
-
203
- const result = await Effect.runPromise(config.initial!({ documentId: "test-doc" }));
204
- expect(result).toEqual({ title: "My Document", count: 0 });
205
- });
206
-
207
- it("should accept initial state function", async () => {
208
- const config = MimicConfig.make({
209
- schema: TestSchema,
210
- initial: ({ documentId }) => Effect.succeed({ title: `Doc ${documentId}`, count: 123 }),
211
- });
212
-
213
- expect(typeof config.initial).toBe("function");
214
- const result = await Effect.runPromise(config.initial!({ documentId: "my-doc-id" }));
215
- expect(result).toEqual({ title: "Doc my-doc-id", count: 123 });
216
- });
217
-
218
- it("should apply defaults to initial state function result", async () => {
219
- const config = MimicConfig.make({
220
- schema: TestSchema,
221
- initial: ({ documentId }) => Effect.succeed({ title: documentId }), // count omitted
222
- });
223
-
224
- const result = await Effect.runPromise(config.initial!({ documentId: "test" }));
225
- expect(result).toEqual({ title: "test", count: 0 });
226
- });
227
-
228
- it("should provide initial function through layer", async () => {
229
- const testLayer = MimicConfig.layer({
230
- schema: TestSchema,
231
- initial: { title: "From Layer", count: 100 },
232
- });
233
-
234
- const result = await Effect.runPromise(
235
- Effect.gen(function* () {
236
- const config = yield* MimicConfig.MimicServerConfigTag;
237
- return yield* config.initial!({ documentId: "layer-doc" });
238
- }).pipe(Effect.provide(testLayer))
239
- );
240
-
241
- expect(result).toEqual({ title: "From Layer", count: 100 });
242
- });
243
-
244
- it("should work with schema that has required fields without defaults", async () => {
245
- const SchemaWithRequired = Primitive.Struct({
246
- name: Primitive.String().required(),
247
- optional: Primitive.String().default("default"),
248
- });
249
-
250
- const config = MimicConfig.make({
251
- schema: SchemaWithRequired,
252
- initial: { name: "Required Name" },
253
- });
254
-
255
- const result = await Effect.runPromise(config.initial!({ documentId: "test" }));
256
- expect(result).toEqual({ name: "Required Name", optional: "default" });
257
- });
258
-
259
- it("should work with all options including initial object", async () => {
260
- const config = MimicConfig.make({
261
- schema: TestSchema,
262
- maxIdleTime: "10 minutes",
263
- maxTransactionHistory: 500,
264
- initial: { title: "Full Options", count: 999 },
265
- });
266
-
267
- expect(config.schema).toBe(TestSchema);
268
- expect(Duration.toMillis(config.maxIdleTime)).toBe(10 * 60 * 1000);
269
- expect(config.maxTransactionHistory).toBe(500);
270
- const result = await Effect.runPromise(config.initial!({ documentId: "test" }));
271
- expect(result).toEqual({ title: "Full Options", count: 999 });
272
- });
273
-
274
- it("should work with initial function that uses documentId", async () => {
275
- const config = MimicConfig.make({
276
- schema: TestSchema,
277
- initial: ({ documentId }) => Effect.succeed({
278
- title: `Document: ${documentId}`,
279
- count: documentId.length,
280
- }),
281
- });
282
-
283
- const result1 = await Effect.runPromise(config.initial!({ documentId: "short" }));
284
- expect(result1).toEqual({ title: "Document: short", count: 5 });
285
-
286
- const result2 = await Effect.runPromise(config.initial!({ documentId: "longer-id" }));
287
- expect(result2).toEqual({ title: "Document: longer-id", count: 9 });
288
- });
289
- });
290
- });