@rocicorp/zero 1.11.0-canary.13 → 1.11.0-canary.15

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 (252) hide show
  1. package/out/analyze-query/src/analyze-cli.js +2 -2
  2. package/out/analyze-query/src/analyze-cli.js.map +1 -1
  3. package/out/ast-to-zql/src/ast-to-zql.d.ts +8 -1
  4. package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
  5. package/out/ast-to-zql/src/ast-to-zql.js +25 -25
  6. package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
  7. package/out/otel/src/log-options.d.ts +16 -0
  8. package/out/otel/src/log-options.d.ts.map +1 -1
  9. package/out/otel/src/log-options.js +54 -1
  10. package/out/otel/src/log-options.js.map +1 -1
  11. package/out/replicache/src/get-kv-store-provider.d.ts +1 -1
  12. package/out/replicache/src/get-kv-store-provider.d.ts.map +1 -1
  13. package/out/replicache/src/get-kv-store-provider.js +4 -4
  14. package/out/replicache/src/get-kv-store-provider.js.map +1 -1
  15. package/out/replicache/src/kv/idb-store.d.ts +10 -1
  16. package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
  17. package/out/replicache/src/kv/idb-store.js +18 -2
  18. package/out/replicache/src/kv/idb-store.js.map +1 -1
  19. package/out/replicache/src/kv/mem-fallback-store.d.ts +54 -0
  20. package/out/replicache/src/kv/mem-fallback-store.d.ts.map +1 -0
  21. package/out/replicache/src/kv/mem-fallback-store.js +177 -0
  22. package/out/replicache/src/kv/mem-fallback-store.js.map +1 -0
  23. package/out/replicache/src/kv/op-sqlite/store.js +3 -3
  24. package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
  25. package/out/replicache/src/kv/sqlite-store.d.ts +9 -0
  26. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
  27. package/out/replicache/src/kv/sqlite-store.js +86 -6
  28. package/out/replicache/src/kv/sqlite-store.js.map +1 -1
  29. package/out/replicache/src/new-client-channel.js.map +1 -1
  30. package/out/replicache/src/persist/collect-idb-databases.d.ts +17 -3
  31. package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
  32. package/out/replicache/src/persist/collect-idb-databases.js +81 -11
  33. package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
  34. package/out/replicache/src/persist/idb-databases-store-db-name.js +1 -1
  35. package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
  36. package/out/replicache/src/persist/persist.d.ts.map +1 -1
  37. package/out/replicache/src/persist/persist.js +6 -3
  38. package/out/replicache/src/persist/persist.js.map +1 -1
  39. package/out/replicache/src/replicache-impl.d.ts +43 -3
  40. package/out/replicache/src/replicache-impl.d.ts.map +1 -1
  41. package/out/replicache/src/replicache-impl.js +135 -17
  42. package/out/replicache/src/replicache-impl.js.map +1 -1
  43. package/out/replicache/src/storage-failure.d.ts +37 -0
  44. package/out/replicache/src/storage-failure.d.ts.map +1 -0
  45. package/out/replicache/src/storage-failure.js +31 -0
  46. package/out/replicache/src/storage-failure.js.map +1 -0
  47. package/out/shared/src/random-values.js +12 -1
  48. package/out/shared/src/random-values.js.map +1 -1
  49. package/out/zero/package.js +1 -1
  50. package/out/zero/package.js.map +1 -1
  51. package/out/zero/src/zero.js +2 -1
  52. package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
  53. package/out/zero-cache/src/config/normalize.js +1 -1
  54. package/out/zero-cache/src/config/normalize.js.map +1 -1
  55. package/out/zero-cache/src/config/zero-config.d.ts +26 -0
  56. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  57. package/out/zero-cache/src/config/zero-config.js +36 -0
  58. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  59. package/out/zero-cache/src/observability/log-throttle.d.ts +44 -0
  60. package/out/zero-cache/src/observability/log-throttle.d.ts.map +1 -0
  61. package/out/zero-cache/src/observability/log-throttle.js +76 -0
  62. package/out/zero-cache/src/observability/log-throttle.js.map +1 -0
  63. package/out/zero-cache/src/scripts/permissions.d.ts +16 -0
  64. package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
  65. package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
  66. package/out/zero-cache/src/server/runner/zero-dispatcher.js +2 -0
  67. package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
  68. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  69. package/out/zero-cache/src/server/syncer.js +20 -2
  70. package/out/zero-cache/src/server/syncer.js.map +1 -1
  71. package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
  72. package/out/zero-cache/src/services/change-source/common/backfill-manager.js +27 -15
  73. package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
  74. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +1 -0
  75. package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
  76. package/out/zero-cache/src/services/change-source/common/replica-schema.js +15 -3
  77. package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
  78. package/out/zero-cache/src/services/change-source/custom/change-source.js +2 -2
  79. package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
  80. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +9 -0
  81. package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
  82. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +204 -18
  83. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  84. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +11 -2
  85. package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
  86. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +11 -2
  87. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  88. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +68 -0
  89. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +1 -0
  90. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +141 -0
  91. package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -0
  92. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +43 -0
  93. package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
  94. package/out/zero-cache/src/services/change-source/protocol/current/data.js +10 -1
  95. package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
  96. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +57 -0
  97. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  98. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +20 -6
  99. package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
  100. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js +17 -7
  101. package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
  102. package/out/zero-cache/src/services/change-source/protocol/current.js +2 -1
  103. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +66 -0
  104. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +1 -0
  105. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js +154 -0
  106. package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -0
  107. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +50 -0
  108. package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +1 -0
  109. package/out/zero-cache/src/services/change-streamer/backfill-state.js +268 -0
  110. package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -0
  111. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +7 -6
  112. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  113. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  114. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +20 -4
  115. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  116. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +26 -1
  117. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  118. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  119. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  120. package/out/zero-cache/src/services/change-streamer/storer.js +1 -1
  121. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  122. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +88 -0
  123. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -1
  124. package/out/zero-cache/src/services/change-streamer/subscribe.js +9 -1
  125. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
  126. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +29 -0
  127. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  128. package/out/zero-cache/src/services/change-streamer/subscriber.js +34 -0
  129. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  130. package/out/zero-cache/src/services/plannerz.d.ts +159 -0
  131. package/out/zero-cache/src/services/plannerz.d.ts.map +1 -0
  132. package/out/zero-cache/src/services/plannerz.js +263 -0
  133. package/out/zero-cache/src/services/plannerz.js.map +1 -0
  134. package/out/zero-cache/src/services/replicator/change-log-cookies.js +1 -1
  135. package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
  136. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  137. package/out/zero-cache/src/services/replicator/change-processor.js +44 -12
  138. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  139. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  140. package/out/zero-cache/src/services/replicator/incremental-sync.js +4 -3
  141. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  142. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +23 -2
  143. package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -1
  144. package/out/zero-cache/src/services/replicator/schema/backfilling.js +54 -2
  145. package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
  146. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +11 -3
  147. package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
  148. package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
  149. package/out/zero-cache/src/services/replicator/write-worker.js +5 -1
  150. package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
  151. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +81 -0
  152. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +1 -0
  153. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +128 -0
  154. package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -0
  155. package/out/zero-cache/src/services/view-syncer/inspect-handler.js +1 -1
  156. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +36 -1
  157. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  158. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +362 -20
  159. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  160. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +7 -0
  161. package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +1 -0
  162. package/out/zero-cache/src/services/view-syncer/plan-warnings.js +35 -0
  163. package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -0
  164. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +25 -0
  165. package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +1 -0
  166. package/out/zero-cache/src/services/view-syncer/query-shape.js +28 -0
  167. package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -0
  168. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +77 -0
  169. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +1 -0
  170. package/out/zero-cache/src/services/view-syncer/query-stats.js +206 -0
  171. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -0
  172. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +11 -1
  173. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  174. package/out/zero-cache/src/services/view-syncer/snapshotter.js +7 -1
  175. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  176. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  177. package/out/zero-cache/src/services/view-syncer/view-syncer.js +49 -3
  178. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  179. package/out/zero-cache/src/workers/connection.js +3 -3
  180. package/out/zero-cache/src/workers/connection.js.map +1 -1
  181. package/out/zero-cache/src/workers/syncer.js +2 -2
  182. package/out/zero-cache/src/workers/syncer.js.map +1 -1
  183. package/out/zero-client/src/client/options.d.ts +29 -0
  184. package/out/zero-client/src/client/options.d.ts.map +1 -1
  185. package/out/zero-client/src/client/options.js.map +1 -1
  186. package/out/zero-client/src/client/version.js +1 -1
  187. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  188. package/out/zero-client/src/client/zero.js +8 -23
  189. package/out/zero-client/src/client/zero.js.map +1 -1
  190. package/out/zero-client/src/mod.d.ts +1 -0
  191. package/out/zero-client/src/mod.d.ts.map +1 -1
  192. package/out/zero-client/src/mod.js +1 -0
  193. package/out/zero-protocol/src/down.d.ts +2 -2
  194. package/out/zero-react/src/zero.js +1 -0
  195. package/out/zero-solid/src/zero.js +1 -0
  196. package/out/zql/src/builder/builder.d.ts +6 -0
  197. package/out/zql/src/builder/builder.d.ts.map +1 -1
  198. package/out/zql/src/builder/builder.js +4 -3
  199. package/out/zql/src/builder/builder.js.map +1 -1
  200. package/out/zql/src/ivm/memory-source.d.ts +13 -0
  201. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  202. package/out/zql/src/ivm/memory-source.js +1 -1
  203. package/out/zql/src/ivm/memory-source.js.map +1 -1
  204. package/out/zql/src/planner/planner-builder.d.ts +12 -1
  205. package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
  206. package/out/zql/src/planner/planner-builder.js +8 -1
  207. package/out/zql/src/planner/planner-builder.js.map +1 -1
  208. package/out/zql/src/planner/planner-connection.d.ts +43 -0
  209. package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
  210. package/out/zql/src/planner/planner-connection.js +31 -4
  211. package/out/zql/src/planner/planner-connection.js.map +1 -1
  212. package/out/zql/src/planner/planner-graph.d.ts +10 -0
  213. package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
  214. package/out/zql/src/planner/planner-graph.js +14 -0
  215. package/out/zql/src/planner/planner-graph.js.map +1 -1
  216. package/out/zql/src/planner/planner-warnings.d.ts +83 -0
  217. package/out/zql/src/planner/planner-warnings.d.ts.map +1 -0
  218. package/out/zql/src/planner/planner-warnings.js +78 -0
  219. package/out/zql/src/planner/planner-warnings.js.map +1 -0
  220. package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
  221. package/out/zql/src/query/measure-push-operator.js +30 -8
  222. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  223. package/out/zqlite/src/pending-delta.d.ts +110 -0
  224. package/out/zqlite/src/pending-delta.d.ts.map +1 -0
  225. package/out/zqlite/src/pending-delta.js +278 -0
  226. package/out/zqlite/src/pending-delta.js.map +1 -0
  227. package/out/zqlite/src/query-delegate.d.ts.map +1 -1
  228. package/out/zqlite/src/query-delegate.js +5 -1
  229. package/out/zqlite/src/query-delegate.js.map +1 -1
  230. package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
  231. package/out/zqlite/src/sqlite-cost-model.js +52 -1
  232. package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
  233. package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
  234. package/out/zqlite/src/sqlite-stat-fanout.js +2 -26
  235. package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
  236. package/out/zqlite/src/sqlite-stat4-sample.d.ts +37 -0
  237. package/out/zqlite/src/sqlite-stat4-sample.d.ts.map +1 -0
  238. package/out/zqlite/src/sqlite-stat4-sample.js +61 -0
  239. package/out/zqlite/src/sqlite-stat4-sample.js.map +1 -0
  240. package/out/zqlite/src/table-source.d.ts +68 -0
  241. package/out/zqlite/src/table-source.d.ts.map +1 -1
  242. package/out/zqlite/src/table-source.js +206 -7
  243. package/out/zqlite/src/table-source.js.map +1 -1
  244. package/package.json +1 -1
  245. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +0 -35
  246. package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +0 -1
  247. package/out/replicache/src/kv/idb-store-with-mem-fallback.js +0 -83
  248. package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +0 -1
  249. package/out/zero-cache/src/services/change-source/pg/backfill-resume.d.ts +0 -156
  250. package/out/zero-cache/src/services/change-source/pg/backfill-resume.d.ts.map +0 -1
  251. package/out/zero-cache/src/services/change-source/pg/backfill-resume.js +0 -15
  252. package/out/zero-cache/src/services/change-source/pg/backfill-resume.js.map +0 -1
