@rocicorp/zero 0.22.2025081301 → 0.23.2025081400

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 (204) hide show
  1. package/out/analyze-query/src/bin-analyze.js +5 -8
  2. package/out/analyze-query/src/bin-analyze.js.map +1 -1
  3. package/out/{chunk-C3ZE2IHA.js → chunk-JHJ3MBXW.js} +8 -6
  4. package/out/chunk-JHJ3MBXW.js.map +7 -0
  5. package/out/chunk-MKB4RXL3.js +15 -0
  6. package/out/chunk-MKB4RXL3.js.map +7 -0
  7. package/out/{chunk-LENWM5WE.js → chunk-O536GEIT.js} +410 -218
  8. package/out/chunk-O536GEIT.js.map +7 -0
  9. package/out/chunk-SGW2EIVJ.js +192 -0
  10. package/out/chunk-SGW2EIVJ.js.map +7 -0
  11. package/out/{chunk-N2EOVSVB.js → chunk-ZKRMVMWK.js} +209 -153
  12. package/out/chunk-ZKRMVMWK.js.map +7 -0
  13. package/out/expo.js +356 -0
  14. package/out/expo.js.map +7 -0
  15. package/out/{inspector-AF3UI76B.js → inspector-J5P4DOGH.js} +122 -26
  16. package/out/inspector-J5P4DOGH.js.map +7 -0
  17. package/out/{inspector-ENPS6L3H.js → inspector-YIRP3TTL.js} +1 -1
  18. package/out/{inspector-ENPS6L3H.js.map → inspector-YIRP3TTL.js.map} +1 -1
  19. package/out/react.js +7 -4
  20. package/out/react.js.map +2 -2
  21. package/out/replicache/src/kv/sqlite-store.d.ts +117 -0
  22. package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -0
  23. package/out/shared/src/binary-search.js +31 -0
  24. package/out/shared/src/binary-search.js.map +1 -0
  25. package/out/shared/src/centroid.d.ts +10 -0
  26. package/out/shared/src/centroid.d.ts.map +1 -0
  27. package/out/shared/src/centroid.js +28 -0
  28. package/out/shared/src/centroid.js.map +1 -0
  29. package/out/shared/src/logging-test-utils.d.ts +12 -0
  30. package/out/shared/src/logging-test-utils.d.ts.map +1 -0
  31. package/out/shared/src/logging-test-utils.js +21 -0
  32. package/out/shared/src/logging-test-utils.js.map +1 -0
  33. package/out/shared/src/objects.d.ts +3 -1
  34. package/out/shared/src/objects.d.ts.map +1 -1
  35. package/out/shared/src/objects.js.map +1 -1
  36. package/out/shared/src/tdigest-schema.d.ts +8 -0
  37. package/out/shared/src/tdigest-schema.d.ts.map +1 -0
  38. package/out/shared/src/tdigest-schema.js +7 -0
  39. package/out/shared/src/tdigest-schema.js.map +1 -0
  40. package/out/shared/src/tdigest.d.ts +53 -0
  41. package/out/shared/src/tdigest.d.ts.map +1 -0
  42. package/out/shared/src/tdigest.js +304 -0
  43. package/out/shared/src/tdigest.js.map +1 -0
  44. package/out/solid.js +13 -9
  45. package/out/solid.js.map +2 -2
  46. package/out/zero/package.json +9 -4
  47. package/out/zero/src/expo.d.ts +2 -0
  48. package/out/zero/src/expo.d.ts.map +1 -0
  49. package/out/zero/src/zero-cache-dev.js.map +1 -1
  50. package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
  51. package/out/zero-cache/src/auth/write-authorizer.js +3 -2
  52. package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
  53. package/out/zero-cache/src/config/zero-config.d.ts +18 -297
  54. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  55. package/out/zero-cache/src/config/zero-config.js +43 -5
  56. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  57. package/out/zero-cache/src/observability/events.d.ts +15 -0
  58. package/out/zero-cache/src/observability/events.d.ts.map +1 -0
  59. package/out/zero-cache/src/observability/events.js +93 -0
  60. package/out/zero-cache/src/observability/events.js.map +1 -0
  61. package/out/zero-cache/src/server/anonymous-otel-start.d.ts +1 -1
  62. package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +1 -1
  63. package/out/zero-cache/src/server/anonymous-otel-start.js +40 -18
  64. package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
  65. package/out/zero-cache/src/server/change-streamer.js +4 -4
  66. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  67. package/out/zero-cache/src/server/main.js +4 -4
  68. package/out/zero-cache/src/server/main.js.map +1 -1
  69. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  70. package/out/zero-cache/src/server/replicator.js +7 -6
  71. package/out/zero-cache/src/server/replicator.js.map +1 -1
  72. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  73. package/out/zero-cache/src/server/runner/run-worker.js +3 -2
  74. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  75. package/out/zero-cache/src/server/syncer.js +5 -5
  76. package/out/zero-cache/src/server/syncer.js.map +1 -1
  77. package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
  78. package/out/zero-cache/src/services/change-source/custom/change-source.js +46 -35
  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/initial-sync.d.ts.map +1 -1
  81. package/out/zero-cache/src/services/change-source/pg/initial-sync.js +7 -2
  82. package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
  83. package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
  84. package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
  85. package/out/zero-cache/src/services/mutagen/pusher.d.ts +28 -2
  86. package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
  87. package/out/zero-cache/src/services/mutagen/pusher.js +1 -1
  88. package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
  89. package/out/zero-cache/src/services/replicator/change-processor.d.ts +5 -1
  90. package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
  91. package/out/zero-cache/src/services/replicator/change-processor.js +10 -8
  92. package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
  93. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +1 -1
  94. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  95. package/out/zero-cache/src/services/replicator/incremental-sync.js +17 -3
  96. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  97. package/out/zero-cache/src/services/replicator/replication-status.d.ts +12 -0
  98. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -0
  99. package/out/zero-cache/src/services/replicator/replication-status.js +92 -0
  100. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -0
  101. package/out/zero-cache/src/services/replicator/replicator.d.ts +1 -1
  102. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  103. package/out/zero-cache/src/services/replicator/replicator.js +2 -2
  104. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  105. package/out/zero-cache/src/services/statz.d.ts.map +1 -1
  106. package/out/zero-cache/src/services/statz.js +0 -23
  107. package/out/zero-cache/src/services/statz.js.map +1 -1
  108. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  109. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +2 -1
  110. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  111. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +10 -1
  112. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  113. package/out/zero-cache/src/services/view-syncer/view-syncer.js +77 -8
  114. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  115. package/out/zero-cache/src/types/pg.d.ts +9 -0
  116. package/out/zero-cache/src/types/pg.d.ts.map +1 -1
  117. package/out/zero-cache/src/types/pg.js +78 -1
  118. package/out/zero-cache/src/types/pg.js.map +1 -1
  119. package/out/zero-client/src/client/context.d.ts +11 -11
  120. package/out/zero-client/src/client/context.d.ts.map +1 -1
  121. package/out/zero-client/src/client/custom.d.ts +6 -6
  122. package/out/zero-client/src/client/custom.d.ts.map +1 -1
  123. package/out/zero-client/src/client/inspector/inspector.d.ts +10 -1
  124. package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
  125. package/out/zero-client/src/client/inspector/types.d.ts +10 -0
  126. package/out/zero-client/src/client/inspector/types.d.ts.map +1 -1
  127. package/out/zero-client/src/client/measure-push-operator.d.ts +17 -0
  128. package/out/zero-client/src/client/measure-push-operator.d.ts.map +1 -0
  129. package/out/zero-client/src/client/options.d.ts +2 -2
  130. package/out/zero-client/src/client/options.d.ts.map +1 -1
  131. package/out/zero-client/src/client/query-manager.d.ts +18 -5
  132. package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
  133. package/out/zero-client/src/client/zero.d.ts +4 -4
  134. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  135. package/out/zero-client/src/mod.d.ts +1 -1
  136. package/out/zero-client/src/mod.d.ts.map +1 -1
  137. package/out/zero-events/src/index.d.ts +29 -0
  138. package/out/zero-events/src/index.d.ts.map +1 -0
  139. package/out/zero-events/src/index.js +28 -0
  140. package/out/zero-events/src/index.js.map +1 -0
  141. package/out/zero-events/src/status.d.ts +113 -0
  142. package/out/zero-events/src/status.d.ts.map +1 -0
  143. package/out/zero-events/src/status.js +72 -0
  144. package/out/zero-events/src/status.js.map +1 -0
  145. package/out/zero-expo/src/mod.d.ts +2 -0
  146. package/out/zero-expo/src/mod.d.ts.map +1 -0
  147. package/out/zero-expo/src/store.d.ts +4 -0
  148. package/out/zero-expo/src/store.d.ts.map +1 -0
  149. package/out/zero-protocol/src/down.d.ts +18 -2
  150. package/out/zero-protocol/src/down.d.ts.map +1 -1
  151. package/out/zero-protocol/src/inspect-down.d.ts +64 -6
  152. package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
  153. package/out/zero-protocol/src/inspect-down.js +18 -3
  154. package/out/zero-protocol/src/inspect-down.js.map +1 -1
  155. package/out/zero-protocol/src/inspect-up.d.ts +25 -6
  156. package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
  157. package/out/zero-protocol/src/inspect-up.js +8 -3
  158. package/out/zero-protocol/src/inspect-up.js.map +1 -1
  159. package/out/zero-protocol/src/protocol-version.d.ts +1 -1
  160. package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
  161. package/out/zero-protocol/src/protocol-version.js +3 -1
  162. package/out/zero-protocol/src/protocol-version.js.map +1 -1
  163. package/out/zero-protocol/src/up.d.ts +7 -2
  164. package/out/zero-protocol/src/up.d.ts.map +1 -1
  165. package/out/zero-react/src/components/inspector.d.ts +1 -1
  166. package/out/zero-react/src/components/inspector.d.ts.map +1 -1
  167. package/out/zero-react/src/components/zero-inspector.d.ts +1 -1
  168. package/out/zero-react/src/components/zero-inspector.d.ts.map +1 -1
  169. package/out/zero-react/src/zero-provider.d.ts +4 -4
  170. package/out/zero-react/src/zero-provider.d.ts.map +1 -1
  171. package/out/zero-schema/src/permissions.d.ts +15 -0
  172. package/out/zero-schema/src/permissions.d.ts.map +1 -1
  173. package/out/zero-schema/src/table-schema.d.ts +1 -8
  174. package/out/zero-schema/src/table-schema.d.ts.map +1 -1
  175. package/out/zero-schema/src/table-schema.js.map +1 -1
  176. package/out/zero-solid/src/use-zero.d.ts +4 -4
  177. package/out/zero-solid/src/use-zero.d.ts.map +1 -1
  178. package/out/zero.js +5 -3
  179. package/out/zql/src/builder/builder.d.ts +3 -2
  180. package/out/zql/src/builder/builder.d.ts.map +1 -1
  181. package/out/zql/src/builder/builder.js +9 -8
  182. package/out/zql/src/builder/builder.js.map +1 -1
  183. package/out/zql/src/ivm/operator.d.ts +1 -1
  184. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  185. package/out/zql/src/ivm/operator.js +0 -1
  186. package/out/zql/src/ivm/operator.js.map +1 -1
  187. package/out/zql/src/query/metrics-delegate.d.ts +14 -0
  188. package/out/zql/src/query/metrics-delegate.d.ts.map +1 -0
  189. package/out/zql/src/query/metrics-delegate.js +2 -0
  190. package/out/zql/src/query/metrics-delegate.js.map +1 -0
  191. package/out/zql/src/query/query-delegate.d.ts +7 -2
  192. package/out/zql/src/query/query-delegate.d.ts.map +1 -1
  193. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  194. package/out/zql/src/query/query-impl.js +17 -14
  195. package/out/zql/src/query/query-impl.js.map +1 -1
  196. package/out/zqlite/src/query-delegate.d.ts +7 -6
  197. package/out/zqlite/src/query-delegate.d.ts.map +1 -1
  198. package/out/zqlite/src/query-delegate.js +5 -2
  199. package/out/zqlite/src/query-delegate.js.map +1 -1
  200. package/package.json +9 -4
  201. package/out/chunk-C3ZE2IHA.js.map +0 -7
  202. package/out/chunk-LENWM5WE.js.map +0 -7
  203. package/out/chunk-N2EOVSVB.js.map +0 -7
  204. package/out/inspector-AF3UI76B.js.map +0 -7
