@spooky-sync/core 0.0.1-canary.157 → 0.0.1-canary.158
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
|
@@ -4010,7 +4010,7 @@ var UpQueue = class {
|
|
|
4010
4010
|
async enqueueFromDatabase(mutationId) {
|
|
4011
4011
|
if (this.queue.some((e) => encodeUpEventId(e) === mutationId)) return;
|
|
4012
4012
|
try {
|
|
4013
|
-
const [records] = await this.local.query(`SELECT * FROM $
|
|
4013
|
+
const [records] = await this.local.query(`SELECT * FROM $mutation_ids`, { mutation_ids: [parseRecordIdString(mutationId)] });
|
|
4014
4014
|
const event = Array.isArray(records) && records[0] ? rowToUpEvent(records[0], this.logger) : null;
|
|
4015
4015
|
if (event) this.addToQueue(event);
|
|
4016
4016
|
} catch (error) {
|
|
@@ -5694,8 +5694,8 @@ async function walkOpfs(maxEntries = 2e3, maxDepth = 8) {
|
|
|
5694
5694
|
|
|
5695
5695
|
//#endregion
|
|
5696
5696
|
//#region src/modules/devtools/index.ts
|
|
5697
|
-
const CORE_VERSION = "0.0.1-canary.
|
|
5698
|
-
const WASM_VERSION = "0.0.1-canary.
|
|
5697
|
+
const CORE_VERSION = "0.0.1-canary.158";
|
|
5698
|
+
const WASM_VERSION = "0.0.1-canary.158";
|
|
5699
5699
|
const SURREAL_VERSION = "3.0.3";
|
|
5700
5700
|
var DevToolsService = class DevToolsService {
|
|
5701
5701
|
eventsHistory = [];
|
|
@@ -8939,7 +8939,7 @@ var Sp00kyClient = class {
|
|
|
8939
8939
|
return new TabsCoordinator({
|
|
8940
8940
|
tabId,
|
|
8941
8941
|
fingerprint: computeTabsFingerprint({
|
|
8942
|
-
coreVersion: "0.0.1-canary.
|
|
8942
|
+
coreVersion: "0.0.1-canary.158",
|
|
8943
8943
|
schemaHash: hash53(this.config.schemaSurql),
|
|
8944
8944
|
endpoint: this.config.database.endpoint ?? "",
|
|
8945
8945
|
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.
|
|
3
|
+
"version": "0.0.1-canary.158",
|
|
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.
|
|
64
|
-
"@spooky-sync/ssp-wasm": "0.0.1-canary.
|
|
63
|
+
"@spooky-sync/query-builder": "0.0.1-canary.158",
|
|
64
|
+
"@spooky-sync/ssp-wasm": "0.0.1-canary.158",
|
|
65
65
|
"@sqlite.org/sqlite-wasm": "3.53.0-build1",
|
|
66
66
|
"@surrealdb/wasm": "^3.0.3",
|
|
67
67
|
"fast-json-patch": "^3.1.1",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, vi } from 'vitest';
|
|
2
2
|
import { UpQueue } from './queue-up';
|
|
3
|
+
import { translateSurql } from '../../../services/database/surql-translate';
|
|
3
4
|
|
|
4
5
|
function makeLogger(): any {
|
|
5
6
|
const noop = () => {};
|
|
@@ -21,7 +22,8 @@ const ROW = {
|
|
|
21
22
|
describe('UpQueue.enqueueFromDatabase', () => {
|
|
22
23
|
function makeQueue(rows: Record<string, unknown[]>) {
|
|
23
24
|
const query = vi.fn(async (_sql: string, vars?: Record<string, unknown>) => {
|
|
24
|
-
const
|
|
25
|
+
const ids = (vars?.mutation_ids as unknown[]) ?? [];
|
|
26
|
+
const id = String(ids[0] ?? '');
|
|
25
27
|
return [rows[id] ?? []];
|
|
26
28
|
});
|
|
27
29
|
const local: any = { query };
|
|
@@ -48,4 +50,26 @@ describe('UpQueue.enqueueFromDatabase', () => {
|
|
|
48
50
|
await queue.enqueueFromDatabase(ROW.id);
|
|
49
51
|
expect(queue.size).toBe(0);
|
|
50
52
|
});
|
|
53
|
+
|
|
54
|
+
// The mock above replaces `local.query` wholesale, so on its own it proves
|
|
55
|
+
// nothing about the SQLite engine actually being able to RUN the statement.
|
|
56
|
+
// That gap shipped a bug: the emitted `SELECT * FROM $mutation_id` passed a
|
|
57
|
+
// single RecordId where the engine's `selectByIds` lowering expects an array,
|
|
58
|
+
// so it threw, the surrounding catch swallowed it at `error` level, and every
|
|
59
|
+
// follower mutation was silently never pushed. Drive the real translator.
|
|
60
|
+
it('emits a statement the SQLite engine can actually translate', async () => {
|
|
61
|
+
const { queue, query } = makeQueue({ [ROW.id]: [ROW] });
|
|
62
|
+
await queue.enqueueFromDatabase(ROW.id);
|
|
63
|
+
|
|
64
|
+
const [sql, vars] = query.mock.calls[0] as [string, Record<string, unknown>];
|
|
65
|
+
const translated = translateSurql(sql, vars);
|
|
66
|
+
const op: any = translated.ops[0];
|
|
67
|
+
|
|
68
|
+
expect(op.kind).toBe('selectByIds');
|
|
69
|
+
// The engine does `ids.length` then `ids.map(...)`: a non-array silently
|
|
70
|
+
// skips the empty-guard and then throws.
|
|
71
|
+
expect(Array.isArray(op.ids)).toBe(true);
|
|
72
|
+
expect(op.ids).toHaveLength(1);
|
|
73
|
+
expect(() => (op.ids as unknown[]).map((x) => x)).not.toThrow();
|
|
74
|
+
});
|
|
51
75
|
});
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import type { RecordId } from 'surrealdb';
|
|
2
2
|
import type { LocalStore } from '../../../services/database/index';
|
|
3
|
-
import type {
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
createSyncQueueEventSystem,
|
|
7
|
-
SyncQueueEventTypes,
|
|
8
|
-
} from '../events/index';
|
|
3
|
+
import type { SyncQueueEventSystem } from '../events/index';
|
|
4
|
+
import { createSyncQueueEventSystem, SyncQueueEventTypes } from '../events/index';
|
|
9
5
|
import {
|
|
10
6
|
parseRecordIdString,
|
|
11
7
|
extractTablePart,
|
|
@@ -50,7 +46,10 @@ export class UpQueue {
|
|
|
50
46
|
private queue: UpEvent[] = [];
|
|
51
47
|
private _events: SyncQueueEventSystem;
|
|
52
48
|
private logger: Logger;
|
|
53
|
-
private debouncedMutations: Map<
|
|
49
|
+
private debouncedMutations: Map<
|
|
50
|
+
string,
|
|
51
|
+
{ timer: any; firstBeforeRecord?: Record<string, unknown> }
|
|
52
|
+
>;
|
|
54
53
|
|
|
55
54
|
get events(): SyncQueueEventSystem {
|
|
56
55
|
return this._events;
|
|
@@ -199,10 +198,19 @@ export class UpQueue {
|
|
|
199
198
|
async enqueueFromDatabase(mutationId: string): Promise<void> {
|
|
200
199
|
if (this.queue.some((e) => encodeUpEventId(e) === mutationId)) return;
|
|
201
200
|
try {
|
|
202
|
-
|
|
203
|
-
|
|
201
|
+
// ARRAY param, matching SyncEngine's `SELECT * FROM $idsToFetch`. A bare
|
|
202
|
+
// `FROM $singleRecordId` looks fine against SurrealDB but the SQLite
|
|
203
|
+
// engine lowers any `FROM $param` to `selectByIds` and calls `.map` on
|
|
204
|
+
// the param (surql-translate.ts, SqliteCacheEngine.selectByIds), so a
|
|
205
|
+
// single RecordId threw. The throw landed in the catch below, which logs
|
|
206
|
+
// at `error` — invisible to an app running `logLevel: 'fatal'` — so every
|
|
207
|
+
// forwarded mutation was silently dropped: the follower's optimistic
|
|
208
|
+
// write stuck locally, was never pushed, and the next down-sync reverted it.
|
|
209
|
+
const [records] = await this.local.query<any>(`SELECT * FROM $mutation_ids`, {
|
|
210
|
+
mutation_ids: [parseRecordIdString(mutationId)],
|
|
204
211
|
});
|
|
205
|
-
const event =
|
|
212
|
+
const event =
|
|
213
|
+
Array.isArray(records) && records[0] ? rowToUpEvent(records[0], this.logger) : null;
|
|
206
214
|
if (event) this.addToQueue(event);
|
|
207
215
|
} catch (error) {
|
|
208
216
|
this.logger.error(
|
|
@@ -266,7 +274,11 @@ function rowToUpEvent(r: any, logger: Logger): UpEvent | null {
|
|
|
266
274
|
};
|
|
267
275
|
default:
|
|
268
276
|
logger.warn(
|
|
269
|
-
{
|
|
277
|
+
{
|
|
278
|
+
mutationType: r.mutationType,
|
|
279
|
+
record: r,
|
|
280
|
+
Category: 'sp00ky-client::UpQueue::rowToUpEvent',
|
|
281
|
+
},
|
|
270
282
|
'Unknown mutation type'
|
|
271
283
|
);
|
|
272
284
|
return null;
|