@voidhash/mimic 0.0.2 → 0.0.3

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 (273) hide show
  1. package/.turbo/turbo-build.log +257 -42
  2. package/dist/Document.cjs +152 -0
  3. package/dist/Document.d.cts +67 -0
  4. package/dist/Document.d.cts.map +1 -0
  5. package/dist/Document.d.mts +68 -0
  6. package/dist/Document.d.mts.map +1 -0
  7. package/dist/Document.mjs +147 -0
  8. package/dist/Document.mjs.map +1 -0
  9. package/dist/EffectSchema.cjs +180 -0
  10. package/dist/EffectSchema.d.cts +84 -0
  11. package/dist/EffectSchema.d.cts.map +1 -0
  12. package/dist/EffectSchema.d.mts +84 -0
  13. package/dist/EffectSchema.d.mts.map +1 -0
  14. package/dist/EffectSchema.mjs +176 -0
  15. package/dist/EffectSchema.mjs.map +1 -0
  16. package/dist/FractionalIndex.cjs +365 -0
  17. package/dist/FractionalIndex.mjs +364 -0
  18. package/dist/FractionalIndex.mjs.map +1 -0
  19. package/dist/Operation.cjs +53 -0
  20. package/dist/Operation.d.cts +39 -0
  21. package/dist/Operation.d.cts.map +1 -0
  22. package/dist/Operation.d.mts +39 -0
  23. package/dist/Operation.d.mts.map +1 -0
  24. package/dist/Operation.mjs +46 -0
  25. package/dist/Operation.mjs.map +1 -0
  26. package/dist/OperationDefinition.cjs +13 -0
  27. package/dist/OperationDefinition.d.cts +12 -0
  28. package/dist/OperationDefinition.d.cts.map +1 -0
  29. package/dist/OperationDefinition.d.mts +12 -0
  30. package/dist/OperationDefinition.d.mts.map +1 -0
  31. package/dist/OperationDefinition.mjs +13 -0
  32. package/dist/OperationDefinition.mjs.map +1 -0
  33. package/dist/OperationPath.cjs +148 -0
  34. package/dist/OperationPath.d.cts +60 -0
  35. package/dist/OperationPath.d.cts.map +1 -0
  36. package/dist/OperationPath.d.mts +60 -0
  37. package/dist/OperationPath.d.mts.map +1 -0
  38. package/dist/OperationPath.mjs +138 -0
  39. package/dist/OperationPath.mjs.map +1 -0
  40. package/dist/{Presence-gWrmGBeu.cjs → Presence.cjs} +4 -39
  41. package/dist/{Presence-N8u7Eppr.d.mts → Presence.d.cts} +2 -2
  42. package/dist/Presence.d.cts.map +1 -0
  43. package/dist/{Presence-DKKP4v5X.d.cts → Presence.d.mts} +2 -2
  44. package/dist/Presence.d.mts.map +1 -0
  45. package/dist/{Presence-DdMVKcOv.mjs → Presence.mjs} +3 -28
  46. package/dist/Presence.mjs.map +1 -0
  47. package/dist/Primitive.cjs +52 -0
  48. package/dist/Primitive.d.cts +20 -0
  49. package/dist/Primitive.d.cts.map +1 -0
  50. package/dist/Primitive.d.mts +20 -0
  51. package/dist/Primitive.d.mts.map +1 -0
  52. package/dist/Primitive.mjs +48 -0
  53. package/dist/Primitive.mjs.map +1 -0
  54. package/dist/ProxyEnvironment.cjs +34 -0
  55. package/dist/ProxyEnvironment.d.cts +31 -0
  56. package/dist/ProxyEnvironment.d.cts.map +1 -0
  57. package/dist/ProxyEnvironment.d.mts +31 -0
  58. package/dist/ProxyEnvironment.d.mts.map +1 -0
  59. package/dist/ProxyEnvironment.mjs +29 -0
  60. package/dist/ProxyEnvironment.mjs.map +1 -0
  61. package/dist/Transaction.cjs +66 -0
  62. package/dist/Transaction.d.cts +56 -0
  63. package/dist/Transaction.d.cts.map +1 -0
  64. package/dist/Transaction.d.mts +56 -0
  65. package/dist/Transaction.d.mts.map +1 -0
  66. package/dist/Transaction.mjs +58 -0
  67. package/dist/Transaction.mjs.map +1 -0
  68. package/dist/Transform.cjs +11 -0
  69. package/dist/Transform.d.cts +21 -0
  70. package/dist/Transform.d.cts.map +1 -0
  71. package/dist/Transform.d.mts +21 -0
  72. package/dist/Transform.d.mts.map +1 -0
  73. package/dist/Transform.mjs +6 -0
  74. package/dist/Transform.mjs.map +1 -0
  75. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.cjs +14 -0
  76. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/defineProperty.mjs +14 -0
  77. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.cjs +27 -0
  78. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/objectSpread2.mjs +27 -0
  79. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.cjs +16 -0
  80. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPrimitive.mjs +16 -0
  81. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.cjs +11 -0
  82. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/toPropertyKey.mjs +11 -0
  83. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.cjs +18 -0
  84. package/dist/_virtual/_@oxc-project_runtime@0.103.0/helpers/typeof.mjs +12 -0
  85. package/dist/_virtual/rolldown_runtime.cjs +43 -0
  86. package/dist/{chunk-CLMFDpHK.mjs → _virtual/rolldown_runtime.mjs} +1 -1
  87. package/dist/client/ClientDocument.cjs +590 -0
  88. package/dist/client/ClientDocument.d.cts +161 -0
  89. package/dist/client/ClientDocument.d.cts.map +1 -0
  90. package/dist/client/ClientDocument.d.mts +162 -0
  91. package/dist/client/ClientDocument.d.mts.map +1 -0
  92. package/dist/client/ClientDocument.mjs +586 -0
  93. package/dist/client/ClientDocument.mjs.map +1 -0
  94. package/dist/client/Rebase.cjs +204 -0
  95. package/dist/client/Rebase.d.cts +87 -0
  96. package/dist/client/Rebase.d.cts.map +1 -0
  97. package/dist/client/Rebase.d.mts +88 -0
  98. package/dist/client/Rebase.d.mts.map +1 -0
  99. package/dist/client/Rebase.mjs +198 -0
  100. package/dist/client/Rebase.mjs.map +1 -0
  101. package/dist/client/StateMonitor.cjs +133 -0
  102. package/dist/client/StateMonitor.d.cts +122 -0
  103. package/dist/client/StateMonitor.d.cts.map +1 -0
  104. package/dist/client/StateMonitor.d.mts +122 -0
  105. package/dist/client/StateMonitor.d.mts.map +1 -0
  106. package/dist/client/StateMonitor.mjs +129 -0
  107. package/dist/client/StateMonitor.mjs.map +1 -0
  108. package/dist/client/Transport.cjs +11 -0
  109. package/dist/client/Transport.d.cts +237 -0
  110. package/dist/client/Transport.d.cts.map +1 -0
  111. package/dist/client/Transport.d.mts +237 -0
  112. package/dist/client/Transport.d.mts.map +1 -0
  113. package/dist/client/Transport.mjs +6 -0
  114. package/dist/client/Transport.mjs.map +1 -0
  115. package/dist/client/WebSocketTransport.cjs +396 -0
  116. package/dist/client/WebSocketTransport.d.cts +29 -0
  117. package/dist/client/WebSocketTransport.d.cts.map +1 -0
  118. package/dist/client/WebSocketTransport.d.mts +29 -0
  119. package/dist/client/WebSocketTransport.d.mts.map +1 -0
  120. package/dist/client/WebSocketTransport.mjs +392 -0
  121. package/dist/client/WebSocketTransport.mjs.map +1 -0
  122. package/dist/client/errors.cjs +135 -0
  123. package/dist/client/errors.d.cts +87 -0
  124. package/dist/client/errors.d.cts.map +1 -0
  125. package/dist/client/errors.d.mts +87 -0
  126. package/dist/client/errors.d.mts.map +1 -0
  127. package/dist/client/errors.mjs +127 -0
  128. package/dist/client/errors.mjs.map +1 -0
  129. package/dist/client/index.cjs +22 -1424
  130. package/dist/client/index.d.cts +8 -692
  131. package/dist/client/index.d.mts +8 -692
  132. package/dist/client/index.mjs +9 -1413
  133. package/dist/index.cjs +20 -2973
  134. package/dist/index.d.cts +12 -419
  135. package/dist/index.d.mts +12 -419
  136. package/dist/index.mjs +13 -2968
  137. package/dist/primitives/Array.cjs +302 -0
  138. package/dist/primitives/Array.d.cts +95 -0
  139. package/dist/primitives/Array.d.cts.map +1 -0
  140. package/dist/primitives/Array.d.mts +95 -0
  141. package/dist/primitives/Array.d.mts.map +1 -0
  142. package/dist/primitives/Array.mjs +301 -0
  143. package/dist/primitives/Array.mjs.map +1 -0
  144. package/dist/primitives/Boolean.cjs +95 -0
  145. package/dist/primitives/Boolean.d.cts +44 -0
  146. package/dist/primitives/Boolean.d.cts.map +1 -0
  147. package/dist/primitives/Boolean.d.mts +44 -0
  148. package/dist/primitives/Boolean.d.mts.map +1 -0
  149. package/dist/primitives/Boolean.mjs +94 -0
  150. package/dist/primitives/Boolean.mjs.map +1 -0
  151. package/dist/primitives/Either.cjs +200 -0
  152. package/dist/primitives/Either.d.cts +113 -0
  153. package/dist/primitives/Either.d.cts.map +1 -0
  154. package/dist/primitives/Either.d.mts +113 -0
  155. package/dist/primitives/Either.d.mts.map +1 -0
  156. package/dist/primitives/Either.mjs +199 -0
  157. package/dist/primitives/Either.mjs.map +1 -0
  158. package/dist/primitives/Lazy.cjs +46 -0
  159. package/dist/primitives/Lazy.d.cts +46 -0
  160. package/dist/primitives/Lazy.d.cts.map +1 -0
  161. package/dist/primitives/Lazy.d.mts +46 -0
  162. package/dist/primitives/Lazy.d.mts.map +1 -0
  163. package/dist/primitives/Lazy.mjs +46 -0
  164. package/dist/primitives/Lazy.mjs.map +1 -0
  165. package/dist/primitives/Literal.cjs +91 -0
  166. package/dist/primitives/Literal.d.cts +46 -0
  167. package/dist/primitives/Literal.d.cts.map +1 -0
  168. package/dist/primitives/Literal.d.mts +46 -0
  169. package/dist/primitives/Literal.d.mts.map +1 -0
  170. package/dist/primitives/Literal.mjs +90 -0
  171. package/dist/primitives/Literal.mjs.map +1 -0
  172. package/dist/primitives/Number.cjs +115 -0
  173. package/dist/primitives/Number.d.cts +54 -0
  174. package/dist/primitives/Number.d.cts.map +1 -0
  175. package/dist/primitives/Number.d.mts +54 -0
  176. package/dist/primitives/Number.d.mts.map +1 -0
  177. package/dist/primitives/Number.mjs +114 -0
  178. package/dist/primitives/Number.mjs.map +1 -0
  179. package/dist/primitives/String.cjs +127 -0
  180. package/dist/primitives/String.d.cts +56 -0
  181. package/dist/primitives/String.d.cts.map +1 -0
  182. package/dist/primitives/String.d.mts +56 -0
  183. package/dist/primitives/String.d.mts.map +1 -0
  184. package/dist/primitives/String.mjs +126 -0
  185. package/dist/primitives/String.mjs.map +1 -0
  186. package/dist/primitives/Struct.cjs +207 -0
  187. package/dist/primitives/Struct.d.cts +96 -0
  188. package/dist/primitives/Struct.d.cts.map +1 -0
  189. package/dist/primitives/Struct.d.mts +97 -0
  190. package/dist/primitives/Struct.d.mts.map +1 -0
  191. package/dist/primitives/Struct.mjs +206 -0
  192. package/dist/primitives/Struct.mjs.map +1 -0
  193. package/dist/primitives/Tree.cjs +575 -0
  194. package/dist/primitives/Tree.d.cts +185 -0
  195. package/dist/primitives/Tree.d.cts.map +1 -0
  196. package/dist/primitives/Tree.d.mts +185 -0
  197. package/dist/primitives/Tree.d.mts.map +1 -0
  198. package/dist/primitives/Tree.mjs +574 -0
  199. package/dist/primitives/Tree.mjs.map +1 -0
  200. package/dist/primitives/TreeNode.cjs +73 -0
  201. package/dist/primitives/TreeNode.d.cts +92 -0
  202. package/dist/primitives/TreeNode.d.cts.map +1 -0
  203. package/dist/primitives/TreeNode.d.mts +93 -0
  204. package/dist/primitives/TreeNode.d.mts.map +1 -0
  205. package/dist/primitives/TreeNode.mjs +72 -0
  206. package/dist/primitives/TreeNode.mjs.map +1 -0
  207. package/dist/primitives/Union.cjs +170 -0
  208. package/dist/primitives/Union.d.cts +81 -0
  209. package/dist/primitives/Union.d.cts.map +1 -0
  210. package/dist/primitives/Union.d.mts +81 -0
  211. package/dist/primitives/Union.d.mts.map +1 -0
  212. package/dist/primitives/Union.mjs +169 -0
  213. package/dist/primitives/Union.mjs.map +1 -0
  214. package/dist/primitives/shared.cjs +60 -0
  215. package/dist/primitives/shared.d.cts +147 -0
  216. package/dist/primitives/shared.d.cts.map +1 -0
  217. package/dist/primitives/shared.d.mts +147 -0
  218. package/dist/primitives/shared.d.mts.map +1 -0
  219. package/dist/primitives/shared.mjs +58 -0
  220. package/dist/primitives/shared.mjs.map +1 -0
  221. package/dist/server/ServerDocument.cjs +110 -0
  222. package/dist/server/ServerDocument.d.cts +98 -0
  223. package/dist/server/ServerDocument.d.cts.map +1 -0
  224. package/dist/server/ServerDocument.d.mts +99 -0
  225. package/dist/server/ServerDocument.d.mts.map +1 -0
  226. package/dist/server/ServerDocument.mjs +106 -0
  227. package/dist/server/ServerDocument.mjs.map +1 -0
  228. package/dist/server/errors.cjs +85 -0
  229. package/dist/server/errors.d.cts +53 -0
  230. package/dist/server/errors.d.cts.map +1 -0
  231. package/dist/server/errors.d.mts +53 -0
  232. package/dist/server/errors.d.mts.map +1 -0
  233. package/dist/server/errors.mjs +81 -0
  234. package/dist/server/errors.mjs.map +1 -0
  235. package/dist/server/index.cjs +9 -185
  236. package/dist/server/index.d.cts +3 -148
  237. package/dist/server/index.d.mts +3 -148
  238. package/dist/server/index.mjs +3 -181
  239. package/dist/types/index.cjs +16 -0
  240. package/dist/types/index.d.cts +16 -0
  241. package/dist/types/index.d.cts.map +1 -0
  242. package/dist/types/index.d.mts +16 -0
  243. package/dist/types/index.d.mts.map +1 -0
  244. package/dist/types/index.mjs +12 -0
  245. package/dist/types/index.mjs.map +1 -0
  246. package/dist/utils/tree-helpers.cjs +443 -0
  247. package/dist/utils/tree-helpers.d.cts +280 -0
  248. package/dist/utils/tree-helpers.d.cts.map +1 -0
  249. package/dist/utils/tree-helpers.d.mts +280 -0
  250. package/dist/utils/tree-helpers.d.mts.map +1 -0
  251. package/dist/utils/tree-helpers.mjs +439 -0
  252. package/dist/utils/tree-helpers.mjs.map +1 -0
  253. package/package.json +2 -2
  254. package/tsdown.config.ts +1 -1
  255. package/dist/Document-ChuFrTk1.cjs +0 -571
  256. package/dist/Document-CwiAFTIq.mjs +0 -438
  257. package/dist/Document-CwiAFTIq.mjs.map +0 -1
  258. package/dist/Presence-DKKP4v5X.d.cts.map +0 -1
  259. package/dist/Presence-DdMVKcOv.mjs.map +0 -1
  260. package/dist/Presence-N8u7Eppr.d.mts.map +0 -1
  261. package/dist/Primitive-DqQFc3Gu.d.mts +0 -1180
  262. package/dist/Primitive-DqQFc3Gu.d.mts.map +0 -1
  263. package/dist/Primitive-awpEjnKL.d.cts +0 -1180
  264. package/dist/Primitive-awpEjnKL.d.cts.map +0 -1
  265. package/dist/client/index.d.cts.map +0 -1
  266. package/dist/client/index.d.mts.map +0 -1
  267. package/dist/client/index.mjs.map +0 -1
  268. package/dist/index.d.cts.map +0 -1
  269. package/dist/index.d.mts.map +0 -1
  270. package/dist/index.mjs.map +0 -1
  271. package/dist/server/index.d.cts.map +0 -1
  272. package/dist/server/index.d.mts.map +0 -1
  273. package/dist/server/index.mjs.map +0 -1
