@rocicorp/zero 0.10.2025010800 → 0.10.2025011100

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 (200) hide show
  1. package/README.md +32 -0
  2. package/out/change-protocol.js +257 -0
  3. package/out/change-protocol.js.map +7 -0
  4. package/out/{chunk-PPRTDNXA.js → chunk-FEVIDCUL.js} +1597 -2356
  5. package/out/chunk-FEVIDCUL.js.map +7 -0
  6. package/out/chunk-ZRR54VX5.js +224 -0
  7. package/out/chunk-ZRR54VX5.js.map +7 -0
  8. package/out/react.js +1 -1
  9. package/out/react.js.map +1 -1
  10. package/out/replicache/src/db/commit.d.ts +12 -35
  11. package/out/replicache/src/db/commit.d.ts.map +1 -1
  12. package/out/replicache/src/db/meta-type-enum.d.ts +1 -7
  13. package/out/replicache/src/db/meta-type-enum.d.ts.map +1 -1
  14. package/out/replicache/src/db/rebase.d.ts.map +1 -1
  15. package/out/replicache/src/db/write.d.ts +0 -1
  16. package/out/replicache/src/db/write.d.ts.map +1 -1
  17. package/out/replicache/src/get-default-puller.d.ts +1 -3
  18. package/out/replicache/src/get-default-puller.d.ts.map +1 -1
  19. package/out/replicache/src/mod.d.ts +5 -5
  20. package/out/replicache/src/mod.d.ts.map +1 -1
  21. package/out/replicache/src/mutation-recovery.d.ts +1 -2
  22. package/out/replicache/src/mutation-recovery.d.ts.map +1 -1
  23. package/out/replicache/src/puller.d.ts +2 -20
  24. package/out/replicache/src/puller.d.ts.map +1 -1
  25. package/out/replicache/src/replicache-impl.d.ts +1 -2
  26. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  27. package/out/replicache/src/sync/pull.d.ts +3 -30
  28. package/out/replicache/src/sync/pull.d.ts.map +1 -1
  29. package/out/replicache/src/sync/push.d.ts +3 -30
  30. package/out/replicache/src/sync/push.d.ts.map +1 -1
  31. package/out/shared/src/options.d.ts.map +1 -1
  32. package/out/shared/src/options.js +15 -7
  33. package/out/shared/src/options.js.map +1 -1
  34. package/out/solid.js +30 -35
  35. package/out/solid.js.map +3 -3
  36. package/out/zero/src/change-protocol.d.ts +2 -0
  37. package/out/zero/src/change-protocol.d.ts.map +1 -0
  38. package/out/zero/src/change-protocol.js +2 -0
  39. package/out/zero/src/change-protocol.js.map +1 -0
  40. package/out/zero-cache/src/config/zero-config.d.ts +30 -4
  41. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  42. package/out/zero-cache/src/config/zero-config.js +31 -15
  43. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  44. package/out/zero-cache/src/db/specs.d.ts +1 -1
  45. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  46. package/out/zero-cache/src/server/change-streamer.js +2 -6
  47. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  48. package/out/zero-cache/src/server/life-cycle.d.ts +3 -2
  49. package/out/zero-cache/src/server/life-cycle.d.ts.map +1 -1
  50. package/out/zero-cache/src/server/life-cycle.js +15 -12
  51. package/out/zero-cache/src/server/life-cycle.js.map +1 -1
  52. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  53. package/out/zero-cache/src/server/main.js +21 -11
  54. package/out/zero-cache/src/server/main.js.map +1 -1
  55. package/out/zero-cache/src/server/multi/config.d.ts +20 -3
  56. package/out/zero-cache/src/server/multi/config.d.ts.map +1 -1
  57. package/out/zero-cache/src/server/multi/config.js +10 -2
  58. package/out/zero-cache/src/server/multi/config.js.map +1 -1
  59. package/out/zero-cache/src/server/multi/main.d.ts.map +1 -1
  60. package/out/zero-cache/src/server/multi/main.js +9 -3
  61. package/out/zero-cache/src/server/multi/main.js.map +1 -1
  62. package/out/zero-cache/src/services/{change-streamer → change-source}/pg/change-source.d.ts +2 -2
  63. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -0
  64. package/out/zero-cache/src/services/{change-streamer → change-source}/pg/change-source.js +1 -1
  65. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -0
  66. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -0
  67. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -0
  68. package/out/zero-cache/src/services/{change-streamer → change-source}/pg/lsn.d.ts +1 -1
  69. package/out/zero-cache/src/services/change-source/pg/lsn.d.ts.map +1 -0
  70. package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -0
  71. package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/ddl.d.ts +5 -5
  72. package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -0
  73. package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -0
  74. package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -0
  75. package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/init.js +1 -1
  76. package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -0
  77. package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/published.d.ts +2 -2
  78. package/out/zero-cache/src/services/change-source/pg/schema/published.d.ts.map +1 -0
  79. package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -0
  80. package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -0
  81. package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -0
  82. package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -0
  83. package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -0
  84. package/out/zero-cache/src/services/change-source/pg/shard-config.d.ts.map +1 -0
  85. package/out/zero-cache/src/services/change-source/pg/shard-config.js.map +1 -0
  86. package/out/zero-cache/src/services/change-source/pg/sync-schema.d.ts.map +1 -0
  87. package/out/zero-cache/src/services/change-source/pg/sync-schema.js.map +1 -0
  88. package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts +38 -0
  89. package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts.map +1 -0
  90. package/out/zero-cache/src/services/change-source/protocol/current/control.js +36 -0
  91. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -0
  92. package/out/zero-cache/src/services/{change-streamer/schema/change.d.ts → change-source/protocol/current/data.d.ts} +28 -23
  93. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -0
  94. package/out/zero-cache/src/services/{change-streamer/schema/change.js → change-source/protocol/current/data.js} +9 -4
  95. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -0
  96. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +469 -0
  97. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -0
  98. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js +19 -0
  99. package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -0
  100. package/out/zero-cache/src/services/change-source/protocol/current/mod.d.ts +6 -0
  101. package/out/zero-cache/src/services/change-source/protocol/current/mod.d.ts.map +1 -0
  102. package/out/zero-cache/src/services/change-source/protocol/current/mod.js +6 -0
  103. package/out/zero-cache/src/services/change-source/protocol/current/mod.js.map +1 -0
  104. package/out/zero-cache/src/services/change-source/protocol/current/path.d.ts +20 -0
  105. package/out/zero-cache/src/services/change-source/protocol/current/path.d.ts.map +1 -0
  106. package/out/zero-cache/src/services/change-source/protocol/current/path.js +20 -0
  107. package/out/zero-cache/src/services/change-source/protocol/current/path.js.map +1 -0
  108. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +17 -0
  109. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -0
  110. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +12 -0
  111. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -0
  112. package/out/zero-cache/src/services/change-source/protocol/mod.d.ts +2 -0
  113. package/out/zero-cache/src/services/change-source/protocol/mod.d.ts.map +1 -0
  114. package/out/zero-cache/src/services/change-source/protocol/mod.js +5 -0
  115. package/out/zero-cache/src/services/change-source/protocol/mod.js.map +1 -0
  116. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +3 -157
  117. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  118. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +3 -13
  119. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  120. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +1 -309
  121. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  122. package/out/zero-cache/src/services/change-streamer/change-streamer.js +3 -11
  123. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  124. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -1
  125. package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
  126. package/out/zero-cache/src/services/change-streamer/storer.d.ts +1 -1
  127. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  128. package/out/zero-cache/src/services/change-streamer/storer.js +1 -0
  129. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  130. package/out/zero-cache/src/services/litestream/commands.d.ts +8 -0
  131. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -0
  132. package/out/zero-cache/src/services/litestream/commands.js +61 -0
  133. package/out/zero-cache/src/services/litestream/commands.js.map +1 -0
  134. package/out/zero-cache/src/services/litestream/config.yml +7 -0
  135. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  136. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  137. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +3 -2
  138. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  139. package/out/zero-cache/src/services/view-syncer/client-handler.js +1 -1
  140. package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
  141. package/out/zero-cache/src/services/view-syncer/cvr.js +1 -1
  142. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  143. package/out/zero-cache/src/types/processes.d.ts +4 -2
  144. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  145. package/out/zero-cache/src/types/processes.js.map +1 -1
  146. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  147. package/out/zero-schema/src/normalize-table-schema.d.ts +4 -3
  148. package/out/zero-schema/src/normalize-table-schema.d.ts.map +1 -1
  149. package/out/zero-schema/src/normalize-table-schema.js +27 -23
  150. package/out/zero-schema/src/normalize-table-schema.js.map +1 -1
  151. package/out/zero-schema/src/normalized-schema.d.ts.map +1 -1
  152. package/out/zero-schema/src/normalized-schema.js +19 -2
  153. package/out/zero-schema/src/normalized-schema.js.map +1 -1
  154. package/out/zero-schema/src/schema.d.ts +1 -1
  155. package/out/zero-schema/src/schema.d.ts.map +1 -1
  156. package/out/zero-schema/src/schema.js +5 -4
  157. package/out/zero-schema/src/schema.js.map +1 -1
  158. package/out/zero-solid/src/solid-view.d.ts +4 -1
  159. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  160. package/out/zero-solid/src/use-query.d.ts +4 -7
  161. package/out/zero-solid/src/use-query.d.ts.map +1 -1
  162. package/out/zero.js +2 -1
  163. package/package.json +9 -5
  164. package/out/chunk-PPRTDNXA.js.map +0 -7
  165. package/out/zero-cache/src/services/change-streamer/pg/change-source.d.ts.map +0 -1
  166. package/out/zero-cache/src/services/change-streamer/pg/change-source.js.map +0 -1
  167. package/out/zero-cache/src/services/change-streamer/pg/initial-sync.d.ts.map +0 -1
  168. package/out/zero-cache/src/services/change-streamer/pg/initial-sync.js.map +0 -1
  169. package/out/zero-cache/src/services/change-streamer/pg/lsn.d.ts.map +0 -1
  170. package/out/zero-cache/src/services/change-streamer/pg/lsn.js.map +0 -1
  171. package/out/zero-cache/src/services/change-streamer/pg/schema/ddl.d.ts.map +0 -1
  172. package/out/zero-cache/src/services/change-streamer/pg/schema/ddl.js.map +0 -1
  173. package/out/zero-cache/src/services/change-streamer/pg/schema/init.d.ts.map +0 -1
  174. package/out/zero-cache/src/services/change-streamer/pg/schema/init.js.map +0 -1
  175. package/out/zero-cache/src/services/change-streamer/pg/schema/published.d.ts.map +0 -1
  176. package/out/zero-cache/src/services/change-streamer/pg/schema/published.js.map +0 -1
  177. package/out/zero-cache/src/services/change-streamer/pg/schema/shard.d.ts.map +0 -1
  178. package/out/zero-cache/src/services/change-streamer/pg/schema/shard.js.map +0 -1
  179. package/out/zero-cache/src/services/change-streamer/pg/schema/validation.d.ts.map +0 -1
  180. package/out/zero-cache/src/services/change-streamer/pg/schema/validation.js.map +0 -1
  181. package/out/zero-cache/src/services/change-streamer/pg/shard-config.d.ts.map +0 -1
  182. package/out/zero-cache/src/services/change-streamer/pg/shard-config.js.map +0 -1
  183. package/out/zero-cache/src/services/change-streamer/pg/sync-schema.d.ts.map +0 -1
  184. package/out/zero-cache/src/services/change-streamer/pg/sync-schema.js.map +0 -1
  185. package/out/zero-cache/src/services/change-streamer/schema/change.d.ts.map +0 -1
  186. package/out/zero-cache/src/services/change-streamer/schema/change.js.map +0 -1
  187. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/initial-sync.d.ts +0 -0
  188. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/initial-sync.js +0 -0
  189. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/lsn.js +0 -0
  190. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/ddl.js +0 -0
  191. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/init.d.ts +0 -0
  192. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/published.js +0 -0
  193. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/shard.d.ts +0 -0
  194. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/shard.js +0 -0
  195. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/validation.d.ts +0 -0
  196. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/schema/validation.js +0 -0
  197. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/shard-config.d.ts +0 -0
  198. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/shard-config.js +0 -0
  199. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/sync-schema.d.ts +0 -0
  200. /package/out/zero-cache/src/services/{change-streamer → change-source}/pg/sync-schema.js +0 -0
@@ -16,10 +16,53 @@ import {
16
16
  unreachable
17
17
  } from "./chunk-Y6OVFUGE.js";
18
18
  import {
19
- __export,
20
- __reExport
19
+ assert as assert2,
20
+ parse,
21
+ readonly,
22
+ readonlyArray,
23
+ readonlyObject,
24
+ readonlyRecord,
25
+ valita_exports
26
+ } from "./chunk-ZRR54VX5.js";
27
+ import {
28
+ __export
21
29
  } from "./chunk-F5QR3K72.js";
22
30
 
31
+ // ../replicache/src/call-default-fetch.ts
32
+ async function callDefaultFetch(url, auth, requestID, requestBody) {
33
+ const init = {
34
+ headers: {
35
+ // eslint-disable-next-line @typescript-eslint/naming-convention
36
+ "Content-type": "application/json",
37
+ // eslint-disable-next-line @typescript-eslint/naming-convention
38
+ "Authorization": auth,
39
+ // eslint-disable-next-line @typescript-eslint/naming-convention
40
+ "X-Replicache-RequestID": requestID
41
+ },
42
+ body: JSON.stringify(requestBody),
43
+ method: "POST"
44
+ };
45
+ const request = new Request(url, init);
46
+ const response = await fetch(request);
47
+ const httpStatusCode = response.status;
48
+ if (httpStatusCode !== 200) {
49
+ return [
50
+ void 0,
51
+ {
52
+ httpStatusCode,
53
+ errorMessage: await response.text()
54
+ }
55
+ ];
56
+ }
57
+ return [
58
+ response,
59
+ {
60
+ httpStatusCode,
61
+ errorMessage: ""
62
+ }
63
+ ];
64
+ }
65
+
23
66
  // ../shared/src/config.ts
24
67
  var isProd = process.env.NODE_ENV === "production";
25
68
 
@@ -77,73 +120,73 @@ function deepEqual(a, b) {
77
120
  }
78
121
  return aSize === bSize;
79
122
  }
