@spooky-sync/core 0.0.1-canary.130 → 0.0.1-canary.131

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.js CHANGED
@@ -1283,25 +1283,36 @@ var SurrealCacheEngine = class extends LocalDatabaseService {
1283
1283
  }
1284
1284
  return result;
1285
1285
  }
1286
- async getById(_table, id) {
1287
- const [row] = await this.query("SELECT * FROM ONLY $__id;", { __id: id });
1288
- return row ?? null;
1286
+ /**
1287
+ * Coerce the contract's `Id` (a RecordId, a stable `table:id` string, or a
1288
+ * bare id + the verb's `table` param) to a real RecordId. SurrealDB binds
1289
+ * `$__id` verbatim: a plain string makes `FROM ONLY $__id` "select" the
1290
+ * string itself (a truthy non-row) and `UPSERT $__id` an InternalError, so
1291
+ * string ids silently broke every id-verb on this engine.
1292
+ */
1293
+ toRecordId(table, id) {
1294
+ if (typeof id !== "string") return id;
1295
+ return new RecordId(table, id.startsWith(`${table}:`) ? id.slice(table.length + 1) : id);
1296
+ }
1297
+ async getById(table, id) {
1298
+ const [row] = await this.query("SELECT * FROM ONLY $__id;", { __id: this.toRecordId(table, id) });
1299
+ return row && typeof row === "object" ? row : null;
1289
1300
  }
1290
- async upsert(_table, id, data, mode) {
1301
+ async upsert(table, id, data, mode) {
1291
1302
  const sql = mode === "merge" ? surql.upsertMerge("__id", "__data") : surql.upsert("__id", "__data");
1292
1303
  await this.query(surql.seal(sql), {
1293
- __id: id,
1304
+ __id: this.toRecordId(table, id),
1294
1305
  __data: data
1295
1306
  });
1296
1307
  }
1297
- async patch(_table, id, patches) {
1308
+ async patch(table, id, patches) {
1298
1309
  await this.query(surql.seal("UPDATE ONLY $__id PATCH $__patches"), {
1299
- __id: id,
1310
+ __id: this.toRecordId(table, id),
1300
1311
  __patches: patches
1301
1312
  });
1302
1313
  }
1303
- async delete(_table, id) {
1304
- await this.query(surql.seal(surql.delete("__id")), { __id: id });
1314
+ async delete(table, id) {
1315
+ await this.query(surql.seal(surql.delete("__id")), { __id: this.toRecordId(table, id) });
1305
1316
  }
1306
1317
  /**
1307
1318
  * Serialized (not strictly atomic) transaction: verbs run in order on the
@@ -2774,8 +2785,8 @@ var DataModule = class {
2774
2785
  */
2775
2786
  async getPreloadMarker(hash) {
2776
2787
  try {
2777
- const row = await this.local.getById("_00_preload", hash);
2778
- if (!row) return null;
2788
+ const row = await this.local.getById("_00_preload", new RecordId("_00_preload", hash));
2789
+ if (!row || typeof row !== "object") return null;
2779
2790
  return {
2780
2791
  fetchedAt: Number(row.fetchedAt) || 0,
2781
2792
  rowCount: Number(row.rowCount) || 0
@@ -2796,7 +2807,7 @@ var DataModule = class {
2796
2807
  }
2797
2808
  /** Stamp the preload freshness marker after a successful snapshot fetch. */
2798
2809
  async writePreloadMarker(hash, rowCount) {
2799
- await this.local.upsert("_00_preload", hash, {
2810
+ await this.local.upsert("_00_preload", new RecordId("_00_preload", hash), {
2800
2811
  fetchedAt: Date.now(),
2801
2812
  rowCount
2802
2813
  }, "replace");
@@ -5130,8 +5141,8 @@ function parseBackendInfo(raw) {
5130
5141
 
5131
5142
  //#endregion
5132
5143
  //#region src/modules/devtools/index.ts
5133
- const CORE_VERSION = "0.0.1-canary.130";
5134
- const WASM_VERSION = "0.0.1-canary.130";
5144
+ const CORE_VERSION = "0.0.1-canary.131";
5145
+ const WASM_VERSION = "0.0.1-canary.131";
5135
5146
  const SURREAL_VERSION = "3.0.3";
5136
5147
  var DevToolsService = class {
5137
5148
  eventsHistory = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spooky-sync/core",
3
- "version": "0.0.1-canary.130",
3
+ "version": "0.0.1-canary.131",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -59,8 +59,8 @@
59
59
  }
60
60
  },
61
61
  "dependencies": {
62
- "@spooky-sync/query-builder": "0.0.1-canary.130",
63
- "@spooky-sync/ssp-wasm": "0.0.1-canary.130",
62
+ "@spooky-sync/query-builder": "0.0.1-canary.131",
63
+ "@spooky-sync/ssp-wasm": "0.0.1-canary.131",
64
64
  "@sqlite.org/sqlite-wasm": "3.53.0-build1",
65
65
  "@surrealdb/wasm": "^3.0.3",
66
66
  "fast-json-patch": "^3.1.1",
@@ -876,8 +876,11 @@ export class DataModule<S extends SchemaStructure> {
876
876
  hash: string
877
877
  ): Promise<{ fetchedAt: number; rowCount: number } | null> {
878
878
  try {
879
- const row = await this.local.getById('_00_preload', hash);
880
- if (!row) return null;
879
+ // Pass a real RecordId: a bare string id hits the SurrealDB engine's
880
+ // `FROM ONLY $__id` as a plain string, which "selects" the string itself
881
+ // (a truthy non-row) instead of the record — misread as a warm marker.
882
+ const row = await this.local.getById('_00_preload', new RecordId('_00_preload', hash));
883
+ if (!row || typeof row !== 'object') return null;
881
884
  return {
882
885
  fetchedAt: Number((row as any).fetchedAt) || 0,
883
886
  rowCount: Number((row as any).rowCount) || 0,
@@ -900,9 +903,12 @@ export class DataModule<S extends SchemaStructure> {
900
903
 
901
904
  /** Stamp the preload freshness marker after a successful snapshot fetch. */
902
905
  async writePreloadMarker(hash: string, rowCount: number): Promise<void> {
906
+ // RecordId, not a bare string: the SurrealDB engine binds the id verbatim,
907
+ // and `UPSERT <string>` is an InternalError — the marker silently never
908
+ // landed (the write is awaited inside preload's best-effort catch).
903
909
  await this.local.upsert(
904
910
  '_00_preload',
905
- hash,
911
+ new RecordId('_00_preload', hash),
906
912
  { fetchedAt: Date.now(), rowCount },
907
913
  'replace'
908
914
  );
@@ -15,6 +15,7 @@ import type {
15
15
  } from './cache-engine';
16
16
  import { stableKey } from './relation-resolver';
17
17
  import { surql } from '../../utils/surql';
18
+ import { RecordId } from 'surrealdb';
18
19
 
19
20
  /**
20
21
  * Default local cache backend: the in-browser SurrealDB-WASM store. Implemented
@@ -83,25 +84,41 @@ export class SurrealCacheEngine extends LocalDatabaseService implements LocalCac
83
84
  return result;
84
85
  }
85
86
 
86
- async getById(_table: string, id: Id): Promise<Row | null> {
87
- const [row] = await this.query<[Row | null]>('SELECT * FROM ONLY $__id;', { __id: id });
88
- return row ?? null;
87
+ /**
88
+ * Coerce the contract's `Id` (a RecordId, a stable `table:id` string, or a
89
+ * bare id + the verb's `table` param) to a real RecordId. SurrealDB binds
90
+ * `$__id` verbatim: a plain string makes `FROM ONLY $__id` "select" the
91
+ * string itself (a truthy non-row) and `UPSERT $__id` an InternalError, so
92
+ * string ids silently broke every id-verb on this engine.
93
+ */
94
+ private toRecordId(table: string, id: Id): unknown {
95
+ if (typeof id !== 'string') return id;
96
+ const raw = id.startsWith(`${table}:`) ? id.slice(table.length + 1) : id;
97
+ return new RecordId(table, raw);
98
+ }
99
+
100
+ async getById(table: string, id: Id): Promise<Row | null> {
101
+ const [row] = await this.query<[Row | null]>('SELECT * FROM ONLY $__id;', {
102
+ __id: this.toRecordId(table, id),
103
+ });
104
+ // `FROM ONLY <non-record>` echoes the value back; only a real row counts.
105
+ return row && typeof row === 'object' ? row : null;
89
106
  }
90
107
 
91
- async upsert(_table: string, id: Id, data: Row, mode: 'replace' | 'merge'): Promise<void> {
108
+ async upsert(table: string, id: Id, data: Row, mode: 'replace' | 'merge'): Promise<void> {
92
109
  const sql = mode === 'merge' ? surql.upsertMerge('__id', '__data') : surql.upsert('__id', '__data');
93
- await this.query(surql.seal(sql), { __id: id, __data: data });
110
+ await this.query(surql.seal(sql), { __id: this.toRecordId(table, id), __data: data });
94
111
  }
95
112
 
96
- async patch(_table: string, id: Id, patches: unknown[]): Promise<void> {
113
+ async patch(table: string, id: Id, patches: unknown[]): Promise<void> {
97
114
  await this.query(surql.seal('UPDATE ONLY $__id PATCH $__patches'), {
98
- __id: id,
115
+ __id: this.toRecordId(table, id),
99
116
  __patches: patches,
100
117
  });
101
118
  }
102
119
 
103
- async delete(_table: string, id: Id): Promise<void> {
104
- await this.query(surql.seal(surql.delete('__id')), { __id: id });
120
+ async delete(table: string, id: Id): Promise<void> {
121
+ await this.query(surql.seal(surql.delete('__id')), { __id: this.toRecordId(table, id) });
105
122
  }
106
123
 
107
124
  /**