@@ -3,8 +3,9 @@ import { assertCookie } from "./cookies.js";
3
3
  import { isClientStateNotFoundResponse, isVersionNotSupportedResponse } from "./error-responses.js";
4
4
  import { getDefaultPuller, isDefaultPuller } from "./get-default-puller.js";
5
5
  import { getBrowserGlobal } from "../../shared/src/browser-env.js";
6
- import { promiseVoid } from "../../shared/src/resolved-promises.js";
6
+ import { promiseFalse, promiseVoid } from "../../shared/src/resolved-promises.js";
7
7
  import { deepFreeze } from "./frozen-json.js";
8
+ import { getStorageFailure } from "./storage-failure.js";
8
9
  import { makeIDBName } from "./make-idb-name.js";
9
10
  import { AbortError } from "../../shared/src/abort-error.js";
10
11
  import { InvalidRefCountError } from "./dag/invalid-ref-count-error.js";
@@ -19,6 +20,7 @@ import { disableClientGroup } from "./persist/client-groups.js";
19
20
  import { makeClientID } from "./persist/make-client-id.js";
20
21
  import { ClientStateNotFoundError, hasClientState, initClientV6 } from "./persist/clients.js";
21
22
  import { getKVStoreProvider } from "./get-kv-store-provider.js";