package/out/expo.js ADDED
@@ -0,0 +1,356 @@
1
+ import {
2
+ promiseUndefined,
3
+ promiseVoid
4
+ } from "./chunk-MKB4RXL3.js";
5
+ import {
6
+ deepFreeze
7
+ } from "./chunk-SGW2EIVJ.js";
8
+ import "./chunk-424PT5DM.js";
9
+
10
+ // ../zero-expo/src/store.ts
11
+ import {
12
+ deleteDatabaseSync,
13
+ openDatabaseSync
14
+ } from "expo-sqlite";
15
+
16
+ // ../replicache/src/kv/sqlite-store.ts
17
+ import { Lock, RWLock } from "@rocicorp/lock";
18
+ var getTransactionPreparedStatements = (db) => ({
19
+ begin: db.prepare("BEGIN"),
20
+ beginImmediate: db.prepare("BEGIN IMMEDIATE"),
21
+ commit: db.prepare("COMMIT"),
22
+ rollback: db.prepare("ROLLBACK")
23
+ });
24
+ var getRWPreparedStatements = (db) => ({
25
+ get: db.prepare("SELECT value FROM entry WHERE key = ?"),
26
+ put: db.prepare("INSERT OR REPLACE INTO entry (key, value) VALUES (?, ?)"),
27
+ del: db.prepare("DELETE FROM entry WHERE key = ?")
28
+ });
29
+ var SQLiteReadConnectionManager = class {
30
+ #pool = [];
31
+ #nextIndex = 0;
32
+ #rwLock;
33
+ constructor(name, manager, rwLock, opts) {
34
+ if (opts.readPoolSize <= 1) {
35
+ throw new Error("readPoolSize must be greater than 1");
36
+ }
37
+ this.#rwLock = rwLock;
38
+ for (let i = 0; i < opts.readPoolSize; i++) {
39
+ const { db, preparedStatements } = manager.open(name, opts);
40
+ this.#pool.push({
41
+ db,
42
+ lock: new Lock(),
43
+ preparedStatements
44
+ });
45
+ }
46
+ }
47
+ /**
48
+ * Acquire a round-robin read connection from the pool.
49
+ *
50
+ * The returned `release` callback **must** be invoked once the caller is done
51
+ * using the prepared statements, otherwise other readers may be blocked
52
+ * indefinitely.
53
+ */
54
+ async acquire() {
55
+ const slot = this.#nextIndex;
56
+ this.#nextIndex = (this.#nextIndex + 1) % this.#pool.length;
57
+ const entry = this.#pool[slot];
58
+ const releaseRWLock = await this.#rwLock.read();
59
+ const releaseLock = await entry.lock.lock();
60
+ return {
61
+ preparedStatements: entry.preparedStatements,
62
+ release: () => {
63
+ releaseRWLock();
64
+ releaseLock();
65
+ }
66
+ };
67
+ }
68
+ /**
69
+ * Finalizes all prepared statements and closes the underlying connections.
70
+ * After calling this method the manager can no longer be used.
71
+ */
72
+ close() {
73
+ for (const entry of this.#pool) {
74
+ for (const stmt of Object.values(entry.preparedStatements)) {
75
+ stmt.finalize();
76
+ }
77
+ entry.db.close();
78
+ }
79
+ this.#pool = [];
80
+ }
81
+ };
82
+ var SQLiteWriteConnectionManager = class {
83
+ #rwLock;
84
+ #preparedStatements;
85
+ #db;
86
+ constructor(name, manager, rwLock, opts) {
87
+ const { db, preparedStatements } = manager.open(name, opts);
88
+ this.#preparedStatements = preparedStatements;
89
+ this.#db = db;
90
+ this.#rwLock = rwLock;
91
+ }
92
+ async acquire() {
93
+ const release = await this.#rwLock.write();
94
+ return { preparedStatements: this.#preparedStatements, release };
95
+ }
96
+ close() {
97
+ for (const stmt of Object.values(this.#preparedStatements)) {
98
+ stmt.finalize();
99
+ }
100
+ this.#db.close();
101
+ }
102
+ };
103
+ var SQLiteStore = class {
104
+ #name;
105
+ #dbm;
106
+ #writeConnectionManager;
107
+ #readConnectionManager;
108
+ #rwLock = new RWLock();
109
+ #closed = false;
110
+ constructor(name, dbm, opts) {
111
+ this.#name = name;
112
+ this.#dbm = dbm;
113
+ this.#writeConnectionManager = new SQLiteWriteConnectionManager(
114
+ name,
115
+ dbm,
116
+ this.#rwLock,
117
+ opts
118
+ );
119
+ this.#readConnectionManager = new SQLiteReadConnectionManager(
120
+ name,
121
+ dbm,
122
+ this.#rwLock,
123
+ opts
124
+ );
125
+ }
126
+ async read() {
127
+ const { preparedStatements, release } = await this.#readConnectionManager.acquire();
128
+ return new SQLiteStoreRead(preparedStatements, release);
129
+ }
130
+ async write() {
131
+ const { preparedStatements, release } = await this.#writeConnectionManager.acquire();
132
+ return new SQLiteStoreWrite(preparedStatements, release);
133
+ }
134
+ close() {
135
+ this.#writeConnectionManager.close();
136
+ this.#readConnectionManager.close();
137
+ this.#dbm.close(this.#name);
138
+ this.#closed = true;
139
+ return promiseVoid;
140
+ }
141
+ get closed() {
142
+ return this.#closed;
143
+ }
144
+ };
145
+ var SQLiteStoreRWBase = class {
146
+ _preparedStatements;
147
+ #release;
148
+ #closed = false;
149
+ constructor(preparedStatements, release) {
150
+ this._preparedStatements = preparedStatements;
151
+ this.#release = release;
152
+ }
153
+ has(key) {
154
+ const unsafeValue = this.#getSql(key);
155
+ return Promise.resolve(unsafeValue !== void 0);
156
+ }
157
+ get(key) {
158
+ const unsafeValue = this.#getSql(key);
159
+ if (unsafeValue === void 0) return promiseUndefined;
160
+ const parsedValue = JSON.parse(unsafeValue);
161
+ const frozenValue = deepFreeze(parsedValue);
162
+ return Promise.resolve(frozenValue);
163
+ }
164
+ #getSql(key) {
165
+ const rows = this._preparedStatements.get.all(key);
166
+ if (rows.length === 0) return void 0;
167
+ return rows[0].value;
168
+ }
169
+ _release() {
170
+ this.#closed = true;
171
+ this.#release();
172
+ }
173
+ get closed() {
174
+ return this.#closed;
175
+ }
176
+ };
177
+ var SQLiteStoreRead = class extends SQLiteStoreRWBase {
178
+ constructor(preparedStatements, release) {
179
+ super(preparedStatements, release);
180
+ this._preparedStatements.begin.run();
181
+ }
182
+ release() {
183
+ this._preparedStatements.commit.run();
184
+ this._release();
185
+ }
186
+ };
187
+ var SQLiteStoreWrite = class extends SQLiteStoreRWBase {
188
+ #committed = false;
189
+ constructor(preparedStatements, release) {
190
+ super(preparedStatements, release);
191
+ this._preparedStatements.beginImmediate.run();
192
+ }
193
+ put(key, value) {
194
+ this._preparedStatements.put.run(key, JSON.stringify(value));
195
+ return promiseVoid;
196
+ }
197
+ del(key) {
198
+ this._preparedStatements.del.run(key);
199
+ return promiseVoid;
200
+ }
201
+ commit() {
202
+ this._preparedStatements.commit.run();
203
+ this.#committed = true;
204
+ return promiseVoid;
205
+ }
206
+ release() {
207
+ if (!this.#committed) {
208
+ this._preparedStatements.rollback.run();
209
+ }
210
+ this._release();
211
+ }
212
+ };
213
+ var safeFilename = (name) => name.replace(/[^a-zA-Z0-9]/g, "_");
214
+ function createSQLiteStore(dbm) {
215
+ return (name, opts) => new SQLiteStore(name, dbm, opts);
216
+ }
217
+ var SQLiteDatabaseManager = class {
218
+ #dbm;
219
+ #dbInstances = /* @__PURE__ */ new Map();
220
+ constructor(dbm) {
221
+ this.#dbm = dbm;
222
+ }
223
+ clearAllStoresForTesting() {
224
+ for (const [name] of this.#dbInstances) {
225
+ this.destroy(name);
226
+ }
227
+ }
228
+ open(name, opts) {
229
+ const dbInstance = this.#dbInstances.get(name);
230
+ const fileName = safeFilename(name);
231
+ const newDb = this.#dbm.open(fileName);
232
+ const txPreparedStatements = getTransactionPreparedStatements(newDb);
233
+ const exec = (sql) => {
234
+ const statement = newDb.prepare(sql);
235
+ statement.run();
236
+ statement.finalize();
237
+ };
238
+ if (!dbInstance) {
239
+ this.#ensureSchema(exec, txPreparedStatements);
240
+ }
241
+ if (opts.busyTimeout !== void 0) {
242
+ exec(`PRAGMA busy_timeout = ${opts.busyTimeout}`);
243
+ }
244
+ if (opts.journalMode !== void 0) {
245
+ exec(`PRAGMA journal_mode = ${opts.journalMode}`);
246
+ }
247
+ if (opts.synchronous !== void 0) {
248
+ exec(`PRAGMA synchronous = ${opts.synchronous}`);
249
+ }
250
+ if (opts.readUncommitted !== void 0) {
251
+ exec(
252
+ `PRAGMA read_uncommitted = ${opts.readUncommitted ? "true" : "false"}`
253
+ );
254
+ }
255
+ const rwPreparedStatements = getRWPreparedStatements(newDb);
256
+ const preparedStatements = {
257
+ ...txPreparedStatements,
258
+ ...rwPreparedStatements
259
+ };
260
+ this.#dbInstances.set(name, {
261
+ instances: [
262
+ ...dbInstance?.instances ?? [],
263
+ { db: newDb, preparedStatements }
264
+ ]
265
+ });
266
+ return {
267
+ db: newDb,
268
+ preparedStatements
269
+ };
270
+ }
271
+ close(name) {
272
+ const dbInstance = this.#dbInstances.get(name);
273
+ if (!dbInstance) return;
274
+ for (const instance of dbInstance.instances) {
275
+ for (const stmt of Object.values(instance.preparedStatements)) {
276
+ stmt.finalize();
277
+ }
278
+ instance.db.close();
279
+ }
280
+ }
281
+ destroy(name) {
282
+ const dbInstance = this.#dbInstances.get(name);
283
+ if (!dbInstance) return;
284
+ for (const instance of dbInstance.instances) {
285
+ for (const stmt of Object.values(instance.preparedStatements)) {
286
+ stmt.finalize();
287
+ }
288
+ instance.db.close();
289
+ }
290
+ for (const instance of dbInstance.instances) {
291
+ instance.db.destroy();
292
+ }
293
+ this.#dbInstances.delete(name);
294
+ }
295
+ #ensureSchema(exec, preparedStatements) {
296
+ preparedStatements.begin.run();
297
+ try {
298
+ exec(
299
+ "CREATE TABLE IF NOT EXISTS entry (key TEXT PRIMARY KEY, value TEXT NOT NULL) WITHOUT ROWID"
300
+ );
301
+ preparedStatements.commit.run();
302
+ } catch (e) {
303
+ preparedStatements.rollback.run();
304
+ throw e;
305
+ }
306
+ }
307
+ };
308
+
309
+ // ../zero-expo/src/store.ts
310
+ var expoDbManagerInstance = new SQLiteDatabaseManager({
311
+ open: (fileName) => {
312
+ const db = openDatabaseSync(fileName);
313
+ const genericDb = {
314
+ close: () => db.closeSync(),
315
+ destroy: () => {
316
+ db.closeSync();
317
+ deleteDatabaseSync(fileName);
318
+ },
319
+ prepare: (sql) => {
320
+ const stmt = db.prepareSync(sql);
321
+ return {
322
+ run: (...params) => {
323
+ stmt.executeSync(params);
324
+ },
325
+ all: (...params) => {
326
+ const result = stmt.executeSync(params);
327
+ return result.getAllSync();
328
+ },
329
+ finalize: () => stmt.finalizeSync()
330
+ };
331
+ }
332
+ };
333
+ return genericDb;
334
+ }
335
+ });
336
+ var expoSQLiteStoreProvider = (opts) => ({
337
+ create: (name) => createSQLiteStore(expoDbManagerInstance)(name, {
338
+ // we default to 3 read connections for mobile devices
339
+ readPoolSize: 3,
340
+ busyTimeout: 200,
341
+ synchronous: "NORMAL",
342
+ readUncommitted: false,
343
+ ...opts,
344
+ // we override the journal mode to undefined because
345
+ // setting it to WAL causes hanging COMMITs on Expo
346
+ journalMode: void 0
347
+ }),
348
+ drop: (name) => {
349
+ expoDbManagerInstance.destroy(name);
350
+ return promiseVoid;
351
+ }
352
+ });
353
+ export {
354
+ expoSQLiteStoreProvider
355
+ };
356
+ //# sourceMappingURL=expo.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../zero-expo/src/store.ts", "../../replicache/src/kv/sqlite-store.ts"],
4
+ "sourcesContent": ["import {\n deleteDatabaseSync,\n openDatabaseSync,\n type SQLiteBindParams,\n} from 'expo-sqlite';\nimport {\n createSQLiteStore,\n SQLiteDatabaseManager,\n type SQLiteDatabase,\n type SQLiteDatabaseManagerOptions,\n} from '../../replicache/src/kv/sqlite-store.ts';\nimport type {StoreProvider} from '../../replicache/src/kv/store.ts';\nimport {promiseVoid} from '../../shared/src/resolved-promises.ts';\n\nconst expoDbManagerInstance = new SQLiteDatabaseManager({\n open: fileName => {\n const db = openDatabaseSync(fileName);\n\n const genericDb: SQLiteDatabase = {\n close: () => db.closeSync(),\n destroy: () => {\n db.closeSync();\n deleteDatabaseSync(fileName);\n },\n prepare: (sql: string) => {\n const stmt = db.prepareSync(sql);\n return {\n run: (...params: unknown[]): void => {\n stmt.executeSync(params as SQLiteBindParams);\n },\n all: <T>(...params: unknown[]): T[] => {\n const result = stmt.executeSync(params as SQLiteBindParams);\n return result.getAllSync() as unknown as T[];\n },\n finalize: () => stmt.finalizeSync(),\n };\n },\n };\n\n return genericDb;\n },\n});\n\nexport const expoSQLiteStoreProvider = (\n opts?: Partial<Omit<SQLiteDatabaseManagerOptions, 'journalMode'>>,\n): StoreProvider => ({\n create: (name: string) =>\n createSQLiteStore(expoDbManagerInstance)(name, {\n // we default to 3 read connections for mobile devices\n readPoolSize: 3,\n busyTimeout: 200,\n synchronous: 'NORMAL',\n readUncommitted: false,\n ...opts,\n // we override the journal mode to undefined because\n // setting it to WAL causes hanging COMMITs on Expo\n journalMode: undefined,\n }),\n drop: (name: string) => {\n expoDbManagerInstance.destroy(name);\n\n return promiseVoid;\n },\n});\n", "import {Lock, RWLock} from '@rocicorp/lock';\nimport type {ReadonlyJSONValue} from '../../../shared/src/json.ts';\nimport {\n promiseUndefined,\n promiseVoid,\n} from '../../../shared/src/resolved-promises.ts';\nimport {deepFreeze} from '../frozen-json.ts';\nimport type {Read, Store, Write} from './store.ts';\n\n/**\n * A SQLite prepared statement.\n *\n * `run` executes the statement with optional parameters.\n * `all` executes the statement and returns the result rows.\n * `finalize` releases the statement.\n */\nexport interface PreparedStatement {\n run(...params: unknown[]): void;\n all<T>(...params: unknown[]): T[];\n finalize(): void;\n}\n\nexport interface SQLiteDatabase {\n /**\n * Close the database connection.\n */\n close(): void;\n\n /**\n * Destroy or delete the database (e.g. delete file).\n */\n destroy(): void;\n\n /**\n * Prepare a SQL string, returning a statement you can execute.\n * E.g. `const stmt = db.prepare(\"SELECT * FROM todos WHERE id=?\");`\n */\n prepare(sql: string): PreparedStatement;\n}\n\ntype SQLiteTransactionPreparedStatements = {\n begin: PreparedStatement;\n beginImmediate: PreparedStatement;\n commit: PreparedStatement;\n rollback: PreparedStatement;\n};\n\nconst getTransactionPreparedStatements = (\n db: SQLiteDatabase,\n): SQLiteTransactionPreparedStatements => ({\n begin: db.prepare('BEGIN'),\n beginImmediate: db.prepare('BEGIN IMMEDIATE'),\n commit: db.prepare('COMMIT'),\n rollback: db.prepare('ROLLBACK'),\n});\n\ntype SQLiteRWPreparedStatements = {\n get: PreparedStatement;\n put: PreparedStatement;\n del: PreparedStatement;\n};\n\nconst getRWPreparedStatements = (\n db: SQLiteDatabase,\n): SQLiteRWPreparedStatements => ({\n get: db.prepare('SELECT value FROM entry WHERE key = ?'),\n put: db.prepare('INSERT OR REPLACE INTO entry (key, value) VALUES (?, ?)'),\n del: db.prepare('DELETE FROM entry WHERE key = ?'),\n});\n\ntype SQLitePreparedStatements = SQLiteTransactionPreparedStatements &\n SQLiteRWPreparedStatements;\n\ninterface SQLiteConnectionManager {\n acquire(): Promise<{\n preparedStatements: SQLitePreparedStatements;\n release: () => void;\n }>;\n close(): void;\n}\n\ntype SQLitePreparedStatementPoolEntry = {\n db: SQLiteDatabase;\n lock: Lock;\n preparedStatements: SQLitePreparedStatements;\n};\n\n/**\n * Manages a pool of read-only SQLite connections.\n *\n * Each connection in the pool is protected by its own `Lock` instance which\n * guarantees that it is held by at most one reader at a time. Consumers call\n * {@link acquire} to get access to a set of prepared statements for a\n * connection and must invoke the provided `release` callback when they are\n * finished.\n *\n * The pool eagerly creates the configured number of connections up-front so\n * that the first `acquire` call never has to pay the connection setup cost.\n */\nclass SQLiteReadConnectionManager implements SQLiteConnectionManager {\n #pool: SQLitePreparedStatementPoolEntry[] = [];\n #nextIndex = 0;\n readonly #rwLock: RWLock;\n\n constructor(\n name: string,\n manager: SQLiteDatabaseManager,\n rwLock: RWLock,\n opts: SQLiteDatabaseManagerOptions,\n ) {\n if (opts.readPoolSize <= 1) {\n throw new Error('readPoolSize must be greater than 1');\n }\n\n this.#rwLock = rwLock;\n\n for (let i = 0; i < opts.readPoolSize; i++) {\n // create a new readonly SQLiteDatabase for each instance in the pool\n const {db, preparedStatements} = manager.open(name, opts);\n this.#pool.push({\n db,\n lock: new Lock(),\n preparedStatements,\n });\n }\n }\n\n /**\n * Acquire a round-robin read connection from the pool.\n *\n * The returned `release` callback **must** be invoked once the caller is done\n * using the prepared statements, otherwise other readers may be blocked\n * indefinitely.\n */\n async acquire(): Promise<{\n preparedStatements: SQLitePreparedStatements;\n release: () => void;\n }> {\n const slot = this.#nextIndex;\n this.#nextIndex = (this.#nextIndex + 1) % this.#pool.length;\n\n const entry = this.#pool[slot];\n\n // we have two levels of locking\n // 1. the RWLock to prevent concurrent read operations while a write is in progress\n // 2. the Lock to prevent concurrent read operations on the same connection\n const releaseRWLock = await this.#rwLock.read();\n const releaseLock = await entry.lock.lock();\n\n return {\n preparedStatements: entry.preparedStatements,\n release: () => {\n releaseRWLock();\n releaseLock();\n },\n };\n }\n\n /**\n * Finalizes all prepared statements and closes the underlying connections.\n * After calling this method the manager can no longer be used.\n */\n close(): void {\n for (const entry of this.#pool) {\n for (const stmt of Object.values(entry.preparedStatements)) {\n stmt.finalize();\n }\n entry.db.close();\n }\n this.#pool = [];\n }\n}\n\n/**\n * Manages a single write connection with an external RWLock.\n */\nclass SQLiteWriteConnectionManager implements SQLiteConnectionManager {\n readonly #rwLock: RWLock;\n readonly #preparedStatements: SQLitePreparedStatements;\n readonly #db: SQLiteDatabase;\n\n constructor(\n name: string,\n manager: SQLiteDatabaseManager,\n rwLock: RWLock,\n opts: SQLiteDatabaseManagerOptions,\n ) {\n const {db, preparedStatements} = manager.open(name, opts);\n this.#preparedStatements = preparedStatements;\n this.#db = db;\n this.#rwLock = rwLock;\n }\n\n async acquire(): Promise<{\n preparedStatements: SQLitePreparedStatements;\n release: () => void;\n }> {\n const release = await this.#rwLock.write();\n return {preparedStatements: this.#preparedStatements, release};\n }\n\n close(): void {\n for (const stmt of Object.values(this.#preparedStatements)) {\n stmt.finalize();\n }\n this.#db.close();\n }\n}\n\n/**\n * A SQLite-based Store implementation.\n *\n * This store provides a generic SQLite implementation that can be used with different\n * SQLite providers (expo-sqlite, better-sqlite3, etc). It implements the Store\n * interface using a single 'entry' table with key-value pairs.\n *\n * The store uses a single RWLock to prevent concurrent read and write operations.\n *\n * The store also uses a pool of read connections to allow concurrent reads with separate transactions.\n */\nexport class SQLiteStore implements Store {\n readonly #name: string;\n readonly #dbm: SQLiteDatabaseManager;\n readonly #writeConnectionManager: SQLiteConnectionManager;\n readonly #readConnectionManager: SQLiteConnectionManager;\n readonly #rwLock = new RWLock();\n\n #closed = false;\n\n constructor(\n name: string,\n dbm: SQLiteDatabaseManager,\n opts: SQLiteDatabaseManagerOptions,\n ) {\n this.#name = name;\n this.#dbm = dbm;\n\n this.#writeConnectionManager = new SQLiteWriteConnectionManager(\n name,\n dbm,\n this.#rwLock,\n opts,\n );\n this.#readConnectionManager = new SQLiteReadConnectionManager(\n name,\n dbm,\n this.#rwLock,\n opts,\n );\n }\n\n async read(): Promise<Read> {\n const {preparedStatements, release} =\n await this.#readConnectionManager.acquire();\n return new SQLiteStoreRead(preparedStatements, release);\n }\n\n async write(): Promise<Write> {\n const {preparedStatements, release} =\n await this.#writeConnectionManager.acquire();\n return new SQLiteStoreWrite(preparedStatements, release);\n }\n\n close(): Promise<void> {\n this.#writeConnectionManager.close();\n this.#readConnectionManager.close();\n this.#dbm.close(this.#name);\n this.#closed = true;\n\n return promiseVoid;\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nclass SQLiteStoreRWBase {\n protected readonly _preparedStatements: SQLitePreparedStatements;\n readonly #release: () => void;\n #closed = false;\n\n constructor(\n preparedStatements: SQLitePreparedStatements,\n release: () => void,\n ) {\n this._preparedStatements = preparedStatements;\n this.#release = release;\n }\n\n has(key: string): Promise<boolean> {\n const unsafeValue = this.#getSql(key);\n return Promise.resolve(unsafeValue !== undefined);\n }\n\n get(key: string): Promise<ReadonlyJSONValue | undefined> {\n const unsafeValue = this.#getSql(key);\n if (unsafeValue === undefined) return promiseUndefined;\n const parsedValue = JSON.parse(unsafeValue) as ReadonlyJSONValue;\n const frozenValue = deepFreeze(parsedValue);\n return Promise.resolve(frozenValue);\n }\n\n #getSql(key: string): string | undefined {\n const rows = this._preparedStatements.get.all<{value: string}>(key);\n if (rows.length === 0) return undefined;\n return rows[0].value;\n }\n\n protected _release(): void {\n this.#closed = true;\n this.#release();\n }\n\n get closed(): boolean {\n return this.#closed;\n }\n}\n\nexport class SQLiteStoreRead extends SQLiteStoreRWBase implements Read {\n constructor(\n preparedStatements: SQLitePreparedStatements,\n release: () => void,\n ) {\n super(preparedStatements, release);\n\n // BEGIN\n this._preparedStatements.begin.run();\n }\n\n release(): void {\n // COMMIT\n this._preparedStatements.commit.run();\n\n this._release();\n }\n}\n\nexport class SQLiteStoreWrite extends SQLiteStoreRWBase implements Write {\n #committed = false;\n\n constructor(\n preparedStatements: SQLitePreparedStatements,\n release: () => void,\n ) {\n super(preparedStatements, release);\n\n // BEGIN IMMEDIATE grabs a RESERVED lock\n this._preparedStatements.beginImmediate.run();\n }\n\n put(key: string, value: ReadonlyJSONValue): Promise<void> {\n this._preparedStatements.put.run(key, JSON.stringify(value));\n return promiseVoid;\n }\n\n del(key: string): Promise<void> {\n this._preparedStatements.del.run(key);\n return promiseVoid;\n }\n\n commit(): Promise<void> {\n // COMMIT\n this._preparedStatements.commit.run();\n this.#committed = true;\n return promiseVoid;\n }\n\n release(): void {\n if (!this.#committed) {\n // ROLLBACK if not committed\n this._preparedStatements.rollback.run();\n }\n\n this._release();\n }\n}\n\nexport interface GenericSQLiteDatabaseManager {\n open(fileName: string): SQLiteDatabase;\n}\n\n// we replace non-alphanumeric characters with underscores\n// because SQLite doesn't allow them in database names\nconst safeFilename = (name: string) => name.replace(/[^a-zA-Z0-9]/g, '_');\n\n/**\n * Creates a function that returns new SQLite store instances.\n * This is the main entry point for using the SQLite store implementation.\n *\n * @param dbm The SQLite database manager implementation\n * @returns A function that creates new store instances\n */\nexport function createSQLiteStore(dbm: SQLiteDatabaseManager) {\n return (name: string, opts: SQLiteDatabaseManagerOptions) =>\n new SQLiteStore(name, dbm, opts);\n}\n\nexport type SQLiteDatabaseManagerOptions = {\n /**\n * The number of read connections to keep open.\n *\n * This must be greater than 1 to support concurrent reads.\n */\n readPoolSize: number;\n\n busyTimeout?: number | undefined;\n journalMode?: 'WAL' | 'DELETE' | undefined;\n synchronous?: 'NORMAL' | 'FULL' | undefined;\n readUncommitted?: boolean | undefined;\n};\n\nexport class SQLiteDatabaseManager {\n readonly #dbm: GenericSQLiteDatabaseManager;\n readonly #dbInstances = new Map<\n string,\n {\n instances: {\n db: SQLiteDatabase;\n preparedStatements: SQLitePreparedStatements;\n }[];\n }\n >();\n\n constructor(dbm: GenericSQLiteDatabaseManager) {\n this.#dbm = dbm;\n }\n\n clearAllStoresForTesting(): void {\n for (const [name] of this.#dbInstances) {\n this.destroy(name);\n }\n }\n\n open(\n name: string,\n opts: Omit<SQLiteDatabaseManagerOptions, 'poolSize'>,\n ): {db: SQLiteDatabase; preparedStatements: SQLitePreparedStatements} {\n const dbInstance = this.#dbInstances.get(name);\n\n const fileName = safeFilename(name);\n const newDb = this.#dbm.open(fileName);\n\n const txPreparedStatements = getTransactionPreparedStatements(newDb);\n\n const exec = (sql: string) => {\n const statement = newDb.prepare(sql);\n statement.run();\n statement.finalize();\n };\n\n if (!dbInstance) {\n // we only ensure the schema for the first open\n // the schema is the same for all connections\n this.#ensureSchema(exec, txPreparedStatements);\n }\n\n if (opts.busyTimeout !== undefined) {\n // we set a busy timeout to wait for write locks to be released\n exec(`PRAGMA busy_timeout = ${opts.busyTimeout}`);\n }\n if (opts.journalMode !== undefined) {\n // WAL allows concurrent readers (improves write throughput ~15x and read throughput ~1.5x)\n // but does not work on all platforms (e.g. Expo)\n exec(`PRAGMA journal_mode = ${opts.journalMode}`);\n }\n if (opts.synchronous !== undefined) {\n exec(`PRAGMA synchronous = ${opts.synchronous}`);\n }\n if (opts.readUncommitted !== undefined) {\n exec(\n `PRAGMA read_uncommitted = ${opts.readUncommitted ? 'true' : 'false'}`,\n );\n }\n\n // we prepare these after the schema is created\n const rwPreparedStatements = getRWPreparedStatements(newDb);\n\n const preparedStatements = {\n ...txPreparedStatements,\n ...rwPreparedStatements,\n };\n\n this.#dbInstances.set(name, {\n instances: [\n ...(dbInstance?.instances ?? []),\n {db: newDb, preparedStatements},\n ],\n });\n\n return {\n db: newDb,\n preparedStatements,\n };\n }\n\n close(name: string) {\n const dbInstance = this.#dbInstances.get(name);\n if (!dbInstance) return;\n\n for (const instance of dbInstance.instances) {\n for (const stmt of Object.values(instance.preparedStatements)) {\n stmt.finalize();\n }\n instance.db.close();\n }\n }\n\n destroy(name: string): void {\n const dbInstance = this.#dbInstances.get(name);\n if (!dbInstance) return;\n\n // we close all databases first before destroying\n for (const instance of dbInstance.instances) {\n for (const stmt of Object.values(instance.preparedStatements)) {\n stmt.finalize();\n }\n instance.db.close();\n }\n for (const instance of dbInstance.instances) {\n instance.db.destroy();\n }\n this.#dbInstances.delete(name);\n }\n\n #ensureSchema(\n exec: (sql: string) => void,\n preparedStatements: SQLiteTransactionPreparedStatements,\n ): void {\n preparedStatements.begin.run();\n\n try {\n // WITHOUT ROWID increases write throughput\n exec(\n 'CREATE TABLE IF NOT EXISTS entry (key TEXT PRIMARY KEY, value TEXT NOT NULL) WITHOUT ROWID',\n );\n preparedStatements.commit.run();\n } catch (e) {\n preparedStatements.rollback.run();\n throw e;\n }\n }\n}\n"],
5
+ "mappings": ";;;;;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;;;ACJP,SAAQ,MAAM,cAAa;AA+C3B,IAAM,mCAAmC,CACvC,QACyC;AAAA,EACzC,OAAO,GAAG,QAAQ,OAAO;AAAA,EACzB,gBAAgB,GAAG,QAAQ,iBAAiB;AAAA,EAC5C,QAAQ,GAAG,QAAQ,QAAQ;AAAA,EAC3B,UAAU,GAAG,QAAQ,UAAU;AACjC;AAQA,IAAM,0BAA0B,CAC9B,QACgC;AAAA,EAChC,KAAK,GAAG,QAAQ,uCAAuC;AAAA,EACvD,KAAK,GAAG,QAAQ,yDAAyD;AAAA,EACzE,KAAK,GAAG,QAAQ,iCAAiC;AACnD;AA+BA,IAAM,8BAAN,MAAqE;AAAA,EACnE,QAA4C,CAAC;AAAA,EAC7C,aAAa;AAAA,EACJ;AAAA,EAET,YACE,MACA,SACA,QACA,MACA;AACA,QAAI,KAAK,gBAAgB,GAAG;AAC1B,YAAM,IAAI,MAAM,qCAAqC;AAAA,IACvD;AAEA,SAAK,UAAU;AAEf,aAAS,IAAI,GAAG,IAAI,KAAK,cAAc,KAAK;AAE1C,YAAM,EAAC,IAAI,mBAAkB,IAAI,QAAQ,KAAK,MAAM,IAAI;AACxD,WAAK,MAAM,KAAK;AAAA,QACd;AAAA,QACA,MAAM,IAAI,KAAK;AAAA,QACf;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,UAGH;AACD,UAAM,OAAO,KAAK;AAClB,SAAK,cAAc,KAAK,aAAa,KAAK,KAAK,MAAM;AAErD,UAAM,QAAQ,KAAK,MAAM,IAAI;AAK7B,UAAM,gBAAgB,MAAM,KAAK,QAAQ,KAAK;AAC9C,UAAM,cAAc,MAAM,MAAM,KAAK,KAAK;AAE1C,WAAO;AAAA,MACL,oBAAoB,MAAM;AAAA,MAC1B,SAAS,MAAM;AACb,sBAAc;AACd,oBAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAc;AACZ,eAAW,SAAS,KAAK,OAAO;AAC9B,iBAAW,QAAQ,OAAO,OAAO,MAAM,kBAAkB,GAAG;AAC1D,aAAK,SAAS;AAAA,MAChB;AACA,YAAM,GAAG,MAAM;AAAA,IACjB;AACA,SAAK,QAAQ,CAAC;AAAA,EAChB;AACF;AAKA,IAAM,+BAAN,MAAsE;AAAA,EAC3D;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACE,MACA,SACA,QACA,MACA;AACA,UAAM,EAAC,IAAI,mBAAkB,IAAI,QAAQ,KAAK,MAAM,IAAI;AACxD,SAAK,sBAAsB;AAC3B,SAAK,MAAM;AACX,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,UAGH;AACD,UAAM,UAAU,MAAM,KAAK,QAAQ,MAAM;AACzC,WAAO,EAAC,oBAAoB,KAAK,qBAAqB,QAAO;AAAA,EAC/D;AAAA,EAEA,QAAc;AACZ,eAAW,QAAQ,OAAO,OAAO,KAAK,mBAAmB,GAAG;AAC1D,WAAK,SAAS;AAAA,IAChB;AACA,SAAK,IAAI,MAAM;AAAA,EACjB;AACF;AAaO,IAAM,cAAN,MAAmC;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU,IAAI,OAAO;AAAA,EAE9B,UAAU;AAAA,EAEV,YACE,MACA,KACA,MACA;AACA,SAAK,QAAQ;AACb,SAAK,OAAO;AAEZ,SAAK,0BAA0B,IAAI;AAAA,MACjC;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF;AACA,SAAK,yBAAyB,IAAI;AAAA,MAChC;AAAA,MACA;AAAA,MACA,KAAK;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,OAAsB;AAC1B,UAAM,EAAC,oBAAoB,QAAO,IAChC,MAAM,KAAK,uBAAuB,QAAQ;AAC5C,WAAO,IAAI,gBAAgB,oBAAoB,OAAO;AAAA,EACxD;AAAA,EAEA,MAAM,QAAwB;AAC5B,UAAM,EAAC,oBAAoB,QAAO,IAChC,MAAM,KAAK,wBAAwB,QAAQ;AAC7C,WAAO,IAAI,iBAAiB,oBAAoB,OAAO;AAAA,EACzD;AAAA,EAEA,QAAuB;AACrB,SAAK,wBAAwB,MAAM;AACnC,SAAK,uBAAuB,MAAM;AAClC,SAAK,KAAK,MAAM,KAAK,KAAK;AAC1B,SAAK,UAAU;AAEf,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,SAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AACF;AAEA,IAAM,oBAAN,MAAwB;AAAA,EACH;AAAA,EACV;AAAA,EACT,UAAU;AAAA,EAEV,YACE,oBACA,SACA;AACA,SAAK,sBAAsB;AAC3B,SAAK,WAAW;AAAA,EAClB;AAAA,EAEA,IAAI,KAA+B;AACjC,UAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,WAAO,QAAQ,QAAQ,gBAAgB,MAAS;AAAA,EAClD;AAAA,EAEA,IAAI,KAAqD;AACvD,UAAM,cAAc,KAAK,QAAQ,GAAG;AACpC,QAAI,gBAAgB,OAAW,QAAO;AACtC,UAAM,cAAc,KAAK,MAAM,WAAW;AAC1C,UAAM,cAAc,WAAW,WAAW;AAC1C,WAAO,QAAQ,QAAQ,WAAW;AAAA,EACpC;AAAA,EAEA,QAAQ,KAAiC;AACvC,UAAM,OAAO,KAAK,oBAAoB,IAAI,IAAqB,GAAG;AAClE,QAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,WAAO,KAAK,CAAC,EAAE;AAAA,EACjB;AAAA,EAEU,WAAiB;AACzB,SAAK,UAAU;AACf,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,IAAI,SAAkB;AACpB,WAAO,KAAK;AAAA,EACd;AACF;AAEO,IAAM,kBAAN,cAA8B,kBAAkC;AAAA,EACrE,YACE,oBACA,SACA;AACA,UAAM,oBAAoB,OAAO;AAGjC,SAAK,oBAAoB,MAAM,IAAI;AAAA,EACrC;AAAA,EAEA,UAAgB;AAEd,SAAK,oBAAoB,OAAO,IAAI;AAEpC,SAAK,SAAS;AAAA,EAChB;AACF;AAEO,IAAM,mBAAN,cAA+B,kBAAmC;AAAA,EACvE,aAAa;AAAA,EAEb,YACE,oBACA,SACA;AACA,UAAM,oBAAoB,OAAO;AAGjC,SAAK,oBAAoB,eAAe,IAAI;AAAA,EAC9C;AAAA,EAEA,IAAI,KAAa,OAAyC;AACxD,SAAK,oBAAoB,IAAI,IAAI,KAAK,KAAK,UAAU,KAAK,CAAC;AAC3D,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,KAA4B;AAC9B,SAAK,oBAAoB,IAAI,IAAI,GAAG;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,SAAwB;AAEtB,SAAK,oBAAoB,OAAO,IAAI;AACpC,SAAK,aAAa;AAClB,WAAO;AAAA,EACT;AAAA,EAEA,UAAgB;AACd,QAAI,CAAC,KAAK,YAAY;AAEpB,WAAK,oBAAoB,SAAS,IAAI;AAAA,IACxC;AAEA,SAAK,SAAS;AAAA,EAChB;AACF;AAQA,IAAM,eAAe,CAAC,SAAiB,KAAK,QAAQ,iBAAiB,GAAG;AASjE,SAAS,kBAAkB,KAA4B;AAC5D,SAAO,CAAC,MAAc,SACpB,IAAI,YAAY,MAAM,KAAK,IAAI;AACnC;AAgBO,IAAM,wBAAN,MAA4B;AAAA,EACxB;AAAA,EACA,eAAe,oBAAI,IAQ1B;AAAA,EAEF,YAAY,KAAmC;AAC7C,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,2BAAiC;AAC/B,eAAW,CAAC,IAAI,KAAK,KAAK,cAAc;AACtC,WAAK,QAAQ,IAAI;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,KACE,MACA,MACoE;AACpE,UAAM,aAAa,KAAK,aAAa,IAAI,IAAI;AAE7C,UAAM,WAAW,aAAa,IAAI;AAClC,UAAM,QAAQ,KAAK,KAAK,KAAK,QAAQ;AAErC,UAAM,uBAAuB,iCAAiC,KAAK;AAEnE,UAAM,OAAO,CAAC,QAAgB;AAC5B,YAAM,YAAY,MAAM,QAAQ,GAAG;AACnC,gBAAU,IAAI;AACd,gBAAU,SAAS;AAAA,IACrB;AAEA,QAAI,CAAC,YAAY;AAGf,WAAK,cAAc,MAAM,oBAAoB;AAAA,IAC/C;AAEA,QAAI,KAAK,gBAAgB,QAAW;AAElC,WAAK,yBAAyB,KAAK,WAAW,EAAE;AAAA,IAClD;AACA,QAAI,KAAK,gBAAgB,QAAW;AAGlC,WAAK,yBAAyB,KAAK,WAAW,EAAE;AAAA,IAClD;AACA,QAAI,KAAK,gBAAgB,QAAW;AAClC,WAAK,wBAAwB,KAAK,WAAW,EAAE;AAAA,IACjD;AACA,QAAI,KAAK,oBAAoB,QAAW;AACtC;AAAA,QACE,6BAA6B,KAAK,kBAAkB,SAAS,OAAO;AAAA,MACtE;AAAA,IACF;AAGA,UAAM,uBAAuB,wBAAwB,KAAK;AAE1D,UAAM,qBAAqB;AAAA,MACzB,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AAEA,SAAK,aAAa,IAAI,MAAM;AAAA,MAC1B,WAAW;AAAA,QACT,GAAI,YAAY,aAAa,CAAC;AAAA,QAC9B,EAAC,IAAI,OAAO,mBAAkB;AAAA,MAChC;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,IAAI;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,MAAc;AAClB,UAAM,aAAa,KAAK,aAAa,IAAI,IAAI;AAC7C,QAAI,CAAC,WAAY;AAEjB,eAAW,YAAY,WAAW,WAAW;AAC3C,iBAAW,QAAQ,OAAO,OAAO,SAAS,kBAAkB,GAAG;AAC7D,aAAK,SAAS;AAAA,MAChB;AACA,eAAS,GAAG,MAAM;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,QAAQ,MAAoB;AAC1B,UAAM,aAAa,KAAK,aAAa,IAAI,IAAI;AAC7C,QAAI,CAAC,WAAY;AAGjB,eAAW,YAAY,WAAW,WAAW;AAC3C,iBAAW,QAAQ,OAAO,OAAO,SAAS,kBAAkB,GAAG;AAC7D,aAAK,SAAS;AAAA,MAChB;AACA,eAAS,GAAG,MAAM;AAAA,IACpB;AACA,eAAW,YAAY,WAAW,WAAW;AAC3C,eAAS,GAAG,QAAQ;AAAA,IACtB;AACA,SAAK,aAAa,OAAO,IAAI;AAAA,EAC/B;AAAA,EAEA,cACE,MACA,oBACM;AACN,uBAAmB,MAAM,IAAI;AAE7B,QAAI;AAEF;AAAA,QACE;AAAA,MACF;AACA,yBAAmB,OAAO,IAAI;AAAA,IAChC,SAAS,GAAG;AACV,yBAAmB,SAAS,IAAI;AAChC,YAAM;AAAA,IACR;AAAA,EACF;AACF;;;ADhhBA,IAAM,wBAAwB,IAAI,sBAAsB;AAAA,EACtD,MAAM,cAAY;AAChB,UAAM,KAAK,iBAAiB,QAAQ;AAEpC,UAAM,YAA4B;AAAA,MAChC,OAAO,MAAM,GAAG,UAAU;AAAA,MAC1B,SAAS,MAAM;AACb,WAAG,UAAU;AACb,2BAAmB,QAAQ;AAAA,MAC7B;AAAA,MACA,SAAS,CAAC,QAAgB;AACxB,cAAM,OAAO,GAAG,YAAY,GAAG;AAC/B,eAAO;AAAA,UACL,KAAK,IAAI,WAA4B;AACnC,iBAAK,YAAY,MAA0B;AAAA,UAC7C;AAAA,UACA,KAAK,IAAO,WAA2B;AACrC,kBAAM,SAAS,KAAK,YAAY,MAA0B;AAC1D,mBAAO,OAAO,WAAW;AAAA,UAC3B;AAAA,UACA,UAAU,MAAM,KAAK,aAAa;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF,CAAC;AAEM,IAAM,0BAA0B,CACrC,UACmB;AAAA,EACnB,QAAQ,CAAC,SACP,kBAAkB,qBAAqB,EAAE,MAAM;AAAA;AAAA,IAE7C,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,GAAG;AAAA;AAAA;AAAA,IAGH,aAAa;AAAA,EACf,CAAC;AAAA,EACH,MAAM,CAAC,SAAiB;AACtB,0BAAsB,QAAQ,IAAI;AAElC,WAAO;AAAA,EACT;AACF;",
6
+ "names": []
7
+ }
@@ -2,20 +2,26 @@ import {
2
2
  ENTITIES_KEY_PREFIX,
3
3
  Latest,
4
4
  SUBQ_PREFIX,
5
- assert,
5
+ TDigest,
6
6
  getClient,
7
7
  getClientGroup,
8
8
  getClients,
9
+ inspectMetricsDownSchema,
9
10
  inspectQueriesDownSchema,
11
+ inspectVersionDownSchema,
12
+ mapValues,
10
13
  must,
11
14
  nanoid,
12
15
  normalizeTTL,
13
16
  readFromHash,
14
17
  test,
15
- unreachable,
16
18
  valita_exports,
17
19
  withRead
18
- } from "./chunk-LENWM5WE.js";
20
+ } from "./chunk-O536GEIT.js";
21
+ import {
22
+ assert,
23
+ unreachable
24
+ } from "./chunk-SGW2EIVJ.js";
19
25
  import "./chunk-424PT5DM.js";
