@yydb/yydb 0.1.1 → 0.1.2

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
@@ -1,6 +1,6 @@
1
- export { Database, type OpenOptions } from './api/database.js';
2
- export { YydbError, YydbErrorCodes, isRetryableYydbCode, isYydbError } from '@yydb/yydb-client';
3
- export type { YydbErrorCode, YydbErrorOptions } from '@yydb/yydb-client';
1
+ export { Database, Statement, type OpenOptions, type SchemaVersion, type ParameterDescriptor, type QueryKind, type SlotType, type StatementInfo } from './api/database.js';
2
+ export { YydbError, YydbErrorCodes, YydbClientErrorCodes, isYydbError } from './shared/errors.js';
3
+ export type { YydbErrorCode, YydbErrorOptions } from './shared/errors.js';
4
4
  export { defineMicro, type DefinedMicro, type MicroHandle, type TsMicroDefinitionInput, MicroSessionRegistry } from './shared/micro.js';
5
5
  export { type InferUdfArgs, type InferUdfReturn, type MicroEffect, type MicroInvocationMode, type UdfScalarDescriptor, type UdfScalarKind, } from './shared/udf-types.js';
6
6
  export { nativeBindingName, platformKey, resolveYydbBinary, resolveYydbCli } from './native/resolve.js';
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { Database } from './api/database.js';
2
- export { YydbError, YydbErrorCodes, isRetryableYydbCode, isYydbError } from '@yydb/yydb-client';
1
+ export { Database, Statement } from './api/database.js';
2
+ export { YydbError, YydbErrorCodes, YydbClientErrorCodes, isYydbError } from './shared/errors.js';
3
3
  export { defineMicro, MicroSessionRegistry } from './shared/micro.js';
4
4
  export { nativeBindingName, platformKey, resolveYydbBinary, resolveYydbCli } from './native/resolve.js';
5
5
  export * from './shared/vos.js';
@@ -1,3 +1,8 @@
1
+ /** Schema version returned by N-API Database.schema_version / Client.schema_version. */
2
+ export interface NativeSchemaVersion {
3
+ version: number;
4
+ document: string;
5
+ }
1
6
  /** One open `.yydb` handle exposed by the native binding. */
