@voidhash/mimic-effect 0.0.9 → 1.0.0-beta.2

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 (227) hide show
  1. package/.turbo/turbo-build.log +136 -90
  2. package/README.md +385 -0
  3. package/dist/ColdStorage.cjs +60 -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 +60 -0
  9. package/dist/ColdStorage.mjs.map +1 -0
  10. package/dist/DocumentManager.cjs +263 -82
  11. package/dist/DocumentManager.d.cts +44 -22
  12. package/dist/DocumentManager.d.cts.map +1 -1
  13. package/dist/DocumentManager.d.mts +44 -22
  14. package/dist/DocumentManager.d.mts.map +1 -1
  15. package/dist/DocumentManager.mjs +259 -67
  16. package/dist/DocumentManager.mjs.map +1 -1
  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 +100 -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 +100 -0
  30. package/dist/HotStorage.mjs.map +1 -0
  31. package/dist/Metrics.cjs +143 -0
  32. package/dist/Metrics.d.cts +31 -0
  33. package/dist/Metrics.d.cts.map +1 -0
  34. package/dist/Metrics.d.mts +31 -0
  35. package/dist/Metrics.d.mts.map +1 -0
  36. package/dist/Metrics.mjs +126 -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 +521 -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 +523 -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 +97 -0
  60. package/dist/MimicServerEngine.d.cts +78 -0
  61. package/dist/MimicServerEngine.d.cts.map +1 -0
  62. package/dist/MimicServerEngine.d.mts +78 -0
  63. package/dist/MimicServerEngine.d.mts.map +1 -0
  64. package/dist/MimicServerEngine.mjs +97 -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 +172 -0
  81. package/dist/Types.d.cts.map +1 -0
  82. package/dist/Types.d.mts +172 -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 -75
  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 +135 -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 +136 -0
  103. package/dist/testing/FailingStorage.mjs.map +1 -0
  104. package/dist/testing/HotStorageTestSuite.cjs +585 -0
  105. package/dist/testing/HotStorageTestSuite.d.cts +40 -0
  106. package/dist/testing/HotStorageTestSuite.d.cts.map +1 -0
  107. package/dist/testing/HotStorageTestSuite.d.mts +40 -0
  108. package/dist/testing/HotStorageTestSuite.d.mts.map +1 -0
  109. package/dist/testing/HotStorageTestSuite.mjs +585 -0
  110. package/dist/testing/HotStorageTestSuite.mjs.map +1 -0
  111. package/dist/testing/StorageIntegrationTestSuite.cjs +349 -0
  112. package/dist/testing/StorageIntegrationTestSuite.d.cts +35 -0
  113. package/dist/testing/StorageIntegrationTestSuite.d.cts.map +1 -0
  114. package/dist/testing/StorageIntegrationTestSuite.d.mts +35 -0
  115. package/dist/testing/StorageIntegrationTestSuite.d.mts.map +1 -0
  116. package/dist/testing/StorageIntegrationTestSuite.mjs +349 -0
  117. package/dist/testing/StorageIntegrationTestSuite.mjs.map +1 -0
  118. package/dist/testing/assertions.cjs +114 -0
  119. package/dist/testing/assertions.mjs +109 -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 +136 -0
  134. package/src/DocumentManager.ts +550 -190
  135. package/src/Errors.ts +114 -0
  136. package/src/HotStorage.ts +239 -0
  137. package/src/Metrics.ts +187 -0
  138. package/src/MimicAuthService.ts +126 -64
  139. package/src/MimicClusterServerEngine.ts +946 -0
  140. package/src/MimicServer.ts +448 -195
  141. package/src/MimicServerEngine.ts +276 -0
  142. package/src/PresenceManager.ts +169 -240
  143. package/src/Protocol.ts +350 -0
  144. package/src/Types.ts +231 -0
  145. package/src/index.ts +57 -23
  146. package/src/testing/ColdStorageTestSuite.ts +589 -0
  147. package/src/testing/FailingStorage.ts +286 -0
  148. package/src/testing/HotStorageTestSuite.ts +762 -0
  149. package/src/testing/StorageIntegrationTestSuite.ts +504 -0
  150. package/src/testing/assertions.ts +181 -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/DocumentManager.test.ts +158 -287
  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/DocumentProtocol.cjs +0 -94
  166. package/dist/DocumentProtocol.d.cts +0 -113
  167. package/dist/DocumentProtocol.d.cts.map +0 -1
  168. package/dist/DocumentProtocol.d.mts +0 -113
  169. package/dist/DocumentProtocol.d.mts.map +0 -1
  170. package/dist/DocumentProtocol.mjs +0 -89
  171. package/dist/DocumentProtocol.mjs.map +0 -1
  172. package/dist/MimicConfig.cjs +0 -60
  173. package/dist/MimicConfig.d.cts +0 -141
  174. package/dist/MimicConfig.d.cts.map +0 -1
  175. package/dist/MimicConfig.d.mts +0 -141
  176. package/dist/MimicConfig.d.mts.map +0 -1
  177. package/dist/MimicConfig.mjs +0 -50
  178. package/dist/MimicConfig.mjs.map +0 -1
  179. package/dist/MimicDataStorage.cjs +0 -83
  180. package/dist/MimicDataStorage.d.cts +0 -113
  181. package/dist/MimicDataStorage.d.cts.map +0 -1
  182. package/dist/MimicDataStorage.d.mts +0 -113
  183. package/dist/MimicDataStorage.d.mts.map +0 -1
  184. package/dist/MimicDataStorage.mjs +0 -74
  185. package/dist/MimicDataStorage.mjs.map +0 -1
  186. package/dist/WebSocketHandler.cjs +0 -365
  187. package/dist/WebSocketHandler.d.cts +0 -34
  188. package/dist/WebSocketHandler.d.cts.map +0 -1
  189. package/dist/WebSocketHandler.d.mts +0 -34
  190. package/dist/WebSocketHandler.d.mts.map +0 -1
  191. package/dist/WebSocketHandler.mjs +0 -355
  192. package/dist/WebSocketHandler.mjs.map +0 -1
  193. package/dist/auth/NoAuth.cjs +0 -43
  194. package/dist/auth/NoAuth.d.cts +0 -22
  195. package/dist/auth/NoAuth.d.cts.map +0 -1
  196. package/dist/auth/NoAuth.d.mts +0 -22
  197. package/dist/auth/NoAuth.d.mts.map +0 -1
  198. package/dist/auth/NoAuth.mjs +0 -36
  199. package/dist/auth/NoAuth.mjs.map +0 -1
  200. package/dist/errors.cjs +0 -74
  201. package/dist/errors.d.cts +0 -89
  202. package/dist/errors.d.cts.map +0 -1
  203. package/dist/errors.d.mts +0 -89
  204. package/dist/errors.d.mts.map +0 -1
  205. package/dist/errors.mjs +0 -67
  206. package/dist/errors.mjs.map +0 -1
  207. package/dist/storage/InMemoryDataStorage.cjs +0 -57
  208. package/dist/storage/InMemoryDataStorage.d.cts +0 -19
  209. package/dist/storage/InMemoryDataStorage.d.cts.map +0 -1
  210. package/dist/storage/InMemoryDataStorage.d.mts +0 -19
  211. package/dist/storage/InMemoryDataStorage.d.mts.map +0 -1
  212. package/dist/storage/InMemoryDataStorage.mjs +0 -48
  213. package/dist/storage/InMemoryDataStorage.mjs.map +0 -1
  214. package/src/DocumentProtocol.ts +0 -112
  215. package/src/MimicConfig.ts +0 -211
  216. package/src/MimicDataStorage.ts +0 -157
  217. package/src/WebSocketHandler.ts +0 -735
  218. package/src/auth/NoAuth.ts +0 -46
  219. package/src/errors.ts +0 -113
  220. package/src/storage/InMemoryDataStorage.ts +0 -66
  221. package/tests/DocumentProtocol.test.ts +0 -113
  222. package/tests/InMemoryDataStorage.test.ts +0 -190
  223. package/tests/MimicConfig.test.ts +0 -290
  224. package/tests/MimicDataStorage.test.ts +0 -190
  225. package/tests/NoAuth.test.ts +0 -94
  226. package/tests/WebSocketHandler.test.ts +0 -321
  227. package/tests/errors.test.ts +0 -77