20
26
 
21
27
  // ../ast-to-zql/src/ast-to-zql.ts
@@ -189,9 +195,16 @@ function transformParameter(param) {
189
195
  }
190
196
 
191
197
  // ../zero-client/src/client/inspector/inspector.ts
192
- async function newInspector(rep, schema, socket) {
198
+ async function newInspector(rep, clientMetricsDelegate, schema, socket) {
193
199
  const clientGroupID = await rep.clientGroupID;
194
- return new Inspector(rep, schema, rep.clientID, clientGroupID, socket);
200
+ return new Inspector(
201
+ rep,
202
+ clientMetricsDelegate,
203
+ schema,
204
+ rep.clientID,
205
+ clientGroupID,
206
+ socket
207
+ );
195
208
  }
196
209
  var Inspector = class {
197
210
  #rep;
@@ -199,25 +212,58 @@ var Inspector = class {
199
212
  clientGroup;
200
213
  #schema;
201
214
  socket;
202
- constructor(rep, schema, clientID, clientGroupID, socket) {
215
+ #metricsDelegate;
216
+ constructor(rep, clientMetricsDelegate, schema, clientID, clientGroupID, socket) {
203
217
  this.#rep = rep;
204
218
  this.#schema = schema;
205
- this.client = new Client(rep, schema, socket, clientID, clientGroupID);
219
+ this.client = new Client(
220
+ rep,
221
+ clientMetricsDelegate,
222
+ schema,
223
+ socket,
224
+ clientID,
225
+ clientGroupID
226
+ );
206
227
  this.clientGroup = this.client.clientGroup;
207
228
  this.socket = socket;
229
+ this.#metricsDelegate = clientMetricsDelegate;
230
+ }
231
+ async metrics() {
232
+ const clientMetrics = this.#metricsDelegate.metrics;
233
+ const serverMetricsJSON = await rpc(
234
+ await this.socket(),
235
+ { op: "metrics" },
236
+ inspectMetricsDownSchema
237
+ );
238
+ return mergeMetrics(clientMetrics, serverMetricsJSON);
208
239
  }
209
240
  clients() {
210
241
  return withDagRead(
211
242
  this.#rep,
212
- (dagRead) => clients(this.#rep, this.socket, this.#schema, dagRead)
243
+ (dagRead) => clients(
244
+ this.#rep,
245
+ this.#metricsDelegate,
246
+ this.socket,
247
+ this.#schema,
248
+ dagRead
249
+ )
213
250
  );
214
251
  }
215
252
  clientsWithQueries() {
216
253
  return withDagRead(
217
254
  this.#rep,
218
- (dagRead) => clientsWithQueries(this.#rep, this.socket, this.#schema, dagRead)
255
+ (dagRead) => clientsWithQueries(
256
+ this.#rep,
257
+ this.#metricsDelegate,
258
+ this.socket,
259
+ this.#schema,
260
+ dagRead
261
+ )
219
262
  );
220
263
  }
264
+ async serverVersion() {
265
+ return rpc(await this.socket(), { op: "version" }, inspectVersionDownSchema);
266
+ }
221
267
  };
222
268
  function rpc(socket, arg, downSchema) {
223
269
  return new Promise((resolve, reject) => {
@@ -248,14 +294,20 @@ var Client = class {
248
294
  #rep;
249
295
  id;
250
296
  clientGroup;
251
- #schema;
252
297
  #socket;
253
- constructor(rep, schema, socket, id, clientGroupID) {
298
+ #clientMetricsDelegate;
299
+ constructor(rep, clientMetricsDelegate, schema, socket, id, clientGroupID) {
254
300
  this.#rep = rep;
255
- this.#schema = schema;
256
301
  this.#socket = socket;
257
302
  this.id = id;
258
- this.clientGroup = new ClientGroup(rep, socket, schema, clientGroupID);
303
+ this.clientGroup = new ClientGroup(
304
+ rep,
305
+ clientMetricsDelegate,
306
+ socket,
307
+ schema,
308
+ clientGroupID
309
+ );
310
+ this.#clientMetricsDelegate = clientMetricsDelegate;
259
311
  }
260
312
  async queries() {
261
313
  const rows = await rpc(
@@ -263,7 +315,7 @@ var Client = class {
263
315
  { op: "queries", clientID: this.id },
264
316
  inspectQueriesDownSchema
265
317
  );
266
- return rows.map((row) => new Query(row, this.#schema));
318
+ return rows.map((row) => new Query(row, this.#clientMetricsDelegate));
267
319
  }
268
320
  map() {
269
321
  return withDagRead(this.#rep, async (dagRead) => {
@@ -295,8 +347,10 @@ var ClientGroup = class {
295
347
  id;
296
348
  #schema;
297
349
  #socket;
298
- constructor(rep, socket, schema, id) {
350
+ #metricsDelegate;
351
+ constructor(rep, metricsDelegate, socket, schema, id) {
299
352
  this.#rep = rep;
353
+ this.#metricsDelegate = metricsDelegate;
300
354
  this.#socket = socket;
301
355
  this.#schema = schema;
302
356
  this.id = id;
@@ -306,6 +360,7 @@ var ClientGroup = class {
306
360
  this.#rep,
307
361
  (dagRead) => clients(
308
362
  this.#rep,
363
+ this.#metricsDelegate,
309
364
  this.#socket,
310
365
  this.#schema,
311
366
  dagRead,
@@ -318,6 +373,7 @@ var ClientGroup = class {
318
373
  this.#rep,
319
374
  (dagRead) => clientsWithQueries(
320
375
  this.#rep,
376
+ this.#metricsDelegate,
321
377
  this.#socket,
322
378
  this.#schema,
323
379
  dagRead,
@@ -331,7 +387,7 @@ var ClientGroup = class {
331
387
  { op: "queries" },
332
388
  inspectQueriesDownSchema
333
389
  );
334
- return rows.map((row) => new Query(row, this.#schema));
390
+ return rows.map((row) => new Query(row, this.#metricsDelegate));
335
391
  }
336
392
  };
337
393
  async function withDagRead(rep, f) {
@@ -352,14 +408,28 @@ async function getBTree(dagRead, clientID) {
352
408
  );
353
409
  return dbRead.map;
354
410
  }
355
- async function clients(rep, socket, schema, dagRead, predicate = () => true) {
411
+ async function clients(rep, metricsDelegate, socket, schema, dagRead, predicate = () => true) {
356
412
  const clients2 = await getClients(dagRead);
357
413
  return [...clients2.entries()].filter(predicate).map(
358
- ([clientID, { clientGroupID }]) => new Client(rep, schema, socket, clientID, clientGroupID)
414
+ ([clientID, { clientGroupID }]) => new Client(
415
+ rep,
416
+ metricsDelegate,
417
+ schema,
418
+ socket,
419
+ clientID,
420
+ clientGroupID
421
+ )
359
422
  );
360
423
  }
361
- async function clientsWithQueries(rep, socket, schema, dagRead, predicate = () => true) {
362
- const allClients = await clients(rep, socket, schema, dagRead, predicate);
424
+ async function clientsWithQueries(rep, metricsDelegate, socket, schema, dagRead, predicate = () => true) {
425
+ const allClients = await clients(
426
+ rep,
427
+ metricsDelegate,
428
+ socket,
429
+ schema,
430
+ dagRead,
431
+ predicate
432
+ );
363
433
  const clientsWithQueries2 = [];
364
434
  await Promise.all(
365
435
  allClients.map(async (client) => {
@@ -383,21 +453,47 @@ var Query = class {
383
453
  id;
384
454
  zql;
385
455
  clientID;
386
- constructor(row, _schema) {
456
+ metrics;
457
+ constructor(row, metricsDelegate) {
458
+ const { ast, queryID, inactivatedAt } = row;
387
459
  this.clientID = row.clientID;
388
- this.id = row.queryID;
389
- this.inactivatedAt = row.inactivatedAt === null ? null : new Date(row.inactivatedAt);
460
+ this.id = queryID;
461
+ this.inactivatedAt = inactivatedAt === null ? null : new Date(inactivatedAt);
390
462
  this.ttl = normalizeTTL(row.ttl);
391
- this.ast = row.ast;
463
+ this.ast = ast;
392
464
  this.name = row.name;
393
465
  this.args = row.args;
394
466
  this.got = row.got;
395
467
  this.rowCount = row.rowCount;
396
468
  this.deleted = row.deleted;
397
- this.zql = this.ast ? this.ast.table + astToZQL(this.ast) : null;
469
+ this.zql = ast ? ast.table + astToZQL(ast) : null;
470
+ const clientMetrics = metricsDelegate.getQueryMetrics(queryID);
471
+ const serverMetrics = row.metrics;
472
+ this.metrics = mergeMetrics(clientMetrics, serverMetrics);
398
473
  }
399
474
  };
475
+ function mergeMetrics(clientMetrics, serverMetrics) {
476
+ return {
477
+ ...clientMetrics ?? newClientMetrics(),
478
+ ...serverMetrics ? convertServerMetrics(serverMetrics) : newServerMetrics()
479
+ };
480
+ }
481
+ function newClientMetrics() {
482
+ return {
483
+ "query-materialization-client": new TDigest(),
484
+ "query-materialization-end-to-end": new TDigest(),
485
+ "query-update-client": new TDigest()
486
+ };
487
+ }
488
+ function newServerMetrics() {
489
+ return {
490
+ "query-materialization-server": new TDigest()
491
+ };
492
+ }
493
+ function convertServerMetrics(metrics) {
494
+ return mapValues(metrics, (v) => TDigest.fromJSON(v));
495
+ }
400
496
  export {
401
497
  newInspector
402
498
  };
403
- //# sourceMappingURL=inspector-AF3UI76B.js.map
499
+ //# sourceMappingURL=inspector-J5P4DOGH.js.map