@spooky-sync/core 0.0.1-canary.233 → 0.0.1-canary.235

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.
package/dist/index.d.ts CHANGED
@@ -39,6 +39,13 @@ declare abstract class AbstractDatabaseService {
39
39
  * each link: on expiry this promise rejects and the chain moves on, even
40
40
  * though the underlying RPC is still parked in the SDK's pending map.
41
41
  */
42
+ /**
43
+ * Hook run inside the query queue, right before a statement is sent. The
44
+ * remote service uses it to hold statements while a connect is in flight,
45
+ * so a query never runs on a socket that is open but has not had its
46
+ * namespace and token applied yet. The default does nothing.
47
+ */
48
+ protected beforeQuery(): Promise<void>;
42
49
  query<T extends unknown[]>(query: string, vars?: Record<string, unknown>): Promise<T>;
43
50
  execute<T>(query: SealedQuery<T>, vars?: Record<string, unknown>): Promise<T>;
44
51
  close(): Promise<void>;
@@ -117,6 +124,19 @@ declare class RemoteDatabaseService extends AbstractDatabaseService {
117
124
  * `disconnected`, which is what drives the supervisor's revive loop.
118
125
  */
119
126
  forceClose(): Promise<void>;
127
+ /**
128
+ * Hold statements while a connect is in flight.
129
+ *
130
+ * `connect()` opens the socket, then selects the namespace/database, then
131
+ * authenticates - three round trips. The SDK considers the connection ready
132
+ * after the first, so a query queued during the other two ran on a socket
133
+ * with no namespace ("Specify a namespace to use") or, worse, no identity.
134
+ * Seen 2026-09-06 after the supervisor rebuilt a socket: a collection
135
+ * recount failed with exactly that error. Waiting on the in-flight connect
136
+ * costs nothing when no connect is running; a failed connect is not
137
+ * swallowed here - the query then fails on its own, as before.
138
+ */
139
+ protected beforeQuery(): Promise<void>;
120
140
  /**
121
141
  * Open (or re-open) the remote connection.
122
142
  *
package/dist/index.js CHANGED
@@ -320,9 +320,17 @@ var AbstractDatabaseService = class {
320
320
  * each link: on expiry this promise rejects and the chain moves on, even
321
321
  * though the underlying RPC is still parked in the SDK's pending map.
322
322
  */
323
+ /**
324
+ * Hook run inside the query queue, right before a statement is sent. The
325
+ * remote service uses it to hold statements while a connect is in flight,
326
+ * so a query never runs on a socket that is open but has not had its
327
+ * namespace and token applied yet. The default does nothing.
328
+ */
329
+ async beforeQuery() {}
323
330
  async query(query, vars) {
324
331
  return new Promise((resolve, reject) => {
325
332
  this.queryQueue = this.queryQueue.then(async () => {
333
+ await this.beforeQuery();
326
334
  const startTime = performance.now();
327
335
  try {
328
336
  this.logger.debug({
@@ -1121,6 +1129,25 @@ var RemoteDatabaseService = class extends AbstractDatabaseService {
1121
1129
  }
1122
1130
  }
1123
1131
  /**
1132
+ * Hold statements while a connect is in flight.
1133
+ *
1134
+ * `connect()` opens the socket, then selects the namespace/database, then
1135
+ * authenticates - three round trips. The SDK considers the connection ready
1136
+ * after the first, so a query queued during the other two ran on a socket
1137
+ * with no namespace ("Specify a namespace to use") or, worse, no identity.
1138
+ * Seen 2026-09-06 after the supervisor rebuilt a socket: a collection
1139
+ * recount failed with exactly that error. Waiting on the in-flight connect
1140
+ * costs nothing when no connect is running; a failed connect is not
1141
+ * swallowed here - the query then fails on its own, as before.
1142
+ */
1143
+ async beforeQuery() {
1144
+ const inflight = this.connecting;
1145
+ if (!inflight) return;
1146
+ try {
1147
+ await inflight;
1148
+ } catch {}
1149
+ }
1150
+ /**
1124
1151
  * Open (or re-open) the remote connection.
1125
1152
  *
1126
1153
  * Safe to call repeatedly: concurrent calls share the in-flight attempt, and
@@ -7764,8 +7791,8 @@ function selfAllowlistedVariant(flag, userId) {
7764
7791
 
7765
7792
  //#endregion
7766
7793
  //#region src/modules/devtools/index.ts
7767
- const CORE_VERSION = "0.0.1-canary.233";
7768
- const WASM_VERSION = "0.0.1-canary.233";
7794
+ const CORE_VERSION = "0.0.1-canary.235";
7795
+ const WASM_VERSION = "0.0.1-canary.235";
7769
7796
  const SURREAL_VERSION = "3.0.3";
7770
7797
  var DevToolsService = class DevToolsService {
7771
7798
  eventsHistory = [];
@@ -12780,7 +12807,7 @@ var Sp00kyClient = class {
12780
12807
  return new TabsCoordinator({
12781
12808
  tabId,
12782
12809
  fingerprint: computeTabsFingerprint({
12783
- coreVersion: "0.0.1-canary.233",
12810
+ coreVersion: "0.0.1-canary.235",
12784
12811
  schemaHash: hash53(this.config.schemaSurql),
12785
12812
  endpoint: this.config.database.endpoint ?? "",
12786
12813
  namespace: this.config.database.namespace,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spooky-sync/core",
3
- "version": "0.0.1-canary.233",
3
+ "version": "0.0.1-canary.235",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -60,8 +60,8 @@
60
60
  }
61
61
  },
62
62
  "dependencies": {
63
- "@spooky-sync/query-builder": "0.0.1-canary.233",
64
- "@spooky-sync/ssp-wasm": "0.0.1-canary.233",
63
+ "@spooky-sync/query-builder": "0.0.1-canary.235",
64
+ "@spooky-sync/ssp-wasm": "0.0.1-canary.235",
65
65
  "@sqlite.org/sqlite-wasm": "3.53.0-build1",
66
66
  "@surrealdb/wasm": "^3.0.3",
67
67
  "blurhash": "^2.0.5",
@@ -60,11 +60,20 @@ export abstract class AbstractDatabaseService {
60
60
  * each link: on expiry this promise rejects and the chain moves on, even
61
61
  * though the underlying RPC is still parked in the SDK's pending map.
62
62
  */
63
+ /**
64
+ * Hook run inside the query queue, right before a statement is sent. The
65
+ * remote service uses it to hold statements while a connect is in flight,
66
+ * so a query never runs on a socket that is open but has not had its
67
+ * namespace and token applied yet. The default does nothing.
68
+ */
69
+ protected async beforeQuery(): Promise<void> {}
70
+
63
71
  async query<T extends unknown[]>(query: string, vars?: Record<string, unknown>): Promise<T> {
64
72
  return new Promise((resolve, reject) => {
65
73
  this.queryQueue = this.queryQueue
66
74
  // oxlint-disable-next-line promise/always-return
67
75
  .then(async () => {
76
+ await this.beforeQuery();
68
77
  const startTime = performance.now();
69
78
  try {
70
79
  this.logger.debug(
@@ -191,6 +191,28 @@ export class RemoteDatabaseService extends AbstractDatabaseService {
191
191
  }
192
192
  }
193
193
 
194
+ /**
195
+ * Hold statements while a connect is in flight.
196
+ *
197
+ * `connect()` opens the socket, then selects the namespace/database, then
198
+ * authenticates - three round trips. The SDK considers the connection ready
199
+ * after the first, so a query queued during the other two ran on a socket
200
+ * with no namespace ("Specify a namespace to use") or, worse, no identity.
201
+ * Seen 2026-09-06 after the supervisor rebuilt a socket: a collection
202
+ * recount failed with exactly that error. Waiting on the in-flight connect
203
+ * costs nothing when no connect is running; a failed connect is not
204
+ * swallowed here - the query then fails on its own, as before.
205
+ */
206
+ protected override async beforeQuery(): Promise<void> {
207
+ const inflight = this.connecting;
208
+ if (!inflight) return;
209
+ try {
210
+ await inflight;
211
+ } catch {
212
+ // The query that follows reports the failure itself.
213
+ }
214
+ }
215
+
194
216
  /**
195
217
  * Open (or re-open) the remote connection.
196
218
  *