@@ -0,0 +1,96 @@
1
+ import * as effect_Types0 from "effect/Types";
2
+ import * as effect_Cause0 from "effect/Cause";
3
+
4
+ //#region src/Errors.d.ts
5
+ declare const ColdStorageError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
6
+ readonly _tag: "ColdStorageError";
7
+ } & Readonly<A>;
8
+ /**
9
+ * Error when ColdStorage (snapshot storage) operations fail
10
+ */
11
+ declare class ColdStorageError extends ColdStorageError_base<{
12
+ readonly documentId: string;
13
+ readonly operation: "load" | "save" | "delete";
14
+ readonly cause: unknown;
15
+ }> {}
16
+ declare const HotStorageError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
17
+ readonly _tag: "HotStorageError";
18
+ } & Readonly<A>;
19
+ /**
20
+ * Error when HotStorage (WAL storage) operations fail
21
+ */
22
+ declare class HotStorageError extends HotStorageError_base<{
23
+ readonly documentId: string;
24
+ readonly operation: "append" | "getEntries" | "truncate" | "appendWithCheck";
25
+ readonly cause: unknown;
26
+ }> {}
27
+ declare const WalVersionGapError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
28
+ readonly _tag: "WalVersionGapError";
29
+ } & Readonly<A>;
30
+ /**
31
+ * Error when WAL append detects a version gap.
32
+ * This indicates either:
33
+ * - A bug in the application (skipped a version)
34
+ * - Concurrent writes to the same document
35
+ * - Data corruption in WAL storage
36
+ */
37
+ declare class WalVersionGapError extends WalVersionGapError_base<{
38
+ readonly documentId: string;
39
+ readonly expectedVersion: number;
40
+ readonly actualPreviousVersion: number | undefined;
41
+ }> {}
42
+ declare const AuthenticationError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
43
+ readonly _tag: "AuthenticationError";
44
+ } & Readonly<A>;
45
+ /**
46
+ * Error when authentication fails (invalid token, expired, etc.)
47
+ */
48
+ declare class AuthenticationError extends AuthenticationError_base<{
49
+ readonly reason: string;
50
+ }> {}
51
+ declare const AuthorizationError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
52
+ readonly _tag: "AuthorizationError";
53
+ } & Readonly<A>;
54
+ /**
55
+ * Error when authorization fails (user doesn't have required permission)
56
+ */
57
+ declare class AuthorizationError extends AuthorizationError_base<{
58
+ readonly reason: string;
59
+ readonly required: "read" | "write";
60
+ readonly actual: "read" | "write";
61
+ }> {}
62
+ declare const MissingDocumentIdError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
63
+ readonly _tag: "MissingDocumentIdError";
64
+ } & Readonly<A>;
65
+ /**
66
+ * Error when document ID is missing from WebSocket request path
67
+ */
68
+ declare class MissingDocumentIdError extends MissingDocumentIdError_base<{
69
+ readonly path: string;
70
+ }> {}
71
+ declare const MessageParseError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
72
+ readonly _tag: "MessageParseError";
73
+ } & Readonly<A>;
74
+ /**
75
+ * Error when WebSocket message cannot be parsed
76
+ */
77
+ declare class MessageParseError extends MessageParseError_base<{
78
+ readonly cause: unknown;
79
+ }> {}
80
+ declare const TransactionRejectedError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
81
+ readonly _tag: "TransactionRejectedError";
82
+ } & Readonly<A>;
83
+ /**
84
+ * Error when a transaction is rejected by the document
85
+ */
86
+ declare class TransactionRejectedError extends TransactionRejectedError_base<{
87
+ readonly transactionId: string;
88
+ readonly reason: string;
89
+ }> {}
90
+ /**
91
+ * Union of all mimic-effect errors
92
+ */
93
+ type MimicError = ColdStorageError | HotStorageError | WalVersionGapError | AuthenticationError | AuthorizationError | MissingDocumentIdError | MessageParseError | TransactionRejectedError;
94
+ //#endregion
95
+ export { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MimicError, MissingDocumentIdError, TransactionRejectedError, WalVersionGapError };
96
+ //# sourceMappingURL=Errors.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Errors.d.mts","names":[],"sources":["../src/Errors.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;cAca,gBAAA,SAAyB;;;;;cAIjC;;;;;AAJL;AAIK,cAKQ,eAAA,SAAwB,oBALhC,CAAA;;;;;cASA;;;;;;;AAJL;AAIK;;cASQ,kBAAA,SAA2B;;;;;cAInC;;;;;AAJL;AAIK,cASQ,mBAAA,SAA4B,wBATpC,CAAA;;;cAaA;;;;;;cAKQ,kBAAA,SAA2B;;;EAT3B,SAAA,MAAA,EAAA,MAAoB,GAAA,OAAA;AAI5B,CAAA,CAAA,CAAA;cASA;;;;;;cASQ,sBAAA,SAA+B;;;cAIvC;EAjBQ,SAAA,IAAA,EAAA,mBAA2B;AAInC,CAAA,WAAA,EAAA,CAAA;;;;cAkBQ,iBAAA,SAA0B;;;cAElC;;;;;AAXL;AAIK,cAgBQ,wBAAA,SAAiC,6BAhBzC,CAAA;;;;;;;KA8BO,UAAA,GACR,mBACA,kBACA,qBACA,sBACA,qBACA,yBACA,oBACA"}
@@ -0,0 +1,48 @@
1
+ import { Data } from "effect";
2
+
3
+ //#region src/Errors.ts
4
+ /**
5
+ * @voidhash/mimic-effect - Error Types
6
+ *
7
+ * All error types used throughout the mimic-effect package.
8
+ */
9
+ /**
10
+ * Error when ColdStorage (snapshot storage) operations fail
11
+ */
12
+ var ColdStorageError = class extends Data.TaggedError("ColdStorageError") {};
13
+ /**
14
+ * Error when HotStorage (WAL storage) operations fail
15
+ */
16
+ var HotStorageError = class extends Data.TaggedError("HotStorageError") {};
17
+ /**
18
+ * Error when WAL append detects a version gap.
19
+ * This indicates either:
20
+ * - A bug in the application (skipped a version)
21
+ * - Concurrent writes to the same document
22
+ * - Data corruption in WAL storage
23
+ */
24
+ var WalVersionGapError = class extends Data.TaggedError("WalVersionGapError") {};
25
+ /**
26
+ * Error when authentication fails (invalid token, expired, etc.)
27
+ */
28
+ var AuthenticationError = class extends Data.TaggedError("AuthenticationError") {};
29
+ /**
30
+ * Error when authorization fails (user doesn't have required permission)
31
+ */
32
+ var AuthorizationError = class extends Data.TaggedError("AuthorizationError") {};
33
+ /**
34
+ * Error when document ID is missing from WebSocket request path
35
+ */
36
+ var MissingDocumentIdError = class extends Data.TaggedError("MissingDocumentIdError") {};
37
+ /**
38
+ * Error when WebSocket message cannot be parsed
39
+ */
40
+ var MessageParseError = class extends Data.TaggedError("MessageParseError") {};
41
+ /**
42
+ * Error when a transaction is rejected by the document
43
+ */
44
+ var TransactionRejectedError = class extends Data.TaggedError("TransactionRejectedError") {};
45
+
46
+ //#endregion
47
+ export { AuthenticationError, AuthorizationError, ColdStorageError, HotStorageError, MessageParseError, MissingDocumentIdError, TransactionRejectedError, WalVersionGapError };
48
+ //# sourceMappingURL=Errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Errors.mjs","names":[],"sources":["../src/Errors.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - Error Types\n *\n * All error types used throughout the mimic-effect package.\n */\nimport { Data } from \"effect\";\n\n// =============================================================================\n// Storage Errors\n// =============================================================================\n\n/**\n * Error when ColdStorage (snapshot storage) operations fail\n */\nexport class ColdStorageError extends Data.TaggedError(\"ColdStorageError\")<{\n readonly documentId: string;\n readonly operation: \"load\" | \"save\" | \"delete\";\n readonly cause: unknown;\n}> {}\n\n/**\n * Error when HotStorage (WAL storage) operations fail\n */\nexport class HotStorageError extends Data.TaggedError(\"HotStorageError\")<{\n readonly documentId: string;\n readonly operation: \"append\" | \"getEntries\" | \"truncate\" | \"appendWithCheck\";\n readonly cause: unknown;\n}> {}\n\n/**\n * Error when WAL append detects a version gap.\n * This indicates either:\n * - A bug in the application (skipped a version)\n * - Concurrent writes to the same document\n * - Data corruption in WAL storage\n */\nexport class WalVersionGapError extends Data.TaggedError(\"WalVersionGapError\")<{\n readonly documentId: string;\n readonly expectedVersion: number;\n readonly actualPreviousVersion: number | undefined;\n}> {}\n\n// =============================================================================\n// Auth Errors\n// =============================================================================\n\n/**\n * Error when authentication fails (invalid token, expired, etc.)\n */\nexport class AuthenticationError extends Data.TaggedError(\n \"AuthenticationError\"\n)<{\n readonly reason: string;\n}> {}\n\n/**\n * Error when authorization fails (user doesn't have required permission)\n */\nexport class AuthorizationError extends Data.TaggedError(\"AuthorizationError\")<{\n readonly reason: string;\n readonly required: \"read\" | \"write\";\n readonly actual: \"read\" | \"write\";\n}> {}\n\n// =============================================================================\n// Connection Errors\n// =============================================================================\n\n/**\n * Error when document ID is missing from WebSocket request path\n */\nexport class MissingDocumentIdError extends Data.TaggedError(\n \"MissingDocumentIdError\"\n)<{\n readonly path: string;\n}> {}\n\n/**\n * Error when WebSocket message cannot be parsed\n */\nexport class MessageParseError extends Data.TaggedError(\"MessageParseError\")<{\n readonly cause: unknown;\n}> {}\n\n// =============================================================================\n// Transaction Errors\n// =============================================================================\n\n/**\n * Error when a transaction is rejected by the document\n */\nexport class TransactionRejectedError extends Data.TaggedError(\n \"TransactionRejectedError\"\n)<{\n readonly transactionId: string;\n readonly reason: string;\n}> {}\n\n// =============================================================================\n// Union Type\n// =============================================================================\n\n/**\n * Union of all mimic-effect errors\n */\nexport type MimicError =\n | ColdStorageError\n | HotStorageError\n | WalVersionGapError\n | AuthenticationError\n | AuthorizationError\n | MissingDocumentIdError\n | MessageParseError\n | TransactionRejectedError;\n"],"mappings":";;;;;;;;;;;AAcA,IAAa,mBAAb,cAAsC,KAAK,YAAY,mBAAmB,CAIvE;;;;AAKH,IAAa,kBAAb,cAAqC,KAAK,YAAY,kBAAkB,CAIrE;;;;;;;;AASH,IAAa,qBAAb,cAAwC,KAAK,YAAY,qBAAqB,CAI3E;;;;AASH,IAAa,sBAAb,cAAyC,KAAK,YAC5C,sBACD,CAEE;;;;AAKH,IAAa,qBAAb,cAAwC,KAAK,YAAY,qBAAqB,CAI3E;;;;AASH,IAAa,yBAAb,cAA4C,KAAK,YAC/C,yBACD,CAEE;;;;AAKH,IAAa,oBAAb,cAAuC,KAAK,YAAY,oBAAoB,CAEzE;;;;AASH,IAAa,2BAAb,cAA8C,KAAK,YACjD,2BACD,CAGE"}
@@ -0,0 +1,100 @@
1
+ const require_Errors = require('./Errors.cjs');
2
+ let effect = require("effect");
3
+
4
+ //#region src/HotStorage.ts
5
+ /**
6
+ * @voidhash/mimic-effect - HotStorage
7
+ *
8
+ * Interface and implementations for Write-Ahead Log (WAL) storage.
9
+ */
10
+ /**
11
+ * Context tag for HotStorage service
12
+ */
13
+ var HotStorageTag = class extends effect.Context.Tag("@voidhash/mimic-effect/HotStorage")() {};
14
+ /**
15
+ * Create a HotStorage layer from an Effect that produces a HotStorage service.
16
+ *
17
+ * This allows you to access other Effect services when implementing custom storage.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const Hot = HotStorage.make(
22
+ * Effect.gen(function*() {
23
+ * const redis = yield* RedisService
24
+ *
25
+ * return {
26
+ * append: (documentId, entry) =>
27
+ * redis.rpush(`wal:${documentId}`, JSON.stringify(entry)),
28
+ * getEntries: (documentId, sinceVersion) =>
29
+ * redis.lrange(`wal:${documentId}`, 0, -1).pipe(
30
+ * Effect.map(entries =>
31
+ * entries
32
+ * .map(e => JSON.parse(e))
33
+ * .filter(e => e.version > sinceVersion)
34
+ * .sort((a, b) => a.version - b.version)
35
+ * )
36
+ * ),
37
+ * truncate: (documentId, upToVersion) =>
38
+ * // Implementation depends on Redis data structure
39
+ * Effect.void,
40
+ * }
41
+ * })
42
+ * )
43
+ * ```
44
+ */
45
+ const make = (effect$1) => effect.Layer.effect(HotStorageTag, effect$1);
46
+ let InMemory;
47
+ (function(_InMemory) {
48
+ _InMemory.make = () => effect.Layer.effect(HotStorageTag, effect.Effect.gen(function* () {
49
+ const store = yield* effect.Ref.make(effect.HashMap.empty());
50
+ return {
51
+ append: (documentId, entry) => effect.Ref.update(store, (map) => {
52
+ const existing = effect.HashMap.get(map, documentId);
53
+ const entries = existing._tag === "Some" ? existing.value : [];
54
+ return effect.HashMap.set(map, documentId, [...entries, entry]);
55
+ }),
56
+ appendWithCheck: (documentId, entry, expectedVersion) => effect.Effect.gen(function* () {
57
+ const result = yield* effect.Ref.modify(store, (map) => {
58
+ const existing = effect.HashMap.get(map, documentId);
59
+ const entries = existing._tag === "Some" ? existing.value : [];
60
+ const lastVersion = entries.length > 0 ? Math.max(...entries.map((e) => e.version)) : 0;
61
+ if (expectedVersion === 1) {
62
+ if (lastVersion >= 1) return [{
63
+ type: "gap",
64
+ lastVersion
65
+ }, map];
66
+ } else if (lastVersion !== expectedVersion - 1) return [{
67
+ type: "gap",
68
+ lastVersion: lastVersion > 0 ? lastVersion : void 0
69
+ }, map];
70
+ return [{ type: "ok" }, effect.HashMap.set(map, documentId, [...entries, entry])];
71
+ });
72
+ if (result.type === "gap") return yield* effect.Effect.fail(new require_Errors.WalVersionGapError({
73
+ documentId,
74
+ expectedVersion,
75
+ actualPreviousVersion: result.lastVersion
76
+ }));
77
+ }),
78
+ getEntries: (documentId, sinceVersion) => effect.Effect.gen(function* () {
79
+ const current = yield* effect.Ref.get(store);
80
+ const existing = effect.HashMap.get(current, documentId);
81
+ return (existing._tag === "Some" ? existing.value : []).filter((e) => e.version > sinceVersion).sort((a, b) => a.version - b.version);
82
+ }),
83
+ truncate: (documentId, upToVersion) => effect.Ref.update(store, (map) => {
84
+ const existing = effect.HashMap.get(map, documentId);
85
+ if (existing._tag === "None") return map;
86
+ const filtered = existing.value.filter((e) => e.version > upToVersion);
87
+ return effect.HashMap.set(map, documentId, filtered);
88
+ })
89
+ };
90
+ }));
91
+ })(InMemory || (InMemory = {}));
92
+ const HotStorage = {
93
+ Tag: HotStorageTag,
94
+ make,
95
+ InMemory
96
+ };
97
+
98
+ //#endregion
99
+ exports.HotStorage = HotStorage;
100
+ exports.HotStorageTag = HotStorageTag;
@@ -0,0 +1,70 @@
1
+ import { WalEntry } from "./Types.cjs";
2
+ import { HotStorageError, WalVersionGapError } from "./Errors.cjs";
3
+ import { Context, Effect, Layer } from "effect";
4
+
5
+ //#region src/HotStorage.d.ts
6
+
7
+ /**
8
+ * HotStorage interface for storing Write-Ahead Log entries.
9
+ *
10
+ * This is the "hot" tier of the two-tier storage system.
11
+ * It stores every transaction as a WAL entry for durability between snapshots.
12
+ * WAL entries are small (just the transaction) and writes are append-only.
13
+ */
14
+ interface HotStorage {
15
+ /**
16
+ * Append a WAL entry for a document.
17
+ */
18
+ readonly append: (documentId: string, entry: WalEntry) => Effect.Effect<void, HotStorageError>;
19
+ /**
20
+ * Append a WAL entry with version gap checking.
21
+ *
22
+ * This is an atomic operation that:
23
+ * 1. Verifies the previous entry has version = expectedVersion - 1
24
+ * (or this is the first entry if expectedVersion === 1)
25
+ * 2. Appends the entry if check passes
26
+ *
27
+ * Use this for two-phase commit to guarantee WAL ordering at write time.
28
+ *
29
+ * @param documentId - Document ID
30
+ * @param entry - WAL entry to append
31
+ * @param expectedVersion - The version this entry should have (entry.version)
32
+ * @returns Effect that fails with WalVersionGapError if gap detected
33
+ */
34
+ readonly appendWithCheck: (documentId: string, entry: WalEntry, expectedVersion: number) => Effect.Effect<void, HotStorageError | WalVersionGapError>;
35
+ /**
36
+ * Get all WAL entries for a document since a given version.
37
+ * Returns entries with version > sinceVersion, ordered by version.
38
+ */
39
+ readonly getEntries: (documentId: string, sinceVersion: number) => Effect.Effect<WalEntry[], HotStorageError>;
40
+ /**
41
+ * Truncate WAL entries up to (and including) a given version.
42
+ * Called after a snapshot is saved to remove entries that are now in the snapshot.
43
+ */
44
+ readonly truncate: (documentId: string, upToVersion: number) => Effect.Effect<void, HotStorageError>;
45
+ }
46
+ declare const HotStorageTag_base: Context.TagClass<HotStorageTag, "@voidhash/mimic-effect/HotStorage", HotStorage>;
47
+ /**
48
+ * Context tag for HotStorage service
49
+ */
50
+ declare class HotStorageTag extends HotStorageTag_base {}
51
+ /**
52
+ * In-memory HotStorage implementation.
53
+ *
54
+ * Useful for testing and development. Not suitable for production
55
+ * as data is lost when the process restarts.
56
+ */
57
+ declare namespace InMemory {
58
+ /**
59
+ * Create an in-memory HotStorage layer.
60
+ */
61
+ const make: () => Layer.Layer<HotStorageTag>;
62
+ }
63
+ declare const HotStorage: {
64
+ Tag: typeof HotStorageTag;
65
+ make: <E, R>(effect: Effect.Effect<HotStorage, E, R>) => Layer.Layer<HotStorageTag, E, R>;
66
+ InMemory: typeof InMemory;
67
+ };
68
+ //#endregion
69
+ export { HotStorage, HotStorageTag };
70
+ //# sourceMappingURL=HotStorage.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HotStorage.d.cts","names":[],"sources":["../src/HotStorage.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;AAyDO,UArCU,UAAA,CAqCH;EASa;;;EAC1B,SAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,KAAA,EAzCU,QAyCV,EAAA,GAxCM,MAAA,CAAO,MAwCb,CAAA,IAAA,EAxC0B,eAwC1B,CAAA;;;;;AASD;AAuDA;AAuGA;;;;;;;;;EApHG,SAAM,eAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,KAAA,EAxEE,QAwEF,EAAA,eAAA,EAAA,MAAA,EAAA,GAtEF,MAAA,CAAO,MAsEL,CAAA,IAAA,EAtEkB,eAsElB,GAtEoC,kBAsEpC,CAAA;;;;;qEA7DF,MAAA,CAAO,OAAO,YAAY;;;;;kEAS1B,MAAA,CAAO,aAAa;;cAC1B;;;;cASY,aAAA,SAAsB,kBAAA;;;;;;;kBAuDlB,QAAA;;;;oBAIS,KAAA,CAAM,MAAM;;cAmGzB;;uBArHH,MAAA,CAAO,OAAO,YAAY,GAAG,OACpC,KAAA,CAAM,MAAM,eAAe,GAAG"}
@@ -0,0 +1,70 @@
1
+ import { WalEntry } from "./Types.mjs";
2
+ import { HotStorageError, WalVersionGapError } from "./Errors.mjs";
3
+ import { Context, Effect, Layer } from "effect";
4
+
5
+ //#region src/HotStorage.d.ts
6
+
7
+ /**
8
+ * HotStorage interface for storing Write-Ahead Log entries.
9
+ *
10
+ * This is the "hot" tier of the two-tier storage system.
11
+ * It stores every transaction as a WAL entry for durability between snapshots.
12
+ * WAL entries are small (just the transaction) and writes are append-only.
13
+ */
14
+ interface HotStorage {
15
+ /**
16
+ * Append a WAL entry for a document.
17
+ */
18
+ readonly append: (documentId: string, entry: WalEntry) => Effect.Effect<void, HotStorageError>;
19
+ /**
20
+ * Append a WAL entry with version gap checking.
21
+ *
22
+ * This is an atomic operation that:
23
+ * 1. Verifies the previous entry has version = expectedVersion - 1
24
+ * (or this is the first entry if expectedVersion === 1)
25
+ * 2. Appends the entry if check passes
26
+ *
27
+ * Use this for two-phase commit to guarantee WAL ordering at write time.
28
+ *
29
+ * @param documentId - Document ID
30
+ * @param entry - WAL entry to append
31
+ * @param expectedVersion - The version this entry should have (entry.version)
32
+ * @returns Effect that fails with WalVersionGapError if gap detected
33
+ */
34
+ readonly appendWithCheck: (documentId: string, entry: WalEntry, expectedVersion: number) => Effect.Effect<void, HotStorageError | WalVersionGapError>;
35
+ /**
36
+ * Get all WAL entries for a document since a given version.
37
+ * Returns entries with version > sinceVersion, ordered by version.
38
+ */
39
+ readonly getEntries: (documentId: string, sinceVersion: number) => Effect.Effect<WalEntry[], HotStorageError>;
40
+ /**
41
+ * Truncate WAL entries up to (and including) a given version.
42
+ * Called after a snapshot is saved to remove entries that are now in the snapshot.
43
+ */
44
+ readonly truncate: (documentId: string, upToVersion: number) => Effect.Effect<void, HotStorageError>;
45
+ }
46
+ declare const HotStorageTag_base: Context.TagClass<HotStorageTag, "@voidhash/mimic-effect/HotStorage", HotStorage>;
47
+ /**
48
+ * Context tag for HotStorage service
49
+ */
50
+ declare class HotStorageTag extends HotStorageTag_base {}
51
+ /**
52
+ * In-memory HotStorage implementation.
53
+ *
54
+ * Useful for testing and development. Not suitable for production
55
+ * as data is lost when the process restarts.
56
+ */
57
+ declare namespace InMemory {
58
+ /**
59
+ * Create an in-memory HotStorage layer.
60
+ */
61
+ const make: () => Layer.Layer<HotStorageTag>;
62
+ }
63
+ declare const HotStorage: {
64
+ Tag: typeof HotStorageTag;
65
+ make: <E, R>(effect: Effect.Effect<HotStorage, E, R>) => Layer.Layer<HotStorageTag, E, R>;
66
+ InMemory: typeof InMemory;
67
+ };
68
+ //#endregion
69
+ export { HotStorage, HotStorageTag };
70
+ //# sourceMappingURL=HotStorage.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HotStorage.d.mts","names":[],"sources":["../src/HotStorage.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;AAyDO,UArCU,UAAA,CAqCH;EASa;;;EAC1B,SAAA,MAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,KAAA,EAzCU,QAyCV,EAAA,GAxCM,MAAA,CAAO,MAwCb,CAAA,IAAA,EAxC0B,eAwC1B,CAAA;;;;;AASD;AAuDA;AAuGA;;;;;;;;;EApHG,SAAM,eAAA,EAAA,CAAA,UAAA,EAAA,MAAA,EAAA,KAAA,EAxEE,QAwEF,EAAA,eAAA,EAAA,MAAA,EAAA,GAtEF,MAAA,CAAO,MAsEL,CAAA,IAAA,EAtEkB,eAsElB,GAtEoC,kBAsEpC,CAAA;;;;;qEA7DF,MAAA,CAAO,OAAO,YAAY;;;;;kEAS1B,MAAA,CAAO,aAAa;;cAC1B;;;;cASY,aAAA,SAAsB,kBAAA;;;;;;;kBAuDlB,QAAA;;;;oBAIS,KAAA,CAAM,MAAM;;cAmGzB;;uBArHH,MAAA,CAAO,OAAO,YAAY,GAAG,OACpC,KAAA,CAAM,MAAM,eAAe,GAAG"}
@@ -0,0 +1,100 @@
1
+ import { WalVersionGapError } from "./Errors.mjs";
2
+ import { Context, Effect, HashMap, Layer, Ref } from "effect";
3
+
4
+ //#region src/HotStorage.ts
5
+ /**
6
+ * @voidhash/mimic-effect - HotStorage
7
+ *
8
+ * Interface and implementations for Write-Ahead Log (WAL) storage.
9
+ */
10
+ /**
11
+ * Context tag for HotStorage service
12
+ */
13
+ var HotStorageTag = class extends Context.Tag("@voidhash/mimic-effect/HotStorage")() {};
14
+ /**
15
+ * Create a HotStorage layer from an Effect that produces a HotStorage service.
16
+ *
17
+ * This allows you to access other Effect services when implementing custom storage.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const Hot = HotStorage.make(
22
+ * Effect.gen(function*() {
23
+ * const redis = yield* RedisService
24
+ *
25
+ * return {
26
+ * append: (documentId, entry) =>
27
+ * redis.rpush(`wal:${documentId}`, JSON.stringify(entry)),
28
+ * getEntries: (documentId, sinceVersion) =>
29
+ * redis.lrange(`wal:${documentId}`, 0, -1).pipe(
30
+ * Effect.map(entries =>
31
+ * entries
32
+ * .map(e => JSON.parse(e))
33
+ * .filter(e => e.version > sinceVersion)
34
+ * .sort((a, b) => a.version - b.version)
35
+ * )
36
+ * ),
37
+ * truncate: (documentId, upToVersion) =>
38
+ * // Implementation depends on Redis data structure
39
+ * Effect.void,
40
+ * }
41
+ * })
42
+ * )
43
+ * ```
44
+ */
45
+ const make = (effect) => Layer.effect(HotStorageTag, effect);
46
+ let InMemory;
47
+ (function(_InMemory) {
48
+ _InMemory.make = () => Layer.effect(HotStorageTag, Effect.gen(function* () {
49
+ const store = yield* Ref.make(HashMap.empty());
50
+ return {
51
+ append: (documentId, entry) => Ref.update(store, (map) => {
52
+ const existing = HashMap.get(map, documentId);
53
+ const entries = existing._tag === "Some" ? existing.value : [];
54
+ return HashMap.set(map, documentId, [...entries, entry]);
55
+ }),
56
+ appendWithCheck: (documentId, entry, expectedVersion) => Effect.gen(function* () {
57
+ const result = yield* Ref.modify(store, (map) => {
58
+ const existing = HashMap.get(map, documentId);
59
+ const entries = existing._tag === "Some" ? existing.value : [];
60
+ const lastVersion = entries.length > 0 ? Math.max(...entries.map((e) => e.version)) : 0;
61
+ if (expectedVersion === 1) {
62
+ if (lastVersion >= 1) return [{
63
+ type: "gap",
64
+ lastVersion
65
+ }, map];
66
+ } else if (lastVersion !== expectedVersion - 1) return [{
67
+ type: "gap",
68
+ lastVersion: lastVersion > 0 ? lastVersion : void 0
69
+ }, map];
70
+ return [{ type: "ok" }, HashMap.set(map, documentId, [...entries, entry])];
71
+ });
72
+ if (result.type === "gap") return yield* Effect.fail(new WalVersionGapError({
73
+ documentId,
74
+ expectedVersion,
75
+ actualPreviousVersion: result.lastVersion
76
+ }));
77
+ }),
78
+ getEntries: (documentId, sinceVersion) => Effect.gen(function* () {
79
+ const current = yield* Ref.get(store);
80
+ const existing = HashMap.get(current, documentId);
81
+ return (existing._tag === "Some" ? existing.value : []).filter((e) => e.version > sinceVersion).sort((a, b) => a.version - b.version);
82
+ }),
83
+ truncate: (documentId, upToVersion) => Ref.update(store, (map) => {
84
+ const existing = HashMap.get(map, documentId);
85
+ if (existing._tag === "None") return map;
86
+ const filtered = existing.value.filter((e) => e.version > upToVersion);
87
+ return HashMap.set(map, documentId, filtered);
88
+ })
89
+ };
90
+ }));
91
+ })(InMemory || (InMemory = {}));
92
+ const HotStorage = {
93
+ Tag: HotStorageTag,
94
+ make,
95
+ InMemory
96
+ };
97
+
98
+ //#endregion
99
+ export { HotStorage, HotStorageTag };
100
+ //# sourceMappingURL=HotStorage.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HotStorage.mjs","names":["result: CheckResult"],"sources":["../src/HotStorage.ts"],"sourcesContent":["/**\n * @voidhash/mimic-effect - HotStorage\n *\n * Interface and implementations for Write-Ahead Log (WAL) storage.\n */\nimport { Context, Effect, HashMap, Layer, Ref } from \"effect\";\nimport type { WalEntry } from \"./Types\";\nimport { HotStorageError, WalVersionGapError } from \"./Errors\";\n\n// =============================================================================\n// HotStorage Interface\n// =============================================================================\n\n/**\n * HotStorage interface for storing Write-Ahead Log entries.\n *\n * This is the \"hot\" tier of the two-tier storage system.\n * It stores every transaction as a WAL entry for durability between snapshots.\n * WAL entries are small (just the transaction) and writes are append-only.\n */\nexport interface HotStorage {\n /**\n * Append a WAL entry for a document.\n */\n readonly append: (\n documentId: string,\n entry: WalEntry\n ) => Effect.Effect<void, HotStorageError>;\n\n /**\n * Append a WAL entry with version gap checking.\n *\n * This is an atomic operation that:\n * 1. Verifies the previous entry has version = expectedVersion - 1\n * (or this is the first entry if expectedVersion === 1)\n * 2. Appends the entry if check passes\n *\n * Use this for two-phase commit to guarantee WAL ordering at write time.\n *\n * @param documentId - Document ID\n * @param entry - WAL entry to append\n * @param expectedVersion - The version this entry should have (entry.version)\n * @returns Effect that fails with WalVersionGapError if gap detected\n */\n readonly appendWithCheck: (\n documentId: string,\n entry: WalEntry,\n expectedVersion: number\n ) => Effect.Effect<void, HotStorageError | WalVersionGapError>;\n\n /**\n * Get all WAL entries for a document since a given version.\n * Returns entries with version > sinceVersion, ordered by version.\n */\n readonly getEntries: (\n documentId: string,\n sinceVersion: number\n ) => Effect.Effect<WalEntry[], HotStorageError>;\n\n /**\n * Truncate WAL entries up to (and including) a given version.\n * Called after a snapshot is saved to remove entries that are now in the snapshot.\n */\n readonly truncate: (\n documentId: string,\n upToVersion: number\n ) => Effect.Effect<void, HotStorageError>;\n}\n\n// =============================================================================\n// Context Tag\n// =============================================================================\n\n/**\n * Context tag for HotStorage service\n */\nexport class HotStorageTag extends Context.Tag(\"@voidhash/mimic-effect/HotStorage\")<\n HotStorageTag,\n HotStorage\n>() {}\n\n// =============================================================================\n// Factory\n// =============================================================================\n\n/**\n * Create a HotStorage layer from an Effect that produces a HotStorage service.\n *\n * This allows you to access other Effect services when implementing custom storage.\n *\n * @example\n * ```typescript\n * const Hot = HotStorage.make(\n * Effect.gen(function*() {\n * const redis = yield* RedisService\n *\n * return {\n * append: (documentId, entry) =>\n * redis.rpush(`wal:${documentId}`, JSON.stringify(entry)),\n * getEntries: (documentId, sinceVersion) =>\n * redis.lrange(`wal:${documentId}`, 0, -1).pipe(\n * Effect.map(entries =>\n * entries\n * .map(e => JSON.parse(e))\n * .filter(e => e.version > sinceVersion)\n * .sort((a, b) => a.version - b.version)\n * )\n * ),\n * truncate: (documentId, upToVersion) =>\n * // Implementation depends on Redis data structure\n * Effect.void,\n * }\n * })\n * )\n * ```\n */\nexport const make = <E, R>(\n effect: Effect.Effect<HotStorage, E, R>\n): Layer.Layer<HotStorageTag, E, R> =>\n Layer.effect(HotStorageTag, effect);\n\n// =============================================================================\n// InMemory Implementation\n// =============================================================================\n\n/**\n * In-memory HotStorage implementation.\n *\n * Useful for testing and development. Not suitable for production\n * as data is lost when the process restarts.\n */\nexport namespace InMemory {\n /**\n * Create an in-memory HotStorage layer.\n */\n export const make = (): Layer.Layer<HotStorageTag> =>\n Layer.effect(\n HotStorageTag,\n Effect.gen(function* () {\n const store = yield* Ref.make(HashMap.empty<string, WalEntry[]>());\n\n return {\n append: (documentId, entry) =>\n Ref.update(store, (map) => {\n const existing = HashMap.get(map, documentId);\n const entries =\n existing._tag === \"Some\" ? existing.value : [];\n return HashMap.set(map, documentId, [...entries, entry]);\n }),\n\n appendWithCheck: (documentId, entry, expectedVersion) =>\n Effect.gen(function* () {\n type CheckResult =\n | { type: \"ok\" }\n | { type: \"gap\"; lastVersion: number | undefined };\n\n // Use Ref.modify for atomic check + update\n const result: CheckResult = yield* Ref.modify(store, (map): [CheckResult, HashMap.HashMap<string, WalEntry[]>] => {\n const existing = HashMap.get(map, documentId);\n const entries = existing._tag === \"Some\" ? existing.value : [];\n\n // Find the highest version in existing entries\n const lastVersion = entries.length > 0\n ? Math.max(...entries.map((e) => e.version))\n : 0;\n\n // Gap check\n if (expectedVersion === 1) {\n // First entry: should have no entries with version >= 1\n if (lastVersion >= 1) {\n return [\n { type: \"gap\", lastVersion },\n map,\n ];\n }\n } else {\n // Not first: last entry should have version = expectedVersion - 1\n if (lastVersion !== expectedVersion - 1) {\n return [\n { type: \"gap\", lastVersion: lastVersion > 0 ? lastVersion : undefined },\n map,\n ];\n }\n }\n\n // No gap: append and return success\n return [\n { type: \"ok\" },\n HashMap.set(map, documentId, [...entries, entry]),\n ];\n });\n\n if (result.type === \"gap\") {\n return yield* Effect.fail(\n new WalVersionGapError({\n documentId,\n expectedVersion,\n actualPreviousVersion: result.lastVersion,\n })\n );\n }\n }),\n\n getEntries: (documentId, sinceVersion) =>\n Effect.gen(function* () {\n const current = yield* Ref.get(store);\n const existing = HashMap.get(current, documentId);\n const entries =\n existing._tag === \"Some\" ? existing.value : [];\n return entries\n .filter((e) => e.version > sinceVersion)\n .sort((a, b) => a.version - b.version);\n }),\n\n truncate: (documentId, upToVersion) =>\n Ref.update(store, (map) => {\n const existing = HashMap.get(map, documentId);\n if (existing._tag === \"None\") {\n return map;\n }\n const filtered = existing.value.filter(\n (e) => e.version > upToVersion\n );\n return HashMap.set(map, documentId, filtered);\n }),\n };\n })\n );\n}\n\n// =============================================================================\n// Re-export namespace\n// =============================================================================\n\nexport const HotStorage = {\n Tag: HotStorageTag,\n make,\n InMemory,\n};\n"],"mappings":";;;;;;;;;;;;AA4EA,IAAa,gBAAb,cAAmC,QAAQ,IAAI,oCAAoC,EAGhF,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCJ,MAAa,QACX,WAEA,MAAM,OAAO,eAAe,OAAO;;;wBAiBjC,MAAM,OACJ,eACA,OAAO,IAAI,aAAa;EACtB,MAAM,QAAQ,OAAO,IAAI,KAAK,QAAQ,OAA2B,CAAC;AAElE,SAAO;GACL,SAAS,YAAY,UACnB,IAAI,OAAO,QAAQ,QAAQ;IACzB,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;IAC7C,MAAM,UACJ,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE;AAChD,WAAO,QAAQ,IAAI,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,CAAC;KACxD;GAEJ,kBAAkB,YAAY,OAAO,oBACnC,OAAO,IAAI,aAAa;IAMtB,MAAMA,SAAsB,OAAO,IAAI,OAAO,QAAQ,QAA4D;KAChH,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;KAC7C,MAAM,UAAU,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE;KAG9D,MAAM,cAAc,QAAQ,SAAS,IACjC,KAAK,IAAI,GAAG,QAAQ,KAAK,MAAM,EAAE,QAAQ,CAAC,GAC1C;AAGJ,SAAI,oBAAoB,GAEtB;UAAI,eAAe,EACjB,QAAO,CACL;OAAE,MAAM;OAAO;OAAa,EAC5B,IACD;gBAIC,gBAAgB,kBAAkB,EACpC,QAAO,CACL;MAAE,MAAM;MAAO,aAAa,cAAc,IAAI,cAAc;MAAW,EACvE,IACD;AAKL,YAAO,CACL,EAAE,MAAM,MAAM,EACd,QAAQ,IAAI,KAAK,YAAY,CAAC,GAAG,SAAS,MAAM,CAAC,CAClD;MACD;AAEF,QAAI,OAAO,SAAS,MAClB,QAAO,OAAO,OAAO,KACnB,IAAI,mBAAmB;KACrB;KACA;KACA,uBAAuB,OAAO;KAC/B,CAAC,CACH;KAEH;GAEJ,aAAa,YAAY,iBACvB,OAAO,IAAI,aAAa;IACtB,MAAM,UAAU,OAAO,IAAI,IAAI,MAAM;IACrC,MAAM,WAAW,QAAQ,IAAI,SAAS,WAAW;AAGjD,YADE,SAAS,SAAS,SAAS,SAAS,QAAQ,EAAE,EAE7C,QAAQ,MAAM,EAAE,UAAU,aAAa,CACvC,MAAM,GAAG,MAAM,EAAE,UAAU,EAAE,QAAQ;KACxC;GAEJ,WAAW,YAAY,gBACrB,IAAI,OAAO,QAAQ,QAAQ;IACzB,MAAM,WAAW,QAAQ,IAAI,KAAK,WAAW;AAC7C,QAAI,SAAS,SAAS,OACpB,QAAO;IAET,MAAM,WAAW,SAAS,MAAM,QAC7B,MAAM,EAAE,UAAU,YACpB;AACD,WAAO,QAAQ,IAAI,KAAK,YAAY,SAAS;KAC7C;GACL;GACD,CACH;;AAOL,MAAa,aAAa;CACxB,KAAK;CACL;CACA;CACD"}