@yydb/yydb 0.0.11 → 0.0.12
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/api/database.d.ts +87 -12
- package/dist/api/database.js +140 -14
- package/dist/native/binding.d.ts +20 -0
- package/dist/shared/errors.d.ts +28 -0
- package/dist/shared/errors.js +63 -0
- package/package.json +5 -5
package/dist/api/database.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type EmittableItem } from '@voml/vos';
|
|
2
2
|
import { defineMicro as buildMicro, type DefinedMicro, type MicroHandle } from '../shared/micro.js';
|
|
3
|
+
import { loadNative } from '../native/binding.js';
|
|
3
4
|
import type { UdfScalarDescriptor } from '../shared/udf-types.js';
|
|
4
5
|
/** Published schema metadata. */
|
|
5
6
|
export interface SchemaVersion {
|
|
@@ -11,6 +12,54 @@ export interface OpenOptions {
|
|
|
11
12
|
/** Create parent directories when missing (default: true). */
|
|
12
13
|
mkdir?: boolean;
|
|
13
14
|
}
|
|
15
|
+
/** One row from a {@link Database.scan}. */
|
|
16
|
+
export interface ScanRow {
|
|
17
|
+
key: string;
|
|
18
|
+
value: Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
/** Options for {@link Database.scan}. */
|
|
21
|
+
export interface ScanOptions {
|
|
22
|
+
/** Include this prefix in every returned key; default `""` returns everything. */
|
|
23
|
+
prefix?: string;
|
|
24
|
+
/** Exclusive continuation cursor from a previous scan's last row; default `null` starts fresh. */
|
|
25
|
+
after?: string | null;
|
|
26
|
+
/** Max rows returned per call; default `1000`. */
|
|
27
|
+
limit?: number;
|
|
28
|
+
}
|
|
29
|
+
/** One change in a {@link Database.batch}. Use `null` to delete. */
|
|
30
|
+
export interface BatchChange {
|
|
31
|
+
key: string;
|
|
32
|
+
value: Uint8Array | string | null;
|
|
33
|
+
}
|
|
34
|
+
/** Options for {@link Database.migrateSchema}. */
|
|
35
|
+
export interface MigrateOptions {
|
|
36
|
+
/** Rename entries — `fromType`/`toType` updates a type name; `type`/`fromField`/`toField` updates one field. */
|
|
37
|
+
renames?: ReadonlyArray<{
|
|
38
|
+
fromType: string;
|
|
39
|
+
toType: string;
|
|
40
|
+
} | {
|
|
41
|
+
type: string;
|
|
42
|
+
fromField: string;
|
|
43
|
+
toField: string;
|
|
44
|
+
}>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Transaction-local handle passed to {@link Database.transaction} callbacks.
|
|
48
|
+
* All CRUD methods forward to the underlying native handle while the
|
|
49
|
+
* transaction is in flight. Commit/rollback are owned by {@link Database}.
|
|
50
|
+
*/
|
|
51
|
+
export declare class TransactionHandle {
|
|
52
|
+
private readonly native;
|
|
53
|
+
constructor(native: ReturnType<ReturnType<typeof loadNative>['Database']['open']>);
|
|
54
|
+
get(key: string): Promise<Uint8Array | null>;
|
|
55
|
+
put(key: string, value: Uint8Array | string): Promise<void>;
|
|
56
|
+
delete(key: string): Promise<void>;
|
|
57
|
+
scan(options?: ScanOptions): Promise<ScanRow[]>;
|
|
58
|
+
batch(changes: readonly BatchChange[]): Promise<void>;
|
|
59
|
+
compareExchange(key: string, expected: Uint8Array | string | null, replacement: Uint8Array | string | null): Promise<boolean>;
|
|
60
|
+
query<T = Record<string, unknown>>(source: string): Promise<T[]>;
|
|
61
|
+
execute(source: string): Promise<void>;
|
|
62
|
+
}
|
|
14
63
|
/**
|
|
15
64
|
* Node-facing YYDB local database handle.
|
|
16
65
|
*
|
|
@@ -39,26 +88,52 @@ export declare class Database {
|
|
|
39
88
|
* Accepts either a raw `.vos` source string, one `@voml/vos` descriptor
|
|
40
89
|
* (`v.table()`, `v.class()`) or a list of descriptors. When descriptors
|
|
41
90
|
* are supplied, they are rendered to source via `emitSource` first.
|
|
42
|
-
*
|
|
43
|
-
* ```ts
|
|
44
|
-
* // Raw source (unchanged behaviour):
|
|
45
|
-
* await db.ensureSchema('namespace demo { table User { @@id: uuid } }');
|
|
46
|
-
*
|
|
47
|
-
* // Zod-like builder — the Vos schema-ecosystem sweet spot:
|
|
48
|
-
* const User = v.table('User', { id: v.uuid().primary(), name: v.utf8() });
|
|
49
|
-
* await db.ensureSchema(User);
|
|
50
|
-
*
|
|
51
|
-
* // Multiple declarations in one shot:
|
|
52
|
-
* await db.ensureSchema(TableA, TableB, ClassC);
|
|
53
|
-
* ```
|
|
54
91
|
*/
|
|
55
92
|
ensureSchema(...input: [string] | [string, ...EmittableItem[]] | EmittableItem[]): Promise<void>;
|
|
56
93
|
/** Read one record, or `null` when the key is absent. */
|
|
57
94
|
get(key: string): Promise<Uint8Array | null>;
|
|
58
95
|
/** Insert or replace one record. */
|
|
59
96
|
put(key: string, value: Uint8Array | string): Promise<void>;
|
|
97
|
+
/** Delete one record by key. Silently succeeds when the key is absent. */
|
|
98
|
+
delete(key: string): Promise<void>;
|
|
99
|
+
/** List key/value pairs in lexical order. `prefix` defaults to `""` (all keys). */
|
|
100
|
+
scan(options?: ScanOptions): Promise<ScanRow[]>;
|
|
101
|
+
/** Atomically write or delete many keys in one call. */
|
|
102
|
+
batch(changes: readonly BatchChange[]): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Compare-and-swap: replace or delete `key` only when its current value
|
|
105
|
+
* exactly equals `expected`. Both `expected` and `replacement` may be
|
|
106
|
+
* `null` (meaning absent / delete). Returns `true` when the swap applied.
|
|
107
|
+
*/
|
|
108
|
+
compareExchange(key: string, expected: Uint8Array | string | null, replacement: Uint8Array | string | null): Promise<boolean>;
|
|
60
109
|
/** Fold the WAL into the main file and truncate the sidecar. */
|
|
61
110
|
checkpoint(): Promise<void>;
|
|
111
|
+
/**
|
|
112
|
+
* Run `fn` inside an explicit transaction. The transaction commits on
|
|
113
|
+
* normal return and rolls back on throw. Nested calls are not supported.
|
|
114
|
+
*
|
|
115
|
+
* ```ts
|
|
116
|
+
* await db.transaction(async (tx) => {
|
|
117
|
+
* await tx.put('a', '1');
|
|
118
|
+
* await tx.put('b', '2');
|
|
119
|
+
* });
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
transaction<T>(fn: (tx: TransactionHandle) => Promise<T>): Promise<T>;
|
|
123
|
+
/** Execute a VOS read pipeline and return typed rows. */
|
|
124
|
+
query<T = Record<string, unknown>>(source: string): Promise<T[]>;
|
|
125
|
+
/** Execute a VOS write program. */
|
|
126
|
+
execute(source: string): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Publish a new schema version, migrating existing records when their
|
|
129
|
+
* shape no longer matches.
|
|
130
|
+
*
|
|
131
|
+
* Accepts raw `.vos` source or `@voml/vos` descriptors (same as
|
|
132
|
+
* {@link Database.ensureSchema}). Use `renames` to tell the engine which
|
|
133
|
+
* old type/field names map to the new ones — records that would otherwise
|
|
134
|
+
* look structurally unrelated get preserved.
|
|
135
|
+
*/
|
|
136
|
+
migrateSchema(documentOrSource: string | EmittableItem, ...rest: (EmittableItem | MigrateOptions)[]): Promise<void>;
|
|
62
137
|
/** Build a typed session-local micro definition (without registering). */
|
|
63
138
|
defineMicro<TArgs extends readonly UdfScalarDescriptor[], TReturn extends UdfScalarDescriptor>(definition: Parameters<typeof buildMicro<TArgs, TReturn>>[0]): DefinedMicro<TArgs, TReturn>;
|
|
64
139
|
/**
|
package/dist/api/database.js
CHANGED
|
@@ -3,6 +3,44 @@ import path from 'node:path';
|
|
|
3
3
|
import { emitSource, } from '@voml/vos';
|
|
4
4
|
import { defineMicro as buildMicro, microFingerprint, udfWireKind, MicroSessionRegistry, } from '../shared/micro.js';
|
|
5
5
|
import { loadNative } from '../native/binding.js';
|
|
6
|
+
import { YydbError } from '../shared/errors.js';
|
|
7
|
+
/**
|
|
8
|
+
* Transaction-local handle passed to {@link Database.transaction} callbacks.
|
|
9
|
+
* All CRUD methods forward to the underlying native handle while the
|
|
10
|
+
* transaction is in flight. Commit/rollback are owned by {@link Database}.
|
|
11
|
+
*/
|
|
12
|
+
export class TransactionHandle {
|
|
13
|
+
native;
|
|
14
|
+
constructor(native) {
|
|
15
|
+
this.native = native;
|
|
16
|
+
}
|
|
17
|
+
async get(key) { return this.native.get(key); }
|
|
18
|
+
async put(key, value) {
|
|
19
|
+
const bytes = typeof value === 'string' ? new TextEncoder().encode(value) : value;
|
|
20
|
+
this.native.put(key, bytes);
|
|
21
|
+
}
|
|
22
|
+
async delete(key) { this.native.delete(key); }
|
|
23
|
+
async scan(options = {}) {
|
|
24
|
+
const rowsJson = this.native.scanPrefix(options.prefix ?? '', options.after ?? null, options.limit ?? 1000);
|
|
25
|
+
const rows = JSON.parse(rowsJson);
|
|
26
|
+
return rows.map((r) => ({ key: r.key, value: new Uint8Array(r.value) }));
|
|
27
|
+
}
|
|
28
|
+
async batch(changes) {
|
|
29
|
+
const body = changes.map((c) => ({
|
|
30
|
+
key: c.key,
|
|
31
|
+
value: c.value === null ? null : typeof c.value === 'string' ? Array.from(new TextEncoder().encode(c.value)) : Array.from(c.value),
|
|
32
|
+
}));
|
|
33
|
+
this.native.writeBatch(JSON.stringify(body));
|
|
34
|
+
}
|
|
35
|
+
async compareExchange(key, expected, replacement) {
|
|
36
|
+
const toBytes = (v) => v === null ? null : typeof v === 'string' ? new TextEncoder().encode(v) : v;
|
|
37
|
+
return this.native.compareExchange(key, toBytes(expected), toBytes(replacement));
|
|
38
|
+
}
|
|
39
|
+
async query(source) {
|
|
40
|
+
return JSON.parse(this.native.queryVos(source));
|
|
41
|
+
}
|
|
42
|
+
async execute(source) { this.native.executeVosWrite(source); }
|
|
43
|
+
}
|
|
6
44
|
/**
|
|
7
45
|
* Node-facing YYDB local database handle.
|
|
8
46
|
*
|
|
@@ -57,27 +95,13 @@ export class Database {
|
|
|
57
95
|
* Accepts either a raw `.vos` source string, one `@voml/vos` descriptor
|
|
58
96
|
* (`v.table()`, `v.class()`) or a list of descriptors. When descriptors
|
|
59
97
|
* are supplied, they are rendered to source via `emitSource` first.
|
|
60
|
-
*
|
|
61
|
-
* ```ts
|
|
62
|
-
* // Raw source (unchanged behaviour):
|
|
63
|
-
* await db.ensureSchema('namespace demo { table User { @@id: uuid } }');
|
|
64
|
-
*
|
|
65
|
-
* // Zod-like builder — the Vos schema-ecosystem sweet spot:
|
|
66
|
-
* const User = v.table('User', { id: v.uuid().primary(), name: v.utf8() });
|
|
67
|
-
* await db.ensureSchema(User);
|
|
68
|
-
*
|
|
69
|
-
* // Multiple declarations in one shot:
|
|
70
|
-
* await db.ensureSchema(TableA, TableB, ClassC);
|
|
71
|
-
* ```
|
|
72
98
|
*/
|
|
73
99
|
async ensureSchema(...input) {
|
|
74
100
|
let document;
|
|
75
101
|
if (typeof input[0] === 'string') {
|
|
76
|
-
// Raw source string, optionally followed by descriptors we just ignore.
|
|
77
102
|
document = input[0];
|
|
78
103
|
}
|
|
79
104
|
else {
|
|
80
|
-
// One or more Vos descriptor items → render to source.
|
|
81
105
|
document = emitSource(input);
|
|
82
106
|
}
|
|
83
107
|
this.native.ensureSchema(document);
|
|
@@ -91,10 +115,112 @@ export class Database {
|
|
|
91
115
|
const bytes = typeof value === 'string' ? new TextEncoder().encode(value) : value;
|
|
92
116
|
this.native.put(key, bytes);
|
|
93
117
|
}
|
|
118
|
+
/** Delete one record by key. Silently succeeds when the key is absent. */
|
|
119
|
+
async delete(key) {
|
|
120
|
+
this.native.delete(key);
|
|
121
|
+
}
|
|
122
|
+
/** List key/value pairs in lexical order. `prefix` defaults to `""` (all keys). */
|
|
123
|
+
async scan(options = {}) {
|
|
124
|
+
const rowsJson = this.native.scanPrefix(options.prefix ?? '', options.after ?? null, options.limit ?? 1000);
|
|
125
|
+
const rows = JSON.parse(rowsJson);
|
|
126
|
+
return rows.map((r) => ({ key: r.key, value: new Uint8Array(r.value) }));
|
|
127
|
+
}
|
|
128
|
+
/** Atomically write or delete many keys in one call. */
|
|
129
|
+
async batch(changes) {
|
|
130
|
+
const body = changes.map((c) => ({
|
|
131
|
+
key: c.key,
|
|
132
|
+
value: c.value === null
|
|
133
|
+
? null
|
|
134
|
+
: typeof c.value === 'string'
|
|
135
|
+
? Array.from(new TextEncoder().encode(c.value))
|
|
136
|
+
: Array.from(c.value),
|
|
137
|
+
}));
|
|
138
|
+
this.native.writeBatch(JSON.stringify(body));
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Compare-and-swap: replace or delete `key` only when its current value
|
|
142
|
+
* exactly equals `expected`. Both `expected` and `replacement` may be
|
|
143
|
+
* `null` (meaning absent / delete). Returns `true` when the swap applied.
|
|
144
|
+
*/
|
|
145
|
+
async compareExchange(key, expected, replacement) {
|
|
146
|
+
const toBytes = (v) => v === null ? null : typeof v === 'string' ? new TextEncoder().encode(v) : v;
|
|
147
|
+
return this.native.compareExchange(key, toBytes(expected), toBytes(replacement));
|
|
148
|
+
}
|
|
94
149
|
/** Fold the WAL into the main file and truncate the sidecar. */
|
|
95
150
|
async checkpoint() {
|
|
96
151
|
this.native.checkpoint();
|
|
97
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Run `fn` inside an explicit transaction. The transaction commits on
|
|
155
|
+
* normal return and rolls back on throw. Nested calls are not supported.
|
|
156
|
+
*
|
|
157
|
+
* ```ts
|
|
158
|
+
* await db.transaction(async (tx) => {
|
|
159
|
+
* await tx.put('a', '1');
|
|
160
|
+
* await tx.put('b', '2');
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
async transaction(fn) {
|
|
165
|
+
this.native.begin();
|
|
166
|
+
const tx = new TransactionHandle(this.native);
|
|
167
|
+
try {
|
|
168
|
+
const result = await fn(tx);
|
|
169
|
+
this.native.commit();
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
try {
|
|
174
|
+
this.native.rollback();
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// rollback already failed, don't mask the original error
|
|
178
|
+
}
|
|
179
|
+
throw YydbError.fromDiagnosticJson(err instanceof Error ? err.message : String(err)) ?? err;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Execute a VOS read pipeline and return typed rows. */
|
|
183
|
+
async query(source) {
|
|
184
|
+
const rowsJson = this.native.queryVos(source);
|
|
185
|
+
return JSON.parse(rowsJson);
|
|
186
|
+
}
|
|
187
|
+
/** Execute a VOS write program. */
|
|
188
|
+
async execute(source) {
|
|
189
|
+
this.native.executeVosWrite(source);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Publish a new schema version, migrating existing records when their
|
|
193
|
+
* shape no longer matches.
|
|
194
|
+
*
|
|
195
|
+
* Accepts raw `.vos` source or `@voml/vos` descriptors (same as
|
|
196
|
+
* {@link Database.ensureSchema}). Use `renames` to tell the engine which
|
|
197
|
+
* old type/field names map to the new ones — records that would otherwise
|
|
198
|
+
* look structurally unrelated get preserved.
|
|
199
|
+
*/
|
|
200
|
+
async migrateSchema(documentOrSource, ...rest) {
|
|
201
|
+
let document;
|
|
202
|
+
let options = {};
|
|
203
|
+
const all = [documentOrSource, ...rest];
|
|
204
|
+
const last = all[all.length - 1];
|
|
205
|
+
if (last &&
|
|
206
|
+
typeof last === 'object' &&
|
|
207
|
+
!('table' in last) &&
|
|
208
|
+
!('class' in last) &&
|
|
209
|
+
!('emit' in last) &&
|
|
210
|
+
('renames' in last || Object.keys(last).length === 0)) {
|
|
211
|
+
options = all.pop() ?? {};
|
|
212
|
+
}
|
|
213
|
+
if (typeof all[0] === 'string') {
|
|
214
|
+
document = all[0];
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
document = emitSource(all);
|
|
218
|
+
}
|
|
219
|
+
const renamesJson = options.renames?.length
|
|
220
|
+
? JSON.stringify(options.renames)
|
|
221
|
+
: null;
|
|
222
|
+
this.native.migrateSchema(document, renamesJson);
|
|
223
|
+
}
|
|
98
224
|
/** Build a typed session-local micro definition (without registering). */
|
|
99
225
|
defineMicro(definition) {
|
|
100
226
|
return buildMicro(definition);
|
package/dist/native/binding.d.ts
CHANGED
|
@@ -18,6 +18,26 @@ export interface NativeDatabase {
|
|
|
18
18
|
walFrameCount(): number;
|
|
19
19
|
get(key: string): Uint8Array | null;
|
|
20
20
|
put(key: string, value: Uint8Array): void;
|
|
21
|
+
/** Delete one record by key. */
|
|
22
|
+
delete(key: string): void;
|
|
23
|
+
/** Scan keys with a prefix; returns JSON `[{ key, value }, ...]`. */
|
|
24
|
+
scanPrefix(prefix: string, after: string | null, limit: number): string;
|
|
25
|
+
/** Atomically write or delete many keys; body is JSON `[{ key, value|null }, ...]`. */
|
|
26
|
+
writeBatch(changesJson: string): void;
|
|
27
|
+
/** Compare-and-swap; returns true on success. */
|
|
28
|
+
compareExchange(key: string, expected: Uint8Array | null, replacement: Uint8Array | null): boolean;
|
|
29
|
+
/** Begin an explicit transaction. */
|
|
30
|
+
begin(): void;
|
|
31
|
+
/** Commit the current transaction. */
|
|
32
|
+
commit(): void;
|
|
33
|
+
/** Roll back the current transaction. */
|
|
34
|
+
rollback(): void;
|
|
35
|
+
/** Execute a VOS read pipeline; returns JSON rows. */
|
|
36
|
+
queryVos(source: string): string;
|
|
37
|
+
/** Execute a VOS write program. */
|
|
38
|
+
executeVosWrite(source: string): void;
|
|
39
|
+
/** Publish a new schema version, optionally with rename map. */
|
|
40
|
+
migrateSchema(document: string, renamesJson?: string | null): void;
|
|
21
41
|
registerMicro(name: string, version: number, args: string[], returns: string, hostId: number, functionId: string, handleVersion: number, fingerprint: Uint8Array): void;
|
|
22
42
|
callScalar(name: string, version: number, argsJson: string): string;
|
|
23
43
|
}
|
package/dist/shared/errors.d.ts
CHANGED
|
@@ -40,6 +40,8 @@ export declare function isRetryableYydbCode(code: string): boolean;
|
|
|
40
40
|
export interface YydbErrorOptions {
|
|
41
41
|
/** Operation that failed (`schemaGet`, `kvPut`, `query`, …). */
|
|
42
42
|
operation?: string;
|
|
43
|
+
/** Structured parameters for catalog templating (when present). */
|
|
44
|
+
params?: Readonly<Record<string, string>>;
|
|
43
45
|
/** Underlying failure when this error wraps one. */
|
|
44
46
|
cause?: unknown;
|
|
45
47
|
}
|
|
@@ -51,7 +53,33 @@ export declare class YydbError extends Error {
|
|
|
51
53
|
readonly operation: string;
|
|
52
54
|
/** Whether the same call may be retried. */
|
|
53
55
|
readonly retryable: boolean;
|
|
56
|
+
/** Structured parameters for catalog templating (when present). */
|
|
57
|
+
readonly params?: Readonly<Record<string, string>>;
|
|
54
58
|
constructor(code: YydbErrorCode, message: string, options?: YydbErrorOptions);
|
|
59
|
+
/**
|
|
60
|
+
* Parse the diagnostic JSON that N-API and WASM surfaces embed in their
|
|
61
|
+
* `Error.message`. Every boundary surface (N-API reason field, WASM JSON
|
|
62
|
+
* envelope, wire protocol) carries the same `{ code, operation, retryable,
|
|
63
|
+
* message, params? }` contract produced by `yydb::Error::to_json`.
|
|
64
|
+
*
|
|
65
|
+
* Returns the parsed {@link YydbError} if `value` is a diagnostic object,
|
|
66
|
+
* or `null` when the input is plain text. Hosts typically use this as a
|
|
67
|
+
* fallback in catch blocks:
|
|
68
|
+
*
|
|
69
|
+
* ```ts
|
|
70
|
+
* try {
|
|
71
|
+
* await db.put('key', value);
|
|
72
|
+
* } catch (err) {
|
|
73
|
+
* const parsed = YydbError.fromDiagnosticJson(
|
|
74
|
+
* err instanceof Error ? err.message : String(err),
|
|
75
|
+
* );
|
|
76
|
+
* if (parsed) {
|
|
77
|
+
* // branch on parsed.code / retryable / operation
|
|
78
|
+
* }
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
static fromDiagnosticJson(value: unknown): YydbError | null;
|
|
55
83
|
}
|
|
56
84
|
/** Narrowing helper so callers can branch without `instanceof` imports. */
|
|
57
85
|
export declare function isYydbError(value: unknown): value is YydbError;
|
package/dist/shared/errors.js
CHANGED
|
@@ -54,12 +54,75 @@ export class YydbError extends Error {
|
|
|
54
54
|
operation;
|
|
55
55
|
/** Whether the same call may be retried. */
|
|
56
56
|
retryable;
|
|
57
|
+
/** Structured parameters for catalog templating (when present). */
|
|
58
|
+
params;
|
|
57
59
|
constructor(code, message, options = {}) {
|
|
58
60
|
super(message, { cause: options.cause });
|
|
59
61
|
this.name = 'YydbError';
|
|
60
62
|
this.code = code;
|
|
61
63
|
this.operation = options.operation ?? 'unknown';
|
|
62
64
|
this.retryable = isRetryableYydbCode(code);
|
|
65
|
+
this.params = options.params;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Parse the diagnostic JSON that N-API and WASM surfaces embed in their
|
|
69
|
+
* `Error.message`. Every boundary surface (N-API reason field, WASM JSON
|
|
70
|
+
* envelope, wire protocol) carries the same `{ code, operation, retryable,
|
|
71
|
+
* message, params? }` contract produced by `yydb::Error::to_json`.
|
|
72
|
+
*
|
|
73
|
+
* Returns the parsed {@link YydbError} if `value` is a diagnostic object,
|
|
74
|
+
* or `null` when the input is plain text. Hosts typically use this as a
|
|
75
|
+
* fallback in catch blocks:
|
|
76
|
+
*
|
|
77
|
+
* ```ts
|
|
78
|
+
* try {
|
|
79
|
+
* await db.put('key', value);
|
|
80
|
+
* } catch (err) {
|
|
81
|
+
* const parsed = YydbError.fromDiagnosticJson(
|
|
82
|
+
* err instanceof Error ? err.message : String(err),
|
|
83
|
+
* );
|
|
84
|
+
* if (parsed) {
|
|
85
|
+
* // branch on parsed.code / retryable / operation
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
static fromDiagnosticJson(value) {
|
|
91
|
+
let obj;
|
|
92
|
+
if (typeof value === 'string') {
|
|
93
|
+
try {
|
|
94
|
+
const parsed = JSON.parse(value);
|
|
95
|
+
if (!parsed || typeof parsed !== 'object')
|
|
96
|
+
return null;
|
|
97
|
+
obj = parsed;
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (value && typeof value === 'object') {
|
|
104
|
+
obj = value;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
const code = typeof obj.code === 'string' ? obj.code : null;
|
|
110
|
+
const message = typeof obj.message === 'string' ? obj.message : '';
|
|
111
|
+
if (!code)
|
|
112
|
+
return null;
|
|
113
|
+
const operation = typeof obj.operation === 'string' ? obj.operation : undefined;
|
|
114
|
+
const retryable = typeof obj.retryable === 'boolean' ? obj.retryable : undefined;
|
|
115
|
+
const params = obj.params && typeof obj.params === 'object'
|
|
116
|
+
? obj.params
|
|
117
|
+
: undefined;
|
|
118
|
+
const err = new YydbError(code, message, {
|
|
119
|
+
operation,
|
|
120
|
+
params,
|
|
121
|
+
});
|
|
122
|
+
if (typeof retryable === 'boolean') {
|
|
123
|
+
err.retryable = retryable;
|
|
124
|
+
}
|
|
125
|
+
return err;
|
|
63
126
|
}
|
|
64
127
|
}
|
|
65
128
|
/** Narrowing helper so callers can branch without `instanceof` imports. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yydb/yydb",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"description": "YYDB Node embedded engine and CLI",
|
|
5
5
|
"license": "MPL-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"node": ">=18"
|
|
60
60
|
},
|
|
61
61
|
"optionalDependencies": {
|
|
62
|
-
"@yydb/yydb-darwin-arm64": "0.0.
|
|
63
|
-
"@yydb/yydb-darwin-x64": "0.0.
|
|
64
|
-
"@yydb/yydb-linux-x64": "0.0.
|
|
65
|
-
"@yydb/yydb-win32-x64": "0.0.
|
|
62
|
+
"@yydb/yydb-darwin-arm64": "0.0.12",
|
|
63
|
+
"@yydb/yydb-darwin-x64": "0.0.12",
|
|
64
|
+
"@yydb/yydb-linux-x64": "0.0.12",
|
|
65
|
+
"@yydb/yydb-win32-x64": "0.0.12"
|
|
66
66
|
}
|
|
67
67
|
}
|