@spooky-sync/core 0.0.1-canary.15 → 0.0.1-canary.151
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/AGENTS.md +56 -0
- package/dist/index.d.ts +1192 -372
- package/dist/index.js +5772 -1270
- package/dist/otel/index.d.ts +21 -0
- package/dist/otel/index.js +86 -0
- package/dist/sqlite-plan-sql.js +194 -0
- package/dist/sqlite-worker.d.ts +1 -0
- package/dist/sqlite-worker.js +202 -0
- package/dist/types.d.ts +755 -0
- package/package.json +40 -8
- package/skills/sp00ky-core/SKILL.md +258 -0
- package/skills/sp00ky-core/references/auth.md +98 -0
- package/skills/sp00ky-core/references/config.md +76 -0
- package/src/build-globals.d.ts +12 -0
- package/src/events/events.test.ts +2 -1
- package/src/events/index.ts +3 -0
- package/src/index.ts +16 -2
- package/src/modules/app-release/index.test.ts +125 -0
- package/src/modules/app-release/index.ts +201 -0
- package/src/modules/auth/events/index.ts +2 -1
- package/src/modules/auth/index.ts +59 -20
- package/src/modules/cache/index.ts +77 -32
- package/src/modules/cache/types.ts +2 -2
- package/src/modules/crdt/crdt-field.ts +294 -0
- package/src/modules/crdt/crdt-hydration.test.ts +206 -0
- package/src/modules/crdt/index.ts +361 -0
- package/src/modules/crdt/loro-loader.ts +25 -0
- package/src/modules/data/data.hydration.test.ts +142 -0
- package/src/modules/data/data.rebind.test.ts +147 -0
- package/src/modules/data/data.run.test.ts +113 -0
- package/src/modules/data/data.status.test.ts +249 -0
- package/src/modules/data/index.ts +1134 -128
- package/src/modules/data/window-query.test.ts +52 -0
- package/src/modules/data/window-query.ts +154 -0
- package/src/modules/devtools/index.ts +191 -30
- package/src/modules/devtools/versions.test.ts +74 -0
- package/src/modules/devtools/versions.ts +81 -0
- package/src/modules/feature-flag/index.test.ts +120 -0
- package/src/modules/feature-flag/index.ts +209 -0
- package/src/modules/ref-tables.test.ts +91 -0
- package/src/modules/ref-tables.ts +88 -0
- package/src/modules/sync/engine.ts +101 -37
- package/src/modules/sync/events/index.ts +9 -2
- package/src/modules/sync/queue/queue-down.ts +12 -5
- package/src/modules/sync/queue/queue-up.ts +29 -14
- package/src/modules/sync/scheduler.pause.test.ts +109 -0
- package/src/modules/sync/scheduler.ts +73 -7
- package/src/modules/sync/sync.health.test.ts +149 -0
- package/src/modules/sync/sync.subquery.test.ts +82 -0
- package/src/modules/sync/sync.ts +1017 -62
- package/src/modules/sync/utils.test.ts +269 -2
- package/src/modules/sync/utils.ts +182 -17
- package/src/otel/index.ts +127 -0
- package/src/services/database/cache-engine.ts +143 -0
- package/src/services/database/database.ts +11 -11
- package/src/services/database/engine-factory.ts +32 -0
- package/src/services/database/events/index.ts +2 -1
- package/src/services/database/index.ts +6 -0
- package/src/services/database/local-migrator.ts +28 -27
- package/src/services/database/local.test.ts +64 -0
- package/src/services/database/local.ts +478 -67
- package/src/services/database/plan-render.test.ts +159 -0
- package/src/services/database/plan-render.ts +108 -0
- package/src/services/database/relation-resolver.test.ts +413 -0
- package/src/services/database/relation-resolver.ts +0 -0
- package/src/services/database/remote.ts +13 -13
- package/src/services/database/sqlite-cache-engine.test.ts +215 -0
- package/src/services/database/sqlite-cache-engine.ts +829 -0
- package/src/services/database/sqlite-plan-sql.test.ts +104 -0
- package/src/services/database/sqlite-plan-sql.ts +106 -0
- package/src/services/database/sqlite-select.integration.test.ts +185 -0
- package/src/services/database/sqlite-select.test.ts +279 -0
- package/src/services/database/sqlite-select.ts +113 -0
- package/src/services/database/sqlite-worker.ts +160 -0
- package/src/services/database/surql-translate.ts +291 -0
- package/src/services/database/surreal-cache-engine.ts +139 -0
- package/src/services/logger/index.ts +6 -101
- package/src/services/persistence/localstorage.ts +2 -2
- package/src/services/persistence/resilient.ts +11 -4
- package/src/services/persistence/surrealdb.ts +10 -10
- package/src/services/stream-processor/index.ts +295 -38
- package/src/services/stream-processor/permissions.test.ts +47 -0
- package/src/services/stream-processor/permissions.ts +53 -0
- package/src/services/stream-processor/stream-processor.batch.test.ts +136 -0
- package/src/services/stream-processor/stream-processor.reset.test.ts +104 -0
- package/src/services/stream-processor/stream-processor.test.ts +1 -1
- package/src/services/stream-processor/wasm-types.ts +18 -2
- package/src/sp00ky.auth-order.test.ts +92 -0
- package/src/sp00ky.init-query.test.ts +183 -0
- package/src/sp00ky.ts +1000 -0
- package/src/types.ts +267 -15
- package/src/utils/error-classification.test.ts +44 -0
- package/src/utils/error-classification.ts +7 -0
- package/src/utils/index.ts +35 -13
- package/src/utils/parser.ts +3 -2
- package/src/utils/semver.test.ts +32 -0
- package/src/utils/semver.ts +30 -0
- package/src/utils/surql.ts +24 -15
- package/src/utils/withRetry.test.ts +1 -1
- package/tsdown.config.ts +77 -1
- package/src/spooky.ts +0 -395
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import type { QueryPlan } from '@spooky-sync/query-builder';
|
|
2
|
+
import { LocalDatabaseService } from './local';
|
|
3
|
+
import { resolveRelations } from './relation-resolver';
|
|
4
|
+
import {
|
|
5
|
+
renderBaseSelectSurql,
|
|
6
|
+
renderRelationFetchSurql,
|
|
7
|
+
} from './plan-render';
|
|
8
|
+
import type {
|
|
9
|
+
EngineTx,
|
|
10
|
+
Id,
|
|
11
|
+
LocalCacheEngine,
|
|
12
|
+
OrderBy,
|
|
13
|
+
RelationFetch,
|
|
14
|
+
Row,
|
|
15
|
+
} from './cache-engine';
|
|
16
|
+
import { stableKey } from './relation-resolver';
|
|
17
|
+
import { surql } from '../../utils/surql';
|
|
18
|
+
import { RecordId } from 'surrealdb';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Default local cache backend: the in-browser SurrealDB-WASM store. Implemented
|
|
22
|
+
* as a subclass of {@link LocalDatabaseService} so it remains a 100% drop-in for
|
|
23
|
+
* every existing `this.local.query(...)` / `execute` / `switchStore` / `epoch`
|
|
24
|
+
* call site (zero behavior change), while adding the engine-neutral verb surface
|
|
25
|
+
* (`select`/`selectByIds`/`getById`/CRUD) used by the pluggable path.
|
|
26
|
+
*
|
|
27
|
+
* Relations are resolved with the SAME shared {@link resolveRelations} as the
|
|
28
|
+
* SQLite backend, so the two engines decompose `.related()` identically.
|
|
29
|
+
*/
|
|
30
|
+
export class SurrealCacheEngine extends LocalDatabaseService implements LocalCacheEngine {
|
|
31
|
+
/** SurrealDB needs its SurrealQL schema provisioned locally. */
|
|
32
|
+
readonly usesSurqlSchema = true;
|
|
33
|
+
|
|
34
|
+
/** {@link LocalCacheEngine} alias for {@link LocalDatabaseService.switchStore}. */
|
|
35
|
+
switchBucket(bucketId: string): Promise<void> {
|
|
36
|
+
return this.switchStore(bucketId);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async fetchRelation(req: RelationFetch): Promise<Row[]> {
|
|
40
|
+
const { sql, vars } = renderRelationFetchSurql(req);
|
|
41
|
+
const [rows] = await this.query<[Row[]]>(sql, vars);
|
|
42
|
+
return rows ?? [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async select(plan: QueryPlan, params: Record<string, unknown> = {}): Promise<Row[]> {
|
|
46
|
+
// Window materialization: base rows are exactly `plan.ids`, ordered.
|
|
47
|
+
if (plan.ids) {
|
|
48
|
+
const result = await this.selectByIds(plan.table, plan.ids, {
|
|
49
|
+
select: plan.select,
|
|
50
|
+
orderBy: plan.orderBy,
|
|
51
|
+
});
|
|
52
|
+
await resolveRelations(result, plan.relations, this);
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
const { sql, vars } = renderBaseSelectSurql(plan, params);
|
|
56
|
+
const [rows] = await this.query<[Row[]]>(sql, vars);
|
|
57
|
+
const result = rows ?? [];
|
|
58
|
+
await resolveRelations(result, plan.relations, this);
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async selectByIds(
|
|
63
|
+
table: string,
|
|
64
|
+
ids: Id[],
|
|
65
|
+
opts?: { select?: string[]; orderBy?: OrderBy }
|
|
66
|
+
): Promise<Row[]> {
|
|
67
|
+
if (ids.length === 0) return [];
|
|
68
|
+
const projection =
|
|
69
|
+
opts?.select && opts.select.length > 0 ? ['id', ...opts.select].join(', ') : '*';
|
|
70
|
+
let sql = `SELECT ${projection} FROM $__ids`;
|
|
71
|
+
if (opts?.orderBy && opts.orderBy.length > 0) {
|
|
72
|
+
sql += ` ORDER BY ${opts.orderBy.map(([f, d]) => `${f} ${d}`).join(', ')}`;
|
|
73
|
+
}
|
|
74
|
+
const [rows] = await this.query<[Row[]]>(`${sql};`, { __ids: ids });
|
|
75
|
+
const result = rows ?? [];
|
|
76
|
+
// Preserve caller's id order when no explicit ORDER BY (SurrealDB does not
|
|
77
|
+
// guarantee `FROM $ids` order).
|
|
78
|
+
if (!opts?.orderBy || opts.orderBy.length === 0) {
|
|
79
|
+
const pos = new Map(ids.map((id, i) => [stableKey(id), i]));
|
|
80
|
+
result.sort(
|
|
81
|
+
(a, b) => (pos.get(stableKey(a.id)) ?? 0) - (pos.get(stableKey(b.id)) ?? 0)
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
return result;
|
|
85
|
+
}
|
|
86
|
+
|
|
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;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async upsert(table: string, id: Id, data: Row, mode: 'replace' | 'merge'): Promise<void> {
|
|
109
|
+
const sql = mode === 'merge' ? surql.upsertMerge('__id', '__data') : surql.upsert('__id', '__data');
|
|
110
|
+
await this.query(surql.seal(sql), { __id: this.toRecordId(table, id), __data: data });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async patch(table: string, id: Id, patches: unknown[]): Promise<void> {
|
|
114
|
+
await this.query(surql.seal('UPDATE ONLY $__id PATCH $__patches'), {
|
|
115
|
+
__id: this.toRecordId(table, id),
|
|
116
|
+
__patches: patches,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async delete(table: string, id: Id): Promise<void> {
|
|
121
|
+
await this.query(surql.seal(surql.delete('__id')), { __id: this.toRecordId(table, id) });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Serialized (not strictly atomic) transaction: verbs run in order on the
|
|
126
|
+
* same serialized query queue. The SurrealDB-WASM store already funnels every
|
|
127
|
+
* `query()` through one queue, so these never interleave with other work;
|
|
128
|
+
* true multi-statement atomicity is not required by the current call sites
|
|
129
|
+
* (single-record CRDT / mutation writes).
|
|
130
|
+
*/
|
|
131
|
+
async transaction<T>(fn: (tx: EngineTx) => Promise<T>): Promise<T> {
|
|
132
|
+
const tx: EngineTx = {
|
|
133
|
+
upsert: (t, id, data, mode) => this.upsert(t, id, data, mode),
|
|
134
|
+
patch: (t, id, patches) => this.patch(t, id, patches),
|
|
135
|
+
delete: (t, id) => this.delete(t, id),
|
|
136
|
+
};
|
|
137
|
+
return fn(tx);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
@@ -1,114 +1,19 @@
|
|
|
1
|
-
import pino, { Level, type Logger as PinoLogger, type LoggerOptions } from 'pino';
|
|
2
|
-
import {
|
|
3
|
-
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';
|
|
4
|
-
import { resourceFromAttributes } from '@opentelemetry/resources';
|
|
5
|
-
import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
|
|
6
|
-
import { createContextKey } from '@opentelemetry/api';
|
|
7
|
-
|
|
8
|
-
const CATEGORY_KEY = createContextKey('Category');
|
|
1
|
+
import pino, { type Level, type Logger as PinoLogger, type LoggerOptions } from 'pino';
|
|
2
|
+
import type { PinoTransmit } from '../../types';
|
|
9
3
|
|
|
10
4
|
export type Logger = PinoLogger;
|
|
11
5
|
|
|
12
|
-
|
|
13
|
-
// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/logs/data-model.md#severity-fields
|
|
14
|
-
function mapLevelToSeverityNumber(level: string): number {
|
|
15
|
-
switch (level) {
|
|
16
|
-
case 'trace':
|
|
17
|
-
return 1;
|
|
18
|
-
case 'debug':
|
|
19
|
-
return 5;
|
|
20
|
-
case 'info':
|
|
21
|
-
return 9;
|
|
22
|
-
case 'warn':
|
|
23
|
-
return 13;
|
|
24
|
-
case 'error':
|
|
25
|
-
return 17;
|
|
26
|
-
case 'fatal':
|
|
27
|
-
return 21;
|
|
28
|
-
default:
|
|
29
|
-
return 9;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function createLogger(level: Level = 'info', otelEndpoint?: string): Logger {
|
|
6
|
+
export function createLogger(level: Level = 'info', transmit?: PinoTransmit): Logger {
|
|
34
7
|
const browserConfig: LoggerOptions['browser'] = {
|
|
35
8
|
asObject: true,
|
|
36
9
|
write: (o: any) => {
|
|
10
|
+
// oxlint-disable-next-line no-console
|
|
37
11
|
console.log(JSON.stringify(o));
|
|
38
12
|
},
|
|
39
13
|
};
|
|
40
14
|
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
const resource = resourceFromAttributes({
|
|
44
|
-
[ATTR_SERVICE_NAME]: 'spooky-client',
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const exporter = new OTLPLogExporter({
|
|
48
|
-
url: otelEndpoint,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Pass processors in constructor as this SDK version requires it
|
|
52
|
-
const loggerProvider = new LoggerProvider({
|
|
53
|
-
resource,
|
|
54
|
-
processors: [new BatchLogRecordProcessor(exporter)],
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const otelLogger: Record<string, ReturnType<typeof loggerProvider.getLogger>> = {};
|
|
58
|
-
|
|
59
|
-
const getOtelLogger = (category: string) => {
|
|
60
|
-
if (!otelLogger[category]) {
|
|
61
|
-
otelLogger[category] = loggerProvider.getLogger(category);
|
|
62
|
-
}
|
|
63
|
-
return otelLogger[category];
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
browserConfig.transmit = {
|
|
67
|
-
level: level,
|
|
68
|
-
send: (levelLabel: string, logEvent: any) => {
|
|
69
|
-
try {
|
|
70
|
-
const messages = [...logEvent.messages];
|
|
71
|
-
const severityNumber = mapLevelToSeverityNumber(levelLabel);
|
|
72
|
-
|
|
73
|
-
// Construct the message body
|
|
74
|
-
let body = '';
|
|
75
|
-
const msg = messages.pop();
|
|
76
|
-
|
|
77
|
-
if (typeof msg === 'string') {
|
|
78
|
-
body = msg;
|
|
79
|
-
} else if (msg) {
|
|
80
|
-
body = JSON.stringify(msg);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let category = 'spooky-client::unknown';
|
|
84
|
-
|
|
85
|
-
const attributes = {};
|
|
86
|
-
for (const msg of messages) {
|
|
87
|
-
if (typeof msg === 'object') {
|
|
88
|
-
if (msg.Category) {
|
|
89
|
-
category = msg.Category;
|
|
90
|
-
delete msg.Category;
|
|
91
|
-
}
|
|
92
|
-
Object.assign(attributes, msg);
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Emit to OTEL SDK
|
|
97
|
-
getOtelLogger(category).emit({
|
|
98
|
-
severityNumber: severityNumber,
|
|
99
|
-
severityText: levelLabel.toUpperCase(),
|
|
100
|
-
body: body,
|
|
101
|
-
attributes: {
|
|
102
|
-
...logEvent.bindings[0],
|
|
103
|
-
...attributes,
|
|
104
|
-
},
|
|
105
|
-
timestamp: new Date(logEvent.ts),
|
|
106
|
-
});
|
|
107
|
-
} catch (e) {
|
|
108
|
-
console.warn('Failed to transmit log to OTEL endpoint', e);
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
};
|
|
15
|
+
if (transmit) {
|
|
16
|
+
browserConfig.transmit = transmit;
|
|
112
17
|
}
|
|
113
18
|
|
|
114
19
|
return pino({
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Logger } from 'pino';
|
|
2
|
-
import { PersistenceClient } from '../../types';
|
|
1
|
+
import type { Logger } from 'pino';
|
|
2
|
+
import type { PersistenceClient } from '../../types';
|
|
3
3
|
|
|
4
4
|
export class LocalStoragePersistenceClient implements PersistenceClient {
|
|
5
5
|
private logger: Logger;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Logger } from 'pino';
|
|
2
|
-
import { PersistenceClient } from '../../types';
|
|
1
|
+
import type { Logger } from 'pino';
|
|
2
|
+
import type { PersistenceClient } from '../../types';
|
|
3
3
|
|
|
4
4
|
export class ResilientPersistenceClient implements PersistenceClient {
|
|
5
5
|
private logger: Logger;
|
|
@@ -20,10 +20,17 @@ export class ResilientPersistenceClient implements PersistenceClient {
|
|
|
20
20
|
return await this.inner.get<T>(key);
|
|
21
21
|
} catch (e) {
|
|
22
22
|
this.logger.warn(
|
|
23
|
-
{ key, error: e, Category: '
|
|
23
|
+
{ key, error: e, Category: 'sp00ky-client::ResilientPersistenceClient::get' },
|
|
24
24
|
'Persistence read failed, dropping key'
|
|
25
25
|
);
|
|
26
|
-
|
|
26
|
+
// Best-effort cleanup of the corrupt key; if removal also fails, the key
|
|
27
|
+
// just gets dropped again on the next failed read, so the failure is safe.
|
|
28
|
+
await this.inner.remove(key).catch((removeErr) => {
|
|
29
|
+
this.logger.debug(
|
|
30
|
+
{ key, error: removeErr, Category: 'sp00ky-client::ResilientPersistenceClient::get' },
|
|
31
|
+
'Failed to drop corrupt persistence key'
|
|
32
|
+
);
|
|
33
|
+
});
|
|
27
34
|
return null;
|
|
28
35
|
}
|
|
29
36
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { PersistenceClient } from '../../types';
|
|
1
|
+
import type { PersistenceClient } from '../../types';
|
|
2
2
|
import { parseRecordIdString, surql } from '../../utils/index';
|
|
3
|
-
import { Logger } from 'pino';
|
|
4
|
-
import {
|
|
3
|
+
import type { Logger } from 'pino';
|
|
4
|
+
import type { LocalStore } from '../database/cache-engine';
|
|
5
5
|
|
|
6
6
|
export class SurrealDBPersistenceClient implements PersistenceClient {
|
|
7
7
|
private logger: Logger;
|
|
8
8
|
|
|
9
9
|
constructor(
|
|
10
|
-
private db:
|
|
10
|
+
private db: LocalStore,
|
|
11
11
|
logger: Logger
|
|
12
12
|
) {
|
|
13
13
|
this.logger = logger.child({ service: 'PersistenceClient:SurrealDb' });
|
|
@@ -15,11 +15,11 @@ export class SurrealDBPersistenceClient implements PersistenceClient {
|
|
|
15
15
|
|
|
16
16
|
async set<T>(key: string, val: T) {
|
|
17
17
|
try {
|
|
18
|
-
const id = parseRecordIdString(`
|
|
18
|
+
const id = parseRecordIdString(`_00_kv:${key}`);
|
|
19
19
|
await this.db.query(surql.seal(surql.upsert('id', 'data')), { id, data: { val } });
|
|
20
20
|
} catch (error) {
|
|
21
21
|
this.logger.error(
|
|
22
|
-
{ error, Category: '
|
|
22
|
+
{ error, Category: 'sp00ky-client::SurrealDBPersistenceClient::set' },
|
|
23
23
|
'Failed to set KV'
|
|
24
24
|
);
|
|
25
25
|
throw error;
|
|
@@ -28,7 +28,7 @@ export class SurrealDBPersistenceClient implements PersistenceClient {
|
|
|
28
28
|
|
|
29
29
|
async get<T>(key: string) {
|
|
30
30
|
try {
|
|
31
|
-
const id = parseRecordIdString(`
|
|
31
|
+
const id = parseRecordIdString(`_00_kv:${key}`);
|
|
32
32
|
const [result] = await this.db.query<[{ val: T }]>(
|
|
33
33
|
surql.seal(surql.selectById('id', ['val'])),
|
|
34
34
|
{
|
|
@@ -41,7 +41,7 @@ export class SurrealDBPersistenceClient implements PersistenceClient {
|
|
|
41
41
|
return result.val;
|
|
42
42
|
} catch (error) {
|
|
43
43
|
this.logger.warn(
|
|
44
|
-
{ error, Category: '
|
|
44
|
+
{ error, Category: 'sp00ky-client::SurrealDBPersistenceClient::get' },
|
|
45
45
|
'Failed to get KV'
|
|
46
46
|
);
|
|
47
47
|
return null;
|
|
@@ -50,11 +50,11 @@ export class SurrealDBPersistenceClient implements PersistenceClient {
|
|
|
50
50
|
|
|
51
51
|
async remove(key: string) {
|
|
52
52
|
try {
|
|
53
|
-
const id = parseRecordIdString(`
|
|
53
|
+
const id = parseRecordIdString(`_00_kv:${key}`);
|
|
54
54
|
await this.db.query(surql.seal(surql.delete('id')), { id });
|
|
55
55
|
} catch (err) {
|
|
56
56
|
this.logger.info(
|
|
57
|
-
{ err, Category: '
|
|
57
|
+
{ err, Category: 'sp00ky-client::SurrealDBPersistenceClient::remove' },
|
|
58
58
|
'Failed to delete KV'
|
|
59
59
|
);
|
|
60
60
|
}
|