80
- function assertJSONValue(v2) {
123
+ function assertJSONValue(v) {
81
124
  if (isProd) {
82
125
  return;
83
126
  }
84
- switch (typeof v2) {
127
+ switch (typeof v) {
85
128
  case "boolean":
86
129
  case "number":
87
130
  case "string":
88
131
  return;
89
132
  case "object":
90
- if (v2 === null) {
133
+ if (v === null) {
91
134
  return;
92
135
  }
93
- if (Array.isArray(v2)) {
94
- return assertJSONArray(v2);
136
+ if (Array.isArray(v)) {
137
+ return assertJSONArray(v);
95
138
  }
96
- return assertObjectIsJSONObject(v2);
139
+ return assertObjectIsJSONObject(v);
97
140
  }
98
- throwInvalidType(v2, "JSON value");
141
+ throwInvalidType(v, "JSON value");
99
142
  }
100
- function assertJSONObject(v2) {
101
- assertObject(v2);
102
- assertObjectIsJSONObject(v2);
143
+ function assertJSONObject(v) {
144
+ assertObject(v);
145
+ assertObjectIsJSONObject(v);
103
146
  }
104
- function assertObjectIsJSONObject(v2) {
105
- for (const k in v2) {
106
- if (hasOwn(v2, k)) {
107
- const value = v2[k];
147
+ function assertObjectIsJSONObject(v) {
148
+ for (const k in v) {
149
+ if (hasOwn(v, k)) {
150
+ const value = v[k];
108
151
  if (value !== void 0) {
109
152
  assertJSONValue(value);
110
153
  }
111
154
  }
112
155
  }
113
156
  }
114
- function assertJSONArray(v2) {
115
- for (const item of v2) {
157
+ function assertJSONArray(v) {
158
+ for (const item of v) {
116
159
  assertJSONValue(item);
117
160
  }
118
161
  }
119
- function isJSONValue(v2, path2) {
120
- switch (typeof v2) {
162
+ function isJSONValue(v, path2) {
163
+ switch (typeof v) {
121
164
  case "boolean":
122
165
  case "number":
123
166
  case "string":
124
167
  return true;
125
168
  case "object":
126
- if (v2 === null) {
169
+ if (v === null) {
127
170
  return true;
128
171
  }
129
- if (Array.isArray(v2)) {
130
- return isJSONArray(v2, path2);
172
+ if (Array.isArray(v)) {
173
+ return isJSONArray(v, path2);
131
174
  }
132
- return objectIsJSONObject(v2, path2);
175
+ return objectIsJSONObject(v, path2);
133
176
  }
134
177
  return false;
135
178
  }
136
- function isJSONObject(v2, path2) {
137
- if (typeof v2 !== "object" || v2 === null) {
179
+ function isJSONObject(v, path2) {
180
+ if (typeof v !== "object" || v === null) {
138
181
  return false;
139
182
  }
140
- return objectIsJSONObject(v2, path2);
183
+ return objectIsJSONObject(v, path2);
141
184
  }
142
- function objectIsJSONObject(v2, path2) {
143
- for (const k in v2) {
144
- if (hasOwn(v2, k)) {
185
+ function objectIsJSONObject(v, path2) {
186
+ for (const k in v) {
187
+ if (hasOwn(v, k)) {
145
188
  path2.push(k);
146
- const value = v2[k];
189
+ const value = v[k];
147
190
  if (value !== void 0 && !isJSONValue(value, path2)) {
148
191
  return false;
149
192
  }
@@ -152,10 +195,10 @@ function objectIsJSONObject(v2, path2) {
152
195
  }
153
196
  return true;
154
197
  }
155
- function isJSONArray(v2, path2) {
156
- for (let i = 0; i < v2.length; i++) {
198
+ function isJSONArray(v, path2) {
199
+ for (let i = 0; i < v.length; i++) {
157
200
  path2.push(i);
158
- if (!isJSONValue(v2[i], path2)) {
201
+ if (!isJSONValue(v[i], path2)) {
159
202
  return false;
160
203
  }
161
204
  path2.pop();
@@ -163,41 +206,6 @@ function isJSONArray(v2, path2) {
163
206
  return true;
164
207
  }
165
208
 
166
- // ../replicache/src/call-default-fetch.ts
167
- async function callDefaultFetch(url, auth, requestID, requestBody) {
168
- const init = {
169
- headers: {
170
- // eslint-disable-next-line @typescript-eslint/naming-convention
171
- "Content-type": "application/json",
172
- // eslint-disable-next-line @typescript-eslint/naming-convention
173
- "Authorization": auth,
174
- // eslint-disable-next-line @typescript-eslint/naming-convention
175
- "X-Replicache-RequestID": requestID
176
- },
177
- body: JSON.stringify(requestBody),
178
- method: "POST"
179
- };
180
- const request = new Request(url, init);
181
- const response = await fetch(request);
182
- const httpStatusCode = response.status;
183
- if (httpStatusCode !== 200) {
184
- return [
185
- void 0,
186
- {
187
- httpStatusCode,
188
- errorMessage: await response.text()
189
- }
190
- ];
191
- }
192
- return [
193
- response,
194
- {
195
- httpStatusCode,
196
- errorMessage: ""
197
- }
198
- ];
199
- }
200
-
201
209
  // ../shared/src/string-compare.ts
202
210
  function stringCompare(a, b) {
203
211
  if (a === b) {
@@ -233,12 +241,12 @@ function getCompareValue(cookie) {
233
241
  }
234
242
  return cookie.order;
235
243
  }
236
- function assertCookie(v2) {
237
- if (v2 === null || typeof v2 === "string" || typeof v2 === "number") {
244
+ function assertCookie(v) {
245
+ if (v === null || typeof v === "string" || typeof v === "number") {
238
246
  return;
239
247
  }
240
- assertJSONObject(v2);
241
- if (typeof v2.order === "string" || typeof v2.order === "number") {
248
+ assertJSONObject(v);
249
+ if (typeof v.order === "string" || typeof v.order === "number") {
242
250
  return;
243
251
  }
244
252
  throw new Error("Invalid cookie");
@@ -251,14 +259,14 @@ function isError(obj, type) {
251
259
  function isErrorResponse(obj) {
252
260
  return typeof obj.error === "string";
253
261
  }
254
- function isClientStateNotFoundResponse(v2) {
255
- return isError(v2, "ClientStateNotFound");
262
+ function isClientStateNotFoundResponse(v) {
263
+ return isError(v, "ClientStateNotFound");
256
264
  }
257
- function isVersionNotSupportedResponse(v2) {
258
- if (!isError(v2, "VersionNotSupported")) {
265
+ function isVersionNotSupportedResponse(v) {
266
+ if (!isError(v, "VersionNotSupported")) {
259
267
  return false;
260
268
  }
261
- const { versionType } = v2;
269
+ const { versionType } = v;
262
270
  switch (versionType) {
263
271
  case void 0:
264
272
  case "pull":
@@ -268,15 +276,15 @@ function isVersionNotSupportedResponse(v2) {
268
276
  }
269
277
  return false;
270
278
  }
271
- function assertVersionNotSupportedResponse(v2) {
272
- assert(isVersionNotSupportedResponse(v2));
279
+ function assertVersionNotSupportedResponse(v) {
280
+ assert(isVersionNotSupportedResponse(v));
273
281
  }
274
282
 
275
283
  // ../replicache/src/http-request-info.ts
276
- function assertHTTPRequestInfo(v2) {
277
- assertObject(v2);
278
- assertNumber(v2.httpStatusCode);
279
- assertString(v2.errorMessage);
284
+ function assertHTTPRequestInfo(v) {
285
+ assertObject(v);
286
+ assertNumber(v.httpStatusCode);
287
+ assertString(v.errorMessage);
280
288
  }
281
289
 
282
290
  // ../replicache/src/patch-operation.ts
@@ -341,29 +349,17 @@ var defaultPullers = /* @__PURE__ */ new WeakSet();
341
349
  function isDefaultPuller(puller) {
342
350
  return defaultPullers.has(puller);
343
351
  }
344
- function assertPullResponseV0(v2) {
345
- assertObject(v2);
346
- if (isClientStateNotFoundResponse(v2) || isVersionNotSupportedResponse(v2)) {
347
- return;
348
- }
349
- const v22 = v2;
350
- if (v22.cookie !== void 0) {
351
- assertJSONValue(v22.cookie);
352
- }
353
- assertNumber(v22.lastMutationID);
354
- assertPatchOperations(v22.patch);
355
- }
356
- function assertPullResponseV1(v2) {
357
- assertObject(v2);
358
- if (isClientStateNotFoundResponse(v2) || isVersionNotSupportedResponse(v2)) {
352
+ function assertPullResponseV1(v) {
353
+ assertObject(v);
354
+ if (isClientStateNotFoundResponse(v) || isVersionNotSupportedResponse(v)) {
359
355
  return;
360
356
  }
361
- const v22 = v2;
362
- if (v22.cookie !== void 0) {
363
- assertCookie(v22.cookie);
357
+ const v2 = v;
358
+ if (v2.cookie !== void 0) {
359
+ assertCookie(v2.cookie);
364
360
  }
365
- assertLastMutationIDChanges(v22.lastMutationIDChanges);
366
- assertPatchOperations(v22.patch);
361
+ assertLastMutationIDChanges(v2.lastMutationIDChanges);
362
+ assertPatchOperations(v2.patch);
367
363
  }
368
364
  function assertLastMutationIDChanges(lastMutationIDChanges) {
369
365
  assertObject(lastMutationIDChanges);
@@ -372,18 +368,11 @@ function assertLastMutationIDChanges(lastMutationIDChanges) {
372
368
  assertNumber(value);
373
369
  }
374
370
  }
375
- function assertPullerResultV1(v2) {
376
- assertObject(v2);
377
- assertHTTPRequestInfo(v2.httpRequestInfo);
378
- if (v2.response !== void 0) {
379
- assertPullResponseV1(v2.response);
380
- }
381
- }
382
- function assertPullerResultV0(v2) {
383
- assertObject(v2);
384
- assertHTTPRequestInfo(v2.httpRequestInfo);
385
- if (v2.response !== void 0) {
386
- assertPullResponseV0(v2.response);
371
+ function assertPullerResultV1(v) {
372
+ assertObject(v);
373
+ assertHTTPRequestInfo(v.httpRequestInfo);
374
+ if (v.response !== void 0) {
375
+ assertPullResponseV1(v.response);
387
376
  }
388
377
  }
389
378
 
@@ -398,15 +387,15 @@ var promiseVoid = Promise.resolve();
398
387
 
399
388
  // ../replicache/src/frozen-json.ts
400
389
  var deepFrozenObjects = /* @__PURE__ */ new WeakSet();
401
- function deepFreeze(v2) {
390
+ function deepFreeze(v) {
402
391
  if (isProd) {
403
- return v2;
392
+ return v;
404
393
  }
405
- deepFreezeInternal(v2, []);
406
- return v2;
394
+ deepFreezeInternal(v, []);
395
+ return v;
407
396
  }
408
- function deepFreezeInternal(v2, seen) {
409
- switch (typeof v2) {
397
+ function deepFreezeInternal(v, seen) {
398
+ switch (typeof v) {
410
399
  case "undefined":
411
400
  throw new TypeError("Unexpected value undefined");
412
401
  case "boolean":
@@ -414,84 +403,84 @@ function deepFreezeInternal(v2, seen) {
414
403
  case "string":
415
404
  return;
416
405
  case "object": {
417
- if (v2 === null) {
406
+ if (v === null) {
418
407
  return;
419
408
  }
420
- if (deepFrozenObjects.has(v2)) {
409
+ if (deepFrozenObjects.has(v)) {
421
410
  return;
422
411
  }
423
- deepFrozenObjects.add(v2);
424
- if (seen.includes(v2)) {
425
- throwInvalidType(v2, "Cyclic JSON object");
412
+ deepFrozenObjects.add(v);
413
+ if (seen.includes(v)) {
414
+ throwInvalidType(v, "Cyclic JSON object");
426
415
  }
427
- seen.push(v2);
428
- Object.freeze(v2);
429
- if (Array.isArray(v2)) {
430
- deepFreezeArray(v2, seen);
416
+ seen.push(v);
417
+ Object.freeze(v);
418
+ if (Array.isArray(v)) {
419
+ deepFreezeArray(v, seen);
431
420
  } else {
432
- deepFreezeObject(v2, seen);
421
+ deepFreezeObject(v, seen);
433
422
  }
434
423
  seen.pop();
435
424
  return;
436
425
  }
437
426
  default:
438
- throwInvalidType(v2, "JSON value");
427
+ throwInvalidType(v, "JSON value");
439
428
  }
440
429
  }
441
- function deepFreezeArray(v2, seen) {
442
- for (const item of v2) {
430
+ function deepFreezeArray(v, seen) {
431
+ for (const item of v) {
443
432
  deepFreezeInternal(item, seen);
444
433
  }
445
434
  }
446
- function deepFreezeObject(v2, seen) {
447
- for (const k in v2) {
448
- if (hasOwn(v2, k)) {
449
- const value = v2[k];
435
+ function deepFreezeObject(v, seen) {
436
+ for (const k in v) {
437
+ if (hasOwn(v, k)) {
438
+ const value = v[k];
450
439
  if (value !== void 0) {
451
440
  deepFreezeInternal(value, seen);
452
441
  }
453
442
  }
454
443
  }
455
444
  }
456
- function assertDeepFrozen(v2) {
445
+ function assertDeepFrozen(v) {
457
446
  if (isProd) {
458
447
  return;
459
448
  }
460
- if (!isDeepFrozen(v2, [])) {
449
+ if (!isDeepFrozen(v, [])) {
461
450
  throw new Error("Expected frozen object");
462
451
  }
463
452
  }
464
- function isDeepFrozen(v2, seen) {
465
- switch (typeof v2) {
453
+ function isDeepFrozen(v, seen) {
454
+ switch (typeof v) {
466
455
  case "boolean":
467
456
  case "number":
468
457
  case "string":
469
458
  return true;
470
459
  case "object":
471
- if (v2 === null) {
460
+ if (v === null) {
472
461
  return true;
473
462
  }
474
- if (deepFrozenObjects.has(v2)) {
463
+ if (deepFrozenObjects.has(v)) {
475
464
  return true;
476
465
  }
477
- if (!Object.isFrozen(v2)) {
466
+ if (!Object.isFrozen(v)) {
478
467
  return false;
479
468
  }
480
- if (seen.includes(v2)) {
481
- throwInvalidType(v2, "Cyclic JSON object");
469
+ if (seen.includes(v)) {
470
+ throwInvalidType(v, "Cyclic JSON object");
482
471
  }
483
- seen.push(v2);
484
- if (Array.isArray(v2)) {
485
- for (const item of v2) {
472
+ seen.push(v);
473
+ if (Array.isArray(v)) {
474
+ for (const item of v) {
486
475
  if (!isDeepFrozen(item, seen)) {
487
476
  seen.pop();
488
477
  return false;
489
478
  }
490
479
  }
491
480
  } else {
492
- for (const k in v2) {
493
- if (hasOwn(v2, k)) {
494
- const value = v2[k];
481
+ for (const k in v) {
482
+ if (hasOwn(v, k)) {
483
+ const value = v[k];
495
484
  if (value !== void 0 && !isDeepFrozen(value, seen)) {
496
485
  seen.pop();
497
486
  return false;
@@ -499,18 +488,18 @@ function isDeepFrozen(v2, seen) {
499
488
  }
500
489
  }
501
490
  }
502
- deepFrozenObjects.add(v2);
491
+ deepFrozenObjects.add(v);
503
492
  seen.pop();
504
493
  return true;
505
494
  default:
506
- throwInvalidType(v2, "JSON value");
495
+ throwInvalidType(v, "JSON value");
507
496
  }
508
497
  }
509
- function deepFreezeAllowUndefined(v2) {
510
- if (v2 === void 0) {
498
+ function deepFreezeAllowUndefined(v) {
499
+ if (v === void 0) {
511
500
  return void 0;
512
501
  }
513
- return deepFreeze(v2);
502
+ return deepFreeze(v);
514
503
  }
515
504
 
516
505
  // ../replicache/src/kv/write-impl-base.ts
@@ -532,16 +521,16 @@ var WriteImplBase = class {
532
521
  }
533
522
  }
534
523
  async get(key) {
535
- const v2 = this._pending.get(key);
536
- switch (v2) {
524
+ const v = this._pending.get(key);
525
+ switch (v) {
537
526
  case deleteSentinel:
538
527
  return void 0;
539
528
  case void 0: {
540
- const v3 = await this.#read.get(key);
541
- return deepFreezeAllowUndefined(v3);
529
+ const v2 = await this.#read.get(key);
530
+ return deepFreezeAllowUndefined(v2);
542
531
  }
543
532
  default:
544
- return v2;
533
+ return v;
545
534
  }
546
535
  }
547
536
  put(key, value) {
@@ -1454,14 +1443,14 @@ var Chunk = class {
1454
1443
  this.meta = refs;
1455
1444
  }
1456
1445
  };
1457
- function assertRefs(v2) {
1458
- if (!Array.isArray(v2)) {
1446
+ function assertRefs(v) {
1447
+ if (!Array.isArray(v)) {
1459
1448
  throw new Error("Refs must be an array");
1460
1449
  }
1461
- if (v2.length > 0) {
1462
- assertString(v2[0]);
1463
- for (let i = 1; i < v2.length; i++) {
1464
- assertString(v2[i]);
1450
+ if (v.length > 0) {
1451
+ assertString(v[0]);
1452
+ for (let i = 1; i < v.length; i++) {
1453
+ assertString(v[i]);
1465
1454
  }
1466
1455
  }
1467
1456
  }
@@ -1480,215 +1469,6 @@ function randomUint64() {
1480
1469
  return BigInt(high) << 32n | BigInt(low);
1481
1470
  }
1482
1471
 
1483
- // ../shared/src/valita.ts
1484
- var valita_exports = {};
1485
- __export(valita_exports, {
1486
- assert: () => assert2,
1487
- deepPartial: () => deepPartial,
1488
- instanceOfAbstractType: () => instanceOfAbstractType,
1489
- is: () => is,
1490
- parse: () => parse,
1491
- readonly: () => readonly,
1492
- readonlyArray: () => readonlyArray,
1493
- readonlyObject: () => readonlyObject,
1494
- readonlyRecord: () => readonlyRecord,
1495
- test: () => test,
1496
- testOptional: () => testOptional
1497
- });
1498
- __reExport(valita_exports, valita_star);
1499
- import * as v from "@badrap/valita";
1500
- import * as valita_star from "@badrap/valita";
1501
- function toDisplay(value) {
1502
- switch (typeof value) {
1503
- case "string":
1504
- case "number":
1505
- case "boolean":
1506
- return JSON.stringify(value);
1507
- case "undefined":
1508
- return "undefined";
1509
- case "bigint":
1510
- return value.toString() + "n";
1511
- default:
1512
- if (value === null) {
1513
- return "null";
1514
- }
1515
- if (Array.isArray(value)) {
1516
- return "array";
1517
- }
1518
- return typeof value;
1519
- }
1520
- }
1521
- function toDisplayAtPath(v2, path2) {
1522
- if (!path2?.length) {
1523
- return toDisplay(v2);
1524
- }
1525
- let cur = v2;
1526
- for (const p of path2) {
1527
- cur = cur[p];
1528
- }
1529
- return toDisplay(cur);
1530
- }
1531
- function displayList(word, expected, toDisplay2 = (x) => String(x)) {
1532
- if (expected.length === 1) {
1533
- return toDisplay2(expected[0]);
1534
- }
1535
- const suffix = `${toDisplay2(
1536
- expected[expected.length - 2]
1537
- )} ${word} ${toDisplay2(expected[expected.length - 1])}`;
1538
- if (expected.length === 2) {
1539
- return suffix;
1540
- }
1541
- return `${expected.slice(0, -2).map(toDisplay2).join(", ")}, ${suffix}`;
1542
- }
1543
- function getMessage(err2, v2, schema, mode) {
1544
- const firstIssue = err2.issues[0];
1545
- const { path: path2 } = firstIssue;
1546
- const atPath = path2?.length ? ` at ${path2.join(".")}` : "";
1547
- switch (firstIssue.code) {
1548
- case "invalid_type":
1549
- return `Expected ${displayList(
1550
- "or",
1551
- firstIssue.expected
1552
- )}${atPath}. Got ${toDisplayAtPath(v2, path2)}`;
1553
- case "missing_value": {
1554
- const atPath2 = path2 && path2.length > 1 ? ` at ${path2.slice(0, -1).join(".")}` : "";
1555
- if (firstIssue.path?.length) {
1556
- return `Missing property ${firstIssue.path.at(-1)}${atPath2}`;
1557
- }
1558
- return `TODO Unknown missing property${atPath2}`;
1559
- }
1560
- case "invalid_literal":
1561
- return `Expected literal value ${displayList(
1562
- "or",
1563
- firstIssue.expected,
1564
- toDisplay
1565
- )}${atPath} Got ${toDisplayAtPath(v2, path2)}`;
1566
- case "invalid_length": {
1567
- return `Expected array with length ${firstIssue.minLength === firstIssue.maxLength ? firstIssue.minLength : `between ${firstIssue.minLength} and ${firstIssue.maxLength}`}${atPath}. Got array with length ${v2.length}`;
1568
- }
1569
- case "unrecognized_keys":
1570
- if (firstIssue.keys.length === 1) {
1571
- return `Unexpected property ${firstIssue.keys[0]}${atPath}`;
1572
- }
1573
- return `Unexpected properties ${displayList(
1574
- "and",
1575
- firstIssue.keys
1576
- )}${atPath}`;
1577
- case "invalid_union":
1578
- return schema.name === "union" ? getDeepestUnionParseError(v2, schema, mode ?? "strict") : `Invalid union value${atPath}`;
1579
- case "custom_error": {
1580
- const { error } = firstIssue;
1581
- const message = !error ? "unknown" : typeof error === "string" ? error : error.message ?? "unknown";
1582
- return `${message}${atPath}. Got ${toDisplayAtPath(v2, path2)}`;
1583
- }
1584
- }
1585
- }
1586
- function getDeepestUnionParseError(value, schema, mode) {
1587
- const failures = [];
1588
- for (const type of schema.options) {
1589
- const r = type.try(value, { mode });
1590
- if (!r.ok) {
1591
- failures.push({ type, err: r });
1592
- }
1593
- }
1594
- if (failures.length) {
1595
- failures.sort(pathCmp);
1596
- if (failures.length === 1 || pathCmp(failures[0], failures[1]) < 0) {
1597
- return getMessage(failures[0].err, value, failures[0].type, mode);
1598
- }
1599
- }
1600
- try {
1601
- const str = JSON.stringify(value);
1602
- return `Invalid union value: ${str}`;
1603
- } catch (e) {
1604
- return `Invalid union value`;
1605
- }
1606
- }
1607
- function pathCmp(a, b) {
1608
- const aPath = a.err.issues[0].path;
1609
- const bPath = b.err.issues[0].path;
1610
- if (aPath.length !== bPath.length) {
1611
- return bPath.length - aPath.length;
1612
- }
1613
- for (let i = 0; i < aPath.length; i++) {
1614
- if (bPath[i] > aPath[i]) {
1615
- return -1;
1616
- }
1617
- if (bPath[i] < aPath[i]) {
1618
- return 1;
1619
- }
1620
- }
1621
- return 0;
1622
- }
1623
- function parse(value, schema, mode) {
1624
- const res = test(value, schema, mode);
1625
- if (!res.ok) {
1626
- throw new TypeError(res.error);
1627
- }
1628
- return res.value;
1629
- }
1630
- function is(value, schema, mode) {
1631
- return test(value, schema, mode).ok;
1632
- }
1633
- function assert2(value, schema, mode) {
1634
- parse(value, schema, mode);
1635
- }
1636
- function test(value, schema, mode) {
1637
- const res = schema.try(value, mode ? { mode } : void 0);
1638
- if (!res.ok) {
1639
- return {
1640
- ok: false,
1641
- error: getMessage(res, value, schema, mode)
1642
- };
1643
- }
1644
- return res;
1645
- }
1646
- function testOptional(value, schema, mode) {
1647
- let flags = 1;
1648
- if (mode === "passthrough") {
1649
- flags = 0;
1650
- } else if (mode === "strip") {
1651
- flags = 2;
1652
- }
1653
- const res = schema.func(value, flags);
1654
- if (res === void 0) {
1655
- return { ok: true, value };
1656
- } else if (res.ok) {
1657
- return res;
1658
- }
1659
- const err2 = new v.ValitaError(res);
1660
- return { ok: false, error: getMessage(err2, value, schema, mode) };
1661
- }
1662
- function readonly(t2) {
1663
- return t2;
1664
- }
1665
- function readonlyObject(t2) {
1666
- return v.object(t2);
1667
- }
1668
- function readonlyArray(t2) {
1669
- return v.array(t2);
1670
- }
1671
- function readonlyRecord(t2) {
1672
- return v.record(t2);
1673
- }
1674
- var AbstractType = Object.getPrototypeOf(
1675
- Object.getPrototypeOf(v.string().optional())
1676
- ).constructor;
1677
- function instanceOfAbstractType(obj) {
1678
- return obj instanceof AbstractType;
1679
- }
1680
- function deepPartial(s) {
1681
- const shape = {};
1682
- for (const [key, type] of Object.entries(s.shape)) {
1683
- if (type.name === "object") {
1684
- shape[key] = deepPartial(type).optional();
1685
- } else {
1686
- shape[key] = type.optional();
1687
- }
1688
- }
1689
- return v.object(shape);
1690
- }
1691
-
1692
1472
  // ../replicache/src/hash.ts
1693
1473
  var STRING_LENGTH = 22;
1694
1474
  var hashRe = /^[0-9a-v-]+$/;
@@ -2095,11 +1875,11 @@ var LazyWrite = class extends LazyRead {
2095
1875
  }
2096
1876
  async #setHead(name, hash2) {
2097
1877
  const oldHash = await this.getHead(name);
2098
- const v2 = this._pendingHeadChanges.get(name);
2099
- if (v2 === void 0) {
1878
+ const v = this._pendingHeadChanges.get(name);
1879
+ if (v === void 0) {
2100
1880
  this._pendingHeadChanges.set(name, { new: hash2, old: oldHash });
2101
1881
  } else {
2102
- v2.new = hash2;
1882
+ v.new = hash2;
2103
1883
  }
2104
1884
  }
2105
1885
  isMemOnlyChunkHash(hash2) {
@@ -2473,11 +2253,11 @@ var WriteImpl3 = class extends ReadImpl3 {
2473
2253
  } else {
2474
2254
  p1 = this._tx.put(hk, hash2);
2475
2255
  }
2476
- const v2 = this.#changedHeads.get(name);
2477
- if (v2 === void 0) {
2256
+ const v = this.#changedHeads.get(name);
2257
+ if (v === void 0) {
2478
2258
  this.#changedHeads.set(name, { new: hash2, old: oldHash });
2479
2259
  } else {
2480
- v2.new = hash2;
2260
+ v.new = hash2;
2481
2261
  }
2482
2262
  await p1;
2483
2263
  }
@@ -2537,31 +2317,19 @@ var WriteImpl3 = class extends ReadImpl3 {
2537
2317
  };
2538
2318
 
2539
2319
  // ../replicache/src/db/meta-type-enum.ts
2540
- var IndexChangeSDD = 1;
2541
- var LocalSDD = 2;
2542
- var SnapshotSDD = 3;
2543
2320
  var LocalDD31 = 4;
2544
2321
  var SnapshotDD31 = 5;
2545
2322
 
2546
2323
  // ../replicache/src/db/commit.ts
2547
2324
  var DEFAULT_HEAD_NAME = "main";
2548
- function commitIsLocalSDD(commit) {
2549
- return isLocalMetaSDD(commit.meta);
2550
- }
2551
2325
  function commitIsLocalDD31(commit) {
2552
2326
  return isLocalMetaDD31(commit.meta);
2553
2327
  }
2554
2328
  function commitIsLocal(commit) {
2555
- return commitIsLocalDD31(commit) || commitIsLocalSDD(commit);
2556
- }
2557
- function commitIsSnapshotDD31(commit) {
2558
- return isSnapshotMetaDD31(commit.meta);
2559
- }
2560
- function commitIsSnapshotSDD(commit) {
2561
- return isSnapshotMetaSDD(commit.meta);
2329
+ return commitIsLocalDD31(commit);
2562
2330
  }
2563
2331
  function commitIsSnapshot(commit) {
2564
- return commitIsSnapshotDD31(commit) || commitIsSnapshotSDD(commit);
2332
+ return isSnapshotMetaDD31(commit.meta);
2565
2333
  }
2566
2334
  var Commit = class {
2567
2335
  chunk;
@@ -2586,14 +2354,8 @@ var Commit = class {
2586
2354
  };
2587
2355
  async function getMutationID(clientID, dagRead, meta) {
2588
2356
  switch (meta.type) {
2589
- case IndexChangeSDD:
2590
- return meta.lastMutationID;
2591
- case SnapshotSDD:
2592
- return meta.lastMutationID;
2593
2357
  case SnapshotDD31:
2594
2358
  return meta.lastMutationIDs[clientID] ?? 0;
2595
- case LocalSDD:
2596
- return meta.mutationID;
2597
2359
  case LocalDD31: {
2598
2360
  if (meta.clientID === clientID) {
2599
2361
  return meta.mutationID;
@@ -2666,11 +2428,8 @@ async function baseSnapshotFromCommit(commit, dagRead) {
2666
2428
  }
2667
2429
  function snapshotMetaParts(c, clientID) {
2668
2430
  const m = c.meta;
2669
- if (isSnapshotMetaDD31(m)) {
2670
- const lmid = m.lastMutationIDs[clientID] ?? 0;
2671
- return [lmid, m.cookieJSON];
2672
- }
2673
- return [m.lastMutationID, m.cookieJSON];
2431
+ const lmid = m.lastMutationIDs[clientID] ?? 0;
2432
+ return [lmid, m.cookieJSON];
2674
2433
  }
2675
2434
  function compareCookiesForSnapshots(a, b) {
2676
2435
  return compareCookies(a.meta.cookieJSON, b.meta.cookieJSON);
@@ -2698,48 +2457,32 @@ async function commitFromHead(name, dagRead) {
2698
2457
  const hash2 = await mustGetHeadHash(name, dagRead);
2699
2458
  return commitFromHash(hash2, dagRead);
2700
2459
  }
2701
- function assertIndexChangeMeta(v2) {
2702
- assertNumber(v2.lastMutationID);
2703
- }
2704
- function assertLocalMetaSDD(v2) {
2705
- assertNumber(v2.mutationID);
2706
- assertString(v2.mutatorName);
2707
- if (!v2.mutatorName) {
2460
+ function assertLocalMetaDD31(v) {
2461
+ assertString(v.clientID);
2462
+ assertNumber(v.mutationID);
2463
+ assertString(v.mutatorName);
2464
+ if (!v.mutatorName) {
2708
2465
  throw new Error("Missing mutator name");
2709
2466
  }
2710
- assertJSONValue(v2.mutatorArgsJSON);
2711
- if (v2.originalHash !== null) {
2712
- assertHash(v2.originalHash);
2467
+ assertJSONValue(v.mutatorArgsJSON);
2468
+ if (v.originalHash !== null) {
2469
+ assertHash(v.originalHash);
2713
2470
  }
2714
- assertNumber(v2.timestamp);
2715
- }
2716
- function assertLocalMetaDD31(v2) {
2717
- assertString(v2.clientID);
2718
- assertLocalMetaSDD(v2);
2471
+ assertNumber(v.timestamp);
2719
2472
  }
2720
2473
  function isLocalMetaDD31(meta) {
2721
2474
  return meta.type === LocalDD31;
2722
2475
  }
2723
- function isLocalMetaSDD(meta) {
2724
- return meta.type === LocalSDD;
2725
- }
2726
- function assertSnapshotMetaBase(v2) {
2727
- if (v2.basisHash !== null) {
2728
- assertHash(v2.basisHash);
2476
+ function assertSnapshotMetaDD31(v) {
2477
+ if (v.basisHash !== null) {
2478
+ assertHash(v.basisHash);
2729
2479
  }
2730
- assertJSONValue(v2.cookieJSON);
2480
+ assertJSONValue(v.cookieJSON);
2481
+ assertLastMutationIDs(v.lastMutationIDs);
2731
2482
  }
2732
- function assertSnapshotMetaSDD(v2) {
2733
- assertSnapshotMetaBase(v2);
2734
- assertNumber(v2.lastMutationID);
2735
- }
2736
- function assertSnapshotMetaDD31(v2) {
2737
- assertSnapshotMetaBase(v2);
2738
- assertLastMutationIDs(v2.lastMutationIDs);
2739
- }
2740
- function assertLastMutationIDs(v2) {
2741
- assertObject(v2);
2742
- for (const e of Object.values(v2)) {
2483
+ function assertLastMutationIDs(v) {
2484
+ assertObject(v);
2485
+ for (const e of Object.values(v)) {
2743
2486
  assertNumber(e);
2744
2487
  }
2745
2488
  }
@@ -2749,47 +2492,35 @@ function assertSnapshotCommitDD31(c) {
2749
2492
  function isSnapshotMetaDD31(meta) {
2750
2493
  return meta.type === SnapshotDD31;
2751
2494
  }
2752
- function isSnapshotMetaSDD(meta) {
2753
- return meta.type === SnapshotSDD;
2754
- }
2755
- function assertMeta(v2) {
2756
- assertObject(v2);
2757
- assertDeepFrozen(v2);
2758
- if (v2.basisHash !== null) {
2759
- assertString(v2.basisHash);
2495
+ function assertMeta(v) {
2496
+ assertObject(v);
2497
+ assertDeepFrozen(v);
2498
+ if (v.basisHash !== null) {
2499
+ assertString(v.basisHash);
2760
2500
  }
2761
- assertNumber(v2.type);
2762
- switch (v2.type) {
2763
- case IndexChangeSDD:
2764
- assertIndexChangeMeta(v2);
2765
- break;
2766
- case LocalSDD:
2767
- assertLocalMetaSDD(v2);
2768
- break;
2501
+ assertNumber(v.type);
2502
+ switch (v.type) {
2769
2503
  case LocalDD31:
2770
- assertLocalMetaDD31(v2);
2771
- break;
2772
- case SnapshotSDD:
2773
- assertSnapshotMetaSDD(v2);
2504
+ assertLocalMetaDD31(v);
2774
2505
  break;
2775
2506
  case SnapshotDD31:
2776
- assertSnapshotMetaDD31(v2);
2507
+ assertSnapshotMetaDD31(v);
2777
2508
  break;
2778
2509
  default:
2779
- throw new Error(`Invalid enum value ${v2.type}`);
2510
+ throw new Error(`Invalid enum value ${v.type}`);
2780
2511
  }
2781
2512
  }
2782
2513
  function chunkIndexDefinitionEqualIgnoreName(a, b) {
2783
2514
  return a.jsonPointer === b.jsonPointer && (a.allowEmpty ?? false) === (b.allowEmpty ?? false) && a.keyPrefix === b.keyPrefix;
2784
2515
  }
2785
- function assertChunkIndexDefinition(v2) {
2786
- assertObject(v2);
2787
- assertDeepFrozen(v2);
2788
- assertString(v2.name);
2789
- assertString(v2.keyPrefix);
2790
- assertString(v2.jsonPointer);
2791
- if (v2.allowEmpty !== void 0) {
2792
- assertBoolean(v2.allowEmpty);
2516
+ function assertChunkIndexDefinition(v) {
2517
+ assertObject(v);
2518
+ assertDeepFrozen(v);
2519
+ assertString(v.name);
2520
+ assertString(v.keyPrefix);
2521
+ assertString(v.jsonPointer);
2522
+ if (v.allowEmpty !== void 0) {
2523
+ assertBoolean(v.allowEmpty);
2793
2524
  }
2794
2525
  }
2795
2526
  function toChunkIndexDefinition(name, indexDefinition) {
@@ -2800,34 +2531,19 @@ function toChunkIndexDefinition(name, indexDefinition) {
2800
2531
  allowEmpty: indexDefinition.allowEmpty ?? false
2801
2532
  };
2802
2533
  }
2803
- function assertIndexRecord(v2) {
2804
- assertObject(v2);
2805
- assertDeepFrozen(v2);
2806
- assertChunkIndexDefinition(v2.definition);
2807
- assertString(v2.valueHash);
2534
+ function assertIndexRecord(v) {
2535
+ assertObject(v);
2536
+ assertDeepFrozen(v);
2537
+ assertChunkIndexDefinition(v.definition);
2538
+ assertString(v.valueHash);
2808
2539
  }
2809
- function assertIndexRecords(v2) {
2810
- assertArray(v2);
2811
- assertDeepFrozen(v2);
2812
- for (const ir of v2) {
2540
+ function assertIndexRecords(v) {
2541
+ assertArray(v);
2542
+ assertDeepFrozen(v);
2543
+ for (const ir of v) {
2813
2544
  assertIndexRecord(ir);
2814
2545
  }
2815
2546
  }
2816
- function newLocalSDD(createChunk2, basisHash, mutationID, mutatorName, mutatorArgsJSON, originalHash, valueHash, indexes, timestamp) {
2817
- const meta = {
2818
- type: LocalSDD,
2819
- basisHash,
2820
- mutationID,
2821
- mutatorName,
2822
- mutatorArgsJSON,
2823
- originalHash,
2824
- timestamp
2825
- };
2826
- return commitFromCommitData(
2827
- createChunk2,
2828
- makeCommitData(meta, valueHash, indexes)
2829
- );
2830
- }
2831
2547
  function newLocalDD31(createChunk2, basisHash, baseSnapshotHash, mutationID, mutatorName, mutatorArgsJSON, originalHash, valueHash, indexes, timestamp, clientID) {
2832
2548
  const meta = {
2833
2549
  type: LocalDD31,
@@ -2845,18 +2561,6 @@ function newLocalDD31(createChunk2, basisHash, baseSnapshotHash, mutationID, mut
2845
2561
  makeCommitData(meta, valueHash, indexes)
2846
2562
  );
2847
2563
  }
2848
- function newSnapshotSDD(createChunk2, basisHash, lastMutationID, cookieJSON, valueHash, indexes) {
2849
- return commitFromCommitData(
2850
- createChunk2,
2851
- newSnapshotCommitDataSDD(
2852
- basisHash,
2853
- lastMutationID,
2854
- cookieJSON,
2855
- valueHash,
2856
- indexes
2857
- )
2858
- );
2859
- }
2860
2564
  function newSnapshotDD31(createChunk2, basisHash, lastMutationIDs, cookieJSON, valueHash, indexes) {
2861
2565
  return commitFromCommitData(
2862
2566
  createChunk2,
@@ -2869,15 +2573,6 @@ function newSnapshotDD31(createChunk2, basisHash, lastMutationIDs, cookieJSON, v
2869
2573
  )
2870
2574
  );
2871
2575
  }
2872
- function newSnapshotCommitDataSDD(basisHash, lastMutationID, cookieJSON, valueHash, indexes) {
2873
- const meta = {
2874
- type: SnapshotSDD,
2875
- basisHash,
2876
- lastMutationID,
2877
- cookieJSON
2878
- };
2879
- return makeCommitData(meta, valueHash, indexes);
2880
- }
2881
2576
  function newSnapshotCommitDataDD31(basisHash, lastMutationIDs, cookieJSON, valueHash, indexes) {
2882
2577
  const meta = {
2883
2578
  type: SnapshotDD31,
@@ -2887,17 +2582,6 @@ function newSnapshotCommitDataDD31(basisHash, lastMutationIDs, cookieJSON, value
2887
2582
  };
2888
2583
  return makeCommitData(meta, valueHash, indexes);
2889
2584
  }
2890
- function newIndexChange(createChunk2, basisHash, lastMutationID, valueHash, indexes) {
2891
- const meta = {
2892
- type: IndexChangeSDD,
2893
- basisHash,
2894
- lastMutationID
2895
- };
2896
- return commitFromCommitData(
2897
- createChunk2,
2898
- makeCommitData(meta, valueHash, indexes)
2899
- );
2900
- }
2901
2585
  function fromChunk(chunk) {
2902
2586
  validateChunk(chunk);
2903
2587
  return new Commit(chunk);
@@ -2910,14 +2594,9 @@ function getRefs(data) {
2910
2594
  refs.add(data.valueHash);
2911
2595
  const { meta } = data;
2912
2596
  switch (meta.type) {
2913
- case IndexChangeSDD:
2914
- meta.basisHash && refs.add(meta.basisHash);
2915
- break;
2916
- case LocalSDD:
2917
2597
  case LocalDD31:
2918
2598
  meta.basisHash && refs.add(meta.basisHash);
2919
2599
  break;
2920
- case SnapshotSDD:
2921
2600
  case SnapshotDD31:
2922
2601
  break;
2923
2602
  default:
@@ -2935,15 +2614,15 @@ function makeCommitData(meta, valueHash, indexes) {
2935
2614
  indexes
2936
2615
  });
2937
2616
  }
2938
- function assertCommitData(v2) {
2617
+ function assertCommitData(v) {
2939
2618
  if (isProd) {
2940
2619
  return;
2941
2620
  }
2942
- assertObject(v2);
2943
- assertDeepFrozen(v2);
2944
- assertMeta(v2.meta);
2945
- assertString(v2.valueHash);
2946
- assertIndexRecords(v2.indexes);
2621
+ assertObject(v);
2622
+ assertDeepFrozen(v);
2623
+ assertMeta(v.meta);
2624
+ assertString(v.valueHash);
2625
+ assertIndexRecords(v.indexes);
2947
2626
  }
2948
2627
  function validateChunk(chunk) {
2949
2628
  const { data } = chunk;
@@ -3013,14 +2692,14 @@ function binarySearch2(key, entries) {
3013
2692
  function binarySearchFound(i, entries, key) {
3014
2693
  return i !== entries.length && entries[i][0] === key;
3015
2694
  }
3016
- function parseBTreeNode(v2, formatVersion, getSizeOfEntry2) {
2695
+ function parseBTreeNode(v, formatVersion, getSizeOfEntry2) {
3017
2696
  if (isProd && formatVersion >= V7) {
3018
- return v2;
2697
+ return v;
3019
2698
  }
3020
- assertArray(v2);
3021
- assertDeepFrozen(v2);
3022
- assert(v2.length >= 2);
3023
- const [level, entries] = v2;
2699
+ assertArray(v);
2700
+ assertDeepFrozen(v);
2701
+ assert(v.length >= 2);
2702
+ const [level, entries] = v;
3024
2703
  assertNumber(level);
3025
2704
  assertArray(entries);
3026
2705
  const f = level > 0 ? assertString : assertJSONValue;
@@ -3028,7 +2707,7 @@ function parseBTreeNode(v2, formatVersion, getSizeOfEntry2) {
3028
2707
  for (const e of entries) {
3029
2708
  assertEntry(e, f);
3030
2709
  }
3031
- return v2;
2710
+ return v;
3032
2711
  }
3033
2712
  const newEntries = entries.map((e) => convertNonV7Entry(e, f, getSizeOfEntry2));
3034
2713
  return [level, newEntries];
@@ -3122,13 +2801,13 @@ var DataNodeImpl = class extends NodeImpl {
3122
2801
  }
3123
2802
  }
3124
2803
  };
3125
- function readonlySplice(array10, start, deleteCount, ...items) {
3126
- const arr = array10.slice(0, start);
2804
+ function readonlySplice(array9, start, deleteCount, ...items) {
2805
+ const arr = array9.slice(0, start);
3127
2806
  for (let i = 0; i < items.length; i++) {
3128
2807
  arr.push(items[i]);
3129
2808
  }
3130
- for (let i = start + deleteCount; i < array10.length; i++) {
3131
- arr.push(array10[i]);
2809
+ for (let i = start + deleteCount; i < array9.length; i++) {
2810
+ arr.push(array9[i]);
3132
2811
  }
3133
2812
  return arr;
3134
2813
  }
@@ -3880,8 +3559,8 @@ import { greaterThan } from "compare-utf8";
3880
3559
  // ../replicache/src/async-iterable-to-array.ts
3881
3560
  async function asyncIterableToArray(it) {
3882
3561
  const arr = [];
3883
- for await (const v2 of it) {
3884
- arr.push(v2);
3562
+ for await (const v of it) {
3563
+ arr.push(v);
3885
3564
  }
3886
3565
  return arr;
3887
3566
  }
@@ -4452,9 +4131,6 @@ var Write = class extends Read {
4452
4131
  * comparison as well as returned in `get`.
4453
4132
  */
4454
4133
  async put(lc, key, value) {
4455
- if (this.#meta.type === IndexChangeSDD) {
4456
- throw new Error("Not allowed");
4457
- }
4458
4134
  const oldVal = lazy(() => this.map.get(key));
4459
4135
  await updateIndexes(lc, this.indexes, key, oldVal, value);
4460
4136
  await this.map.put(key, value);
@@ -4463,9 +4139,6 @@ var Write = class extends Read {
4463
4139
  return getMutationID(this.#clientID, this.#dagWrite, this.#meta);
4464
4140
  }
4465
4141
  async del(lc, key) {
4466
- if (this.#meta.type === IndexChangeSDD) {
4467
- throw new Error("Not allowed");
4468
- }
4469
4142
  const oldVal = lazy(() => this.map.get(key));
4470
4143
  if (oldVal !== void 0) {
4471
4144
  await updateIndexes(lc, this.indexes, key, oldVal, void 0);
@@ -4473,9 +4146,6 @@ var Write = class extends Read {
4473
4146
  return this.map.del(key);
4474
4147
  }
4475
4148
  async clear() {
4476
- if (this.#meta.type === IndexChangeSDD) {
4477
- throw new Error("Not allowed");
4478
- }
4479
4149
  await this.map.clear();
4480
4150
  const ps = [];
4481
4151
  for (const idx of this.indexes.values()) {
@@ -4497,28 +4167,6 @@ var Write = class extends Read {
4497
4167
  let commit;
4498
4168
  const meta = this.#meta;
4499
4169
  switch (meta.type) {
4500
- case LocalSDD: {
4501
- const {
4502
- basisHash,
4503
- mutationID,
4504
- mutatorName,
4505
- mutatorArgsJSON,
4506
- originalHash,
4507
- timestamp
4508
- } = meta;
4509
- commit = newLocalSDD(
4510
- this.#dagWrite.createChunk,
4511
- basisHash,
4512
- mutationID,
4513
- mutatorName,
4514
- mutatorArgsJSON,
4515
- originalHash,
4516
- valueHash,
4517
- indexRecords,
4518
- timestamp
4519
- );
4520
- break;
4521
- }
4522
4170
  case LocalDD31: {
4523
4171
  assert(this.#formatVersion >= DD31);
4524
4172
  const {
@@ -4544,19 +4192,6 @@ var Write = class extends Read {
4544
4192
  );
4545
4193
  break;
4546
4194
  }
4547
- case SnapshotSDD: {
4548
- assert(this.#formatVersion <= SDD);
4549
- const { basisHash, lastMutationID, cookieJSON } = meta;
4550
- commit = newSnapshotSDD(
4551
- this.#dagWrite.createChunk,
4552
- basisHash,
4553
- lastMutationID,
4554
- cookieJSON,
4555
- valueHash,
4556
- indexRecords
4557
- );
4558
- break;
4559
- }
4560
4195
  case SnapshotDD31: {
4561
4196
  assert(this.#formatVersion > DD31);
4562
4197
  const { basisHash, lastMutationIDs, cookieJSON } = meta;
@@ -4570,28 +4205,6 @@ var Write = class extends Read {
4570
4205
  );
4571
4206
  break;
4572
4207
  }
4573
- case IndexChangeSDD: {
4574
- const { basisHash, lastMutationID } = meta;
4575
- if (this.#basis !== void 0) {
4576
- if (await this.#basis.getMutationID(
4577
- this.#clientID,
4578
- this.#dagWrite
4579
- ) !== lastMutationID) {
4580
- throw new Error("Index change must not change mutationID");
4581
- }
4582
- if (this.#basis.valueHash !== valueHash) {
4583
- throw new Error("Index change must not change valueHash");
4584
- }
4585
- }
4586
- commit = newIndexChange(
4587
- this.#dagWrite.createChunk,
4588
- basisHash,
4589
- lastMutationID,
4590
- valueHash,
4591
- indexRecords
4592
- );
4593
- break;
4594
- }
4595
4208
  }
4596
4209
  await this.#dagWrite.putChunk(commit.chunk);
4597
4210
  return commit;
@@ -4666,11 +4279,12 @@ async function newWriteLocal(basisHash, mutatorName, mutatorArgsJSON, originalHa
4666
4279
  const bTreeWrite = new BTreeWrite(dagWrite, formatVersion, basis.valueHash);
4667
4280
  const mutationID = await basis.getNextMutationID(clientID, dagWrite);
4668
4281
  const indexes = readIndexesForWrite(basis, dagWrite, formatVersion);
4282
+ assert(formatVersion >= DD31);
4669
4283
  return new Write(
4670
4284
  dagWrite,
4671
4285
  bTreeWrite,
4672
4286
  basis,
4673
- formatVersion >= DD31 ? {
4287
+ {
4674
4288
  type: LocalDD31,
4675
4289
  basisHash,
4676
4290
  baseSnapshotHash: await baseSnapshotHashFromHash(basisHash, dagWrite),
@@ -4680,34 +4294,12 @@ async function newWriteLocal(basisHash, mutatorName, mutatorArgsJSON, originalHa
4680
4294
  originalHash,
4681
4295
  timestamp,
4682
4296
  clientID
4683
- } : {
4684
- type: LocalSDD,
4685
- basisHash,
4686
- mutatorName,
4687
- mutatorArgsJSON,
4688
- mutationID,
4689
- originalHash,
4690
- timestamp
4691
4297
  },
4692
4298
  indexes,
4693
4299
  clientID,
4694
4300
  formatVersion
4695
4301
  );
4696
4302
  }
4697
- async function newWriteSnapshotSDD(basisHash, lastMutationID, cookieJSON, dagWrite, indexes, clientID, formatVersion) {
4698
- assert(formatVersion <= SDD);
4699
- const basis = await commitFromHash(basisHash, dagWrite);
4700
- const bTreeWrite = new BTreeWrite(dagWrite, formatVersion, basis.valueHash);
4701
- return new Write(
4702
- dagWrite,
4703
- bTreeWrite,
4704
- basis,
4705
- { basisHash, type: SnapshotSDD, lastMutationID, cookieJSON },
4706
- indexes,
4707
- clientID,
4708
- formatVersion
4709
- );
4710
- }
4711
4303
  async function newWriteSnapshotDD31(basisHash, lastMutationIDs, cookieJSON, dagWrite, clientID, formatVersion) {
4712
4304
  const basis = await commitFromHash(basisHash, dagWrite);
4713
4305
  const bTreeWrite = new BTreeWrite(dagWrite, formatVersion, basis.valueHash);
@@ -4911,11 +4503,11 @@ function createLogContext(logLevel = "info", logSinks = [consoleLogSink], contex
4911
4503
  }
4912
4504
 
4913
4505
  // ../replicache/src/format-version.ts
4914
- function parseReplicacheFormatVersion(v2) {
4915
- if (v2 !== (v2 | 0) || v2 < SDD || v2 > Latest) {
4916
- throw new Error(`Unsupported format version: ${v2}`);
4506
+ function parseReplicacheFormatVersion(v) {
4507
+ if (v !== (v | 0) || v < SDD || v > Latest) {
4508
+ throw new Error(`Unsupported format version: ${v}`);
4917
4509
  }
4918
- return v2;
4510
+ return v;
4919
4511
  }
4920
4512
 
4921
4513
  // ../replicache/src/index-defs.ts
@@ -5111,9 +4703,13 @@ async function disableClientGroup(clientGroupID, dagWrite) {
5111
4703
  await setClientGroup(clientGroupID, disabledClientGroup, dagWrite);
5112
4704
  }
5113
4705
 
5114
- // ../replicache/src/sync/ids.ts
5115
- var clientGroupIDSchema = valita_exports.string();
5116
- var clientIDSchema = valita_exports.string();
4706
+ // ../replicache/src/to-error.ts
4707
+ function toError(e) {
4708
+ if (e instanceof Error) {
4709
+ return e;
4710
+ }
4711
+ return new Error(String(e));
4712
+ }
5117
4713
 
5118
4714
  // ../replicache/src/with-transactions.ts
5119
4715
  function withRead(store, fn) {
@@ -5138,1763 +4734,1339 @@ async function using(x, fn) {
5138
4734
  }
5139
4735
  }
5140
4736
 
5141
- // ../replicache/src/persist/make-client-id.ts
5142
- function makeClientID() {
5143
- const length = 18;
5144
- const high = randomUint64();
5145
- const low = randomUint64();
5146
- const combined = high << 64n | low;
5147
- return combined.toString(32).slice(-length).padStart(length, "0");
5148
- }
4737
+ // ../replicache/src/sync/handle-pull-response-result-type-enum.ts
4738
+ var Applied = 0;
4739
+ var NoOp = 1;
4740
+ var CookieMismatch = 2;
5149
4741
 
5150
- // ../replicache/src/persist/clients.ts
5151
- var clientV4Schema = readonlyObject({
5152
- /**
5153
- * A UNIX timestamp in milliseconds updated by the client once a minute
5154
- * while it is active and every time the client persists its state to
5155
- * the perdag.
5156
- * Should only be updated by the client represented by this structure.
5157
- */
5158
- heartbeatTimestampMs: valita_exports.number(),
5159
- /**
5160
- * The hash of the commit in the perdag this client last persisted.
5161
- * Should only be updated by the client represented by this structure.
5162
- */
5163
- headHash: hashSchema,
5164
- /**
5165
- * The mutationID of the commit at headHash (mutationID if it is a
5166
- * local commit, lastMutationID if it is an index change or snapshot commit).
5167
- * Should only be updated by the client represented by this structure.
5168
- * Read by other clients to determine if there are unacknowledged pending
5169
- * mutations for them to push on behalf of the client represented by this
5170
- * structure.
5171
- * This is redundant with information in the commit graph at headHash,
5172
- * but allows other clients to determine if there are unacknowledged pending
5173
- * mutations without having to load the commit graph at headHash.
5174
- */
5175
- mutationID: valita_exports.number(),
5176
- /**
5177
- * The highest lastMutationID received from the server for this client.
5178
- *
5179
- * Should be updated by the client represented by this structure whenever
5180
- * it persists its state to the perdag.
5181
- * Read by other clients to determine if there are unacknowledged pending
5182
- * mutations for them to push on behalf of the client represented by this
5183
- * structure, and *updated* by other clients upon successfully pushing
5184
- * pending mutations to avoid redundant pushes of those mutations.
5185
- *
5186
- * Note: This will be the same as the lastMutationID of the base snapshot of
5187
- * the commit graph at headHash when written by the client represented by this
5188
- * structure. However, when written by another client pushing pending
5189
- * mutations on this client's behalf it will be different. This is because
5190
- * the other client does not update the commit graph (it is unsafe to update
5191
- * another client's commit graph).
5192
- */
5193
- lastServerAckdMutationID: valita_exports.number()
5194
- });
5195
- var clientV5Schema = readonlyObject({
5196
- heartbeatTimestampMs: valita_exports.number(),
5197
- headHash: hashSchema,
5198
- /**
5199
- * The hash of a commit we are in the middle of refreshing into this client's
5200
- * memdag.
5201
- */
5202
- tempRefreshHash: hashSchema.nullable(),
5203
- /**
5204
- * ID of this client's perdag client group. This needs to be sent in pull
5205
- * request (to enable syncing all last mutation ids in the client group).
5206
- */
5207
- clientGroupID: clientGroupIDSchema
5208
- });
5209
- var clientV6Schema = readonlyObject({
5210
- heartbeatTimestampMs: valita_exports.number(),
5211
- /**
5212
- * A set of hashes, which contains:
5213
- * 1. The hash of the last commit this client refreshed from its client group
5214
- * (this is the commit it bootstrapped from until it completes its first
5215
- * refresh).
5216
- * 2. One or more hashes that were added to retain chunks of a commit while it
5217
- * was being refreshed into this client's memdag. (This can be one or more
5218
- * because refresh's cleanup step is a separate transaction and can fail).
5219
- * Upon refresh completing and successfully running its clean up step, this
5220
- * set will contain a single hash: the hash of the last commit this client
5221
- * refreshed.
5222
- */
5223
- refreshHashes: readonlyArray(hashSchema),
5224
- /**
5225
- * The hash of the last snapshot commit persisted by this client to this
5226
- * client's client group, or null if has never persisted a snapshot.
5227
- */
5228
- persistHash: hashSchema.nullable(),
5229
- /**
5230
- * ID of this client's perdag client group. This needs to be sent in pull
5231
- * request (to enable syncing all last mutation ids in the client group).
5232
- */
5233
- clientGroupID: clientGroupIDSchema
5234
- });
5235
- function isClientV6(client) {
5236
- return client.refreshHashes !== void 0;
5237
- }
5238
- function isClientV5(client) {
5239
- return client.clientGroupID !== void 0;
5240
- }
5241
- var CLIENTS_HEAD_NAME = "clients";
5242
- var clientSchema = valita_exports.union(
5243
- clientV4Schema,
5244
- clientV5Schema,
5245
- clientV6Schema
5246
- );
5247
- function assertClient(value) {
5248
- assert2(value, clientSchema);
5249
- }
5250
- function assertClientV4(value) {
5251
- assert2(value, clientV4Schema);
5252
- }
5253
- function assertClientV6(value) {
5254
- assert2(value, clientV6Schema);
5255
- }
5256
- function chunkDataToClientMap(chunkData) {
5257
- assertObject(chunkData);
5258
- const clients = /* @__PURE__ */ new Map();
5259
- for (const key in chunkData) {
5260
- if (hasOwn(chunkData, key)) {
5261
- const value = chunkData[key];
5262
- if (value !== void 0) {
5263
- assertClient(value);
5264
- clients.set(key, value);
5265
- }
5266
- }
5267
- }
5268
- return clients;
5269
- }
5270
- function clientMapToChunkData(clients, dagWrite) {
5271
- for (const client of clients.values()) {
5272
- if (isClientV6(client)) {
5273
- client.refreshHashes.forEach(dagWrite.assertValidHash);
5274
- if (client.persistHash) {
5275
- dagWrite.assertValidHash(client.persistHash);
4742
+ // ../replicache/src/sync/patch.ts
4743
+ async function apply(lc, dbWrite, patch) {
4744
+ for (const p of patch) {
4745
+ switch (p.op) {
4746
+ case "put": {
4747
+ await dbWrite.put(lc, p.key, deepFreeze(p.value));
4748
+ break;
5276
4749
  }
5277
- } else {
5278
- dagWrite.assertValidHash(client.headHash);
5279
- if (isClientV5(client) && client.tempRefreshHash) {
5280
- dagWrite.assertValidHash(client.tempRefreshHash);
4750
+ case "update": {
4751
+ const existing = await dbWrite.get(p.key);
4752
+ const entries = [];
4753
+ const addToEntries = (toAdd) => {
4754
+ for (const [key, value] of Object.entries(toAdd)) {
4755
+ if (!p.constrain || p.constrain.length === 0 || p.constrain.indexOf(key) > -1) {
4756
+ entries.push([key, value]);
4757
+ }
4758
+ }
4759
+ };
4760
+ if (existing !== void 0) {
4761
+ assertObject(existing);
4762
+ addToEntries(existing);
4763
+ }
4764
+ if (p.merge) {
4765
+ addToEntries(p.merge);
4766
+ }
4767
+ await dbWrite.put(lc, p.key, deepFreeze(Object.fromEntries(entries)));
4768
+ break;
5281
4769
  }
4770
+ case "del":
4771
+ await dbWrite.del(lc, p.key);
4772
+ break;
4773
+ case "clear":
4774
+ await dbWrite.clear();
4775
+ break;
5282
4776
  }
5283
4777
  }
5284
- return deepFreeze(Object.fromEntries(clients));
5285
- }
5286
- async function getClients(dagRead) {
5287
- const hash2 = await dagRead.getHead(CLIENTS_HEAD_NAME);
5288
- return getClientsAtHash(hash2, dagRead);
5289
- }
5290
- async function getClientsAtHash(hash2, dagRead) {
5291
- if (!hash2) {
5292
- return /* @__PURE__ */ new Map();
5293
- }
5294
- const chunk = await dagRead.getChunk(hash2);
5295
- return chunkDataToClientMap(chunk?.data);
5296
4778
  }
5297
- var ClientStateNotFoundError = class extends Error {
5298
- name = "ClientStateNotFoundError";
5299
- id;
5300
- constructor(id) {
5301
- super(`Client state not found, id: ${id}`);
5302
- this.id = id;
4779
+
4780
+ // ../replicache/src/sync/pull-error.ts
4781
+ var PullError = class extends Error {
4782
+ name = "PullError";
4783
+ // causedBy is used instead of cause, because while cause has been proposed as a
4784
+ // JavaScript language standard for this purpose (see
4785
+ // https://github.com/tc39/proposal-error-cause) current browser behavior is
4786
+ // inconsistent.
4787
+ causedBy;
4788
+ constructor(causedBy) {
4789
+ super("Failed to pull");
4790
+ this.causedBy = causedBy;
5303
4791
  }
5304
4792
  };
5305
- async function assertHasClientState(id, dagRead) {
5306
- if (!await hasClientState(id, dagRead)) {
5307
- throw new ClientStateNotFoundError(id);
4793
+
4794
+ // ../replicache/src/sync/sync-head-name.ts
4795
+ var SYNC_HEAD_NAME = "sync";
4796
+
4797
+ // ../replicache/src/sync/pull.ts
4798
+ var PULL_VERSION_DD31 = 1;
4799
+ async function beginPullV1(profileID, clientID, clientGroupID, schemaVersion, puller, requestID, store, formatVersion, lc, createSyncBranch = true) {
4800
+ const baseCookie = await withRead(store, async (dagRead) => {
4801
+ const mainHeadHash = await dagRead.getHead(DEFAULT_HEAD_NAME);
4802
+ if (!mainHeadHash) {
4803
+ throw new Error("Internal no main head found");
4804
+ }
4805
+ const baseSnapshot = await baseSnapshotFromHash(mainHeadHash, dagRead);
4806
+ const baseSnapshotMeta = baseSnapshot.meta;
4807
+ assertSnapshotMetaDD31(baseSnapshotMeta);
4808
+ return baseSnapshotMeta.cookieJSON;
4809
+ });
4810
+ const pullReq = {
4811
+ profileID,
4812
+ clientGroupID,
4813
+ cookie: baseCookie,
4814
+ pullVersion: PULL_VERSION_DD31,
4815
+ schemaVersion
4816
+ };
4817
+ const { response, httpRequestInfo } = await callPuller(
4818
+ lc,
4819
+ puller,
4820
+ pullReq,
4821
+ requestID
4822
+ );
4823
+ if (!response) {
4824
+ return {
4825
+ httpRequestInfo,
4826
+ syncHead: emptyHash
4827
+ };
5308
4828
  }
5309
- }
5310
- async function hasClientState(id, dagRead) {
5311
- return !!await getClient(id, dagRead);
5312
- }
5313
- async function getClient(id, dagRead) {
5314
- const clients = await getClients(dagRead);
5315
- return clients.get(id);
5316
- }
5317
- async function mustGetClient(id, dagRead) {
5318
- const client = await getClient(id, dagRead);
5319
- if (!client) {
5320
- throw new ClientStateNotFoundError(id);
4829
+ if (!createSyncBranch || isErrorResponse(response)) {
4830
+ return {
4831
+ httpRequestInfo,
4832
+ pullResponse: response,
4833
+ syncHead: emptyHash
4834
+ };
5321
4835
  }
5322
- return client;
5323
- }
5324
- function initClientV6(newClientID, lc, perdag, mutatorNames, indexes, formatVersion, enableClientGroupForking) {
5325
- return withWriteNoImplicitCommit(perdag, async (dagWrite) => {
5326
- async function setClientsAndClientGroupAndCommit(basisHash, cookieJSON, valueHash2, indexRecords2) {
5327
- const newSnapshotData = newSnapshotCommitDataDD31(
5328
- basisHash,
5329
- {},
5330
- cookieJSON,
5331
- valueHash2,
5332
- indexRecords2
5333
- );
5334
- const chunk = dagWrite.createChunk(
5335
- newSnapshotData,
5336
- getRefs(newSnapshotData)
5337
- );
5338
- const newClientGroupID = makeClientID();
5339
- const newClient = {
5340
- heartbeatTimestampMs: Date.now(),
5341
- refreshHashes: [chunk.hash],
5342
- persistHash: null,
5343
- clientGroupID: newClientGroupID
5344
- };
5345
- const newClients = new Map(clients).set(newClientID, newClient);
5346
- const clientGroup = {
5347
- headHash: chunk.hash,
5348
- mutatorNames,
5349
- indexes,
5350
- mutationIDs: {},
5351
- lastServerAckdMutationIDs: {},
5352
- disabled: false
5353
- };
5354
- await Promise.all([
5355
- dagWrite.putChunk(chunk),
5356
- setClients(newClients, dagWrite),
5357
- setClientGroup(newClientGroupID, clientGroup, dagWrite)
5358
- ]);
5359
- await dagWrite.commit();
5360
- return [newClient, chunk.hash, newClients, true];
4836
+ const result = await handlePullResponseV1(
4837
+ lc,
4838
+ store,
4839
+ baseCookie,
4840
+ response,
4841
+ clientID,
4842
+ formatVersion
4843
+ );
4844
+ return {
4845
+ httpRequestInfo,
4846
+ pullResponse: response,
4847
+ syncHead: result.type === Applied ? result.syncHead : emptyHash
4848
+ };
4849
+ }
4850
+ async function callPuller(lc, puller, pullReq, requestID) {
4851
+ lc.debug?.("Starting pull...");
4852
+ const pullStart = Date.now();
4853
+ let pullerResult;
4854
+ try {
4855
+ pullerResult = await puller(pullReq, requestID);
4856
+ lc.debug?.(
4857
+ `...Pull ${pullerResult.response ? "complete" : "failed"} in `,
4858
+ Date.now() - pullStart,
4859
+ "ms"
4860
+ );
4861
+ } catch (e) {
4862
+ throw new PullError(toError(e));
4863
+ }
4864
+ try {
4865
+ assertPullerResultV1(pullerResult);
4866
+ return pullerResult;
4867
+ } catch (e) {
4868
+ throw new ReportError("Invalid puller result", toError(e));
4869
+ }
4870
+ }
4871
+ function badOrderMessage(name, receivedValue, lastSnapshotValue) {
4872
+ return `Received ${name} ${receivedValue} is < than last snapshot ${name} ${lastSnapshotValue}; ignoring client view`;
4873
+ }
4874
+ function handlePullResponseV1(lc, store, expectedBaseCookie, response, clientID, formatVersion) {
4875
+ return withWriteNoImplicitCommit(store, async (dagWrite) => {
4876
+ const dagRead = dagWrite;
4877
+ const mainHead = await dagRead.getHead(DEFAULT_HEAD_NAME);
4878
+ if (mainHead === void 0) {
4879
+ throw new Error("Main head disappeared");
5361
4880
  }
5362
- const clients = await getClients(dagWrite);
5363
- const res = await findMatchingClient(dagWrite, mutatorNames, indexes);
5364
- if (res.type === FIND_MATCHING_CLIENT_TYPE_HEAD) {
5365
- const { clientGroupID, headHash } = res;
5366
- const newClient = {
5367
- clientGroupID,
5368
- refreshHashes: [headHash],
5369
- heartbeatTimestampMs: Date.now(),
5370
- persistHash: null
4881
+ const baseSnapshot = await baseSnapshotFromHash(mainHead, dagRead);
4882
+ const baseSnapshotMeta = baseSnapshot.meta;
4883
+ assertSnapshotMetaDD31(baseSnapshotMeta);
4884
+ const baseCookie = baseSnapshotMeta.cookieJSON;
4885
+ if (!deepEqual(expectedBaseCookie, baseCookie)) {
4886
+ lc.debug?.(
4887
+ "handlePullResponse: cookie mismatch, response is not applicable"
4888
+ );
4889
+ return {
4890
+ type: CookieMismatch
5371
4891
  };
5372
- const newClients = new Map(clients).set(newClientID, newClient);
5373
- await setClients(newClients, dagWrite);
5374
- await dagWrite.commit();
5375
- return [newClient, headHash, newClients, false];
5376
4892
  }
5377
- if (!enableClientGroupForking || res.type === FIND_MATCHING_CLIENT_TYPE_NEW) {
5378
- const emptyBTreeChunk = dagWrite.createChunk(emptyDataNode, []);
5379
- await dagWrite.putChunk(emptyBTreeChunk);
5380
- const indexRecords2 = [];
5381
- for (const [name, indexDefinition] of Object.entries(indexes)) {
5382
- const chunkIndexDefinition = toChunkIndexDefinition(
5383
- name,
5384
- indexDefinition
4893
+ for (const [clientID2, lmidChange] of Object.entries(
4894
+ response.lastMutationIDChanges
4895
+ )) {
4896
+ const lastMutationID = baseSnapshotMeta.lastMutationIDs[clientID2];
4897
+ if (lastMutationID !== void 0 && lmidChange < lastMutationID) {
4898
+ throw new Error(
4899
+ badOrderMessage(
4900
+ `${clientID2} lastMutationID`,
4901
+ String(lmidChange),
4902
+ String(lastMutationID)
4903
+ )
5385
4904
  );
5386
- indexRecords2.push({
5387
- definition: chunkIndexDefinition,
5388
- valueHash: emptyBTreeChunk.hash
5389
- });
5390
4905
  }
5391
- return setClientsAndClientGroupAndCommit(
5392
- null,
5393
- null,
5394
- emptyBTreeChunk.hash,
5395
- indexRecords2
4906
+ }
4907
+ const frozenResponseCookie = deepFreeze(response.cookie);
4908
+ if (compareCookies(frozenResponseCookie, baseCookie) < 0) {
4909
+ throw new Error(
4910
+ badOrderMessage(
4911
+ "cookie",
4912
+ JSON.stringify(frozenResponseCookie),
4913
+ JSON.stringify(baseCookie)
4914
+ )
5396
4915
  );
5397
4916
  }
5398
- assert(res.type === FIND_MATCHING_CLIENT_TYPE_FORK);
5399
- const { snapshot } = res;
5400
- const indexRecords = [];
5401
- const { valueHash, indexes: oldIndexes } = snapshot;
5402
- const map = new BTreeRead(dagWrite, formatVersion, valueHash);
5403
- for (const [name, indexDefinition] of Object.entries(indexes)) {
5404
- const { prefix = "", jsonPointer, allowEmpty = false } = indexDefinition;
5405
- const chunkIndexDefinition = {
5406
- name,
5407
- keyPrefix: prefix,
5408
- jsonPointer,
5409
- allowEmpty
5410
- };
5411
- const oldIndex = findMatchingOldIndex(oldIndexes, chunkIndexDefinition);
5412
- if (oldIndex) {
5413
- indexRecords.push({
5414
- definition: chunkIndexDefinition,
5415
- valueHash: oldIndex.valueHash
5416
- });
5417
- } else {
5418
- const indexBTree = await createIndexBTree(
5419
- lc,
5420
- dagWrite,
5421
- map,
5422
- prefix,
5423
- jsonPointer,
5424
- allowEmpty,
5425
- formatVersion
4917
+ if (deepEqual(frozenResponseCookie, baseCookie)) {
4918
+ if (response.patch.length > 0) {
4919
+ lc.error?.(
4920
+ `handlePullResponse: cookie ${JSON.stringify(
4921
+ baseCookie
4922
+ )} did not change, but patch is not empty`
4923
+ );
4924
+ }
4925
+ if (Object.keys(response.lastMutationIDChanges).length > 0) {
4926
+ console.log(response.lastMutationIDChanges);
4927
+ lc.error?.(
4928
+ `handlePullResponse: cookie ${JSON.stringify(
4929
+ baseCookie
4930
+ )} did not change, but lastMutationIDChanges is not empty`
5426
4931
  );
5427
- indexRecords.push({
5428
- definition: chunkIndexDefinition,
5429
- valueHash: await indexBTree.flush()
5430
- });
5431
4932
  }
5432
- }
5433
- return setClientsAndClientGroupAndCommit(
5434
- snapshot.meta.basisHash,
5435
- snapshot.meta.cookieJSON,
5436
- snapshot.valueHash,
5437
- indexRecords
5438
- );
5439
- });
5440
- }
5441
- function findMatchingOldIndex(oldIndexes, chunkIndexDefinition) {
5442
- return oldIndexes.find(
5443
- (index) => chunkIndexDefinitionEqualIgnoreName(index.definition, chunkIndexDefinition)
5444
- );
5445
- }
5446
- var FIND_MATCHING_CLIENT_TYPE_NEW = 0;
5447
- var FIND_MATCHING_CLIENT_TYPE_FORK = 1;
5448
- var FIND_MATCHING_CLIENT_TYPE_HEAD = 2;
5449
- async function findMatchingClient(dagRead, mutatorNames, indexes) {
5450
- let newestCookie;
5451
- let bestSnapshot;
5452
- const mutatorNamesSet = new Set(mutatorNames);
5453
- const clientGroups = await getClientGroups(dagRead);
5454
- for (const [clientGroupID, clientGroup] of clientGroups) {
5455
- if (!clientGroup.disabled && mutatorNamesEqual(mutatorNamesSet, clientGroup.mutatorNames) && indexDefinitionsEqual(indexes, clientGroup.indexes)) {
5456
4933
  return {
5457
- type: FIND_MATCHING_CLIENT_TYPE_HEAD,
5458
- clientGroupID,
5459
- headHash: clientGroup.headHash
4934
+ type: NoOp
5460
4935
  };
5461
4936
  }
5462
- const clientGroupSnapshotCommit = await baseSnapshotFromHash(
5463
- clientGroup.headHash,
5464
- dagRead
4937
+ const dbWrite = await newWriteSnapshotDD31(
4938
+ baseSnapshot.chunk.hash,
4939
+ { ...baseSnapshotMeta.lastMutationIDs, ...response.lastMutationIDChanges },
4940
+ frozenResponseCookie,
4941
+ dagWrite,
4942
+ clientID,
4943
+ formatVersion
5465
4944
  );
5466
- assertSnapshotCommitDD31(clientGroupSnapshotCommit);
5467
- const { cookieJSON } = clientGroupSnapshotCommit.meta;
5468
- if (newestCookie === void 0 || compareCookies(cookieJSON, newestCookie) > 0) {
5469
- newestCookie = cookieJSON;
5470
- bestSnapshot = clientGroupSnapshotCommit;
5471
- }
5472
- }
5473
- if (bestSnapshot) {
4945
+ await apply(lc, dbWrite, response.patch);
5474
4946
  return {
5475
- type: FIND_MATCHING_CLIENT_TYPE_FORK,
5476
- snapshot: bestSnapshot
4947
+ type: Applied,
4948
+ syncHead: await dbWrite.commit(SYNC_HEAD_NAME)
5477
4949
  };
5478
- }
5479
- return { type: FIND_MATCHING_CLIENT_TYPE_NEW };
4950
+ });
5480
4951
  }
5481
- function getRefsForClients(clients) {
5482
- const refs = /* @__PURE__ */ new Set();
5483
- for (const client of clients.values()) {
5484
- if (isClientV6(client)) {
5485
- for (const hash2 of client.refreshHashes) {
5486
- refs.add(hash2);
5487
- }
5488
- if (client.persistHash) {
5489
- refs.add(client.persistHash);
5490
- }
5491
- } else {
5492
- refs.add(client.headHash);
5493
- if (isClientV5(client) && client.tempRefreshHash) {
5494
- refs.add(client.tempRefreshHash);
5495
- }
4952
+ function maybeEndPull(store, lc, expectedSyncHead, clientID, diffConfig, formatVersion) {
4953
+ return withWriteNoImplicitCommit(store, async (dagWrite) => {
4954
+ const dagRead = dagWrite;
4955
+ const syncHeadHash = await dagRead.getHead(SYNC_HEAD_NAME);
4956
+ if (syncHeadHash === void 0) {
4957
+ throw new Error("Missing sync head");
5496
4958
  }
5497
- }
5498
- return toRefs(refs);
5499
- }
5500
- async function getClientGroupForClient(clientID, read) {
5501
- const clientGroupID = await getClientGroupIDForClient(clientID, read);
5502
- if (!clientGroupID) {
5503
- return void 0;
5504
- }
5505
- return getClientGroup(clientGroupID, read);
4959
+ if (syncHeadHash !== expectedSyncHead) {
4960
+ lc.error?.(
4961
+ "maybeEndPull, Wrong sync head. Expecting:",
4962
+ expectedSyncHead,
4963
+ "got:",
4964
+ syncHeadHash
4965
+ );
4966
+ throw new Error("Wrong sync head");
4967
+ }
4968
+ const syncSnapshot = await baseSnapshotFromHash(syncHeadHash, dagRead);
4969
+ const mainHeadHash = await dagRead.getHead(DEFAULT_HEAD_NAME);
4970
+ if (mainHeadHash === void 0) {
4971
+ throw new Error("Missing main head");
4972
+ }
4973
+ const mainSnapshot = await baseSnapshotFromHash(mainHeadHash, dagRead);
4974
+ const { meta } = syncSnapshot;
4975
+ const syncSnapshotBasis = meta.basisHash;
4976
+ if (syncSnapshot === null) {
4977
+ throw new Error("Sync snapshot with no basis");
4978
+ }
4979
+ if (syncSnapshotBasis !== mainSnapshot.chunk.hash) {
4980
+ throw new Error("Overlapping syncs");
4981
+ }
4982
+ const syncHead = await commitFromHash(syncHeadHash, dagRead);
4983
+ const pending = [];
4984
+ const localMutations2 = await localMutations(mainHeadHash, dagRead);
4985
+ for (const commit of localMutations2) {
4986
+ let cid = clientID;
4987
+ assert(commitIsLocalDD31(commit));
4988
+ cid = commit.meta.clientID;
4989
+ if (await commit.getMutationID(cid, dagRead) > await syncHead.getMutationID(cid, dagRead)) {
4990
+ pending.push(commit);
4991
+ }
4992
+ }
4993
+ pending.reverse();
4994
+ const diffsMap = new DiffsMap();
4995
+ if (pending.length > 0) {
4996
+ return {
4997
+ syncHead: syncHeadHash,
4998
+ replayMutations: pending,
4999
+ // The changed keys are not reported when further replays are
5000
+ // needed. The diffs will be reported at the end when there
5001
+ // are no more mutations to be replay and then it will be reported
5002
+ // relative to DEFAULT_HEAD_NAME.
5003
+ diffs: diffsMap
5004
+ };
5005
+ }
5006
+ const mainHead = await commitFromHash(mainHeadHash, dagRead);
5007
+ if (diffConfig.shouldComputeDiffs()) {
5008
+ const mainHeadMap = new BTreeRead(
5009
+ dagRead,
5010
+ formatVersion,
5011
+ mainHead.valueHash
5012
+ );
5013
+ const syncHeadMap = new BTreeRead(
5014
+ dagRead,
5015
+ formatVersion,
5016
+ syncHead.valueHash
5017
+ );
5018
+ const valueDiff = await diff(mainHeadMap, syncHeadMap);
5019
+ diffsMap.set("", valueDiff);
5020
+ await addDiffsForIndexes(
5021
+ mainHead,
5022
+ syncHead,
5023
+ dagRead,
5024
+ diffsMap,
5025
+ diffConfig,
5026
+ formatVersion
5027
+ );
5028
+ }
5029
+ await Promise.all([
5030
+ dagWrite.setHead(DEFAULT_HEAD_NAME, syncHeadHash),
5031
+ dagWrite.removeHead(SYNC_HEAD_NAME)
5032
+ ]);
5033
+ await dagWrite.commit();
5034
+ if (lc.debug) {
5035
+ const [oldLastMutationID, oldCookie] = snapshotMetaParts(
5036
+ mainSnapshot,
5037
+ clientID
5038
+ );
5039
+ const [newLastMutationID, newCookie] = snapshotMetaParts(
5040
+ syncSnapshot,
5041
+ clientID
5042
+ );
5043
+ lc.debug(
5044
+ `Successfully pulled new snapshot with lastMutationID:`,
5045
+ newLastMutationID,
5046
+ `(prev:`,
5047
+ oldLastMutationID,
5048
+ `), cookie: `,
5049
+ newCookie,
5050
+ `(prev:`,
5051
+ oldCookie,
5052
+ `), sync head hash:`,
5053
+ syncHeadHash,
5054
+ ", main head hash:",
5055
+ mainHeadHash,
5056
+ `, valueHash:`,
5057
+ syncHead.valueHash,
5058
+ `(prev:`,
5059
+ mainSnapshot.valueHash
5060
+ );
5061
+ }
5062
+ return {
5063
+ syncHead: syncHeadHash,
5064
+ replayMutations: [],
5065
+ diffs: diffsMap
5066
+ };
5067
+ });
5506
5068
  }
5507
- async function getClientGroupIDForClient(clientID, read) {
5508
- const client = await getClient(clientID, read);
5509
- if (!client || !isClientV5(client)) {
5510
- return void 0;
5069
+
5070
+ // ../shared/src/json-schema.ts
5071
+ import * as valita from "@badrap/valita";
5072
+ var path = [];
5073
+ var jsonSchema = valita_exports.unknown().chain((v) => {
5074
+ if (isProd) {
5075
+ return valita.ok(v);
5511
5076
  }
5512
- return client.clientGroupID;
5513
- }
5514
- async function setClient(clientID, client, dagWrite) {
5515
- const clients = await getClients(dagWrite);
5516
- const newClients = new Map(clients).set(clientID, client);
5517
- return setClients(newClients, dagWrite);
5518
- }
5519
- async function setClients(clients, dagWrite) {
5520
- const chunkData = clientMapToChunkData(clients, dagWrite);
5521
- const chunk = dagWrite.createChunk(chunkData, getRefsForClients(clients));
5522
- await dagWrite.putChunk(chunk);
5523
- await dagWrite.setHead(CLIENTS_HEAD_NAME, chunk.hash);
5524
- return chunk.hash;
5525
- }
5077
+ const rv = isJSONValue(v, path) ? valita.ok(v) : valita.err({
5078
+ message: `Not a JSON value`,
5079
+ path: path.slice()
5080
+ });
5081
+ path.length = 0;
5082
+ return rv;
5083
+ });
5084
+ var jsonObjectSchema = valita_exports.unknown().chain((v) => {
5085
+ if (isProd) {
5086
+ return valita.ok(v);
5087
+ }
5088
+ const rv = isJSONObject(v, path) ? valita.ok(v) : valita.err({
5089
+ message: `Not a JSON object`,
5090
+ path: path.slice()
5091
+ });
5092
+ path.length = 0;
5093
+ return rv;
5094
+ });
5526
5095
 
5527
- // ../replicache/src/to-error.ts
5528
- function toError(e) {
5529
- if (e instanceof Error) {
5530
- return e;
5096
+ // ../replicache/src/pusher.ts
5097
+ function assertPusherResult(v) {
5098
+ assertObject(v);
5099
+ assertHTTPRequestInfo(v.httpRequestInfo);
5100
+ if (v.response !== void 0) {
5101
+ assertPushResponse(v.response);
5531
5102
  }
5532
- return new Error(String(e));
5533
5103
  }
5534
-
5535
- // ../replicache/src/sync/handle-pull-response-result-type-enum.ts
5536
- var Applied = 0;
5537
- var NoOp = 1;
5538
- var CookieMismatch = 2;
5539
-
5540
- // ../replicache/src/sync/patch.ts
5541
- async function apply(lc, dbWrite, patch) {
5542
- for (const p of patch) {
5543
- switch (p.op) {
5544
- case "put": {
5545
- await dbWrite.put(lc, p.key, deepFreeze(p.value));
5546
- break;
5547
- }
5548
- case "update": {
5549
- const existing = await dbWrite.get(p.key);
5550
- const entries = [];
5551
- const addToEntries = (toAdd) => {
5552
- for (const [key, value] of Object.entries(toAdd)) {
5553
- if (!p.constrain || p.constrain.length === 0 || p.constrain.indexOf(key) > -1) {
5554
- entries.push([key, value]);
5555
- }
5556
- }
5557
- };
5558
- if (existing !== void 0) {
5559
- assertObject(existing);
5560
- addToEntries(existing);
5561
- }
5562
- if (p.merge) {
5563
- addToEntries(p.merge);
5564
- }
5565
- await dbWrite.put(lc, p.key, deepFreeze(Object.fromEntries(entries)));
5566
- break;
5567
- }
5568
- case "del":
5569
- await dbWrite.del(lc, p.key);
5570
- break;
5571
- case "clear":
5572
- await dbWrite.clear();
5573
- break;
5574
- }
5104
+ function assertPushResponse(v) {
5105
+ if (isClientStateNotFoundResponse(v)) {
5106
+ return;
5575
5107
  }
5108
+ assertVersionNotSupportedResponse(v);
5576
5109
  }
5577
-
5578
- // ../replicache/src/sync/pull-error.ts
5579
- var PullError = class extends Error {
5580
- name = "PullError";
5110
+ var PushError = class extends Error {
5111
+ name = "PushError";
5581
5112
  // causedBy is used instead of cause, because while cause has been proposed as a
5582
5113
  // JavaScript language standard for this purpose (see
5583
5114
  // https://github.com/tc39/proposal-error-cause) current browser behavior is
5584
5115
  // inconsistent.
5585
5116
  causedBy;
5586
5117
  constructor(causedBy) {
5587
- super("Failed to pull");
5118
+ super("Failed to push");
5588
5119
  this.causedBy = causedBy;
5589
5120
  }
5590
5121
  };
5591
5122
 
5592
- // ../replicache/src/sync/sync-head-name.ts
5593
- var SYNC_HEAD_NAME = "sync";
5123
+ // ../replicache/src/sync/ids.ts
5124
+ var clientGroupIDSchema = valita_exports.string();
5125
+ var clientIDSchema = valita_exports.string();
5594
5126
 
5595
- // ../replicache/src/sync/pull.ts
5596
- var PULL_VERSION_SDD = 0;
5597
- var PULL_VERSION_DD31 = 1;
5598
- function isPullRequestV1(pr) {
5599
- return pr.pullVersion === PULL_VERSION_DD31;
5127
+ // ../replicache/src/sync/push.ts
5128
+ var PUSH_VERSION_DD31 = 1;
5129
+ var mutationV1Schema = readonlyObject({
5130
+ id: valita_exports.number(),
5131
+ name: valita_exports.string(),
5132
+ args: jsonSchema,
5133
+ timestamp: valita_exports.number(),
5134
+ clientID: clientIDSchema
5135
+ });
5136
+ var pushRequestV1Schema = valita_exports.object({
5137
+ pushVersion: valita_exports.literal(1),
5138
+ schemaVersion: valita_exports.string(),
5139
+ profileID: valita_exports.string(),
5140
+ clientGroupID: clientGroupIDSchema,
5141
+ mutations: valita_exports.array(mutationV1Schema)
5142
+ });
5143
+ function convertDD31(lm) {
5144
+ return {
5145
+ id: lm.mutationID,
5146
+ name: lm.mutatorName,
5147
+ args: lm.mutatorArgsJSON,
5148
+ timestamp: lm.timestamp,
5149
+ clientID: lm.clientID
5150
+ };
5600
5151
  }
5601
- async function beginPullV0(profileID, clientID, schemaVersion, puller, requestID, store, formatVersion, lc, createSyncBranch = true) {
5602
- const [lastMutationID, baseCookie] = await withRead(store, async (dagRead) => {
5152
+ async function push(requestID, store, lc, profileID, clientGroupID, _clientID, pusher, schemaVersion, pushVersion) {
5153
+ const pending = await withRead(store, async (dagRead) => {
5603
5154
  const mainHeadHash = await dagRead.getHead(DEFAULT_HEAD_NAME);
5604
5155
  if (!mainHeadHash) {
5605
- throw new Error("Internal no main head found");
5156
+ throw new Error("Internal no main head");
5606
5157
  }
5607
- const baseSnapshot = await baseSnapshotFromHash(mainHeadHash, dagRead);
5608
- const baseSnapshotMeta = baseSnapshot.meta;
5609
- const baseCookie2 = baseSnapshotMeta.cookieJSON;
5610
- const lastMutationID2 = await baseSnapshot.getMutationID(clientID, dagRead);
5611
- return [lastMutationID2, baseCookie2];
5158
+ return localMutations(mainHeadHash, dagRead);
5612
5159
  });
5613
- const pullReq = {
5160
+ if (pending.length === 0) {
5161
+ return void 0;
5162
+ }
5163
+ pending.reverse();
5164
+ assert(pushVersion === PUSH_VERSION_DD31);
5165
+ const pushMutations = [];
5166
+ for (const commit of pending) {
5167
+ if (commitIsLocalDD31(commit)) {
5168
+ pushMutations.push(convertDD31(commit.meta));
5169
+ } else {
5170
+ throw new Error("Internal non local pending commit");
5171
+ }
5172
+ }
5173
+ assert(clientGroupID);
5174
+ const pushReq = {
5614
5175
  profileID,
5615
- clientID,
5616
- cookie: baseCookie,
5617
- lastMutationID,
5618
- pullVersion: PULL_VERSION_SDD,
5176
+ clientGroupID,
5177
+ mutations: pushMutations,
5178
+ pushVersion: PUSH_VERSION_DD31,
5619
5179
  schemaVersion
5620
5180
  };
5621
- const { response, httpRequestInfo } = await callPuller(
5622
- lc,
5623
- puller,
5624
- pullReq,
5625
- requestID
5626
- );
5627
- if (!response) {
5628
- return {
5629
- httpRequestInfo,
5630
- syncHead: emptyHash
5631
- };
5632
- }
5633
- if (!createSyncBranch || isErrorResponse(response)) {
5634
- return {
5635
- httpRequestInfo,
5636
- pullResponse: response,
5637
- syncHead: emptyHash
5638
- };
5639
- }
5640
- const result = await handlePullResponseV0(
5641
- lc,
5642
- store,
5643
- baseCookie,
5644
- response,
5645
- clientID,
5646
- formatVersion
5647
- );
5648
- if (result.type === CookieMismatch) {
5649
- throw new Error("Overlapping sync");
5650
- }
5651
- return {
5652
- httpRequestInfo,
5653
- pullResponse: response,
5654
- syncHead: result.type === Applied ? result.syncHead : emptyHash
5655
- };
5656
- }
5657
- async function beginPullV1(profileID, clientID, clientGroupID, schemaVersion, puller, requestID, store, formatVersion, lc, createSyncBranch = true) {
5658
- const baseCookie = await withRead(store, async (dagRead) => {
5659
- const mainHeadHash = await dagRead.getHead(DEFAULT_HEAD_NAME);
5660
- if (!mainHeadHash) {
5661
- throw new Error("Internal no main head found");
5662
- }
5663
- const baseSnapshot = await baseSnapshotFromHash(mainHeadHash, dagRead);
5664
- const baseSnapshotMeta = baseSnapshot.meta;
5665
- assertSnapshotMetaDD31(baseSnapshotMeta);
5666
- return baseSnapshotMeta.cookieJSON;
5667
- });
5668
- const pullReq = {
5669
- profileID,
5670
- clientGroupID,
5671
- cookie: baseCookie,
5672
- pullVersion: PULL_VERSION_DD31,
5673
- schemaVersion
5674
- };
5675
- const { response, httpRequestInfo } = await callPuller(
5676
- lc,
5677
- puller,
5678
- pullReq,
5679
- requestID
5680
- );
5681
- if (!response) {
5682
- return {
5683
- httpRequestInfo,
5684
- syncHead: emptyHash
5685
- };
5686
- }
5687
- if (!createSyncBranch || isErrorResponse(response)) {
5688
- return {
5689
- httpRequestInfo,
5690
- pullResponse: response,
5691
- syncHead: emptyHash
5692
- };
5693
- }
5694
- const result = await handlePullResponseV1(
5695
- lc,
5696
- store,
5697
- baseCookie,
5698
- response,
5699
- clientID,
5700
- formatVersion
5701
- );
5702
- return {
5703
- httpRequestInfo,
5704
- pullResponse: response,
5705
- syncHead: result.type === Applied ? result.syncHead : emptyHash
5706
- };
5181
+ lc.debug?.("Starting push...");
5182
+ const pushStart = Date.now();
5183
+ const pusherResult = await callPusher(pusher, pushReq, requestID);
5184
+ lc.debug?.("...Push complete in ", Date.now() - pushStart, "ms");
5185
+ return pusherResult;
5707
5186
  }
5708
- async function callPuller(lc, puller, pullReq, requestID) {
5709
- lc.debug?.("Starting pull...");
5710
- const pullStart = Date.now();
5711
- let pullerResult;
5187
+ async function callPusher(pusher, body, requestID) {
5188
+ let pusherResult;
5712
5189
  try {
5713
- pullerResult = await puller(pullReq, requestID);
5714
- lc.debug?.(
5715
- `...Pull ${pullerResult.response ? "complete" : "failed"} in `,
5716
- Date.now() - pullStart,
5717
- "ms"
5718
- );
5190
+ pusherResult = await pusher(body, requestID);
5719
5191
  } catch (e) {
5720
- throw new PullError(toError(e));
5192
+ throw new PushError(toError(e));
5721
5193
  }
5722
5194
  try {
5723
- if (isPullRequestV1(pullReq)) {
5724
- assertPullerResultV1(pullerResult);
5725
- } else {
5726
- assertPullerResultV0(pullerResult);
5727
- }
5728
- return pullerResult;
5195
+ assertPusherResult(pusherResult);
5196
+ return pusherResult;
5729
5197
  } catch (e) {
5730
- throw new ReportError("Invalid puller result", toError(e));
5198
+ throw new ReportError("Invalid pusher result", toError(e));
5731
5199
  }
5732
5200
  }
5733
- function handlePullResponseV0(lc, store, expectedBaseCookie, response, clientID, formatVersion) {
5734
- return withWriteNoImplicitCommit(store, async (dagWrite) => {
5735
- assert(formatVersion <= SDD);
5736
- const dagRead = dagWrite;
5737
- const mainHead = await dagRead.getHead(DEFAULT_HEAD_NAME);
5738
- if (mainHead === void 0) {
5739
- throw new Error("Main head disappeared");
5740
- }
5741
- const baseSnapshot = await baseSnapshotFromHash(mainHead, dagRead);
5742
- const [baseLastMutationID, baseCookie] = snapshotMetaParts(
5743
- baseSnapshot,
5744
- clientID
5745
- );
5746
- if (!deepEqual(expectedBaseCookie, baseCookie)) {
5747
- return {
5748
- type: CookieMismatch
5749
- };
5750
- }
5751
- if (response.lastMutationID < baseLastMutationID) {
5752
- throw new Error(
5753
- badOrderMessage(
5754
- `lastMutationID`,
5755
- String(response.lastMutationID),
5756
- String(baseLastMutationID)
5757
- )
5758
- );
5759
- }
5760
- const frozenCookie = deepFreeze(response.cookie ?? null);
5761
- if (deepEqual(frozenCookie, baseCookie)) {
5762
- if (response.patch.length > 0) {
5763
- lc.error?.(
5764
- `handlePullResponse: cookie ${JSON.stringify(
5765
- baseCookie
5766
- )} did not change, but patch is not empty`
5767
- );
5768
- }
5769
- if (response.lastMutationID !== baseLastMutationID) {
5770
- lc.error?.(
5771
- `handlePullResponse: cookie ${JSON.stringify(
5772
- baseCookie
5773
- )} did not change, but lastMutationID did change`
5774
- );
5775
- }
5776
- return {
5777
- type: NoOp
5778
- };
5201
+
5202
+ // ../replicache/src/mutation-recovery.ts
5203
+ var MUTATION_RECOVERY_LAZY_STORE_SOURCE_CHUNK_CACHE_SIZE_LIMIT = 10 * 2 ** 20;
5204
+ var MutationRecovery = class {
5205
+ #recoveringMutations = false;
5206
+ #options;
5207
+ constructor(options) {
5208
+ this.#options = options;
5209
+ }
5210
+ async recoverMutations(ready, perdag, idbDatabase, idbDatabases, createStore) {
5211
+ const { lc, enableMutationRecovery, isPushDisabled, delegate } = this.#options;
5212
+ if (!enableMutationRecovery || this.#recoveringMutations || !delegate.online || delegate.closed || isPushDisabled()) {
5213
+ return false;
5779
5214
  }
5780
- const chain = await commitChain(mainHead, dagRead);
5781
- let lastIntegrated;
5782
- for (const commit of chain) {
5783
- if (await commit.getMutationID(clientID, dagRead) <= response.lastMutationID) {
5784
- lastIntegrated = commit;
5785
- break;
5215
+ const stepDescription = "Recovering mutations.";
5216
+ lc.debug?.("Start:", stepDescription);
5217
+ try {
5218
+ this.#recoveringMutations = true;
5219
+ await ready;
5220
+ await recoverMutationsFromPerdag(idbDatabase, this.#options, perdag);
5221
+ for (const database of Object.values(await idbDatabases.getDatabases())) {
5222
+ if (delegate.closed) {
5223
+ lc.debug?.("Exiting early due to close:", stepDescription);
5224
+ return true;
5225
+ }
5226
+ if (database.replicacheName === delegate.name && database.name !== delegate.idbName) {
5227
+ switch (database.replicacheFormatVersion) {
5228
+ case SDD:
5229
+ case DD31:
5230
+ case V6:
5231
+ case V7:
5232
+ await recoverMutationsWithNewPerdag(
5233
+ database,
5234
+ this.#options,
5235
+ createStore
5236
+ );
5237
+ }
5238
+ }
5786
5239
  }
5240
+ } catch (e) {
5241
+ logMutationRecoveryError(e, lc, stepDescription, delegate);
5242
+ } finally {
5243
+ lc.debug?.("End:", stepDescription);
5244
+ this.#recoveringMutations = false;
5787
5245
  }
5788
- if (!lastIntegrated) {
5789
- throw new Error("Internal invalid chain");
5790
- }
5791
- const dbWrite = await newWriteSnapshotSDD(
5792
- baseSnapshot.chunk.hash,
5793
- response.lastMutationID,
5794
- frozenCookie,
5795
- dagWrite,
5796
- readIndexesForWrite(lastIntegrated, dagWrite, formatVersion),
5797
- clientID,
5798
- formatVersion
5246
+ return true;
5247
+ }
5248
+ };
5249
+ function logMutationRecoveryError(e, lc, stepDescription, closedDelegate) {
5250
+ if (closedDelegate.closed) {
5251
+ lc.debug?.(
5252
+ `Mutation recovery error likely due to close during:
5253
+ ${stepDescription}
5254
+ Error:
5255
+ `,
5256
+ e
5799
5257
  );
5800
- await apply(lc, dbWrite, response.patch);
5801
- const lastIntegratedMap = new BTreeRead(
5802
- dagRead,
5803
- formatVersion,
5804
- lastIntegrated.valueHash
5258
+ } else {
5259
+ lc.error?.(
5260
+ `Mutation recovery error during:
5261
+ ${stepDescription}
5262
+ Error:
5263
+ `,
5264
+ e
5805
5265
  );
5806
- for await (const change of dbWrite.map.diff(lastIntegratedMap)) {
5807
- await updateIndexes(
5808
- lc,
5809
- dbWrite.indexes,
5810
- change.key,
5811
- () => Promise.resolve(change.oldValue),
5812
- change.newValue
5813
- );
5814
- }
5815
- return {
5816
- type: Applied,
5817
- syncHead: await dbWrite.commit(SYNC_HEAD_NAME)
5818
- };
5819
- });
5266
+ }
5820
5267
  }
5821
- function badOrderMessage(name, receivedValue, lastSnapshotValue) {
5822
- return `Received ${name} ${receivedValue} is < than last snapshot ${name} ${lastSnapshotValue}; ignoring client view`;
5268
+ async function recoverMutationsWithNewPerdag(database, options, createStore) {
5269
+ const perKvStore = createStore(database.name);
5270
+ const perdag = new StoreImpl(perKvStore, newRandomHash, assertHash);
5271
+ try {
5272
+ await recoverMutationsFromPerdag(database, options, perdag);
5273
+ } finally {
5274
+ await perdag.close();
5275
+ }
5823
5276
  }
5824
- function handlePullResponseV1(lc, store, expectedBaseCookie, response, clientID, formatVersion) {
5825
- return withWriteNoImplicitCommit(store, async (dagWrite) => {
5826
- const dagRead = dagWrite;
5827
- const mainHead = await dagRead.getHead(DEFAULT_HEAD_NAME);
5828
- if (mainHead === void 0) {
5829
- throw new Error("Main head disappeared");
5830
- }
5831
- const baseSnapshot = await baseSnapshotFromHash(mainHead, dagRead);
5832
- const baseSnapshotMeta = baseSnapshot.meta;
5833
- assertSnapshotMetaDD31(baseSnapshotMeta);
5834
- const baseCookie = baseSnapshotMeta.cookieJSON;
5835
- if (!deepEqual(expectedBaseCookie, baseCookie)) {
5836
- lc.debug?.(
5837
- "handlePullResponse: cookie mismatch, response is not applicable"
5838
- );
5839
- return {
5840
- type: CookieMismatch
5841
- };
5842
- }
5843
- for (const [clientID2, lmidChange] of Object.entries(
5844
- response.lastMutationIDChanges
5845
- )) {
5846
- const lastMutationID = baseSnapshotMeta.lastMutationIDs[clientID2];
5847
- if (lastMutationID !== void 0 && lmidChange < lastMutationID) {
5848
- throw new Error(
5849
- badOrderMessage(
5850
- `${clientID2} lastMutationID`,
5851
- String(lmidChange),
5852
- String(lastMutationID)
5853
- )
5854
- );
5855
- }
5856
- }
5857
- const frozenResponseCookie = deepFreeze(response.cookie);
5858
- if (compareCookies(frozenResponseCookie, baseCookie) < 0) {
5859
- throw new Error(
5860
- badOrderMessage(
5861
- "cookie",
5862
- JSON.stringify(frozenResponseCookie),
5863
- JSON.stringify(baseCookie)
5864
- )
5865
- );
5866
- }
5867
- if (deepEqual(frozenResponseCookie, baseCookie)) {
5868
- if (response.patch.length > 0) {
5869
- lc.error?.(
5870
- `handlePullResponse: cookie ${JSON.stringify(
5871
- baseCookie
5872
- )} did not change, but patch is not empty`
5873
- );
5874
- }
5875
- if (Object.keys(response.lastMutationIDChanges).length > 0) {
5876
- console.log(response.lastMutationIDChanges);
5877
- lc.error?.(
5878
- `handlePullResponse: cookie ${JSON.stringify(
5879
- baseCookie
5880
- )} did not change, but lastMutationIDChanges is not empty`
5881
- );
5277
+ function recoverMutationsFromPerdag(database, options, perdag) {
5278
+ assert(database.replicacheFormatVersion >= DD31);
5279
+ return recoverMutationsFromPerdagDD31(database, options, perdag);
5280
+ }
5281
+ async function recoverMutationsFromPerdagDD31(database, options, perdag) {
5282
+ const { delegate, lc } = options;
5283
+ const stepDescription = `Recovering mutations from db ${database.name}.`;
5284
+ lc.debug?.("Start:", stepDescription);
5285
+ try {
5286
+ const formatVersion = parseReplicacheFormatVersion(database.replicacheFormatVersion);
5287
+ let clientGroups = await withRead(
5288
+ perdag,
5289
+ (read) => getClientGroups(read)
5290
+ );
5291
+ const clientGroupIDsVisited = /* @__PURE__ */ new Set();
5292
+ while (clientGroups) {
5293
+ let newClientGroups;
5294
+ for (const [clientGroupID, clientGroup] of clientGroups) {
5295
+ if (delegate.closed) {
5296
+ lc.debug?.("Exiting early due to close:", stepDescription);
5297
+ return;
5298
+ }
5299
+ if (!clientGroupIDsVisited.has(clientGroupID)) {
5300
+ clientGroupIDsVisited.add(clientGroupID);
5301
+ newClientGroups = await recoverMutationsOfClientGroupDD31(
5302
+ clientGroup,
5303
+ clientGroupID,
5304
+ perdag,
5305
+ database,
5306
+ options,
5307
+ formatVersion
5308
+ );
5309
+ if (newClientGroups) {
5310
+ break;
5311
+ }
5312
+ }
5882
5313
  }
5883
- return {
5884
- type: NoOp
5885
- };
5314
+ clientGroups = newClientGroups;
5886
5315
  }
5887
- const dbWrite = await newWriteSnapshotDD31(
5888
- baseSnapshot.chunk.hash,
5889
- { ...baseSnapshotMeta.lastMutationIDs, ...response.lastMutationIDChanges },
5890
- frozenResponseCookie,
5891
- dagWrite,
5892
- clientID,
5893
- formatVersion
5316
+ } catch (e) {
5317
+ logMutationRecoveryError(e, lc, stepDescription, delegate);
5318
+ }
5319
+ lc.debug?.("End:", stepDescription);
5320
+ }
5321
+ function isResponseThatShouldDisableClientGroup(response) {
5322
+ return isClientStateNotFoundResponse(response) || isVersionNotSupportedResponse(response);
5323
+ }
5324
+ async function disableClientGroup2(lc, selfClientGroupID, clientGroupID, response, perdag) {
5325
+ if (isClientStateNotFoundResponse(response)) {
5326
+ lc.debug?.(
5327
+ `Client group ${selfClientGroupID} cannot recover mutations for client group ${clientGroupID}. The client group is unknown on the server. Marking it as disabled.`
5894
5328
  );
5895
- await apply(lc, dbWrite, response.patch);
5896
- return {
5897
- type: Applied,
5898
- syncHead: await dbWrite.commit(SYNC_HEAD_NAME)
5899
- };
5900
- });
5329
+ } else if (isVersionNotSupportedResponse(response)) {
5330
+ lc.debug?.(
5331
+ `Client group ${selfClientGroupID} cannot recover mutations for client group ${clientGroupID}. The client group's version is not supported on the server. versionType: ${response.versionType}. Marking it as disabled.`
5332
+ );
5333
+ }
5334
+ await withWrite(
5335
+ perdag,
5336
+ (perdagWrite) => disableClientGroup(clientGroupID, perdagWrite)
5337
+ );
5901
5338
  }
5902
- function maybeEndPull(store, lc, expectedSyncHead, clientID, diffConfig, formatVersion) {
5903
- return withWriteNoImplicitCommit(store, async (dagWrite) => {
5904
- const dagRead = dagWrite;
5905
- const syncHeadHash = await dagRead.getHead(SYNC_HEAD_NAME);
5906
- if (syncHeadHash === void 0) {
5907
- throw new Error("Missing sync head");
5339
+ async function recoverMutationsOfClientGroupDD31(clientGroup, clientGroupID, perdag, database, options, formatVersion) {
5340
+ assert(database.replicacheFormatVersion >= DD31);
5341
+ const {
5342
+ delegate,
5343
+ lc,
5344
+ wrapInOnlineCheck,
5345
+ wrapInReauthRetries,
5346
+ isPushDisabled,
5347
+ isPullDisabled,
5348
+ clientGroupIDPromise
5349
+ } = options;
5350
+ const selfClientGroupID = await clientGroupIDPromise;
5351
+ assertNotUndefined(selfClientGroupID);
5352
+ if (selfClientGroupID === clientGroupID) {
5353
+ return;
5354
+ }
5355
+ let clientID;
5356
+ let allAckd = true;
5357
+ for (const [cid, mutationID] of Object.entries(clientGroup.mutationIDs)) {
5358
+ if (!clientGroup.lastServerAckdMutationIDs[cid] || clientGroup.lastServerAckdMutationIDs[cid] < mutationID) {
5359
+ clientID = cid;
5360
+ allAckd = false;
5361
+ break;
5908
5362
  }
5909
- if (syncHeadHash !== expectedSyncHead) {
5910
- lc.error?.(
5911
- "maybeEndPull, Wrong sync head. Expecting:",
5912
- expectedSyncHead,
5913
- "got:",
5914
- syncHeadHash
5363
+ }
5364
+ if (allAckd) {
5365
+ return;
5366
+ }
5367
+ if (clientGroup.disabled) {
5368
+ lc.debug?.(
5369
+ `Not recovering mutations for client group ${clientGroupID} because group is disabled.`
5370
+ );
5371
+ return;
5372
+ }
5373
+ const stepDescription = `Recovering mutations for client group ${clientGroupID}.`;
5374
+ lc.debug?.("Start:", stepDescription);
5375
+ const lazyDagForOtherClientGroup = new LazyStore(
5376
+ perdag,
5377
+ MUTATION_RECOVERY_LAZY_STORE_SOURCE_CHUNK_CACHE_SIZE_LIMIT,
5378
+ throwChunkHasher,
5379
+ assertHash
5380
+ );
5381
+ try {
5382
+ await withWrite(
5383
+ lazyDagForOtherClientGroup,
5384
+ (write) => write.setHead(DEFAULT_HEAD_NAME, clientGroup.headHash)
5385
+ );
5386
+ if (isPushDisabled()) {
5387
+ lc.debug?.(
5388
+ `Cannot recover mutations for client group ${clientGroupID} because push is disabled.`
5915
5389
  );
5916
- throw new Error("Wrong sync head");
5917
- }
5918
- const syncSnapshot = await baseSnapshotFromHash(syncHeadHash, dagRead);
5919
- const mainHeadHash = await dagRead.getHead(DEFAULT_HEAD_NAME);
5920
- if (mainHeadHash === void 0) {
5921
- throw new Error("Missing main head");
5922
- }
5923
- const mainSnapshot = await baseSnapshotFromHash(mainHeadHash, dagRead);
5924
- const { meta } = syncSnapshot;
5925
- const syncSnapshotBasis = meta.basisHash;
5926
- if (syncSnapshot === null) {
5927
- throw new Error("Sync snapshot with no basis");
5928
- }
5929
- if (syncSnapshotBasis !== mainSnapshot.chunk.hash) {
5930
- throw new Error("Overlapping syncs");
5390
+ return;
5931
5391
  }
5932
- const syncHead = await commitFromHash(syncHeadHash, dagRead);
5933
- const pending = [];
5934
- const localMutations2 = await localMutations(mainHeadHash, dagRead);
5935
- for (const commit of localMutations2) {
5936
- let cid = clientID;
5937
- if (commitIsLocalDD31(commit)) {
5938
- cid = commit.meta.clientID;
5392
+ const { pusher } = delegate;
5393
+ const pushDescription = "recoveringMutationsPush";
5394
+ const pushSucceeded = await wrapInOnlineCheck(async () => {
5395
+ const { result: pusherResult } = await wrapInReauthRetries(
5396
+ async (requestID, requestLc) => {
5397
+ assert(clientID);
5398
+ assert(lazyDagForOtherClientGroup);
5399
+ const pusherResult2 = await push(
5400
+ requestID,
5401
+ lazyDagForOtherClientGroup,
5402
+ requestLc,
5403
+ await delegate.profileID,
5404
+ clientGroupID,
5405
+ // TODO(DD31): clientID is not needed in DD31. It is currently kept for debugging purpose.
5406
+ clientID,
5407
+ pusher,
5408
+ database.schemaVersion,
5409
+ PUSH_VERSION_DD31
5410
+ );
5411
+ return {
5412
+ result: pusherResult2,
5413
+ httpRequestInfo: pusherResult2?.httpRequestInfo
5414
+ };
5415
+ },
5416
+ pushDescription,
5417
+ lc
5418
+ );
5419
+ if (!pusherResult) {
5420
+ return false;
5939
5421
  }
5940
- if (await commit.getMutationID(cid, dagRead) > await syncHead.getMutationID(cid, dagRead)) {
5941
- pending.push(commit);
5422
+ const pusherResponse = pusherResult.response;
5423
+ if (isResponseThatShouldDisableClientGroup(pusherResponse)) {
5424
+ await disableClientGroup2(
5425
+ lc,
5426
+ selfClientGroupID,
5427
+ clientGroupID,
5428
+ pusherResponse,
5429
+ perdag
5430
+ );
5431
+ return false;
5942
5432
  }
5943
- }
5944
- pending.reverse();
5945
- const diffsMap = new DiffsMap();
5946
- if (pending.length > 0) {
5947
- return {
5948
- syncHead: syncHeadHash,
5949
- replayMutations: pending,
5950
- // The changed keys are not reported when further replays are
5951
- // needed. The diffs will be reported at the end when there
5952
- // are no more mutations to be replay and then it will be reported
5953
- // relative to DEFAULT_HEAD_NAME.
5954
- diffs: diffsMap
5955
- };
5956
- }
5957
- const mainHead = await commitFromHash(mainHeadHash, dagRead);
5958
- if (diffConfig.shouldComputeDiffs()) {
5959
- const mainHeadMap = new BTreeRead(
5960
- dagRead,
5961
- formatVersion,
5962
- mainHead.valueHash
5433
+ return pusherResult.httpRequestInfo.httpStatusCode === 200;
5434
+ }, pushDescription);
5435
+ if (!pushSucceeded) {
5436
+ lc.debug?.(
5437
+ `Failed to recover mutations for client ${clientGroupID} due to a push error.`
5963
5438
  );
5964
- const syncHeadMap = new BTreeRead(
5965
- dagRead,
5966
- formatVersion,
5967
- syncHead.valueHash
5968
- );
5969
- const valueDiff = await diff(mainHeadMap, syncHeadMap);
5970
- diffsMap.set("", valueDiff);
5971
- await addDiffsForIndexes(
5972
- mainHead,
5973
- syncHead,
5974
- dagRead,
5975
- diffsMap,
5976
- diffConfig,
5977
- formatVersion
5439
+ return;
5440
+ }
5441
+ if (isPullDisabled()) {
5442
+ lc.debug?.(
5443
+ `Cannot confirm mutations were recovered for client ${clientGroupID} because pull is disabled.`
5978
5444
  );
5445
+ return;
5979
5446
  }
5980
- await Promise.all([
5981
- dagWrite.setHead(DEFAULT_HEAD_NAME, syncHeadHash),
5982
- dagWrite.removeHead(SYNC_HEAD_NAME)
5983
- ]);
5984
- await dagWrite.commit();
5985
- if (lc.debug) {
5986
- const [oldLastMutationID, oldCookie] = snapshotMetaParts(
5987
- mainSnapshot,
5988
- clientID
5989
- );
5990
- const [newLastMutationID, newCookie] = snapshotMetaParts(
5991
- syncSnapshot,
5992
- clientID
5447
+ const { puller } = delegate;
5448
+ const pullDescription = "recoveringMutationsPull";
5449
+ let okPullResponse;
5450
+ const pullSucceeded = await wrapInOnlineCheck(async () => {
5451
+ const { result: beginPullResponse } = await wrapInReauthRetries(
5452
+ async (requestID, requestLc) => {
5453
+ assert(clientID);
5454
+ const beginPullResponse2 = await beginPullV1(
5455
+ await delegate.profileID,
5456
+ clientID,
5457
+ clientGroupID,
5458
+ database.schemaVersion,
5459
+ puller,
5460
+ requestID,
5461
+ lazyDagForOtherClientGroup,
5462
+ formatVersion,
5463
+ requestLc,
5464
+ false
5465
+ );
5466
+ return {
5467
+ result: beginPullResponse2,
5468
+ httpRequestInfo: beginPullResponse2.httpRequestInfo
5469
+ };
5470
+ },
5471
+ pullDescription,
5472
+ lc
5993
5473
  );
5994
- lc.debug(
5995
- `Successfully pulled new snapshot with lastMutationID:`,
5996
- newLastMutationID,
5997
- `(prev:`,
5998
- oldLastMutationID,
5999
- `), cookie: `,
6000
- newCookie,
6001
- `(prev:`,
6002
- oldCookie,
6003
- `), sync head hash:`,
6004
- syncHeadHash,
6005
- ", main head hash:",
6006
- mainHeadHash,
6007
- `, valueHash:`,
6008
- syncHead.valueHash,
6009
- `(prev:`,
6010
- mainSnapshot.valueHash
5474
+ const { pullResponse } = beginPullResponse;
5475
+ if (isResponseThatShouldDisableClientGroup(pullResponse)) {
5476
+ await disableClientGroup2(
5477
+ lc,
5478
+ selfClientGroupID,
5479
+ clientGroupID,
5480
+ pullResponse,
5481
+ perdag
5482
+ );
5483
+ return false;
5484
+ }
5485
+ if (!pullResponse || beginPullResponse.httpRequestInfo.httpStatusCode !== 200) {
5486
+ return false;
5487
+ }
5488
+ okPullResponse = pullResponse;
5489
+ return true;
5490
+ }, pullDescription);
5491
+ if (!pullSucceeded) {
5492
+ lc.debug?.(
5493
+ `Failed to recover mutations for client ${clientGroupID} due to a pull error.`
6011
5494
  );
5495
+ return;
6012
5496
  }
6013
- return {
6014
- syncHead: syncHeadHash,
6015
- replayMutations: [],
6016
- diffs: diffsMap
6017
- };
6018
- });
5497
+ assert(okPullResponse);
5498
+ lc.debug?.(
5499
+ `Client group ${selfClientGroupID} recovered mutations for client group ${clientGroupID}. Details`,
5500
+ {
5501
+ mutationIDs: clientGroup.mutationIDs,
5502
+ lastServerAckdMutationIDs: clientGroup.lastServerAckdMutationIDs,
5503
+ lastMutationIDChanges: okPullResponse.lastMutationIDChanges
5504
+ }
5505
+ );
5506
+ return await withWrite(perdag, async (dagWrite) => {
5507
+ const clientGroups = await getClientGroups(dagWrite);
5508
+ const clientGroupToUpdate = clientGroups.get(clientGroupID);
5509
+ if (!clientGroupToUpdate) {
5510
+ return clientGroups;
5511
+ }
5512
+ assert(okPullResponse);
5513
+ const lastServerAckdMutationIDsUpdates = {};
5514
+ let anyMutationIDsUpdated = false;
5515
+ for (const [clientID2, lastMutationIDChange] of Object.entries(
5516
+ okPullResponse.lastMutationIDChanges
5517
+ )) {
5518
+ if ((clientGroupToUpdate.lastServerAckdMutationIDs[clientID2] ?? 0) < lastMutationIDChange) {
5519
+ lastServerAckdMutationIDsUpdates[clientID2] = lastMutationIDChange;
5520
+ anyMutationIDsUpdated = true;
5521
+ }
5522
+ }
5523
+ if (!anyMutationIDsUpdated) {
5524
+ return clientGroups;
5525
+ }
5526
+ const newClientGroups = new Map(clientGroups).set(clientGroupID, {
5527
+ ...clientGroupToUpdate,
5528
+ lastServerAckdMutationIDs: {
5529
+ ...clientGroupToUpdate.lastServerAckdMutationIDs,
5530
+ ...lastServerAckdMutationIDsUpdates
5531
+ }
5532
+ });
5533
+ await setClientGroups(newClientGroups, dagWrite);
5534
+ return newClientGroups;
5535
+ });
5536
+ } catch (e) {
5537
+ logMutationRecoveryError(e, lc, stepDescription, delegate);
5538
+ } finally {
5539
+ await lazyDagForOtherClientGroup.close();
5540
+ lc.debug?.("End:", stepDescription);
5541
+ }
5542
+ return;
6019
5543
  }
6020
5544
 
6021
- // ../shared/src/json-schema.ts
6022
- import * as valita from "@badrap/valita";
6023
- var path = [];
6024
- var jsonSchema = valita_exports.unknown().chain((v2) => {
6025
- if (isProd) {
6026
- return valita.ok(v2);
5545
+ // ../replicache/src/broadcast-channel.ts
5546
+ var NoopBroadcastChannel = class {
5547
+ name;
5548
+ onmessage = null;
5549
+ onmessageerror = null;
5550
+ constructor(name) {
5551
+ this.name = name;
6027
5552
  }
6028
- const rv = isJSONValue(v2, path) ? valita.ok(v2) : valita.err({
6029
- message: `Not a JSON value`,
6030
- path: path.slice()
6031
- });
6032
- path.length = 0;
6033
- return rv;
6034
- });
6035
- var jsonObjectSchema = valita_exports.unknown().chain((v2) => {
6036
- if (isProd) {
6037
- return valita.ok(v2);
5553
+ addEventListener() {
6038
5554
  }
6039
- const rv = isJSONObject(v2, path) ? valita.ok(v2) : valita.err({
6040
- message: `Not a JSON object`,
6041
- path: path.slice()
6042
- });
6043
- path.length = 0;
6044
- return rv;
6045
- });
6046
-
6047
- // ../replicache/src/pusher.ts
6048
- function assertPusherResult(v2) {
6049
- assertObject(v2);
6050
- assertHTTPRequestInfo(v2.httpRequestInfo);
6051
- if (v2.response !== void 0) {
6052
- assertPushResponse(v2.response);
5555
+ removeEventListener() {
6053
5556
  }
6054
- }
6055
- function assertPushResponse(v2) {
6056
- if (isClientStateNotFoundResponse(v2)) {
6057
- return;
5557
+ dispatchEvent() {
5558
+ return false;
6058
5559
  }
6059
- assertVersionNotSupportedResponse(v2);
6060
- }
6061
- var PushError = class extends Error {
6062
- name = "PushError";
6063
- // causedBy is used instead of cause, because while cause has been proposed as a
6064
- // JavaScript language standard for this purpose (see
6065
- // https://github.com/tc39/proposal-error-cause) current browser behavior is
6066
- // inconsistent.
6067
- causedBy;
6068
- constructor(causedBy) {
6069
- super("Failed to push");
6070
- this.causedBy = causedBy;
5560
+ close() {
5561
+ }
5562
+ postMessage() {
6071
5563
  }
6072
5564
  };
5565
+ var bc = typeof BroadcastChannel === "undefined" ? NoopBroadcastChannel : BroadcastChannel;
6073
5566
 
6074
- // ../replicache/src/sync/push.ts
6075
- var PUSH_VERSION_SDD = 0;
6076
- var PUSH_VERSION_DD31 = 1;
6077
- var mutationV0Schema = readonlyObject({
6078
- id: valita_exports.number(),
6079
- name: valita_exports.string(),
6080
- args: jsonSchema,
6081
- timestamp: valita_exports.number()
6082
- });
6083
- var mutationV1Schema = readonlyObject({
6084
- id: valita_exports.number(),
6085
- name: valita_exports.string(),
6086
- args: jsonSchema,
6087
- timestamp: valita_exports.number(),
6088
- clientID: clientIDSchema
6089
- });
6090
- var pushRequestV0Schema = valita_exports.object({
6091
- pushVersion: valita_exports.literal(0),
6092
- schemaVersion: valita_exports.string(),
6093
- profileID: valita_exports.string(),
6094
- clientID: clientIDSchema,
6095
- mutations: valita_exports.array(mutationV0Schema)
6096
- });
6097
- var pushRequestV1Schema = valita_exports.object({
6098
- pushVersion: valita_exports.literal(1),
6099
- schemaVersion: valita_exports.string(),
6100
- profileID: valita_exports.string(),
6101
- clientGroupID: clientGroupIDSchema,
6102
- mutations: valita_exports.array(mutationV1Schema)
6103
- });
6104
- function convertSDD(lm) {
6105
- return {
6106
- id: lm.mutationID,
6107
- name: lm.mutatorName,
6108
- args: lm.mutatorArgsJSON,
6109
- timestamp: lm.timestamp
6110
- };
5567
+ // ../replicache/src/new-client-channel.ts
5568
+ function makeChannelNameV0(replicacheName) {
5569
+ return `replicache-new-client-group:${replicacheName}`;
6111
5570
  }
6112
- function convertDD31(lm) {
6113
- return {
6114
- id: lm.mutationID,
6115
- name: lm.mutatorName,
6116
- args: lm.mutatorArgsJSON,
6117
- timestamp: lm.timestamp,
6118
- clientID: lm.clientID
6119
- };
5571
+ function makeChannelNameV1(replicacheName) {
5572
+ return `replicache-new-client-group-v1:${replicacheName}`;
6120
5573
  }
6121
- async function push(requestID, store, lc, profileID, clientGroupID, clientID, pusher, schemaVersion, pushVersion) {
6122
- const pending = await withRead(store, async (dagRead) => {
6123
- const mainHeadHash = await dagRead.getHead(DEFAULT_HEAD_NAME);
6124
- if (!mainHeadHash) {
6125
- throw new Error("Internal no main head");
6126
- }
6127
- return localMutations(mainHeadHash, dagRead);
6128
- });
6129
- if (pending.length === 0) {
6130
- return void 0;
5574
+ function isNewClientChannelMessageV1(message) {
5575
+ return typeof message === "object" && typeof message.clientGroupID === "string" && typeof message.idbName === "string";
5576
+ }
5577
+ function initNewClientChannel(replicacheName, idbName, signal, clientGroupID, isNewClientGroup, onUpdateNeeded, perdag) {
5578
+ if (signal.aborted) {
5579
+ return;
6131
5580
  }
6132
- pending.reverse();
6133
- let pushReq;
6134
- if (pushVersion === PUSH_VERSION_DD31) {
6135
- const pushMutations = [];
6136
- for (const commit of pending) {
6137
- if (commitIsLocalDD31(commit)) {
6138
- pushMutations.push(convertDD31(commit.meta));
6139
- } else {
6140
- throw new Error("Internal non local pending commit");
6141
- }
6142
- }
6143
- assert(clientGroupID);
6144
- const r = {
6145
- profileID,
6146
- clientGroupID,
6147
- mutations: pushMutations,
6148
- pushVersion: PUSH_VERSION_DD31,
6149
- schemaVersion
6150
- };
6151
- pushReq = r;
6152
- } else {
6153
- assert(pushVersion === PUSH_VERSION_SDD);
6154
- const pushMutations = [];
6155
- for (const commit of pending) {
6156
- if (commitIsLocalSDD(commit)) {
6157
- pushMutations.push(convertSDD(commit.meta));
6158
- } else {
6159
- throw new Error("Internal non local pending commit");
6160
- }
6161
- }
6162
- pushReq = {
6163
- profileID,
6164
- clientID,
6165
- mutations: pushMutations,
6166
- pushVersion: PUSH_VERSION_SDD,
6167
- schemaVersion
6168
- };
5581
+ const channelV1 = new bc(makeChannelNameV1(replicacheName));
5582
+ if (isNewClientGroup) {
5583
+ channelV1.postMessage({ clientGroupID, idbName });
5584
+ const channelV0 = new bc(makeChannelNameV0(replicacheName));
5585
+ channelV0.postMessage([clientGroupID]);
5586
+ channelV0.close();
6169
5587
  }
6170
- lc.debug?.("Starting push...");
6171
- const pushStart = Date.now();
6172
- const pusherResult = await callPusher(pusher, pushReq, requestID);
6173
- lc.debug?.("...Push complete in ", Date.now() - pushStart, "ms");
6174
- return pusherResult;
5588
+ channelV1.onmessage = async (e) => {
5589
+ const { data } = e;
5590
+ if (isNewClientChannelMessageV1(data)) {
5591
+ const { clientGroupID: newClientGroupID, idbName: newClientIDBName } = data;
5592
+ if (newClientGroupID !== clientGroupID) {
5593
+ if (newClientIDBName === idbName) {
5594
+ const updateNeeded = await withRead(
5595
+ perdag,
5596
+ async (perdagRead) => await getClientGroup(newClientGroupID, perdagRead) !== void 0
5597
+ );
5598
+ if (updateNeeded) {
5599
+ onUpdateNeeded();
5600
+ }
5601
+ } else {
5602
+ onUpdateNeeded();
5603
+ return;
5604
+ }
5605
+ }
5606
+ }
5607
+ };
5608
+ signal.addEventListener("abort", () => channelV1.close(), { once: true });
6175
5609
  }
6176
- async function callPusher(pusher, body, requestID) {
6177
- let pusherResult;
6178
- try {
6179
- pusherResult = await pusher(body, requestID);
6180
- } catch (e) {
6181
- throw new PushError(toError(e));
6182
- }
6183
- try {
6184
- assertPusherResult(pusherResult);
6185
- return pusherResult;
6186
- } catch (e) {
6187
- throw new ReportError("Invalid pusher result", toError(e));
5610
+
5611
+ // ../replicache/src/on-persist-channel.ts
5612
+ function makeChannelName(replicacheName) {
5613
+ return `replicache-on-persist:${replicacheName}`;
5614
+ }
5615
+ function assertPersistInfo(value) {
5616
+ assertObject(value);
5617
+ assertString(value.clientGroupID);
5618
+ assertString(value.clientID);
5619
+ }
5620
+ function initOnPersistChannel(replicacheName, signal, handlePersist) {
5621
+ if (signal.aborted) {
5622
+ return () => void 0;
6188
5623
  }
5624
+ const channel = new bc(makeChannelName(replicacheName));
5625
+ channel.onmessage = (e) => {
5626
+ const { data } = e;
5627
+ assertPersistInfo(data);
5628
+ handlePersist({
5629
+ clientGroupID: data.clientGroupID,
5630
+ clientID: data.clientID
5631
+ });
5632
+ };
5633
+ signal.addEventListener("abort", () => channel.close(), { once: true });
5634
+ return (persistInfo) => {
5635
+ if (signal.aborted) {
5636
+ return;
5637
+ }
5638
+ channel.postMessage(persistInfo);
5639
+ handlePersist(persistInfo);
5640
+ };
6189
5641
  }
6190
5642
 
6191
- // ../replicache/src/mutation-recovery.ts
6192
- var MUTATION_RECOVERY_LAZY_STORE_SOURCE_CHUNK_CACHE_SIZE_LIMIT = 10 * 2 ** 20;
6193
- var MutationRecovery = class {
6194
- #recoveringMutations = false;
6195
- #options;
6196
- constructor(options) {
6197
- this.#options = options;
5643
+ // ../replicache/src/pending-mutations.ts
5644
+ async function pendingMutationsForAPI(dagRead) {
5645
+ const mainHeadHash = await mustGetHeadHash(DEFAULT_HEAD_NAME, dagRead);
5646
+ const pending = await localMutationsDD31(mainHeadHash, dagRead);
5647
+ return pending.map((p) => ({
5648
+ id: p.meta.mutationID,
5649
+ name: p.meta.mutatorName,
5650
+ args: p.meta.mutatorArgsJSON,
5651
+ clientID: p.meta.clientID
5652
+ })).reverse();
5653
+ }
5654
+
5655
+ // ../replicache/src/bg-interval.ts
5656
+ function initBgIntervalProcess(processName, process2, delayMs, lc, signal) {
5657
+ void runBgIntervalProcess(processName, process2, delayMs, lc, signal);
5658
+ }
5659
+ async function runBgIntervalProcess(processName, process2, delayMs, lc, signal) {
5660
+ if (signal.aborted) {
5661
+ return;
6198
5662
  }
6199
- async recoverMutations(preReadClientMap, ready, perdag, idbDatabase, idbDatabases, createStore) {
6200
- const { lc, enableMutationRecovery, isPushDisabled, delegate } = this.#options;
6201
- if (!enableMutationRecovery || this.#recoveringMutations || !delegate.online || delegate.closed || isPushDisabled()) {
6202
- return false;
6203
- }
6204
- const stepDescription = "Recovering mutations.";
6205
- lc.debug?.("Start:", stepDescription);
5663
+ lc = lc.withContext("bgIntervalProcess", processName);
5664
+ lc.debug?.("Starting");
5665
+ while (!signal.aborted) {
6206
5666
  try {
6207
- this.#recoveringMutations = true;
6208
- await ready;
6209
- await recoverMutationsFromPerdag(
6210
- idbDatabase,
6211
- this.#options,
6212
- perdag,
6213
- preReadClientMap
6214
- );
6215
- for (const database of Object.values(await idbDatabases.getDatabases())) {
6216
- if (delegate.closed) {
6217
- lc.debug?.("Exiting early due to close:", stepDescription);
6218
- return true;
6219
- }
6220
- if (database.replicacheName === delegate.name && database.name !== delegate.idbName) {
6221
- switch (database.replicacheFormatVersion) {
6222
- case SDD:
6223
- case DD31:
6224
- case V6:
6225
- case V7:
6226
- await recoverMutationsWithNewPerdag(
6227
- database,
6228
- this.#options,
6229
- void 0,
6230
- createStore
6231
- );
6232
- }
5667
+ await sleep(delayMs(), signal);
5668
+ } catch (e) {
5669
+ if (!(e instanceof AbortError)) {
5670
+ throw e;
5671
+ }
5672
+ }
5673
+ if (!signal.aborted) {
5674
+ lc.debug?.("Running");
5675
+ try {
5676
+ await process2();
5677
+ } catch (e) {
5678
+ if (signal.aborted) {
5679
+ lc.debug?.("Error running most likely due to close.", e);
5680
+ } else {
5681
+ lc.error?.("Error running.", e);
6233
5682
  }
6234
5683
  }
6235
- } catch (e) {
6236
- logMutationRecoveryError(e, lc, stepDescription, delegate);
6237
- } finally {
6238
- lc.debug?.("End:", stepDescription);
6239
- this.#recoveringMutations = false;
6240
5684
  }
6241
- return true;
6242
- }
6243
- };
6244
- function logMutationRecoveryError(e, lc, stepDescription, closedDelegate) {
6245
- if (closedDelegate.closed) {
6246
- lc.debug?.(
6247
- `Mutation recovery error likely due to close during:
6248
- ${stepDescription}
6249
- Error:
6250
- `,
6251
- e
6252
- );
6253
- } else {
6254
- lc.error?.(
6255
- `Mutation recovery error during:
6256
- ${stepDescription}
6257
- Error:
6258
- `,
6259
- e
6260
- );
6261
5685
  }
5686
+ lc.debug?.("Stopping");
6262
5687
  }
6263
- async function recoverMutationsOfClientV4(client, clientID, perdag, database, options, formatVersion) {
6264
- assert(database.replicacheFormatVersion === SDD);
6265
- assertClientV4(client);
6266
- const {
6267
- delegate,
6268
- lc,
6269
- wrapInOnlineCheck,
6270
- wrapInReauthRetries,
6271
- isPushDisabled,
6272
- isPullDisabled
6273
- } = options;
6274
- const selfClientID = delegate.clientID;
6275
- if (selfClientID === clientID) {
6276
- return;
6277
- }
6278
- if (client.lastServerAckdMutationID >= client.mutationID) {
6279
- return;
6280
- }
6281
- const stepDescription = `Recovering mutations for ${clientID}.`;
6282
- lc.debug?.("Start:", stepDescription);
6283
- const lazyDagForOtherClient = new LazyStore(
6284
- perdag,
6285
- MUTATION_RECOVERY_LAZY_STORE_SOURCE_CHUNK_CACHE_SIZE_LIMIT,
6286
- throwChunkHasher,
6287
- assertHash
6288
- );
6289
- try {
6290
- await withWrite(
6291
- lazyDagForOtherClient,
6292
- (write) => write.setHead(DEFAULT_HEAD_NAME, client.headHash)
6293
- );
6294
- if (isPushDisabled()) {
6295
- lc.debug?.(
6296
- `Cannot recover mutations for client ${clientID} because push is disabled.`
6297
- );
6298
- return;
6299
- }
6300
- const { pusher } = delegate;
6301
- const pushDescription = "recoveringMutationsPush";
6302
- const pushSucceeded = await wrapInOnlineCheck(async () => {
6303
- const { result: pusherResult } = await wrapInReauthRetries(
6304
- async (requestID, requestLc) => {
6305
- assertNotUndefined(lazyDagForOtherClient);
6306
- const pusherResult2 = await push(
6307
- requestID,
6308
- lazyDagForOtherClient,
6309
- requestLc,
6310
- await delegate.profileID,
6311
- void 0,
6312
- clientID,
6313
- pusher,
6314
- database.schemaVersion,
6315
- PUSH_VERSION_SDD
6316
- );
6317
- return {
6318
- result: pusherResult2,
6319
- httpRequestInfo: pusherResult2?.httpRequestInfo
6320
- };
6321
- },
6322
- pushDescription,
6323
- lc
6324
- );
6325
- return !!pusherResult && pusherResult.httpRequestInfo.httpStatusCode === 200;
6326
- }, pushDescription);
6327
- if (!pushSucceeded) {
6328
- lc.debug?.(
6329
- `Failed to recover mutations for client ${clientID} due to a push error.`
6330
- );
6331
- return;
6332
- }
6333
- if (isPullDisabled()) {
6334
- lc.debug?.(
6335
- `Cannot confirm mutations were recovered for client ${clientID} because pull is disabled.`
6336
- );
6337
- return;
6338
- }
6339
- const { puller } = delegate;
6340
- const pullDescription = "recoveringMutationsPull";
6341
- let pullResponse;
6342
- const pullSucceeded = await wrapInOnlineCheck(async () => {
6343
- const { result: beginPullResponse } = await wrapInReauthRetries(
6344
- async (requestID, requestLc) => {
6345
- const beginPullResponse2 = await beginPullV0(
6346
- await delegate.profileID,
6347
- clientID,
6348
- database.schemaVersion,
6349
- puller,
6350
- requestID,
6351
- lazyDagForOtherClient,
6352
- formatVersion,
6353
- requestLc,
6354
- false
6355
- );
6356
- return {
6357
- result: beginPullResponse2,
6358
- httpRequestInfo: beginPullResponse2.httpRequestInfo
6359
- };
6360
- },
6361
- pullDescription,
6362
- lc
6363
- );
6364
- ({ pullResponse } = beginPullResponse);
6365
- return !!pullResponse && beginPullResponse.httpRequestInfo.httpStatusCode === 200;
6366
- }, pullDescription);
6367
- if (!pullSucceeded) {
6368
- lc.debug?.(
6369
- `Failed to recover mutations for client ${clientID} due to a pull error.`
6370
- );
6371
- return;
6372
- }
6373
- if (lc.debug && pullResponse) {
6374
- if (isClientStateNotFoundResponse(pullResponse)) {
6375
- lc.debug?.(
6376
- `Client ${selfClientID} cannot recover mutations for client ${clientID}. The client no longer exists on the server.`
6377
- );
6378
- } else if (isVersionNotSupportedResponse(pullResponse)) {
6379
- lc.debug?.(
6380
- `Version is not supported on the server. versionType: ${pullResponse.versionType}. Cannot recover mutations for client ${clientID}.`
6381
- );
6382
- } else {
6383
- lc.debug?.(
6384
- `Client ${selfClientID} recovered mutations for client ${clientID}. Details`,
6385
- {
6386
- mutationID: client.mutationID,
6387
- lastServerAckdMutationID: client.lastServerAckdMutationID,
6388
- lastMutationID: pullResponse.lastMutationID
6389
- }
6390
- );
6391
- }
6392
- }
6393
- return await withWrite(perdag, async (dagWrite) => {
6394
- const clients = await getClients(dagWrite);
6395
- const clientToUpdate = clients.get(clientID);
6396
- if (!clientToUpdate) {
6397
- return clients;
6398
- }
6399
- assertClientV4(clientToUpdate);
6400
- const setNewClients = async (newClients2) => {
6401
- await setClients(newClients2, dagWrite);
6402
- return newClients2;
6403
- };
6404
- if (isClientStateNotFoundResponse(pullResponse) || // Even though SDD did not have VersionNotSupported we can still get
6405
- // this if the server was upgraded to handle this. It seems better to
6406
- // delete the client at this point.
6407
- isVersionNotSupportedResponse(pullResponse)) {
6408
- const newClients2 = new Map(clients);
6409
- newClients2.delete(clientID);
6410
- return setNewClients(newClients2);
6411
- }
6412
- assert(pullResponse);
6413
- if (clientToUpdate.lastServerAckdMutationID >= pullResponse.lastMutationID) {
6414
- return clients;
6415
- }
6416
- const newClients = new Map(clients).set(clientID, {
6417
- ...clientToUpdate,
6418
- lastServerAckdMutationID: pullResponse.lastMutationID
6419
- });
6420
- return setNewClients(newClients);
6421
- });
6422
- } catch (e) {
6423
- logMutationRecoveryError(e, lc, stepDescription, delegate);
6424
- } finally {
6425
- await lazyDagForOtherClient.close();
6426
- lc.debug?.("End:", stepDescription);
6427
- }
6428
- return;
6429
- }
6430
- async function recoverMutationsWithNewPerdag(database, options, preReadClientMap, createStore) {
6431
- const perKvStore = createStore(database.name);
6432
- const perdag = new StoreImpl(perKvStore, newRandomHash, assertHash);
6433
- try {
6434
- await recoverMutationsFromPerdag(
6435
- database,
6436
- options,
6437
- perdag,
6438
- preReadClientMap
6439
- );
6440
- } finally {
6441
- await perdag.close();
6442
- }
6443
- }
6444
- function recoverMutationsFromPerdag(database, options, perdag, preReadClientMap) {
6445
- if (database.replicacheFormatVersion >= DD31) {
6446
- return recoverMutationsFromPerdagDD31(database, options, perdag);
6447
- }
6448
- return recoverMutationsFromPerdagSDD(
6449
- database,
6450
- options,
6451
- perdag,
6452
- preReadClientMap
6453
- );
6454
- }
6455
- async function recoverMutationsFromPerdagSDD(database, options, perdag, preReadClientMap) {
6456
- const { delegate, lc } = options;
6457
- const stepDescription = `Recovering mutations from db ${database.name}.`;
6458
- lc.debug?.("Start:", stepDescription);
6459
- try {
6460
- const formatVersion = parseReplicacheFormatVersion(database.replicacheFormatVersion);
6461
- let clientMap = preReadClientMap || await withRead(perdag, (read) => getClients(read));
6462
- const clientIDsVisited = /* @__PURE__ */ new Set();
6463
- while (clientMap) {
6464
- let newClientMap;
6465
- for (const [clientID, client] of clientMap) {
6466
- if (delegate.closed) {
6467
- lc.debug?.("Exiting early due to close:", stepDescription);
6468
- return;
6469
- }
6470
- if (!clientIDsVisited.has(clientID)) {
6471
- clientIDsVisited.add(clientID);
6472
- newClientMap = await recoverMutationsOfClientV4(
6473
- client,
6474
- clientID,
6475
- perdag,
6476
- database,
6477
- options,
6478
- formatVersion
6479
- );
6480
- if (newClientMap) {
6481
- break;
6482
- }
6483
- }
6484
- }
6485
- clientMap = newClientMap;
6486
- }
6487
- } catch (e) {
6488
- logMutationRecoveryError(e, lc, stepDescription, delegate);
6489
- }
6490
- lc.debug?.("End:", stepDescription);
5688
+
5689
+ // ../replicache/src/persist/make-client-id.ts
5690
+ function makeClientID() {
5691
+ const length = 18;
5692
+ const high = randomUint64();
5693
+ const low = randomUint64();
5694
+ const combined = high << 64n | low;
5695
+ return combined.toString(32).slice(-length).padStart(length, "0");
6491
5696
  }
6492
- async function recoverMutationsFromPerdagDD31(database, options, perdag) {
6493
- const { delegate, lc } = options;
6494
- const stepDescription = `Recovering mutations from db ${database.name}.`;
6495
- lc.debug?.("Start:", stepDescription);
6496
- try {
6497
- const formatVersion = parseReplicacheFormatVersion(database.replicacheFormatVersion);
6498
- let clientGroups = await withRead(
6499
- perdag,
6500
- (read) => getClientGroups(read)
6501
- );
6502
- const clientGroupIDsVisited = /* @__PURE__ */ new Set();
6503
- while (clientGroups) {
6504
- let newClientGroups;
6505
- for (const [clientGroupID, clientGroup] of clientGroups) {
6506
- if (delegate.closed) {
6507
- lc.debug?.("Exiting early due to close:", stepDescription);
6508
- return;
6509
- }
6510
- if (!clientGroupIDsVisited.has(clientGroupID)) {
6511
- clientGroupIDsVisited.add(clientGroupID);
6512
- newClientGroups = await recoverMutationsOfClientGroupDD31(
6513
- clientGroup,
6514
- clientGroupID,
6515
- perdag,
6516
- database,
6517
- options,
6518
- formatVersion
6519
- );
6520
- if (newClientGroups) {
6521
- break;
6522
- }
6523
- }
6524
- }
6525
- clientGroups = newClientGroups;
6526
- }
6527
- } catch (e) {
6528
- logMutationRecoveryError(e, lc, stepDescription, delegate);
6529
- }
6530
- lc.debug?.("End:", stepDescription);
5697
+
5698
+ // ../replicache/src/persist/clients.ts
5699
+ var clientV4Schema = readonlyObject({
5700
+ /**
5701
+ * A UNIX timestamp in milliseconds updated by the client once a minute
5702
+ * while it is active and every time the client persists its state to
5703
+ * the perdag.
5704
+ * Should only be updated by the client represented by this structure.
5705
+ */
5706
+ heartbeatTimestampMs: valita_exports.number(),
5707
+ /**
5708
+ * The hash of the commit in the perdag this client last persisted.
5709
+ * Should only be updated by the client represented by this structure.
5710
+ */
5711
+ headHash: hashSchema,
5712
+ /**
5713
+ * The mutationID of the commit at headHash (mutationID if it is a
5714
+ * local commit, lastMutationID if it is an index change or snapshot commit).
5715
+ * Should only be updated by the client represented by this structure.
5716
+ * Read by other clients to determine if there are unacknowledged pending
5717
+ * mutations for them to push on behalf of the client represented by this
5718
+ * structure.
5719
+ * This is redundant with information in the commit graph at headHash,
5720
+ * but allows other clients to determine if there are unacknowledged pending
5721
+ * mutations without having to load the commit graph at headHash.
5722
+ */
5723
+ mutationID: valita_exports.number(),
5724
+ /**
5725
+ * The highest lastMutationID received from the server for this client.
5726
+ *
5727
+ * Should be updated by the client represented by this structure whenever
5728
+ * it persists its state to the perdag.
5729
+ * Read by other clients to determine if there are unacknowledged pending
5730
+ * mutations for them to push on behalf of the client represented by this
5731
+ * structure, and *updated* by other clients upon successfully pushing
5732
+ * pending mutations to avoid redundant pushes of those mutations.
5733
+ *
5734
+ * Note: This will be the same as the lastMutationID of the base snapshot of
5735
+ * the commit graph at headHash when written by the client represented by this
5736
+ * structure. However, when written by another client pushing pending
5737
+ * mutations on this client's behalf it will be different. This is because
5738
+ * the other client does not update the commit graph (it is unsafe to update
5739
+ * another client's commit graph).
5740
+ */
5741
+ lastServerAckdMutationID: valita_exports.number()
5742
+ });
5743
+ var clientV5Schema = readonlyObject({
5744
+ heartbeatTimestampMs: valita_exports.number(),
5745
+ headHash: hashSchema,
5746
+ /**
5747
+ * The hash of a commit we are in the middle of refreshing into this client's
5748
+ * memdag.
5749
+ */
5750
+ tempRefreshHash: hashSchema.nullable(),
5751
+ /**
5752
+ * ID of this client's perdag client group. This needs to be sent in pull
5753
+ * request (to enable syncing all last mutation ids in the client group).
5754
+ */
5755
+ clientGroupID: clientGroupIDSchema
5756
+ });
5757
+ var clientV6Schema = readonlyObject({
5758
+ heartbeatTimestampMs: valita_exports.number(),
5759
+ /**
5760
+ * A set of hashes, which contains:
5761
+ * 1. The hash of the last commit this client refreshed from its client group
5762
+ * (this is the commit it bootstrapped from until it completes its first
5763
+ * refresh).
5764
+ * 2. One or more hashes that were added to retain chunks of a commit while it
5765
+ * was being refreshed into this client's memdag. (This can be one or more
5766
+ * because refresh's cleanup step is a separate transaction and can fail).
5767
+ * Upon refresh completing and successfully running its clean up step, this
5768
+ * set will contain a single hash: the hash of the last commit this client
5769
+ * refreshed.
5770
+ */
5771
+ refreshHashes: readonlyArray(hashSchema),
5772
+ /**
5773
+ * The hash of the last snapshot commit persisted by this client to this
5774
+ * client's client group, or null if has never persisted a snapshot.
5775
+ */
5776
+ persistHash: hashSchema.nullable(),
5777
+ /**
5778
+ * ID of this client's perdag client group. This needs to be sent in pull
5779
+ * request (to enable syncing all last mutation ids in the client group).
5780
+ */
5781
+ clientGroupID: clientGroupIDSchema
5782
+ });
5783
+ function isClientV6(client) {
5784
+ return client.refreshHashes !== void 0;
6531
5785
  }
6532
- function isResponseThatShouldDisableClientGroup(response) {
6533
- return isClientStateNotFoundResponse(response) || isVersionNotSupportedResponse(response);
5786
+ function isClientV5(client) {
5787
+ return client.clientGroupID !== void 0;
6534
5788
  }
6535
- async function disableClientGroup2(lc, selfClientGroupID, clientGroupID, response, perdag) {
6536
- if (isClientStateNotFoundResponse(response)) {
6537
- lc.debug?.(
6538
- `Client group ${selfClientGroupID} cannot recover mutations for client group ${clientGroupID}. The client group is unknown on the server. Marking it as disabled.`
6539
- );
6540
- } else if (isVersionNotSupportedResponse(response)) {
6541
- lc.debug?.(
6542
- `Client group ${selfClientGroupID} cannot recover mutations for client group ${clientGroupID}. The client group's version is not supported on the server. versionType: ${response.versionType}. Marking it as disabled.`
6543
- );
6544
- }
6545
- await withWrite(
6546
- perdag,
6547
- (perdagWrite) => disableClientGroup(clientGroupID, perdagWrite)
6548
- );
5789
+ var CLIENTS_HEAD_NAME = "clients";
5790
+ var clientSchema = valita_exports.union(
5791
+ clientV4Schema,
5792
+ clientV5Schema,
5793
+ clientV6Schema
5794
+ );
5795
+ function assertClient(value) {
5796
+ assert2(value, clientSchema);
6549
5797
  }
6550
- async function recoverMutationsOfClientGroupDD31(clientGroup, clientGroupID, perdag, database, options, formatVersion) {
6551
- assert(database.replicacheFormatVersion >= DD31);
6552
- const {
6553
- delegate,
6554
- lc,
6555
- wrapInOnlineCheck,
6556
- wrapInReauthRetries,
6557
- isPushDisabled,
6558
- isPullDisabled,
6559
- clientGroupIDPromise
6560
- } = options;
6561
- const selfClientGroupID = await clientGroupIDPromise;
6562
- assertNotUndefined(selfClientGroupID);
6563
- if (selfClientGroupID === clientGroupID) {
6564
- return;
6565
- }
6566
- let clientID;
6567
- let allAckd = true;
6568
- for (const [cid, mutationID] of Object.entries(clientGroup.mutationIDs)) {
6569
- if (!clientGroup.lastServerAckdMutationIDs[cid] || clientGroup.lastServerAckdMutationIDs[cid] < mutationID) {
6570
- clientID = cid;
6571
- allAckd = false;
6572
- break;
6573
- }
6574
- }
6575
- if (allAckd) {
6576
- return;
6577
- }
6578
- if (clientGroup.disabled) {
6579
- lc.debug?.(
6580
- `Not recovering mutations for client group ${clientGroupID} because group is disabled.`
6581
- );
6582
- return;
6583
- }
6584
- const stepDescription = `Recovering mutations for client group ${clientGroupID}.`;
6585
- lc.debug?.("Start:", stepDescription);
6586
- const lazyDagForOtherClientGroup = new LazyStore(
6587
- perdag,
6588
- MUTATION_RECOVERY_LAZY_STORE_SOURCE_CHUNK_CACHE_SIZE_LIMIT,
6589
- throwChunkHasher,
6590
- assertHash
6591
- );
6592
- try {
6593
- await withWrite(
6594
- lazyDagForOtherClientGroup,
6595
- (write) => write.setHead(DEFAULT_HEAD_NAME, clientGroup.headHash)
6596
- );
6597
- if (isPushDisabled()) {
6598
- lc.debug?.(
6599
- `Cannot recover mutations for client group ${clientGroupID} because push is disabled.`
6600
- );
6601
- return;
6602
- }
6603
- const { pusher } = delegate;
6604
- const pushDescription = "recoveringMutationsPush";
6605
- const pushSucceeded = await wrapInOnlineCheck(async () => {
6606
- const { result: pusherResult } = await wrapInReauthRetries(
6607
- async (requestID, requestLc) => {
6608
- assert(clientID);
6609
- assert(lazyDagForOtherClientGroup);
6610
- const pusherResult2 = await push(
6611
- requestID,
6612
- lazyDagForOtherClientGroup,
6613
- requestLc,
6614
- await delegate.profileID,
6615
- clientGroupID,
6616
- // TODO(DD31): clientID is not needed in DD31. It is currently kept for debugging purpose.
6617
- clientID,
6618
- pusher,
6619
- database.schemaVersion,
6620
- PUSH_VERSION_DD31
6621
- );
6622
- return {
6623
- result: pusherResult2,
6624
- httpRequestInfo: pusherResult2?.httpRequestInfo
6625
- };
6626
- },
6627
- pushDescription,
6628
- lc
6629
- );
6630
- if (!pusherResult) {
6631
- return false;
6632
- }
6633
- const pusherResponse = pusherResult.response;
6634
- if (isResponseThatShouldDisableClientGroup(pusherResponse)) {
6635
- await disableClientGroup2(
6636
- lc,
6637
- selfClientGroupID,
6638
- clientGroupID,
6639
- pusherResponse,
6640
- perdag
6641
- );
6642
- return false;
5798
+ function assertClientV6(value) {
5799
+ assert2(value, clientV6Schema);
5800
+ }
5801
+ function chunkDataToClientMap(chunkData) {
5802
+ assertObject(chunkData);
5803
+ const clients = /* @__PURE__ */ new Map();
5804
+ for (const key in chunkData) {
5805
+ if (hasOwn(chunkData, key)) {
5806
+ const value = chunkData[key];
5807
+ if (value !== void 0) {
5808
+ assertClient(value);
5809
+ clients.set(key, value);
6643
5810
  }
6644
- return pusherResult.httpRequestInfo.httpStatusCode === 200;
6645
- }, pushDescription);
6646
- if (!pushSucceeded) {
6647
- lc.debug?.(
6648
- `Failed to recover mutations for client ${clientGroupID} due to a push error.`
6649
- );
6650
- return;
6651
- }
6652
- if (isPullDisabled()) {
6653
- lc.debug?.(
6654
- `Cannot confirm mutations were recovered for client ${clientGroupID} because pull is disabled.`
6655
- );
6656
- return;
6657
5811
  }
6658
- const { puller } = delegate;
6659
- const pullDescription = "recoveringMutationsPull";
6660
- let okPullResponse;
6661
- const pullSucceeded = await wrapInOnlineCheck(async () => {
6662
- const { result: beginPullResponse } = await wrapInReauthRetries(
6663
- async (requestID, requestLc) => {
6664
- assert(clientID);
6665
- const beginPullResponse2 = await beginPullV1(
6666
- await delegate.profileID,
6667
- clientID,
6668
- clientGroupID,
6669
- database.schemaVersion,
6670
- puller,
6671
- requestID,
6672
- lazyDagForOtherClientGroup,
6673
- formatVersion,
6674
- requestLc,
6675
- false
6676
- );
6677
- return {
6678
- result: beginPullResponse2,
6679
- httpRequestInfo: beginPullResponse2.httpRequestInfo
6680
- };
6681
- },
6682
- pullDescription,
6683
- lc
6684
- );
6685
- const { pullResponse } = beginPullResponse;
6686
- if (isResponseThatShouldDisableClientGroup(pullResponse)) {
6687
- await disableClientGroup2(
6688
- lc,
6689
- selfClientGroupID,
6690
- clientGroupID,
6691
- pullResponse,
6692
- perdag
6693
- );
6694
- return false;
5812
+ }
5813
+ return clients;
5814
+ }
5815
+ function clientMapToChunkData(clients, dagWrite) {
5816
+ for (const client of clients.values()) {
5817
+ if (isClientV6(client)) {
5818
+ client.refreshHashes.forEach(dagWrite.assertValidHash);
5819
+ if (client.persistHash) {
5820
+ dagWrite.assertValidHash(client.persistHash);
6695
5821
  }
6696
- if (!pullResponse || beginPullResponse.httpRequestInfo.httpStatusCode !== 200) {
6697
- return false;
5822
+ } else {
5823
+ dagWrite.assertValidHash(client.headHash);
5824
+ if (isClientV5(client) && client.tempRefreshHash) {
5825
+ dagWrite.assertValidHash(client.tempRefreshHash);
6698
5826
  }
6699
- okPullResponse = pullResponse;
6700
- return true;
6701
- }, pullDescription);
6702
- if (!pullSucceeded) {
6703
- lc.debug?.(
6704
- `Failed to recover mutations for client ${clientGroupID} due to a pull error.`
6705
- );
6706
- return;
6707
5827
  }
6708
- assert(okPullResponse);
6709
- lc.debug?.(
6710
- `Client group ${selfClientGroupID} recovered mutations for client group ${clientGroupID}. Details`,
6711
- {
6712
- mutationIDs: clientGroup.mutationIDs,
6713
- lastServerAckdMutationIDs: clientGroup.lastServerAckdMutationIDs,
6714
- lastMutationIDChanges: okPullResponse.lastMutationIDChanges
6715
- }
6716
- );
6717
- return await withWrite(perdag, async (dagWrite) => {
6718
- const clientGroups = await getClientGroups(dagWrite);
6719
- const clientGroupToUpdate = clientGroups.get(clientGroupID);
6720
- if (!clientGroupToUpdate) {
6721
- return clientGroups;
6722
- }
6723
- assert(okPullResponse);
6724
- const lastServerAckdMutationIDsUpdates = {};
6725
- let anyMutationIDsUpdated = false;
6726
- for (const [clientID2, lastMutationIDChange] of Object.entries(
6727
- okPullResponse.lastMutationIDChanges
6728
- )) {
6729
- if ((clientGroupToUpdate.lastServerAckdMutationIDs[clientID2] ?? 0) < lastMutationIDChange) {
6730
- lastServerAckdMutationIDsUpdates[clientID2] = lastMutationIDChange;
6731
- anyMutationIDsUpdated = true;
6732
- }
6733
- }
6734
- if (!anyMutationIDsUpdated) {
6735
- return clientGroups;
6736
- }
6737
- const newClientGroups = new Map(clientGroups).set(clientGroupID, {
6738
- ...clientGroupToUpdate,
6739
- lastServerAckdMutationIDs: {
6740
- ...clientGroupToUpdate.lastServerAckdMutationIDs,
6741
- ...lastServerAckdMutationIDsUpdates
6742
- }
6743
- });
6744
- await setClientGroups(newClientGroups, dagWrite);
6745
- return newClientGroups;
6746
- });
6747
- } catch (e) {
6748
- logMutationRecoveryError(e, lc, stepDescription, delegate);
6749
- } finally {
6750
- await lazyDagForOtherClientGroup.close();
6751
- lc.debug?.("End:", stepDescription);
6752
5828
  }
6753
- return;
5829
+ return deepFreeze(Object.fromEntries(clients));
6754
5830
  }
6755
-
6756
- // ../replicache/src/broadcast-channel.ts
6757
- var NoopBroadcastChannel = class {
6758
- name;
6759
- onmessage = null;
6760
- onmessageerror = null;
6761
- constructor(name) {
6762
- this.name = name;
6763
- }
6764
- addEventListener() {
6765
- }
6766
- removeEventListener() {
5831
+ async function getClients(dagRead) {
5832
+ const hash2 = await dagRead.getHead(CLIENTS_HEAD_NAME);
5833
+ return getClientsAtHash(hash2, dagRead);
5834
+ }
5835
+ async function getClientsAtHash(hash2, dagRead) {
5836
+ if (!hash2) {
5837
+ return /* @__PURE__ */ new Map();
6767
5838
  }
6768
- dispatchEvent() {
6769
- return false;
5839
+ const chunk = await dagRead.getChunk(hash2);
5840
+ return chunkDataToClientMap(chunk?.data);
5841
+ }
5842
+ var ClientStateNotFoundError = class extends Error {
5843
+ name = "ClientStateNotFoundError";
5844
+ id;
5845
+ constructor(id) {
5846
+ super(`Client state not found, id: ${id}`);
5847
+ this.id = id;
6770
5848
  }
6771
- close() {
5849
+ };
5850
+ async function assertHasClientState(id, dagRead) {
5851
+ if (!await hasClientState(id, dagRead)) {
5852
+ throw new ClientStateNotFoundError(id);
6772
5853
  }
6773
- postMessage() {
5854
+ }
5855
+ async function hasClientState(id, dagRead) {
5856
+ return !!await getClient(id, dagRead);
5857
+ }
5858
+ async function getClient(id, dagRead) {
5859
+ const clients = await getClients(dagRead);
5860
+ return clients.get(id);
5861
+ }
5862
+ async function mustGetClient(id, dagRead) {
5863
+ const client = await getClient(id, dagRead);
5864
+ if (!client) {
5865
+ throw new ClientStateNotFoundError(id);
6774
5866
  }
6775
- };
6776
- var bc = typeof BroadcastChannel === "undefined" ? NoopBroadcastChannel : BroadcastChannel;
6777
-
6778
- // ../replicache/src/new-client-channel.ts
6779
- function makeChannelNameV0(replicacheName) {
6780
- return `replicache-new-client-group:${replicacheName}`;
5867
+ return client;
6781
5868
  }
6782
- function makeChannelNameV1(replicacheName) {
6783
- return `replicache-new-client-group-v1:${replicacheName}`;
5869
+ function initClientV6(newClientID, lc, perdag, mutatorNames, indexes, formatVersion, enableClientGroupForking) {
5870
+ return withWriteNoImplicitCommit(perdag, async (dagWrite) => {
5871
+ async function setClientsAndClientGroupAndCommit(basisHash, cookieJSON, valueHash2, indexRecords2) {
5872
+ const newSnapshotData = newSnapshotCommitDataDD31(
5873
+ basisHash,
5874
+ {},
5875
+ cookieJSON,
5876
+ valueHash2,
5877
+ indexRecords2
5878
+ );
5879
+ const chunk = dagWrite.createChunk(
5880
+ newSnapshotData,
5881
+ getRefs(newSnapshotData)
5882
+ );
5883
+ const newClientGroupID = makeClientID();
5884
+ const newClient = {
5885
+ heartbeatTimestampMs: Date.now(),
5886
+ refreshHashes: [chunk.hash],
5887
+ persistHash: null,
5888
+ clientGroupID: newClientGroupID
5889
+ };
5890
+ const newClients = new Map(clients).set(newClientID, newClient);
5891
+ const clientGroup = {
5892
+ headHash: chunk.hash,
5893
+ mutatorNames,
5894
+ indexes,
5895
+ mutationIDs: {},
5896
+ lastServerAckdMutationIDs: {},
5897
+ disabled: false
5898
+ };
5899
+ await Promise.all([
5900
+ dagWrite.putChunk(chunk),
5901
+ setClients(newClients, dagWrite),
5902
+ setClientGroup(newClientGroupID, clientGroup, dagWrite)
5903
+ ]);
5904
+ await dagWrite.commit();
5905
+ return [newClient, chunk.hash, newClients, true];
5906
+ }
5907
+ const clients = await getClients(dagWrite);
5908
+ const res = await findMatchingClient(dagWrite, mutatorNames, indexes);
5909
+ if (res.type === FIND_MATCHING_CLIENT_TYPE_HEAD) {
5910
+ const { clientGroupID, headHash } = res;
5911
+ const newClient = {
5912
+ clientGroupID,
5913
+ refreshHashes: [headHash],
5914
+ heartbeatTimestampMs: Date.now(),
5915
+ persistHash: null
5916
+ };
5917
+ const newClients = new Map(clients).set(newClientID, newClient);
5918
+ await setClients(newClients, dagWrite);
5919
+ await dagWrite.commit();
5920
+ return [newClient, headHash, newClients, false];
5921
+ }
5922
+ if (!enableClientGroupForking || res.type === FIND_MATCHING_CLIENT_TYPE_NEW) {
5923
+ const emptyBTreeChunk = dagWrite.createChunk(emptyDataNode, []);
5924
+ await dagWrite.putChunk(emptyBTreeChunk);
5925
+ const indexRecords2 = [];
5926
+ for (const [name, indexDefinition] of Object.entries(indexes)) {
5927
+ const chunkIndexDefinition = toChunkIndexDefinition(
5928
+ name,
5929
+ indexDefinition
5930
+ );
5931
+ indexRecords2.push({
5932
+ definition: chunkIndexDefinition,
5933
+ valueHash: emptyBTreeChunk.hash
5934
+ });
5935
+ }
5936
+ return setClientsAndClientGroupAndCommit(
5937
+ null,
5938
+ null,
5939
+ emptyBTreeChunk.hash,
5940
+ indexRecords2
5941
+ );
5942
+ }
5943
+ assert(res.type === FIND_MATCHING_CLIENT_TYPE_FORK);
5944
+ const { snapshot } = res;
5945
+ const indexRecords = [];
5946
+ const { valueHash, indexes: oldIndexes } = snapshot;
5947
+ const map = new BTreeRead(dagWrite, formatVersion, valueHash);
5948
+ for (const [name, indexDefinition] of Object.entries(indexes)) {
5949
+ const { prefix = "", jsonPointer, allowEmpty = false } = indexDefinition;
5950
+ const chunkIndexDefinition = {
5951
+ name,
5952
+ keyPrefix: prefix,
5953
+ jsonPointer,
5954
+ allowEmpty
5955
+ };
5956
+ const oldIndex = findMatchingOldIndex(oldIndexes, chunkIndexDefinition);
5957
+ if (oldIndex) {
5958
+ indexRecords.push({
5959
+ definition: chunkIndexDefinition,
5960
+ valueHash: oldIndex.valueHash
5961
+ });
5962
+ } else {
5963
+ const indexBTree = await createIndexBTree(
5964
+ lc,
5965
+ dagWrite,
5966
+ map,
5967
+ prefix,
5968
+ jsonPointer,
5969
+ allowEmpty,
5970
+ formatVersion
5971
+ );
5972
+ indexRecords.push({
5973
+ definition: chunkIndexDefinition,
5974
+ valueHash: await indexBTree.flush()
5975
+ });
5976
+ }
5977
+ }
5978
+ return setClientsAndClientGroupAndCommit(
5979
+ snapshot.meta.basisHash,
5980
+ snapshot.meta.cookieJSON,
5981
+ snapshot.valueHash,
5982
+ indexRecords
5983
+ );
5984
+ });
6784
5985
  }
6785
- function isNewClientChannelMessageV1(message) {
6786
- return typeof message === "object" && typeof message.clientGroupID === "string" && typeof message.idbName === "string";
5986
+ function findMatchingOldIndex(oldIndexes, chunkIndexDefinition) {
5987
+ return oldIndexes.find(
5988
+ (index) => chunkIndexDefinitionEqualIgnoreName(index.definition, chunkIndexDefinition)
5989
+ );
6787
5990
  }
6788
- function initNewClientChannel(replicacheName, idbName, signal, clientGroupID, isNewClientGroup, onUpdateNeeded, perdag) {
6789
- if (signal.aborted) {
6790
- return;
5991
+ var FIND_MATCHING_CLIENT_TYPE_NEW = 0;
5992
+ var FIND_MATCHING_CLIENT_TYPE_FORK = 1;
5993
+ var FIND_MATCHING_CLIENT_TYPE_HEAD = 2;
5994
+ async function findMatchingClient(dagRead, mutatorNames, indexes) {
5995
+ let newestCookie;
5996
+ let bestSnapshot;
5997
+ const mutatorNamesSet = new Set(mutatorNames);
5998
+ const clientGroups = await getClientGroups(dagRead);
5999
+ for (const [clientGroupID, clientGroup] of clientGroups) {
6000
+ if (!clientGroup.disabled && mutatorNamesEqual(mutatorNamesSet, clientGroup.mutatorNames) && indexDefinitionsEqual(indexes, clientGroup.indexes)) {
6001
+ return {
6002
+ type: FIND_MATCHING_CLIENT_TYPE_HEAD,
6003
+ clientGroupID,
6004
+ headHash: clientGroup.headHash
6005
+ };
6006
+ }
6007
+ const clientGroupSnapshotCommit = await baseSnapshotFromHash(
6008
+ clientGroup.headHash,
6009
+ dagRead
6010
+ );
6011
+ assertSnapshotCommitDD31(clientGroupSnapshotCommit);
6012
+ const { cookieJSON } = clientGroupSnapshotCommit.meta;
6013
+ if (newestCookie === void 0 || compareCookies(cookieJSON, newestCookie) > 0) {
6014
+ newestCookie = cookieJSON;
6015
+ bestSnapshot = clientGroupSnapshotCommit;
6016
+ }
6791
6017
  }
6792
- const channelV1 = new bc(makeChannelNameV1(replicacheName));
6793
- if (isNewClientGroup) {
6794
- channelV1.postMessage({ clientGroupID, idbName });
6795
- const channelV0 = new bc(makeChannelNameV0(replicacheName));
6796
- channelV0.postMessage([clientGroupID]);
6797
- channelV0.close();
6018
+ if (bestSnapshot) {
6019
+ return {
6020
+ type: FIND_MATCHING_CLIENT_TYPE_FORK,
6021
+ snapshot: bestSnapshot
6022
+ };
6798
6023
  }
6799
- channelV1.onmessage = async (e) => {
6800
- const { data } = e;
6801
- if (isNewClientChannelMessageV1(data)) {
6802
- const { clientGroupID: newClientGroupID, idbName: newClientIDBName } = data;
6803
- if (newClientGroupID !== clientGroupID) {
6804
- if (newClientIDBName === idbName) {
6805
- const updateNeeded = await withRead(
6806
- perdag,
6807
- async (perdagRead) => await getClientGroup(newClientGroupID, perdagRead) !== void 0
6808
- );
6809
- if (updateNeeded) {
6810
- onUpdateNeeded();
6811
- }
6812
- } else {
6813
- onUpdateNeeded();
6814
- return;
6815
- }
6024
+ return { type: FIND_MATCHING_CLIENT_TYPE_NEW };
6025
+ }
6026
+ function getRefsForClients(clients) {
6027
+ const refs = /* @__PURE__ */ new Set();
6028
+ for (const client of clients.values()) {
6029
+ if (isClientV6(client)) {
6030
+ for (const hash2 of client.refreshHashes) {
6031
+ refs.add(hash2);
6032
+ }
6033
+ if (client.persistHash) {
6034
+ refs.add(client.persistHash);
6035
+ }
6036
+ } else {
6037
+ refs.add(client.headHash);
6038
+ if (isClientV5(client) && client.tempRefreshHash) {
6039
+ refs.add(client.tempRefreshHash);
6816
6040
  }
6817
6041
  }
6818
- };
6819
- signal.addEventListener("abort", () => channelV1.close(), { once: true });
6820
- }
6821
-
6822
- // ../replicache/src/on-persist-channel.ts
6823
- function makeChannelName(replicacheName) {
6824
- return `replicache-on-persist:${replicacheName}`;
6825
- }
6826
- function assertPersistInfo(value) {
6827
- assertObject(value);
6828
- assertString(value.clientGroupID);
6829
- assertString(value.clientID);
6042
+ }
6043
+ return toRefs(refs);
6830
6044
  }
6831
- function initOnPersistChannel(replicacheName, signal, handlePersist) {
6832
- if (signal.aborted) {
6833
- return () => void 0;
6045
+ async function getClientGroupForClient(clientID, read) {
6046
+ const clientGroupID = await getClientGroupIDForClient(clientID, read);
6047
+ if (!clientGroupID) {
6048
+ return void 0;
6834
6049
  }
6835
- const channel = new bc(makeChannelName(replicacheName));
6836
- channel.onmessage = (e) => {
6837
- const { data } = e;
6838
- assertPersistInfo(data);
6839
- handlePersist({
6840
- clientGroupID: data.clientGroupID,
6841
- clientID: data.clientID
6842
- });
6843
- };
6844
- signal.addEventListener("abort", () => channel.close(), { once: true });
6845
- return (persistInfo) => {
6846
- if (signal.aborted) {
6847
- return;
6848
- }
6849
- channel.postMessage(persistInfo);
6850
- handlePersist(persistInfo);
6851
- };
6050
+ return getClientGroup(clientGroupID, read);
6852
6051
  }
6853
-
6854
- // ../replicache/src/pending-mutations.ts
6855
- async function pendingMutationsForAPI(dagRead) {
6856
- const mainHeadHash = await mustGetHeadHash(DEFAULT_HEAD_NAME, dagRead);
6857
- const pending = await localMutationsDD31(mainHeadHash, dagRead);
6858
- return pending.map((p) => ({
6859
- id: p.meta.mutationID,
6860
- name: p.meta.mutatorName,
6861
- args: p.meta.mutatorArgsJSON,
6862
- clientID: p.meta.clientID
6863
- })).reverse();
6052
+ async function getClientGroupIDForClient(clientID, read) {
6053
+ const client = await getClient(clientID, read);
6054
+ if (!client || !isClientV5(client)) {
6055
+ return void 0;
6056
+ }
6057
+ return client.clientGroupID;
6864
6058
  }
6865
-
6866
- // ../replicache/src/bg-interval.ts
6867
- function initBgIntervalProcess(processName, process2, delayMs, lc, signal) {
6868
- void runBgIntervalProcess(processName, process2, delayMs, lc, signal);
6059
+ async function setClient(clientID, client, dagWrite) {
6060
+ const clients = await getClients(dagWrite);
6061
+ const newClients = new Map(clients).set(clientID, client);
6062
+ return setClients(newClients, dagWrite);
6869
6063
  }
6870
- async function runBgIntervalProcess(processName, process2, delayMs, lc, signal) {
6871
- if (signal.aborted) {
6872
- return;
6873
- }
6874
- lc = lc.withContext("bgIntervalProcess", processName);
6875
- lc.debug?.("Starting");
6876
- while (!signal.aborted) {
6877
- try {
6878
- await sleep(delayMs(), signal);
6879
- } catch (e) {
6880
- if (!(e instanceof AbortError)) {
6881
- throw e;
6882
- }
6883
- }
6884
- if (!signal.aborted) {
6885
- lc.debug?.("Running");
6886
- try {
6887
- await process2();
6888
- } catch (e) {
6889
- if (signal.aborted) {
6890
- lc.debug?.("Error running most likely due to close.", e);
6891
- } else {
6892
- lc.error?.("Error running.", e);
6893
- }
6894
- }
6895
- }
6896
- }
6897
- lc.debug?.("Stopping");
6064
+ async function setClients(clients, dagWrite) {
6065
+ const chunkData = clientMapToChunkData(clients, dagWrite);
6066
+ const chunk = dagWrite.createChunk(chunkData, getRefsForClients(clients));
6067
+ await dagWrite.putChunk(chunk);
6068
+ await dagWrite.setHead(CLIENTS_HEAD_NAME, chunk.hash);
6069
+ return chunk.hash;
6898
6070
  }
6899
6071
 
6900
6072
  // ../replicache/src/persist/client-gc.ts
@@ -8109,14 +7281,14 @@ function diffBinarySearch(diff2, prefix, compareKey) {
8109
7281
  }
8110
7282
 
8111
7283
  // ../shared/src/random-values.ts
8112
- function getNonCryptoRandomValues(array10) {
8113
- if (array10 === null) {
7284
+ function getNonCryptoRandomValues(array9) {
7285
+ if (array9 === null) {
8114
7286
  throw new TypeError("array cannot be null");
8115
7287
  }
8116
- for (let i = 0; i < array10.length; i++) {
8117
- array10[i] = Math.floor(Math.random() * 256);
7288
+ for (let i = 0; i < array9.length; i++) {
7289
+ array9[i] = Math.floor(Math.random() * 256);
8118
7290
  }
8119
- return array10;
7291
+ return array9;
8120
7292
  }
8121
7293
 
8122
7294
  // ../replicache/src/sync/request-id.ts
@@ -8427,7 +7599,7 @@ var ReplicacheImpl = class {
8427
7599
  await closingInstances.get(this.name);
8428
7600
  await this.#idbDatabases.getProfileID().then(profileIDResolver);
8429
7601
  await this.#idbDatabases.putDatabase(this.#idbDatabase);
8430
- const [client, headHash, clients, isNewClientGroup] = await initClientV6(
7602
+ const [client, headHash, , isNewClientGroup] = await initClientV6(
8431
7603
  clientID,
8432
7604
  this.#lc,
8433
7605
  this.perdag,
@@ -8492,7 +7664,7 @@ var ReplicacheImpl = class {
8492
7664
  RECOVER_MUTATIONS_INTERVAL_MS,
8493
7665
  signal
8494
7666
  );
8495
- void this.recoverMutations(clients);
7667
+ void this.recoverMutations();
8496
7668
  getBrowserGlobal("document")?.addEventListener(
8497
7669
  "visibilitychange",
8498
7670
  this.#onVisibilityChange
@@ -9209,9 +8381,8 @@ var ReplicacheImpl = class {
9209
8381
  }
9210
8382
  return ex;
9211
8383
  }
9212
- recoverMutations(preReadClientMap) {
8384
+ recoverMutations() {
9213
8385
  const result = this.#mutationRecovery.recoverMutations(
9214
- preReadClientMap,
9215
8386
  this.#ready,
9216
8387
  this.perdag,
9217
8388
  this.#idbDatabase,
@@ -9304,9 +8475,9 @@ __export(column_exports, {
9304
8475
  enumeration: () => enumeration,
9305
8476
  json: () => json,
9306
8477
  number: () => number4,
9307
- string: () => string7
8478
+ string: () => string6
9308
8479
  });
9309
- function string7(optional) {
8480
+ function string6(optional) {
9310
8481
  return {
9311
8482
  type: "string",
9312
8483
  optional: optional ?? false,
@@ -9355,8 +8526,8 @@ function isJunctionRelationship(relationship) {
9355
8526
  }
9356
8527
 
9357
8528
  // ../shared/src/sorted-entries.ts
9358
- function sortedEntries(object18) {
9359
- return Object.entries(object18).sort((a, b) => stringCompare(a[0], b[0]));
8529
+ function sortedEntries(object17) {
8530
+ return Object.entries(object17).sort((a, b) => stringCompare(a[0], b[0]));
9360
8531
  }
9361
8532
 
9362
8533
  // ../zero-schema/src/normalize-table-schema.ts
@@ -9365,32 +8536,37 @@ var NormalizedTableSchema = class {
9365
8536
  primaryKey;
9366
8537
  columns;
9367
8538
  relationships;
9368
- constructor(tableSchema, tableSchemaCache) {
8539
+ constructor(tableSchema, tableSchemaCache, assertFieldRelation) {
9369
8540
  this.tableName = tableSchema.tableName;
9370
8541
  const primaryKey = normalizePrimaryKey(tableSchema.primaryKey);
9371
8542
  this.primaryKey = primaryKey;
9372
8543
  this.columns = normalizeColumns(tableSchema.columns, primaryKey);
9373
8544
  tableSchemaCache.set(tableSchema, this);
9374
8545
  this.relationships = normalizeRelationships(
8546
+ this.tableName,
9375
8547
  tableSchema.relationships,
9376
- tableSchemaCache
8548
+ tableSchemaCache,
8549
+ assertFieldRelation
9377
8550
  );
9378
8551
  }
9379
8552
  };
8553
+ var noop3 = () => {
8554
+ };
9380
8555
  function normalizeTableSchema(tableSchema) {
9381
8556
  return normalizeTableSchemaWithCache(
9382
8557
  tableSchema,
9383
8558
  tableSchema.tableName,
9384
- /* @__PURE__ */ new Map()
8559
+ /* @__PURE__ */ new Map(),
8560
+ noop3
9385
8561
  );
9386
8562
  }
9387
- function normalizeTableSchemaWithCache(tableSchema, expectedName, tableSchemaCache) {
8563
+ function normalizeTableSchemaWithCache(tableSchema, expectedTableName, tableSchemaCache, assertFieldRelation) {
9388
8564
  if (tableSchema instanceof NormalizedTableSchema) {
9389
8565
  return tableSchema;
9390
8566
  }
9391
8567
  assert(
9392
- tableSchema.tableName === expectedName,
9393
- `Table name mismatch: "${tableSchema.tableName}" !== "${expectedName}"`
8568
+ tableSchema.tableName === expectedTableName,
8569
+ `Table name mismatch: "${tableSchema.tableName}" !== "${expectedTableName}"`
9394
8570
  );
9395
8571
  let normalizedTableSchema = tableSchemaCache.get(tableSchema);
9396
8572
  if (normalizedTableSchema) {
@@ -9398,7 +8574,8 @@ function normalizeTableSchemaWithCache(tableSchema, expectedName, tableSchemaCac
9398
8574
  }
9399
8575
  normalizedTableSchema = new NormalizedTableSchema(
9400
8576
  tableSchema,
9401
- tableSchemaCache
8577
+ tableSchemaCache,
8578
+ assertFieldRelation
9402
8579
  );
9403
8580
  return normalizedTableSchema;
9404
8581
  }
@@ -9443,50 +8620,86 @@ function normalizeColumn(value) {
9443
8620
  optional: value.optional ?? false
9444
8621
  };
9445
8622
  }
9446
- function normalizeRelationships(relationships, tableSchemaCache) {
8623
+ function normalizeRelationships(tableName, relationships, tableSchemaCache, assertFieldRelation) {
9447
8624
  const rv = {};
9448
8625
  if (relationships) {
9449
- for (const [name, relationship] of sortedEntries(relationships)) {
9450
- rv[name] = normalizeRelationship(relationship, tableSchemaCache);
8626
+ for (const [relationshipName, relationship] of sortedEntries(
8627
+ relationships
8628
+ )) {
8629
+ rv[relationshipName] = normalizeRelationship(
8630
+ tableName,
8631
+ relationshipName,
8632
+ relationship,
8633
+ tableSchemaCache,
8634
+ assertFieldRelation
8635
+ );
9451
8636
  }
9452
8637
  }
9453
8638
  return rv;
9454
8639
  }
9455
- function normalizeRelationship(relationship, tableSchemaCache) {
8640
+ function normalizeRelationship(tableName, relationshipName, relationship, tableSchemaCache, assertFieldRelation) {
9456
8641
  if (isFieldRelationship(relationship)) {
9457
- return normalizeFieldRelationship(relationship, tableSchemaCache);
8642
+ return normalizeFieldRelationship(
8643
+ tableName,
8644
+ relationshipName,
8645
+ relationship,
8646
+ tableSchemaCache,
8647
+ assertFieldRelation
8648
+ );
9458
8649
  }
9459
- return normalizeJunctionRelationship(relationship, tableSchemaCache);
8650
+ return normalizeJunctionRelationship(
8651
+ tableName,
8652
+ relationshipName,
8653
+ relationship,
8654
+ tableSchemaCache,
8655
+ assertFieldRelation
8656
+ );
9460
8657
  }
9461
- function normalizeFieldRelationship(relationship, tableSchemaCache) {
8658
+ function normalizeFieldRelationship(tableName, relationshipName, relationship, tableSchemaCache, assertFieldRelation) {
9462
8659
  const sourceField = normalizeFieldName(relationship.sourceField);
9463
8660
  const destField = normalizeFieldName(relationship.destField);
9464
8661
  assert(
9465
8662
  sourceField.length === destField.length,
9466
8663
  "Source and destination fields must have the same length"
9467
8664
  );
9468
- return {
8665
+ const destSchema = normalizeLazyTableSchema(
8666
+ relationship.destSchema,
8667
+ tableSchemaCache,
8668
+ assertFieldRelation
8669
+ );
8670
+ const normalized = {
9469
8671
  sourceField,
9470
8672
  destField,
9471
- destSchema: normalizeLazyTableSchema(
9472
- relationship.destSchema,
9473
- tableSchemaCache
9474
- )
8673
+ destSchema
9475
8674
  };
8675
+ assertFieldRelation(tableName, relationshipName, normalized);
8676
+ return normalized;
9476
8677
  }
9477
- function normalizeJunctionRelationship(relationship, tableSchemaCache) {
9478
- return [
9479
- normalizeFieldRelationship(relationship[0], tableSchemaCache),
9480
- normalizeFieldRelationship(relationship[1], tableSchemaCache)
9481
- ];
8678
+ function normalizeJunctionRelationship(tableName, relationshipName, relationship, tableSchemaCache, assertFieldRelation) {
8679
+ const first2 = normalizeFieldRelationship(
8680
+ tableName,
8681
+ relationshipName,
8682
+ relationship[0],
8683
+ tableSchemaCache,
8684
+ assertFieldRelation
8685
+ );
8686
+ const second = normalizeFieldRelationship(
8687
+ first2.destSchema.tableName,
8688
+ relationshipName,
8689
+ relationship[1],
8690
+ tableSchemaCache,
8691
+ assertFieldRelation
8692
+ );
8693
+ return [first2, second];
9482
8694
  }
9483
- function normalizeLazyTableSchema(tableSchema, buildCache) {
8695
+ function normalizeLazyTableSchema(tableSchema, buildCache, assertFieldRelation) {
9484
8696
  const tableSchemaInstance = typeof tableSchema === "function" ? tableSchema() : tableSchema;
9485
8697
  return normalizeTableSchemaWithCache(
9486
8698
  tableSchemaInstance,
9487
8699
  tableSchemaInstance.tableName,
9488
8700
  // Don't care about name here.
9489
- buildCache
8701
+ buildCache,
8702
+ assertFieldRelation
9490
8703
  );
9491
8704
  }
9492
8705
  function normalizeFieldName(sourceField) {
@@ -9498,18 +8711,29 @@ function normalizeFieldName(sourceField) {
9498
8711
  }
9499
8712
  function normalizeTables(tables) {
9500
8713
  const result = {};
8714
+ const assertFieldRelation = (tableName) => tableName in tables;
9501
8715
  for (const [name, table] of sortedEntries(tables)) {
9502
- result[name] = normalizeTableSchemaWithCache(table, name, /* @__PURE__ */ new Map());
8716
+ result[name] = normalizeTableSchemaWithCache(
8717
+ table,
8718
+ name,
8719
+ /* @__PURE__ */ new Map(),
8720
+ assertFieldRelation
8721
+ );
9503
8722
  }
9504
8723
  return result;
9505
8724
  }
9506
8725
 
9507
8726
  // ../zero-schema/src/normalized-schema.ts
8727
+ var normalizedCache = /* @__PURE__ */ new WeakMap();
9508
8728
  function normalizeSchema(schema) {
9509
8729
  if (schema instanceof NormalizedSchema) {
9510
8730
  return schema;
9511
8731
  }
9512
- return new NormalizedSchema(schema);
8732
+ let s;
8733
+ if (!(s = normalizedCache.get(schema))) {
8734
+ normalizedCache.set(schema, s = new NormalizedSchema(schema));
8735
+ }
8736
+ return s;
9513
8737
  }
9514
8738
  var NormalizedSchema = class {
9515
8739
  version;
@@ -9522,8 +8746,30 @@ var NormalizedSchema = class {
9522
8746
  function normalizeTables2(tables) {
9523
8747
  const rv = {};
9524
8748
  const tableSchemaCache = /* @__PURE__ */ new Map();
8749
+ function assertFieldRelation(tableName, relationShipName, relation) {
8750
+ const destTableName = relation.destSchema.tableName;
8751
+ assert(
8752
+ destTableName in tables,
8753
+ `Relationship "${tableName}"."${relationShipName}" destination "${destTableName}" is missing in schema`
8754
+ );
8755
+ assertColumns(relation.sourceField, tables[tableName]);
8756
+ assertColumns(relation.destField, tables[destTableName]);
8757
+ }
8758
+ function assertColumns(columnNames, table) {
8759
+ for (const columnName of columnNames) {
8760
+ assert(
8761
+ columnName in table.columns,
8762
+ `Column "${columnName}" is missing in table "${table.tableName}"`
8763
+ );
8764
+ }
8765
+ }
9525
8766
  for (const [name, table] of sortedEntries(tables)) {
9526
- rv[name] = normalizeTableSchemaWithCache(table, name, tableSchemaCache);
8767
+ rv[name] = normalizeTableSchemaWithCache(
8768
+ table,
8769
+ name,
8770
+ tableSchemaCache,
8771
+ assertFieldRelation
8772
+ );
9527
8773
  }
9528
8774
  return rv;
9529
8775
  }
@@ -9941,8 +9187,8 @@ var negateOperatorMap = {
9941
9187
  function negateOperator(op) {
9942
9188
  return must(negateOperatorMap[op]);
9943
9189
  }
9944
- function filterUndefined(array10) {
9945
- return array10.filter((e) => e !== void 0);
9190
+ function filterUndefined(array9) {
9191
+ return array9.filter((e) => e !== void 0);
9946
9192
  }
9947
9193
  function filterTrue(conditions) {
9948
9194
  return conditions.filter((c) => !isAlwaysTrue(c));
@@ -10013,8 +9259,8 @@ function compareValues(a, b) {
10013
9259
  }
10014
9260
  throw new Error(`Unsupported type: ${a}`);
10015
9261
  }
10016
- function normalizeUndefined(v2) {
10017
- return v2 ?? null;
9262
+ function normalizeUndefined(v) {
9263
+ return v ?? null;
10018
9264
  }
10019
9265
  function makeComparator(order, reverse) {
10020
9266
  return (a, b) => {
@@ -10042,8 +9288,8 @@ function* take(stream, limit) {
10042
9288
  return;
10043
9289
  }
10044
9290
  let count = 0;
10045
- for (const v2 of stream) {
10046
- yield v2;
9291
+ for (const v of stream) {
9292
+ yield v;
10047
9293
  if (++count === limit) {
10048
9294
  break;
10049
9295
  }
@@ -12244,9 +11490,9 @@ var QueryImpl = class extends AbstractQuery {
12244
11490
  return view;
12245
11491
  }
12246
11492
  run() {
12247
- const v2 = this.materialize();
12248
- const ret = v2.data;
12249
- v2.destroy();
11493
+ const v = this.materialize();
11494
+ const ret = v.data;
11495
+ v.destroy();
12250
11496
  return ret;
12251
11497
  }
12252
11498
  preload() {
@@ -12285,12 +11531,12 @@ function addPrimaryKeysToAst(schema, ast) {
12285
11531
  };
12286
11532
  }
12287
11533
  function arrayViewFactory(_query, input, format, onDestroy, onTransactionCommit, queryComplete) {
12288
- const v2 = new ArrayView(input, format, queryComplete);
12289
- v2.onDestroy = onDestroy;
11534
+ const v = new ArrayView(input, format, queryComplete);
11535
+ v.onDestroy = onDestroy;
12290
11536
  onTransactionCommit(() => {
12291
- v2.flush();
11537
+ v.flush();
12292
11538
  });
12293
- return v2;
11539
+ return v;
12294
11540
  }
12295
11541
 
12296
11542
  // ../zql/src/query/auth-query.ts
@@ -12432,12 +11678,7 @@ var preMutationRowRef = baseTracker("preMutationRow");
12432
11678
 
12433
11679
  // ../zero-schema/src/schema.ts
12434
11680
  function createSchema(schema) {
12435
- for (const [tableName, table] of Object.entries(schema.tables)) {
12436
- assert(
12437
- tableName === table.tableName,
12438
- `createSchema tableName mismatch, expected ${tableName} === ${table.tableName}`
12439
- );
12440
- }
11681
+ normalizeSchema(schema);
12441
11682
  return schema;
12442
11683
  }
12443
11684
 
@@ -12896,7 +12137,7 @@ var BTree = class _BTree {
12896
12137
  forEach(callback, thisArg) {
12897
12138
  if (thisArg !== void 0)
12898
12139
  callback = callback.bind(thisArg);
12899
- return this.forEachPair((k, v2) => callback(v2, k, this));
12140
+ return this.forEachPair((k, v) => callback(v, k, this));
12900
12141
  }
12901
12142
  /** Runs a function for each key-value pair, in order from smallest to
12902
12143
  * largest key. The callback can return {break:R} (where R is any value
@@ -13021,8 +12262,8 @@ var BTree = class _BTree {
13021
12262
  filter(callback, returnThisIfUnchanged) {
13022
12263
  var nu = this.greedyClone();
13023
12264
  var del;
13024
- nu.editAll((k, v2, i) => {
13025
- if (!callback(k, v2, i))
12265
+ nu.editAll((k, v, i) => {
12266
+ if (!callback(k, v, i))
13026
12267
  return del = Delete;
13027
12268
  return void 0;
13028
12269
  });
@@ -13034,8 +12275,8 @@ var BTree = class _BTree {
13034
12275
  mapValues(callback) {
13035
12276
  var tmp = {};
13036
12277
  var nu = this.greedyClone();
13037
- nu.editAll((k, v2, i) => {
13038
- return tmp.value = callback(v2, k, i), tmp;
12278
+ nu.editAll((k, v, i) => {
12279
+ return tmp.value = callback(v, k, i), tmp;
13039
12280
  });
13040
12281
  return nu;
13041
12282
  }
@@ -13507,8 +12748,8 @@ var BTree = class _BTree {
13507
12748
  false,
13508
12749
  this,
13509
12750
  0,
13510
- (_k, v2) => {
13511
- results.push(v2);
12751
+ (_k, v) => {
12752
+ results.push(v);
13512
12753
  }
13513
12754
  );
13514
12755
  return results;
@@ -13623,8 +12864,8 @@ var BTree = class _BTree {
13623
12864
  */
13624
12865
  getRange(low, high, includeHigh, maxLength = 67108863) {
13625
12866
  var results = [];
13626
- this._root.forRange(low, high, includeHigh, false, this, 0, (k, v2) => {
13627
- results.push([k, v2]);
12867
+ this._root.forRange(low, high, includeHigh, false, this, 0, (k, v) => {
12868
+ results.push([k, v]);
13628
12869
  return results.length > maxLength ? Break : void 0;
13629
12870
  });
13630
12871
  return results;
@@ -13885,10 +13126,10 @@ var BNode = class _BNode {
13885
13126
  return reusedArray;
13886
13127
  }
13887
13128
  clone() {
13888
- var v2 = this.values;
13129
+ var v = this.values;
13889
13130
  return new _BNode(
13890
13131
  this.keys.slice(0),
13891
- v2 === undefVals ? v2 : v2.slice(0)
13132
+ v === undefVals ? v : v.slice(0)
13892
13133
  );
13893
13134
  }
13894
13135
  greedyClone(force) {
@@ -13988,24 +13229,24 @@ var BNode = class _BNode {
13988
13229
  return true;
13989
13230
  }
13990
13231
  takeFromRight(rhs) {
13991
- var v2 = this.values;
13232
+ var v = this.values;
13992
13233
  if (rhs.values === undefVals) {
13993
- if (v2 !== undefVals)
13994
- v2.push(void 0);
13234
+ if (v !== undefVals)
13235
+ v.push(void 0);
13995
13236
  } else {
13996
- v2 = this.reifyValues();
13997
- v2.push(rhs.values.shift());
13237
+ v = this.reifyValues();
13238
+ v.push(rhs.values.shift());
13998
13239
  }
13999
13240
  this.keys.push(rhs.keys.shift());
14000
13241
  }
14001
13242
  takeFromLeft(lhs) {
14002
- var v2 = this.values;
13243
+ var v = this.values;
14003
13244
  if (lhs.values === undefVals) {
14004
- if (v2 !== undefVals)
14005
- v2.unshift(void 0);
13245
+ if (v !== undefVals)
13246
+ v.unshift(void 0);
14006
13247
  } else {
14007
- v2 = this.reifyValues();
14008
- v2.unshift(lhs.values.pop());
13248
+ v = this.reifyValues();
13249
+ v.unshift(lhs.values.pop());
14009
13250
  }
14010
13251
  this.keys.unshift(lhs.keys.pop());
14011
13252
  }
@@ -15478,7 +14719,7 @@ function makeMessage(message, context, logLevel) {
15478
14719
  }
15479
14720
 
15480
14721
  // ../zero-client/src/client/version.ts
15481
- var version2 = "0.10.2025010800+ca1811";
14722
+ var version2 = "0.10.2025011100+4a1fd2";
15482
14723
 
15483
14724
  // ../zero-client/src/client/log-options.ts
15484
14725
  var LevelFilterLogSink = class {
@@ -17509,4 +16750,4 @@ export {
17509
16750
  escapeLike,
17510
16751
  Zero
17511
16752
  };
17512
- //# sourceMappingURL=chunk-PPRTDNXA.js.map
16753
+ //# sourceMappingURL=chunk-FEVIDCUL.js.map