@@ -0,0 +1,198 @@
1
+ import { __export } from "../_virtual/rolldown_runtime.mjs";
2
+ import { isPrefix, pathsEqual, pathsOverlap } from "../OperationPath.mjs";
3
+
4
+ //#region src/client/Rebase.ts
5
+ var Rebase_exports = /* @__PURE__ */ __export({
6
+ rebaseAfterRejection: () => rebaseAfterRejection,
7
+ rebaseAfterRejectionWithPrimitive: () => rebaseAfterRejectionWithPrimitive,
8
+ rebasePendingTransactions: () => rebasePendingTransactions,
9
+ rebasePendingTransactionsWithPrimitive: () => rebasePendingTransactionsWithPrimitive,
10
+ transformOperation: () => transformOperation,
11
+ transformOperationWithPrimitive: () => transformOperationWithPrimitive,
12
+ transformTransaction: () => transformTransaction,
13
+ transformTransactionWithPrimitive: () => transformTransactionWithPrimitive
14
+ });
15
+ /**
16
+ * Transforms a client operation against a server operation using a primitive.
17
+ *
18
+ * This delegates to the primitive's transformOperation method, which handles
19
+ * type-specific conflict resolution.
20
+ *
21
+ * @param clientOp - The client's operation to transform
22
+ * @param serverOp - The server's operation that has already been applied
23
+ * @param primitive - The root primitive to use for transformation
24
+ * @returns TransformResult indicating how the client operation should be handled
25
+ */
26
+ const transformOperationWithPrimitive = (clientOp, serverOp, primitive) => {
27
+ return primitive._internal.transformOperation(clientOp, serverOp);
28
+ };
29
+ /**
30
+ * Transforms a client operation against a server operation.
31
+ *
32
+ * This is a standalone implementation for cases where the primitive is not available.
33
+ * For schema-aware transformation, use transformOperationWithPrimitive instead.
34
+ *
35
+ * The key principle: client ops "shadow" server ops for the same path,
36
+ * meaning if both touch the same field, the client's intention wins
37
+ * (since it was made with knowledge of the server state at that time).
38
+ */
39
+ const transformOperation = (clientOp, serverOp) => {
40
+ const clientPath = clientOp.path;
41
+ const serverPath = serverOp.path;
42
+ if (!pathsOverlap(clientPath, serverPath)) return {
43
+ type: "transformed",
44
+ operation: clientOp
45
+ };
46
+ if (serverOp.kind === "array.remove") {
47
+ const removedId = serverOp.payload.id;
48
+ const clientTokens = clientPath.toTokens().filter((t) => t !== "");
49
+ const serverTokens = serverPath.toTokens().filter((t) => t !== "");
50
+ if (clientTokens.length > serverTokens.length) {
51
+ if (clientTokens[serverTokens.length] === removedId) return { type: "noop" };
52
+ }
53
+ }
54
+ if (serverOp.kind === "array.insert" && clientOp.kind === "array.insert") return {
55
+ type: "transformed",
56
+ operation: clientOp
57
+ };
58
+ if (serverOp.kind === "array.move" && clientOp.kind === "array.move") {
59
+ if (serverOp.payload.id === clientOp.payload.id) return {
60
+ type: "transformed",
61
+ operation: clientOp
62
+ };
63
+ return {
64
+ type: "transformed",
65
+ operation: clientOp
66
+ };
67
+ }
68
+ if (pathsEqual(clientPath, serverPath)) return {
69
+ type: "transformed",
70
+ operation: clientOp
71
+ };
72
+ if (isPrefix(serverPath, clientPath)) {
73
+ const serverKind = serverOp.kind;
74
+ if (serverKind === "struct.set" || serverKind === "array.set" || serverKind === "union.set") return {
75
+ type: "transformed",
76
+ operation: clientOp
77
+ };
78
+ }
79
+ return {
80
+ type: "transformed",
81
+ operation: clientOp
82
+ };
83
+ };
84
+ /**
85
+ * Transforms all operations in a client transaction against a server transaction.
86
+ * Uses the primitive's transformOperation for schema-aware transformation.
87
+ */
88
+ const transformTransactionWithPrimitive = (clientTx, serverTx, primitive) => {
89
+ const transformedOps = [];
90
+ for (const clientOp of clientTx.ops) {
91
+ let currentOp = clientOp;
92
+ for (const serverOp of serverTx.ops) {
93
+ if (currentOp === null) break;
94
+ const result = transformOperationWithPrimitive(currentOp, serverOp, primitive);
95
+ switch (result.type) {
96
+ case "transformed":
97
+ currentOp = result.operation;
98
+ break;
99
+ case "noop":
100
+ currentOp = null;
101
+ break;
102
+ case "conflict": break;
103
+ }
104
+ }
105
+ if (currentOp !== null) transformedOps.push(currentOp);
106
+ }
107
+ return {
108
+ id: clientTx.id,
109
+ ops: transformedOps,
110
+ timestamp: clientTx.timestamp
111
+ };
112
+ };
113
+ /**
114
+ * Transforms all operations in a client transaction against a server transaction.
115
+ * This is a standalone version that doesn't require a primitive.
116
+ */
117
+ const transformTransaction = (clientTx, serverTx) => {
118
+ const transformedOps = [];
119
+ for (const clientOp of clientTx.ops) {
120
+ let currentOp = clientOp;
121
+ for (const serverOp of serverTx.ops) {
122
+ if (currentOp === null) break;
123
+ const result = transformOperation(currentOp, serverOp);
124
+ switch (result.type) {
125
+ case "transformed":
126
+ currentOp = result.operation;
127
+ break;
128
+ case "noop":
129
+ currentOp = null;
130
+ break;
131
+ case "conflict": break;
132
+ }
133
+ }
134
+ if (currentOp !== null) transformedOps.push(currentOp);
135
+ }
136
+ return {
137
+ id: clientTx.id,
138
+ ops: transformedOps,
139
+ timestamp: clientTx.timestamp
140
+ };
141
+ };
142
+ /**
143
+ * Rebases a list of pending transactions against a server transaction using a primitive.
144
+ *
145
+ * This is called when a server transaction arrives that is NOT one of our pending
146
+ * transactions. We need to transform all pending transactions to work correctly
147
+ * on top of the new server state.
148
+ */
149
+ const rebasePendingTransactionsWithPrimitive = (pendingTxs, serverTx, primitive) => {
150
+ return pendingTxs.map((pendingTx) => transformTransactionWithPrimitive(pendingTx, serverTx, primitive));
151
+ };
152
+ /**
153
+ * Rebases a list of pending transactions against a server transaction.
154
+ *
155
+ * This is called when a server transaction arrives that is NOT one of our pending
156
+ * transactions. We need to transform all pending transactions to work correctly
157
+ * on top of the new server state.
158
+ */
159
+ const rebasePendingTransactions = (pendingTxs, serverTx) => {
160
+ return pendingTxs.map((pendingTx) => transformTransaction(pendingTx, serverTx));
161
+ };
162
+ /**
163
+ * Rebases pending transactions after a rejection using a primitive.
164
+ *
165
+ * When a transaction is rejected, we need to re-transform remaining pending
166
+ * transactions as if the rejected transaction never happened. This is done by
167
+ * rebuilding from the original operations against the current server state.
168
+ *
169
+ * @param originalPendingTxs - The original pending transactions before any rebasing
170
+ * @param rejectedTxId - ID of the rejected transaction
171
+ * @param serverTxsSinceOriginal - Server transactions that have arrived since original
172
+ * @param primitive - The root primitive to use for transformation
173
+ */
174
+ const rebaseAfterRejectionWithPrimitive = (originalPendingTxs, rejectedTxId, serverTxsSinceOriginal, primitive) => {
175
+ let result = [...originalPendingTxs.filter((tx) => tx.id !== rejectedTxId)];
176
+ for (const serverTx of serverTxsSinceOriginal) result = rebasePendingTransactionsWithPrimitive(result, serverTx, primitive);
177
+ return result;
178
+ };
179
+ /**
180
+ * Rebases pending transactions after a rejection.
181
+ *
182
+ * When a transaction is rejected, we need to re-transform remaining pending
183
+ * transactions as if the rejected transaction never happened. This is done by
184
+ * rebuilding from the original operations against the current server state.
185
+ *
186
+ * @param originalPendingTxs - The original pending transactions before any rebasing
187
+ * @param rejectedTxId - ID of the rejected transaction
188
+ * @param serverTxsSinceOriginal - Server transactions that have arrived since original
189
+ */
190
+ const rebaseAfterRejection = (originalPendingTxs, rejectedTxId, serverTxsSinceOriginal) => {
191
+ let result = [...originalPendingTxs.filter((tx) => tx.id !== rejectedTxId)];
192
+ for (const serverTx of serverTxsSinceOriginal) result = rebasePendingTransactions(result, serverTx);
193
+ return result;
194
+ };
195
+
196
+ //#endregion
197
+ export { Rebase_exports, rebaseAfterRejectionWithPrimitive, transformTransactionWithPrimitive };
198
+ //# sourceMappingURL=Rebase.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Rebase.mjs","names":["OperationPath.pathsOverlap","OperationPath.pathsEqual","OperationPath.isPrefix","transformedOps: Operation.Operation<any, any, any>[]","currentOp: Operation.Operation<any, any, any> | null"],"sources":["../../src/client/Rebase.ts"],"sourcesContent":["import type * as Operation from \"../Operation\";\nimport type * as Transaction from \"../Transaction\";\nimport type * as Primitive from \"../Primitive\";\nimport * as OperationPath from \"../OperationPath\";\nimport * as Transform from \"../Transform\";\n\n// =============================================================================\n// Re-export Transform types from mimic for backwards compatibility\n// =============================================================================\n\nexport type TransformResult = Transform.TransformResult;\n\n// =============================================================================\n// Operation Transformation\n// =============================================================================\n\n/**\n * Transforms a client operation against a server operation using a primitive.\n * \n * This delegates to the primitive's transformOperation method, which handles\n * type-specific conflict resolution.\n * \n * @param clientOp - The client's operation to transform\n * @param serverOp - The server's operation that has already been applied\n * @param primitive - The root primitive to use for transformation\n * @returns TransformResult indicating how the client operation should be handled\n */\nexport const transformOperationWithPrimitive = (\n clientOp: Operation.Operation<any, any, any>,\n serverOp: Operation.Operation<any, any, any>,\n primitive: Primitive.AnyPrimitive\n): TransformResult => {\n return primitive._internal.transformOperation(clientOp, serverOp);\n};\n\n/**\n * Transforms a client operation against a server operation.\n *\n * This is a standalone implementation for cases where the primitive is not available.\n * For schema-aware transformation, use transformOperationWithPrimitive instead.\n *\n * The key principle: client ops \"shadow\" server ops for the same path,\n * meaning if both touch the same field, the client's intention wins\n * (since it was made with knowledge of the server state at that time).\n */\nexport const transformOperation = (\n clientOp: Operation.Operation<any, any, any>,\n serverOp: Operation.Operation<any, any, any>\n): TransformResult => {\n const clientPath = clientOp.path;\n const serverPath = serverOp.path;\n\n // If paths don't overlap at all, no transformation needed\n if (!OperationPath.pathsOverlap(clientPath, serverPath)) {\n return { type: \"transformed\", operation: clientOp };\n }\n\n // Handle array operations specially\n if (serverOp.kind === \"array.remove\") {\n // If server removed an array element that client is operating on\n const removedId = (serverOp.payload as { id: string }).id;\n const clientTokens = clientPath.toTokens().filter((t: string) => t !== \"\");\n const serverTokens = serverPath.toTokens().filter((t: string) => t !== \"\");\n\n // Check if client is operating on the removed element or its children\n if (clientTokens.length > serverTokens.length) {\n const elementId = clientTokens[serverTokens.length];\n if (elementId === removedId) {\n // Client operation targets a removed element - becomes noop\n return { type: \"noop\" };\n }\n }\n }\n\n if (serverOp.kind === \"array.insert\" && clientOp.kind === \"array.insert\") {\n // Both inserting into same array - positions are independent (fractional indexing)\n // No transformation needed as fractional indices handle ordering\n return { type: \"transformed\", operation: clientOp };\n }\n\n if (serverOp.kind === \"array.move\" && clientOp.kind === \"array.move\") {\n // Both moving elements - if same element, client wins (last-write-wins for position)\n const serverMoveId = (serverOp.payload as { id: string }).id;\n const clientMoveId = (clientOp.payload as { id: string }).id;\n\n if (serverMoveId === clientMoveId) {\n // Client's move supersedes server's move\n return { type: \"transformed\", operation: clientOp };\n }\n // Different elements - no conflict\n return { type: \"transformed\", operation: clientOp };\n }\n\n // For set operations on the same exact path: client wins (last-write-wins)\n if (OperationPath.pathsEqual(clientPath, serverPath)) {\n // Both operations target the same path\n // Client operation was made with intent to set this value,\n // so it should override the server's change\n return { type: \"transformed\", operation: clientOp };\n }\n\n // If server set a parent path, client's child operation might be invalid\n if (OperationPath.isPrefix(serverPath, clientPath)) {\n const serverKind = serverOp.kind;\n if (\n serverKind === \"struct.set\" ||\n serverKind === \"array.set\" ||\n serverKind === \"union.set\"\n ) {\n // Server replaced the entire parent - client's child op may be invalid\n // However, for optimistic updates, we let the client op proceed\n // and the server will validate/reject if needed\n return { type: \"transformed\", operation: clientOp };\n }\n }\n\n // Default: no transformation needed, client op proceeds as-is\n return { type: \"transformed\", operation: clientOp };\n};\n\n/**\n * Transforms all operations in a client transaction against a server transaction.\n * Uses the primitive's transformOperation for schema-aware transformation.\n */\nexport const transformTransactionWithPrimitive = (\n clientTx: Transaction.Transaction,\n serverTx: Transaction.Transaction,\n primitive: Primitive.AnyPrimitive\n): Transaction.Transaction => {\n const transformedOps: Operation.Operation<any, any, any>[] = [];\n\n for (const clientOp of clientTx.ops) {\n let currentOp: Operation.Operation<any, any, any> | null = clientOp;\n\n // Transform against each server operation\n for (const serverOp of serverTx.ops) {\n if (currentOp === null) break;\n\n const result = transformOperationWithPrimitive(currentOp, serverOp, primitive);\n\n switch (result.type) {\n case \"transformed\":\n currentOp = result.operation;\n break;\n case \"noop\":\n currentOp = null;\n break;\n case \"conflict\":\n // For now, treat conflicts as the client op proceeding\n // Server will ultimately validate\n break;\n }\n }\n\n if (currentOp !== null) {\n transformedOps.push(currentOp);\n }\n }\n\n // Return a new transaction with the same ID but transformed ops\n return {\n id: clientTx.id,\n ops: transformedOps,\n timestamp: clientTx.timestamp,\n };\n};\n\n/**\n * Transforms all operations in a client transaction against a server transaction.\n * This is a standalone version that doesn't require a primitive.\n */\nexport const transformTransaction = (\n clientTx: Transaction.Transaction,\n serverTx: Transaction.Transaction\n): Transaction.Transaction => {\n const transformedOps: Operation.Operation<any, any, any>[] = [];\n\n for (const clientOp of clientTx.ops) {\n let currentOp: Operation.Operation<any, any, any> | null = clientOp;\n\n // Transform against each server operation\n for (const serverOp of serverTx.ops) {\n if (currentOp === null) break;\n\n const result = transformOperation(currentOp, serverOp);\n\n switch (result.type) {\n case \"transformed\":\n currentOp = result.operation;\n break;\n case \"noop\":\n currentOp = null;\n break;\n case \"conflict\":\n // For now, treat conflicts as the client op proceeding\n // Server will ultimately validate\n break;\n }\n }\n\n if (currentOp !== null) {\n transformedOps.push(currentOp);\n }\n }\n\n // Return a new transaction with the same ID but transformed ops\n return {\n id: clientTx.id,\n ops: transformedOps,\n timestamp: clientTx.timestamp,\n };\n};\n\n/**\n * Rebases a list of pending transactions against a server transaction using a primitive.\n *\n * This is called when a server transaction arrives that is NOT one of our pending\n * transactions. We need to transform all pending transactions to work correctly\n * on top of the new server state.\n */\nexport const rebasePendingTransactionsWithPrimitive = (\n pendingTxs: ReadonlyArray<Transaction.Transaction>,\n serverTx: Transaction.Transaction,\n primitive: Primitive.AnyPrimitive\n): Transaction.Transaction[] => {\n return pendingTxs.map((pendingTx) =>\n transformTransactionWithPrimitive(pendingTx, serverTx, primitive)\n );\n};\n\n/**\n * Rebases a list of pending transactions against a server transaction.\n *\n * This is called when a server transaction arrives that is NOT one of our pending\n * transactions. We need to transform all pending transactions to work correctly\n * on top of the new server state.\n */\nexport const rebasePendingTransactions = (\n pendingTxs: ReadonlyArray<Transaction.Transaction>,\n serverTx: Transaction.Transaction\n): Transaction.Transaction[] => {\n return pendingTxs.map((pendingTx) =>\n transformTransaction(pendingTx, serverTx)\n );\n};\n\n/**\n * Rebases pending transactions after a rejection using a primitive.\n *\n * When a transaction is rejected, we need to re-transform remaining pending\n * transactions as if the rejected transaction never happened. This is done by\n * rebuilding from the original operations against the current server state.\n *\n * @param originalPendingTxs - The original pending transactions before any rebasing\n * @param rejectedTxId - ID of the rejected transaction\n * @param serverTxsSinceOriginal - Server transactions that have arrived since original\n * @param primitive - The root primitive to use for transformation\n */\nexport const rebaseAfterRejectionWithPrimitive = (\n originalPendingTxs: ReadonlyArray<Transaction.Transaction>,\n rejectedTxId: string,\n serverTxsSinceOriginal: ReadonlyArray<Transaction.Transaction>,\n primitive: Primitive.AnyPrimitive\n): Transaction.Transaction[] => {\n // Filter out the rejected transaction\n const remainingOriginals = originalPendingTxs.filter(\n (tx) => tx.id !== rejectedTxId\n );\n\n // Re-transform each remaining transaction against all server transactions\n let result = [...remainingOriginals];\n\n for (const serverTx of serverTxsSinceOriginal) {\n result = rebasePendingTransactionsWithPrimitive(result, serverTx, primitive);\n }\n\n return result;\n};\n\n/**\n * Rebases pending transactions after a rejection.\n *\n * When a transaction is rejected, we need to re-transform remaining pending\n * transactions as if the rejected transaction never happened. This is done by\n * rebuilding from the original operations against the current server state.\n *\n * @param originalPendingTxs - The original pending transactions before any rebasing\n * @param rejectedTxId - ID of the rejected transaction\n * @param serverTxsSinceOriginal - Server transactions that have arrived since original\n */\nexport const rebaseAfterRejection = (\n originalPendingTxs: ReadonlyArray<Transaction.Transaction>,\n rejectedTxId: string,\n serverTxsSinceOriginal: ReadonlyArray<Transaction.Transaction>\n): Transaction.Transaction[] => {\n // Filter out the rejected transaction\n const remainingOriginals = originalPendingTxs.filter(\n (tx) => tx.id !== rejectedTxId\n );\n\n // Re-transform each remaining transaction against all server transactions\n let result = [...remainingOriginals];\n\n for (const serverTx of serverTxsSinceOriginal) {\n result = rebasePendingTransactions(result, serverTx);\n }\n\n return result;\n};\n"],"mappings":"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"}
@@ -0,0 +1,133 @@
1
+ const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
2
+
3
+ //#region src/client/StateMonitor.ts
4
+ var StateMonitor_exports = /* @__PURE__ */ require_rolldown_runtime.__export({
5
+ determineRecoveryAction: () => determineRecoveryAction,
6
+ make: () => make
7
+ });
8
+ /**
9
+ * Creates a new StateMonitor.
10
+ */
11
+ const make = (options = {}) => {
12
+ const { onEvent, healthCheckInterval = 5e3, stalePendingThreshold = 1e4, maxVersionGap = 10 } = options;
13
+ let _expectedVersion = 0;
14
+ let _pendingMap = /* @__PURE__ */ new Map();
15
+ let _isRecovering = false;
16
+ let _healthCheckHandle = null;
17
+ /**
18
+ * Emits an event if handler is provided.
19
+ */
20
+ const emit = (event) => {
21
+ onEvent === null || onEvent === void 0 || onEvent(event);
22
+ };
23
+ /**
24
+ * Checks if there's a version gap indicating drift.
25
+ */
26
+ const checkVersionGap = (receivedVersion) => {
27
+ const expectedNext = _expectedVersion + 1;
28
+ if (receivedVersion < expectedNext) return true;
29
+ if (receivedVersion > expectedNext + maxVersionGap) {
30
+ emit({
31
+ type: "drift_detected",
32
+ expectedVersion: expectedNext,
33
+ receivedVersion
34
+ });
35
+ return false;
36
+ }
37
+ return true;
38
+ };
39
+ /**
40
+ * Runs a health check.
41
+ */
42
+ const runHealthCheck = () => {
43
+ const now = Date.now();
44
+ let oldestPendingMs = null;
45
+ for (const [id, info] of _pendingMap) {
46
+ const elapsed = now - info.sentAt;
47
+ if (oldestPendingMs === null || elapsed > oldestPendingMs) oldestPendingMs = elapsed;
48
+ if (elapsed > stalePendingThreshold) emit({
49
+ type: "pending_timeout",
50
+ transactionId: id,
51
+ elapsedMs: elapsed
52
+ });
53
+ }
54
+ emit({
55
+ type: "health_check",
56
+ pendingCount: _pendingMap.size,
57
+ oldestPendingMs
58
+ });
59
+ };
60
+ return {
61
+ onServerVersion: (version) => {
62
+ const isValid = checkVersionGap(version);
63
+ if (isValid) _expectedVersion = Math.max(_expectedVersion, version);
64
+ return isValid;
65
+ },
66
+ trackPending: (info) => {
67
+ _pendingMap.set(info.id, info);
68
+ },
69
+ untrackPending: (id) => {
70
+ _pendingMap.delete(id);
71
+ },
72
+ getStalePending: () => {
73
+ const now = Date.now();
74
+ const stale = [];
75
+ for (const info of _pendingMap.values()) if (now - info.sentAt > stalePendingThreshold) stale.push(info);
76
+ return stale;
77
+ },
78
+ getStatus: () => {
79
+ const now = Date.now();
80
+ let oldestPendingMs = null;
81
+ for (const info of _pendingMap.values()) {
82
+ const elapsed = now - info.sentAt;
83
+ if (oldestPendingMs === null || elapsed > oldestPendingMs) oldestPendingMs = elapsed;
84
+ }
85
+ const isHealthy = !_isRecovering && (oldestPendingMs === null || oldestPendingMs < stalePendingThreshold * 2);
86
+ return {
87
+ expectedVersion: _expectedVersion,
88
+ pendingCount: _pendingMap.size,
89
+ oldestPendingMs,
90
+ isHealthy,
91
+ isRecovering: _isRecovering
92
+ };
93
+ },
94
+ start: () => {
95
+ if (_healthCheckHandle !== null) return;
96
+ _healthCheckHandle = setInterval(runHealthCheck, healthCheckInterval);
97
+ },
98
+ stop: () => {
99
+ if (_healthCheckHandle !== null) {
100
+ clearInterval(_healthCheckHandle);
101
+ _healthCheckHandle = null;
102
+ }
103
+ },
104
+ reset: (newVersion) => {
105
+ _expectedVersion = newVersion;
106
+ _pendingMap.clear();
107
+ _isRecovering = false;
108
+ emit({
109
+ type: "recovery_completed",
110
+ version: newVersion
111
+ });
112
+ }
113
+ };
114
+ };
115
+ /**
116
+ * Determines the appropriate recovery action based on current state.
117
+ */
118
+ const determineRecoveryAction = (status, stalePending) => {
119
+ if (!status.isHealthy || stalePending.length > 3) return { type: "request_snapshot" };
120
+ if (stalePending.length > 0) return {
121
+ type: "drop_pending",
122
+ transactionIds: stalePending.map((p) => p.id)
123
+ };
124
+ return { type: "request_snapshot" };
125
+ };
126
+
127
+ //#endregion
128
+ Object.defineProperty(exports, 'StateMonitor_exports', {
129
+ enumerable: true,
130
+ get: function () {
131
+ return StateMonitor_exports;
132
+ }
133
+ });
@@ -0,0 +1,122 @@
1
+ declare namespace StateMonitor_d_exports {
2
+ export { PendingInfo, RecoveryAction, StateMonitor, StateMonitorEvent, StateMonitorEventHandler, StateMonitorOptions, StateMonitorStatus, determineRecoveryAction, make };
3
+ }
4
+ /**
5
+ * Events emitted by the state monitor.
6
+ */
7
+ type StateMonitorEvent = {
8
+ type: "drift_detected";
9
+ expectedVersion: number;
10
+ receivedVersion: number;
11
+ } | {
12
+ type: "recovery_started";
13
+ } | {
14
+ type: "recovery_completed";
15
+ version: number;
16
+ } | {
17
+ type: "recovery_failed";
18
+ error: Error;
19
+ } | {
20
+ type: "pending_timeout";
21
+ transactionId: string;
22
+ elapsedMs: number;
23
+ } | {
24
+ type: "health_check";
25
+ pendingCount: number;
26
+ oldestPendingMs: number | null;
27
+ };
28
+ /**
29
+ * Handler for state monitor events.
30
+ */
31
+ type StateMonitorEventHandler = (event: StateMonitorEvent) => void;
32
+ /**
33
+ * Options for creating a StateMonitor.
34
+ */
35
+ interface StateMonitorOptions {
36
+ /** Handler for monitor events */
37
+ readonly onEvent?: StateMonitorEventHandler;
38
+ /** Interval for health checks in ms (default: 5000) */
39
+ readonly healthCheckInterval?: number;
40
+ /** Threshold for considering a pending transaction "stale" in ms (default: 10000) */
41
+ readonly stalePendingThreshold?: number;
42
+ /** Maximum allowed version gap before triggering recovery (default: 10) */
43
+ readonly maxVersionGap?: number;
44
+ }
45
+ /**
46
+ * Pending transaction info for monitoring.
47
+ */
48
+ interface PendingInfo {
49
+ readonly id: string;
50
+ readonly sentAt: number;
51
+ }
52
+ /**
53
+ * A StateMonitor watches for state drift and triggers recovery.
54
+ */
55
+ interface StateMonitor {
56
+ /**
57
+ * Called when a server transaction is received.
58
+ * Returns true if the version is valid, false if drift is detected.
59
+ */
60
+ readonly onServerVersion: (version: number) => boolean;
61
+ /**
62
+ * Called when a pending transaction is added.
63
+ */
64
+ readonly trackPending: (info: PendingInfo) => void;
65
+ /**
66
+ * Called when a pending transaction is confirmed or rejected.
67
+ */
68
+ readonly untrackPending: (id: string) => void;
69
+ /**
70
+ * Returns pending transactions that have exceeded the stale threshold.
71
+ */
72
+ readonly getStalePending: () => PendingInfo[];
73
+ /**
74
+ * Returns current monitoring status.
75
+ */
76
+ readonly getStatus: () => StateMonitorStatus;
77
+ /**
78
+ * Starts the health check loop.
79
+ */
80
+ readonly start: () => void;
81
+ /**
82
+ * Stops the health check loop.
83
+ */
84
+ readonly stop: () => void;
85
+ /**
86
+ * Resets the monitor state (called after recovery).
87
+ */
88
+ readonly reset: (newVersion: number) => void;
89
+ }
90
+ /**
91
+ * Current monitoring status.
92
+ */
93
+ interface StateMonitorStatus {
94
+ readonly expectedVersion: number;
95
+ readonly pendingCount: number;
96
+ readonly oldestPendingMs: number | null;
97
+ readonly isHealthy: boolean;
98
+ readonly isRecovering: boolean;
99
+ }
100
+ /**
101
+ * Creates a new StateMonitor.
102
+ */
103
+ declare const make: (options?: StateMonitorOptions) => StateMonitor;
104
+ /**
105
+ * Recovery actions that can be taken.
106
+ */
107
+ type RecoveryAction = {
108
+ type: "request_snapshot";
109
+ } | {
110
+ type: "retry_pending";
111
+ transactionIds: string[];
112
+ } | {
113
+ type: "drop_pending";
114
+ transactionIds: string[];
115
+ };
116
+ /**
117
+ * Determines the appropriate recovery action based on current state.
118
+ */
119
+ declare const determineRecoveryAction: (status: StateMonitorStatus, stalePending: PendingInfo[]) => RecoveryAction;
120
+ //#endregion
121
+ export { StateMonitor_d_exports };
122
+ //# sourceMappingURL=StateMonitor.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StateMonitor.d.cts","names":[],"sources":["../../src/client/StateMonitor.ts"],"sourcesContent":[],"mappings":";;;;;;KASY,iBAAA;;;;;;;;;;;EAAA,KAAA,EAI0B,KAJ1B;AAWZ,CAAA,GAAY;EAKK,IAAA,EAAA,iBAAmB;EAcnB,aAAA,EAAW,MAAA;EAQX,SAAA,EAAA,MAAY;CAUG,GAAA;EAUE,IAAA,EAAA,cAAA;EAKN,YAAA,EAAA,MAAA;EAAkB,eAAA,EAAA,MAAA,GAAA,IAAA;AAqB9C,CAAA;AAeA;AA2KA;AAQA;AACU,KA5QE,wBAAA,GA4QF,CAAA,KAAA,EA5QqC,iBA4QrC,EAAA,GAAA,IAAA;;;;UAvQO,mBAAA;;qBAEI;;;;;;;;;;;UAYJ,WAAA;;;;;;;UAQA,YAAA;;;;;;;;;gCAUe;;;;;;;;kCAUE;;;;4BAKN;;;;;;;;;;;;;;;;;UAqBX,kBAAA;;;;;;;;;;cAeJ,iBAAiB,wBAA2B;;;;KA2K7C,cAAA;;;;;;;;;;;;cAQC,kCACH,kCACM,kBACb"}
@@ -0,0 +1,122 @@
1
+ declare namespace StateMonitor_d_exports {
2
+ export { PendingInfo, RecoveryAction, StateMonitor, StateMonitorEvent, StateMonitorEventHandler, StateMonitorOptions, StateMonitorStatus, determineRecoveryAction, make };
3
+ }
4
+ /**
5
+ * Events emitted by the state monitor.
6
+ */
7
+ type StateMonitorEvent = {
8
+ type: "drift_detected";
9
+ expectedVersion: number;
10
+ receivedVersion: number;
11
+ } | {
12
+ type: "recovery_started";
13
+ } | {
14
+ type: "recovery_completed";
15
+ version: number;
16
+ } | {
17
+ type: "recovery_failed";
18
+ error: Error;
19
+ } | {
20
+ type: "pending_timeout";
21
+ transactionId: string;
22
+ elapsedMs: number;
23
+ } | {
24
+ type: "health_check";
25
+ pendingCount: number;
26
+ oldestPendingMs: number | null;
27
+ };
28
+ /**
29
+ * Handler for state monitor events.
30
+ */
31
+ type StateMonitorEventHandler = (event: StateMonitorEvent) => void;
32
+ /**
33
+ * Options for creating a StateMonitor.
34
+ */
35
+ interface StateMonitorOptions {
36
+ /** Handler for monitor events */
37
+ readonly onEvent?: StateMonitorEventHandler;
38
+ /** Interval for health checks in ms (default: 5000) */
39
+ readonly healthCheckInterval?: number;
40
+ /** Threshold for considering a pending transaction "stale" in ms (default: 10000) */
41
+ readonly stalePendingThreshold?: number;
42
+ /** Maximum allowed version gap before triggering recovery (default: 10) */
43
+ readonly maxVersionGap?: number;
44
+ }
45
+ /**
46
+ * Pending transaction info for monitoring.
47
+ */
48
+ interface PendingInfo {
49
+ readonly id: string;
50
+ readonly sentAt: number;
51
+ }
52
+ /**
53
+ * A StateMonitor watches for state drift and triggers recovery.
54
+ */
55
+ interface StateMonitor {
56
+ /**
57
+ * Called when a server transaction is received.
58
+ * Returns true if the version is valid, false if drift is detected.
59
+ */
60
+ readonly onServerVersion: (version: number) => boolean;
61
+ /**
62
+ * Called when a pending transaction is added.
63
+ */
64
+ readonly trackPending: (info: PendingInfo) => void;
65
+ /**
66
+ * Called when a pending transaction is confirmed or rejected.
67
+ */
68
+ readonly untrackPending: (id: string) => void;
69
+ /**
70
+ * Returns pending transactions that have exceeded the stale threshold.
71
+ */
72
+ readonly getStalePending: () => PendingInfo[];
73
+ /**
74
+ * Returns current monitoring status.
75
+ */
76
+ readonly getStatus: () => StateMonitorStatus;
77
+ /**
78
+ * Starts the health check loop.
79
+ */
80
+ readonly start: () => void;
81
+ /**
82
+ * Stops the health check loop.
83
+ */
84
+ readonly stop: () => void;
85
+ /**
86
+ * Resets the monitor state (called after recovery).
87
+ */
88
+ readonly reset: (newVersion: number) => void;
89
+ }
90
+ /**
91
+ * Current monitoring status.
92
+ */
93
+ interface StateMonitorStatus {
94
+ readonly expectedVersion: number;
95
+ readonly pendingCount: number;
96
+ readonly oldestPendingMs: number | null;
97
+ readonly isHealthy: boolean;
98
+ readonly isRecovering: boolean;
99
+ }
100
+ /**
101
+ * Creates a new StateMonitor.
102
+ */
103
+ declare const make: (options?: StateMonitorOptions) => StateMonitor;
104
+ /**
105
+ * Recovery actions that can be taken.
106
+ */
107
+ type RecoveryAction = {
108
+ type: "request_snapshot";
109
+ } | {
110
+ type: "retry_pending";
111
+ transactionIds: string[];
112
+ } | {
113
+ type: "drop_pending";
114
+ transactionIds: string[];
115
+ };
116
+ /**
117
+ * Determines the appropriate recovery action based on current state.
118
+ */
119
+ declare const determineRecoveryAction: (status: StateMonitorStatus, stalePending: PendingInfo[]) => RecoveryAction;
120
+ //#endregion
121
+ export { StateMonitor_d_exports };
122
+ //# sourceMappingURL=StateMonitor.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StateMonitor.d.mts","names":[],"sources":["../../src/client/StateMonitor.ts"],"sourcesContent":[],"mappings":";;;;;;KASY,iBAAA;;;;;;;;;;;EAAA,KAAA,EAI0B,KAJ1B;AAWZ,CAAA,GAAY;EAKK,IAAA,EAAA,iBAAmB;EAcnB,aAAA,EAAW,MAAA;EAQX,SAAA,EAAA,MAAY;CAUG,GAAA;EAUE,IAAA,EAAA,cAAA;EAKN,YAAA,EAAA,MAAA;EAAkB,eAAA,EAAA,MAAA,GAAA,IAAA;AAqB9C,CAAA;AAeA;AA2KA;AAQA;AACU,KA5QE,wBAAA,GA4QF,CAAA,KAAA,EA5QqC,iBA4QrC,EAAA,GAAA,IAAA;;;;UAvQO,mBAAA;;qBAEI;;;;;;;;;;;UAYJ,WAAA;;;;;;;UAQA,YAAA;;;;;;;;;gCAUe;;;;;;;;kCAUE;;;;4BAKN;;;;;;;;;;;;;;;;;UAqBX,kBAAA;;;;;;;;;;cAeJ,iBAAiB,wBAA2B;;;;KA2K7C,cAAA;;;;;;;;;;;;cAQC,kCACH,kCACM,kBACb"}