23
+ import { MemFallbackStoreProvider } from "./kv/mem-fallback-store.js";
22
24
  import { createLogContext } from "./log-options.js";
23
25
  import { IDBDatabasesStore } from "./persist/idb-databases-store.js";
24
26
  import { COLLECT_IDB_INTERVAL, INITIAL_COLLECT_IDB_DELAY, dropDatabaseInternal, initCollectIDBDatabases } from "./persist/collect-idb-databases.js";
@@ -100,12 +102,12 @@ var ReplicacheImpl = class {
100
102
  return makeIDBName(this.name, this.schemaVersion);
101
103
  }
102
104
  /**
103
- * The KV store backing this instance. Its `kind` reflects the storage
104
- * currently in use, e.g. `'mem'` after an IndexedDB store fell back to
105
- * memory.
105
+ * The KV store backing this instance. It is a memory store once a storage
106
+ * failure while opening moved the instance onto memory (see
107
+ * `onStorageFailure`).
106
108
  */
107
109
  get kvStore() {
108
- return this.#perKVStore;
110
+ return this.#perKVStore.backing;
109
111
  }
110
112
  set auth(auth) {
111
113
  if (this.#zero) this.#zero.auth = auth;
@@ -171,6 +173,16 @@ var ReplicacheImpl = class {
171
173
  #lc;
172
174
  #zero;
173
175
  #closeAbortController = new AbortController();
176
+ /**
177
+ * Aborted on close AND on a storage failure after the open. The store-using
178
+ * background processes (heartbeat, client and client-group GC, database
179
+ * collection, mutation recovery, the new-client channel's store read) run
180
+ * on this signal, so the first detected failure stops them instead of
181
+ * letting each retry the fault at its interval and log `Error running.`
182
+ * every time. A failure during the open moves the stores onto memory
183
+ * instead, where they keep running.
184
+ */
185
+ #storeProcessesAbortController = new AbortController();
174
186
  #persistLock = new Lock();
175
187
  #enableScheduledPersist;
176
188
  #enableScheduledRefresh;
@@ -217,6 +229,51 @@ var ReplicacheImpl = class {
217
229
  */
218
230
  onClientStateNotFound = reload;
219
231
  /**
232
+ * `onStorageFailure` is called once, the first time the local kv store
233
+ * reports that its storage has failed rather than its data, by throwing a
234
+ * {@link StorageFailureError}: the device is out of space (`full`), the
235
+ * database cannot be opened (`cannot-open`), or a read or write to it failed
236
+ * (`io-error`). The SQLite stores and the IndexedDB store report these; a
237
+ * custom `StoreProvider` can throw a `StorageFailureError` itself.
238
+ *
239
+ * A failure while the instance is opening moves it onto memory for the
240
+ * session, where it runs as with `kvStore: 'mem'`: it persists and
241
+ * refreshes against the memory stores, and nothing reaches the disk.
242
+ *
243
+ * A failure after that stops persisting and refreshing: a rebuild would
244
+ * open the same failing storage, and a wipe would destroy an intact replica
245
+ * for a fault that is not in the data. Queries and mutations keep running
246
+ * against what the in-memory dag holds, and mutations keep pushing to the
247
+ * server, but nothing is persisted locally until the app creates a new
248
+ * instance. A read that needs a chunk the in-memory dag has not loaded from
249
+ * the store yet, or has since evicted from its cache, still goes to the
250
+ * store and fails the way any store read does; that failure reaches its
251
+ * caller and is not reclassified here. An invalid ref count reported while
252
+ * the store is failing with `cannot-open` or `io-error` is NOT treated as
253
+ * corruption (the database is not dropped and {@link onClientStateNotFound}
254
+ * is not called), because a store that cannot complete a read or write is
255
+ * what produces such readings. A `full` disk keeps the drop: a torn write
256
+ * there is real corruption, and deleting the database is also what frees
257
+ * the space.
258
+ *
259
+ * After the open, the failure is detected when a transaction on the store
260
+ * fails to begin or to commit, whichever caller ran it (`persist()`, the
261
+ * heartbeat, garbage collection, ...), and when `persist()` or `refresh()`
262
+ * fails. The background maintenance processes (heartbeat, client and
263
+ * client-group GC, database collection, mutation recovery) stop on it
264
+ * instead of retrying against the store at their interval.
265
+ *
266
+ * There is no default behavior other than logging. An app that shows a
267
+ * "free up space" or "restart" screen can do so from here.
268
+ */
269
+ onStorageFailure = null;
270
+ /**
271
+ * Set the first time the kv store reports a storage failure. Read by every
272
+ * path that writes the perdag so none of them retries against storage
273
+ * that has failed.
274
+ */
275
+ #storageFailure;
276
+ /**
220
277
  * `onUpdateNeeded` is called when a code update is needed.
221
278
  *
222
279
  * A code update can be needed because:
@@ -268,8 +325,9 @@ var ReplicacheImpl = class {
268
325
  name,
269
326
  "replicache version": version
270
327
  });
328
+ this.#closeAbortController.signal.addEventListener("abort", () => this.#storeProcessesAbortController.abort(), { once: true });
271
329
  this.#subscriptions = new SubscriptionsManagerImpl(this.#queryInternal, this.#lc, this.#closeAbortController.signal);
272
- const kvStoreProvider = getKVStoreProvider(this.#lc, options.kvStore);
330
+ const kvStoreProvider = new MemFallbackStoreProvider(getKVStoreProvider(this.#lc, options.kvStore), (failure) => this.#onMemFallBack(failure), (failure) => this.#handleStorageFailure(failure));
273
331
  this.#kvStoreProvider = kvStoreProvider;
274
332
  const perKVStore = kvStoreProvider.create(this.idbName);
275
333
  this.#perKVStore = perKVStore;
@@ -294,12 +352,19 @@ var ReplicacheImpl = class {
294
352
  this.#onPersist = initOnPersistChannel(this.name, this.#closeAbortController.signal, (persistInfo) => {
295
353
  this.#handlePersist(persistInfo);
296
354
  });
297
- this.#open(indexes, enableClientGroupForking, enableMutationRecovery, clientMaxAgeMs, profileIDResolver.resolve, clientGroupIDResolver.resolve, readyResolver.resolve, onClientsDeleted).catch((e) => {
298
- this.#openFailed.resolve();
355
+ const open = () => this.#open(indexes, enableClientGroupForking, enableMutationRecovery, clientMaxAgeMs, profileIDResolver.resolve, clientGroupIDResolver.resolve, readyResolver.resolve, onClientsDeleted);
356
+ open().catch((e) => {
299
357
  if (e instanceof InvalidRefCountError) {
358
+ this.#openFailed.resolve();
300
359
  this.#lc.debug?.("Open failed because the persistent store is corrupt");
301
360
  return;
302
361
  }
362
+ if (!this.#closed && this.#kvStoreProvider.fallBack(e)) return open().catch((e) => {
363
+ this.#openFailed.resolve();
364
+ if (this.#closed) this.#lc.debug?.("Open on memory ended by close", e);
365
+ else this.#lc.error?.("Open failed again on memory", e);
366
+ });
367
+ this.#openFailed.resolve();
303
368
  throw e;
304
369
  });
305
370
  }
@@ -316,12 +381,13 @@ var ReplicacheImpl = class {
316
381
  if (dbOpenMs > SLOW_DB_OPEN_THRESHOLD_MS) this.#lc.warn?.(`Opening the database took ${Math.round(dbOpenMs)}ms`, { name: this.idbName });
317
382
  else this.#lc.debug?.("Opened the database in", Math.round(dbOpenMs), "ms");
318
383
  await this.#zero?.init(headHash, this.memdag);
384
+ this.#kvStoreProvider.opened();
319
385
  resolveReady();
320
386
  if (this.#enablePullAndPushInOpen) {
321
387
  this.pull().catch(noop);
322
388
  this.push().catch(noop);
323
389
  }
324
- const { signal } = this.#closeAbortController;
390
+ const { signal } = this.#storeProcessesAbortController;
325
391
  startHeartbeats(clientID, this.perdag, () => {
326
392
  this.#clientStateNotFoundOnClient(clientID);
327
393
  }, HEARTBEAT_INTERVAL, this.#lc, signal);
@@ -336,7 +402,7 @@ var ReplicacheImpl = class {
336
402
  getBrowserGlobal("document")?.addEventListener("visibilitychange", this.#onVisibilityChange);
337
403
  }
338
404
  #onVisibilityChange = async () => {
339
- if (this.#closed) return;
405
+ if (this.#closed || this.#storageFailure !== void 0) return;
340
406
  if (getBrowserGlobal("document")?.visibilityState !== "visible") return;
341
407
  await this.#checkForClientStateNotFoundAndCallHandler();
342
408
  };
@@ -653,7 +719,7 @@ var ReplicacheImpl = class {
653
719
  return this.#persistLock.withLock(async () => {
654
720
  const { clientID } = this;
655
721
  await this.#ready;
656
- if (this.#closed) return;
722
+ if (this.#closed || this.#storageFailure) return;
657
723
  try {
658
724
  await persistDD31(this.#lc, clientID, this.memdag, this.perdag, this.#mutatorRegistry, () => this.#closed, 7, this.#zero?.getTxData);
659
725
  } catch (e) {
@@ -662,7 +728,12 @@ var ReplicacheImpl = class {
662
728
  await this.#handleInvalidRefCount(e);
663
729
  return;
664
730
  } else if (this.#closed) this.#lc.debug?.("Exception persisting during close", e);
665
- else throw e;
731
+ else {
732
+ const failure = getStorageFailure(e);
733
+ if (failure === void 0) throw e;
734
+ this.#handleStorageFailure(failure);
735
+ return;
736
+ }
666
737
  }
667
738
  const clientGroupID = await this.#clientGroupIDPromise;
668
739
  assert(clientGroupID, "Expected clientGroupID to be defined");
@@ -675,7 +746,7 @@ var ReplicacheImpl = class {
675
746
  async refresh() {
676
747
  await this.#ready;
677
748
  const { clientID } = this;
678
- if (this.#closed || !this.#enableRefresh()) return;
749
+ if (this.#closed || this.#storageFailure || !this.#enableRefresh()) return;
679
750
  let refreshResult;
680
751
  try {
681
752
  refreshResult = await refresh(this.#lc, this.memdag, this.perdag, clientID, this.#mutatorRegistry, this.#subscriptions, () => this.closed, 7, this.#zero);
@@ -683,7 +754,12 @@ var ReplicacheImpl = class {
683
754
  if (e instanceof ClientStateNotFoundError) this.#clientStateNotFoundOnClient(clientID);
684
755
  else if (e instanceof InvalidRefCountError) await this.#handleInvalidRefCount(e);
685
756
  else if (this.#closed) this.#lc.debug?.("Exception refreshing during close", e);
686
- else throw e;
757
+ else {
758
+ const failure = getStorageFailure(e);
759
+ if (failure === void 0) throw e;
760
+ this.#handleStorageFailure(failure);
761
+ return;
762
+ }
687
763
  }
688
764
  if (refreshResult !== void 0) await this.#subscriptions.fire(refreshResult.diffs);
689
765
  }
@@ -701,6 +777,42 @@ var ReplicacheImpl = class {
701
777
  */
702
778
  #corruptDatabaseRecovery;
703
779
  /**
780
+ * A storage failure after the open. Records the first one, stops the
781
+ * store-using background processes, logs it once and tells the app. Later
782
+ * failures of the same instance are the same fault and are not reported
783
+ * again; the scheduled persist and refresh stop asking.
784
+ */
785
+ #handleStorageFailure(failure) {
786
+ if (this.#storageFailure !== void 0) return;
787
+ this.#storageFailure = failure;
788
+ this.#storeProcessesAbortController.abort();
789
+ this.#lc.warn?.(`Local store storage failed (${failure.kind}) for ${this.idbName}; persistence is stopped for this instance`, failure);
790
+ this.#fireOnStorageFailure(failure);
791
+ }
792
+ /**
793
+ * A storage failure during the open: the stores have moved onto memory, so
794
+ * the instance runs on them for the session, as with `kvStore: 'mem'`.
795
+ * Reported on a
796
+ * later microtask: the SQLite stores open in `create`, while the
797
+ * constructor is still running and before the app can attach the callback.
798
+ */
799
+ #onMemFallBack(failure) {
800
+ this.#lc.warn?.(`Local store storage failed (${failure.kind}) opening ${this.idbName}; running this instance in memory`, failure);
801
+ queueMicrotask(() => this.#fireOnStorageFailure(failure));
802
+ }
803
+ /**
804
+ * The app's callback must not be able to stop the recovery around it: in
805
+ * the open path, a throw here would skip the open on memory and leave the
806
+ * instance never ready.
807
+ */
808
+ #fireOnStorageFailure(failure) {
809
+ try {
810
+ this.onStorageFailure?.(failure);
811
+ } catch (e) {
812
+ this.#lc.error?.("onStorageFailure threw", e);
813
+ }
814
+ }
815
+ /**
704
816
  * Installed on the dag store that writes to our database. The store calls
705
817
  * it after the failing transaction has been released, so dropping the
706
818
  * database from here does not race with the rollback.
@@ -728,6 +840,10 @@ var ReplicacheImpl = class {
728
840
  * something we don't expect to ever happen.
729
841
  */
730
842
  #handleInvalidRefCount(e) {
843
+ if (this.#storageFailure !== void 0 && this.#storageFailure.kind !== "full") {
844
+ this.#lc.warn?.(`Invalid ref count while the local store is failing (${this.#storageFailure.kind}); not dropping database ${this.idbName}`, e);
845
+ return promiseVoid;
846
+ }
731
847
  if (this.#corruptDatabaseRecovery === void 0) {
732
848
  this.#lc.error?.(`Client state is corrupt on client, clientID: ${this.clientID}. Dropping database ${this.idbName}`, e);
733
849
  this.#corruptDatabaseRecovery = this.#dropDatabaseAndFireOnClientStateNotFound();
@@ -774,7 +890,7 @@ var ReplicacheImpl = class {
774
890
  this.onUpdateNeeded?.(reason);
775
891
  }
776
892
  async #schedulePersist() {
777
- if (!this.#enableScheduledPersist) return;
893
+ if (!this.#enableScheduledPersist || this.#storageFailure) return;
778
894
  await this.#schedule("persist", this.#persistScheduler);
779
895
  }
780
896
  async #handlePersist(persistInfo) {
@@ -783,7 +899,7 @@ var ReplicacheImpl = class {
783
899
  if (persistInfo.clientGroupID === clientGroupID) this.#scheduleRefresh();
784
900
  }
785
901
  async #scheduleRefresh() {
786
- if (!this.#enableScheduledRefresh) return;
902
+ if (!this.#enableScheduledRefresh || this.#storageFailure) return;
787
903
  await this.#schedule("refresh from storage", this.#refreshScheduler);
788
904
  }
789
905
  async #schedule(name, scheduler) {
@@ -941,7 +1057,9 @@ var ReplicacheImpl = class {
941
1057
  if (ex instanceof ChunkNotFoundError && await this.#checkForClientStateNotFoundAndCallHandler()) return new ClientStateNotFoundError(this.clientID);
942
1058
  return ex;
943
1059
  }
944
- recoverMutations() {}
1060
+ recoverMutations() {
1061
+ if (this.#storeProcessesAbortController.signal.aborted) return promiseFalse;
1062
+ }
945
1063
  /**
946
1064
  * List of pending mutations. The order of this is from oldest to newest.
947
1065
  *