2
7
  export interface NativeDatabase {
3
8
  path(): string | null;
@@ -13,6 +18,65 @@ export interface NativeDatabase {
13
18
  walFrameCount(): number;
14
19
  get(key: string): Uint8Array | null;
15
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
+ /** Prepare a VOS read pipeline into a reusable plan; returns a native Statement handle. */
40
+ prepare(source: string): NativeStatement;
41
+ /** Execute a previously prepared statement with optional JSON parameters. */
42
+ queryPrepared(statement: NativeStatement, paramsJson?: string | null): string;
43
+ /** Publish a new schema version, optionally with rename map. */
44
+ migrateSchema(document: string, renamesJson?: string | null): void;
45
+ /** Checkpoint + copy self-contained `.yydb` main file (no WAL sidecars). */
46
+ backup(dest: string): void;
47
+ /** Copy main + WAL + SHM without checkpoint (opening replays the tail). */
48
+ backupWithWal(dest: string): void;
49
+ /** Read-only consistency probe; returns DoctorReport JSON. */
50
+ doctor(): string;
51
+ /** Fold WAL + reclaim orphan blobs (`.yydx` only); returns CompactReport JSON. */
52
+ compactYydx(): string;
53
+ registerMicro(name: string, version: number, args: string[], returns: string, hostId: number, functionId: string, handleVersion: number, fingerprint: Uint8Array): void;
54
+ callScalar(name: string, version: number, argsJson: string): string;
55
+ }
56
+ /** A prepared VOS query plan handle exposed by the native binding. */
57
+ export interface NativeStatement {
58
+ /** Fingerprint-prefixed unique id for this prepared statement. */
59
+ statementId(): string;
60
+ /** Parameter descriptors JSON — the `parameters` field from a `PreparedStatement`. */
61
+ parametersJson(): string;
62
+ /** Full statement metadata as JSON (statementId, queryKind, parameters, readSet, writeSet, sourceFingerprint, source). */
63
+ info(): string;
64
+ /** Release this statement's plan from the registry; returns true when actually removed. */
65
+ close(): boolean;
66
+ }
67
+ /** One remote `yydb serve` handle exposed by the native binding. */
68
+ export interface NativeClient {
69
+ endpoint(): string;
70
+ serverVersion(): string;
71
+ info(): string;
72
+ schemaVersion(): number | null;
73
+ schemaDocument(): string | null;
74
+ ensureSchema(document: string): void;
75
+ get(key: string): Uint8Array | null;
76
+ put(key: string, value: Uint8Array): void;
77
+ registerMicro(name: string, version: number, args: string[], returns: string, hostId: number, functionId: string, handleVersion: number, fingerprint: Uint8Array): void;
78
+ callScalar(name: string, version: number, argsJson: string): string;
79
+ close(): void;
16
80
  }
17
81
  /** Atomic operations exported by the Node-API binding. */
18
82
  export interface YydbNative {
@@ -21,6 +85,9 @@ export interface YydbNative {
21
85
  Database: {
22
86
  open(dbPath: string): NativeDatabase;
23
87
  };
88
+ Client: {
89
+ connect(endpoint: string): NativeClient;
90
+ };
24
91
  }
25
92
  /** Load the platform native binding used by the `yydb` CLI. */
26
93
  export declare function loadNative(): YydbNative;
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Host-facing YYDB error surface.
3
+ *
4
+ * Every public failure carries a stable `code`: engine codes come from the
5
+ * Rust core (`yydb.schema.invalid`, …) over N-API or the wire; client codes
6
+ * are minted locally with the `yydb.client.` prefix. **Branch on `code`** —
7
+ * `message` is display text only and must never be used for retry decisions.
8
+ *
9
+ * ## Where codes live
10
+ *
11
+ * Engine codes live in Rust (`yydb_types::Error` variants → DiagnosticEnvelope).
12
+ * The TS side no longer keeps a hardcoded engine-code table — when Rust gains a
13
+ * new variant, hosts pick up the new code string via {@link fromDiagnosticJson}
14
+ * without any TS change. Client codes (`yydb.client.*`) are minted only on the
15
+ * host side and remain available as constants below.
16
+ */
17
+ /**
18
+ * Client-side error codes that never originate from Rust.
19
+ *
20
+ * Engine codes (`yydb.schema.*`, `yydb.udf.*`, `yydb.io`, …) are emitted by
21
+ * Rust and should be matched via string literals or from the diagnostic JSON
22
+ * envelope — they are intentionally not duplicated here.
23
+ */
24
+ export declare const YydbClientErrorCodes: {
25
+ /** serve() endpoint is empty or invalid. */
26
+ readonly clientInvalidEndpoint: "yydb.client.invalid_endpoint";
27
+ /** connect() socket / transport layer failure. */
28
+ readonly clientTransportFailure: "yydb.client.transport_failure";
29
+ /** Server replied with a request id we did not send. */
30
+ readonly clientRequestIdMismatch: "yydb.client.request_id_mismatch";
31
+ /** Server replied with a msg_type we did not request. */
32
+ readonly clientUnexpectedResponse: "yydb.client.unexpected_response";
33
+ /** Could not parse an Error frame body from the wire. */
34
+ readonly clientDecodeFailure: "yydb.client.decode_failure";
35
+ /** The YYDB session is already closed. */
36
+ readonly sessionClosed: "yydb.session.closed";
37
+ };
38
+ /**
39
+ * @deprecated Engine codes moved to Rust — use string literals or match on
40
+ * {@link YydbError.code} returned from {@link fromDiagnosticJson}. This table
41
+ * exists only for transition; new engine error variants will **not** be added here.
42
+ */
43
+ export declare const YydbErrorCodes: {
44
+ /** serve() endpoint is empty or invalid. */
45
+ readonly clientInvalidEndpoint: "yydb.client.invalid_endpoint";
46
+ /** connect() socket / transport layer failure. */
47
+ readonly clientTransportFailure: "yydb.client.transport_failure";
48
+ /** Server replied with a request id we did not send. */
49
+ readonly clientRequestIdMismatch: "yydb.client.request_id_mismatch";
50
+ /** Server replied with a msg_type we did not request. */
51
+ readonly clientUnexpectedResponse: "yydb.client.unexpected_response";
52
+ /** Could not parse an Error frame body from the wire. */
53
+ readonly clientDecodeFailure: "yydb.client.decode_failure";
54
+ /** The YYDB session is already closed. */
55
+ readonly sessionClosed: "yydb.session.closed";
56
+ readonly io: "yydb.io";
57
+ readonly corrupt: "yydb.corrupt";
58
+ readonly schemaConflict: "yydb.schema.conflict";
59
+ readonly schemaInvalid: "yydb.schema.invalid";
60
+ readonly udfNotFound: "yydb.udf.not_found";
61
+ readonly udfArity: "yydb.udf.arity";
62
+ readonly udfFailed: "yydb.udf.failed";
63
+ readonly udfVersionMismatch: "yydb.udf.version_mismatch";
64
+ readonly objectNotFound: "yydb.object.not_found";
65
+ readonly objectCorrupt: "yydb.object.corrupt";
66
+ readonly unsupported: "yydb.unsupported";
67
+ readonly protocol: "yydb.protocol";
68
+ readonly casConflict: "yydb.cas.conflict";
69
+ readonly leaseUnavailable: "yydb.lease.unavailable";
70
+ readonly fencingMismatch: "yydb.fencing.mismatch";
71
+ readonly leaseExpired: "yydb.lease.expired";
72
+ readonly quotaExceeded: "yydb.quota.exceeded";
73
+ };
74
+ /** Any stable YYDB error code string — engine, client, or future variant. */
75
+ export type YydbErrorCode = string;
76
+ /** Options carried by a {@link YydbError}. */
77
+ export interface YydbErrorOptions {
78
+ /** Operation that failed (`schemaGet`, `kvPut`, `query`, …). */
79
+ operation?: string;
80
+ /**
81
+ * Whether the caller may retry with the same arguments.
82
+ *
83
+ * When omitted, constructor defaults to `false` (conservative). Callers
84
+ * that mint their own errors (especially client-local retryable ones like
85
+ * `yydb.client.transport_failure`) **must** set this explicitly. Engine
86
+ * errors coming through {@link fromDiagnosticJson} always carry the Rust-
87
+ * authoritative `retryable` value and override the default.
88
+ */
89
+ retryable?: boolean;
90
+ /** Structured parameters for catalog templating (when present). */
91
+ params?: Readonly<Record<string, string>>;
92
+ /** Underlying failure when this error wraps one. */
93
+ cause?: unknown;
94
+ }
95
+ /** YYDB failure with a stable machine-readable {@link YydbError.code}. */
96
+ export declare class YydbError extends Error {
97
+ /** Stable code — engine code (from Rust) or `yydb.client.*`. */
98
+ readonly code: string;
99
+ /** Operation that failed. */
100
+ readonly operation: string;
101
+ /** Whether the same call may be retried. */
102
+ readonly retryable: boolean;
103
+ /** Structured parameters for catalog templating (when present). */
104
+ readonly params?: Readonly<Record<string, string>>;
105
+ constructor(code: YydbErrorCode, message: string, options?: YydbErrorOptions);
106
+ /**
107
+ * Parse the diagnostic JSON that N-API and WASM surfaces embed in their
108
+ * `Error.message`. Every boundary surface (N-API reason field, WASM JSON
109
+ * envelope, wire protocol) carries the same `{ code, operation, retryable,
110
+ * message, params? }` contract produced by `yydb::Error::to_json`.
111
+ *
112
+ * Returns the parsed {@link YydbError} if `value` is a diagnostic object,
113
+ * or `null` when the input is plain text. Hosts typically use this as a
114
+ * fallback in catch blocks:
115
+ *
116
+ * ```ts
117
+ * try {
118
+ * await db.put('key', value);
119
+ * } catch (err) {
120
+ * const parsed = YydbError.fromDiagnosticJson(
121
+ * err instanceof Error ? err.message : String(err),
122
+ * );
123
+ * if (parsed) {
124
+ * // branch on parsed.code / retryable / operation
125
+ * }
126
+ * }
127
+ * ```
128
+ */
129
+ static fromDiagnosticJson(value: unknown): YydbError | null;
130
+ }
131
+ /** Narrowing helper so callers can branch without `instanceof` imports. */
132
+ export declare function isYydbError(value: unknown): value is YydbError;
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Host-facing YYDB error surface.
3
+ *
4
+ * Every public failure carries a stable `code`: engine codes come from the
5
+ * Rust core (`yydb.schema.invalid`, …) over N-API or the wire; client codes
6
+ * are minted locally with the `yydb.client.` prefix. **Branch on `code`** —
7
+ * `message` is display text only and must never be used for retry decisions.
8
+ *
9
+ * ## Where codes live
10
+ *
11
+ * Engine codes live in Rust (`yydb_types::Error` variants → DiagnosticEnvelope).
12
+ * The TS side no longer keeps a hardcoded engine-code table — when Rust gains a
13
+ * new variant, hosts pick up the new code string via {@link fromDiagnosticJson}
14
+ * without any TS change. Client codes (`yydb.client.*`) are minted only on the
15
+ * host side and remain available as constants below.
16
+ */
17
+ /**
18
+ * Client-side error codes that never originate from Rust.
19
+ *
20
+ * Engine codes (`yydb.schema.*`, `yydb.udf.*`, `yydb.io`, …) are emitted by
21
+ * Rust and should be matched via string literals or from the diagnostic JSON
22
+ * envelope — they are intentionally not duplicated here.
23
+ */
24
+ export const YydbClientErrorCodes = {
25
+ /** serve() endpoint is empty or invalid. */
26
+ clientInvalidEndpoint: 'yydb.client.invalid_endpoint',
27
+ /** connect() socket / transport layer failure. */
28
+ clientTransportFailure: 'yydb.client.transport_failure',
29
+ /** Server replied with a request id we did not send. */
30
+ clientRequestIdMismatch: 'yydb.client.request_id_mismatch',
31
+ /** Server replied with a msg_type we did not request. */
32
+ clientUnexpectedResponse: 'yydb.client.unexpected_response',
33
+ /** Could not parse an Error frame body from the wire. */
34
+ clientDecodeFailure: 'yydb.client.decode_failure',
35
+ /** The YYDB session is already closed. */
36
+ sessionClosed: 'yydb.session.closed',
37
+ };
38
+ /**
39
+ * @deprecated Engine codes moved to Rust — use string literals or match on
40
+ * {@link YydbError.code} returned from {@link fromDiagnosticJson}. This table
41
+ * exists only for transition; new engine error variants will **not** be added here.
42
+ */
43
+ export const YydbErrorCodes = {
44
+ // Engine codes (deprecated)
45
+ io: 'yydb.io',
46
+ corrupt: 'yydb.corrupt',
47
+ schemaConflict: 'yydb.schema.conflict',
48
+ schemaInvalid: 'yydb.schema.invalid',
49
+ udfNotFound: 'yydb.udf.not_found',
50
+ udfArity: 'yydb.udf.arity',
51
+ udfFailed: 'yydb.udf.failed',
52
+ udfVersionMismatch: 'yydb.udf.version_mismatch',
53
+ objectNotFound: 'yydb.object.not_found',
54
+ objectCorrupt: 'yydb.object.corrupt',
55
+ unsupported: 'yydb.unsupported',
56
+ protocol: 'yydb.protocol',
57
+ casConflict: 'yydb.cas.conflict',
58
+ leaseUnavailable: 'yydb.lease.unavailable',
59
+ fencingMismatch: 'yydb.fencing.mismatch',
60
+ leaseExpired: 'yydb.lease.expired',
61
+ quotaExceeded: 'yydb.quota.exceeded',
62
+ // Client codes (still canonical for client-local errors)
63
+ ...YydbClientErrorCodes,
64
+ };
65
+ /** YYDB failure with a stable machine-readable {@link YydbError.code}. */
66
+ export class YydbError extends Error {
67
+ /** Stable code — engine code (from Rust) or `yydb.client.*`. */
68
+ code;
69
+ /** Operation that failed. */
70
+ operation;
71
+ /** Whether the same call may be retried. */
72
+ retryable;
73
+ /** Structured parameters for catalog templating (when present). */
74
+ params;
75
+ constructor(code, message, options = {}) {
76
+ super(message, { cause: options.cause });
77
+ this.name = 'YydbError';
78
+ this.code = code;
79
+ this.operation = options.operation ?? 'unknown';
80
+ this.retryable = options.retryable ?? false;
81
+ if (options.params !== undefined) {
82
+ this.params = options.params;
83
+ }
84
+ }
85
+ /**
86
+ * Parse the diagnostic JSON that N-API and WASM surfaces embed in their
87
+ * `Error.message`. Every boundary surface (N-API reason field, WASM JSON
88
+ * envelope, wire protocol) carries the same `{ code, operation, retryable,
89
+ * message, params? }` contract produced by `yydb::Error::to_json`.
90
+ *
91
+ * Returns the parsed {@link YydbError} if `value` is a diagnostic object,
92
+ * or `null` when the input is plain text. Hosts typically use this as a
93
+ * fallback in catch blocks:
94
+ *
95
+ * ```ts
96
+ * try {
97
+ * await db.put('key', value);
98
+ * } catch (err) {
99
+ * const parsed = YydbError.fromDiagnosticJson(
100
+ * err instanceof Error ? err.message : String(err),
101
+ * );
102
+ * if (parsed) {
103
+ * // branch on parsed.code / retryable / operation
104
+ * }
105
+ * }
106
+ * ```
107
+ */
108
+ static fromDiagnosticJson(value) {
109
+ let obj;
110
+ if (typeof value === 'string') {
111
+ try {
112
+ const parsed = JSON.parse(value);
113
+ if (!parsed || typeof parsed !== 'object')
114
+ return null;
115
+ obj = parsed;
116
+ }
117
+ catch {
118
+ return null;
119
+ }
120
+ }
121
+ else if (value && typeof value === 'object') {
122
+ obj = value;
123
+ }
124
+ else {
125
+ return null;
126
+ }
127
+ // WASM envelopes nest the diagnostic under `{ ok, error: {...} }`.
128
+ let diag = obj;
129
+ if (typeof obj['ok'] === 'boolean' && !obj['ok'] && obj['error'] && typeof obj['error'] === 'object') {
130
+ diag = obj['error'];
131
+ }
132
+ const code = typeof diag['code'] === 'string' ? diag['code'] : null;
133
+ const message = typeof diag['message'] === 'string' ? diag['message'] : '';
134
+ if (!code)
135
+ return null;
136
+ const operation = typeof diag['operation'] === 'string' ? diag['operation'] : undefined;
137
+ const retryable = typeof diag['retryable'] === 'boolean' ? diag['retryable'] : undefined;
138
+ const params = diag['params'] && typeof diag['params'] === 'object'
139
+ ? diag['params']
140
+ : undefined;
141
+ const opts = {};
142
+ if (operation !== undefined)
143
+ opts.operation = operation;
144
+ if (retryable !== undefined)
145
+ opts.retryable = retryable;
146
+ if (params !== undefined)
147
+ opts.params = params;
148
+ return new YydbError(code, message, opts);
149
+ }
150
+ }
151
+ /** Narrowing helper so callers can branch without `instanceof` imports. */
152
+ export function isYydbError(value) {
153
+ return value instanceof YydbError;
154
+ }
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@yydb/yydb",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "YYDB Node embedded engine and CLI",
5
5
  "license": "MPL-2.0",
6
6
  "type": "module",
7
7
  "bin": {
8
- "yydb": "./dist/cli.js"
8
+ "yydb": "dist/cli.js"
9
9
  },
10
10
  "main": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts",
@@ -47,9 +47,9 @@
47
47
  "access": "public"
48
48
  },
49
49
  "dependencies": {
50
- "@vmz/commander": "^0.2.0",
51
- "@voml/vos": "^0.0.1",
52
- "@yydb/yydb-client": "0.1.1"
50
+ "@vmz/commander": "^0.3.5",
51
+ "@vmz/diagnostic": "^0.3.5",
52
+ "@voml/vos": "^0.0.5"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@types/node": "^20.10.0",
@@ -59,9 +59,9 @@
59
59
  "node": ">=18"
60
60
  },
61
61
  "optionalDependencies": {
62
- "@yydb/yydb-win32-x64": "0.1.1",
63
- "@yydb/yydb-linux-x64": "0.1.1",
64
- "@yydb/yydb-darwin-x64": "0.1.1",
65
- "@yydb/yydb-darwin-arm64": "0.1.1"
62
+ "@yydb/yydb-darwin-arm64": "0.1.2",
63
+ "@yydb/yydb-darwin-x64": "0.1.2",
64
+ "@yydb/yydb-linux-x64": "0.1.2",
65
+ "@yydb/yydb-win32-x64": "0.1.2"
66
66
  }
67
67
  }