@zvndev/powdb-client 0.16.0 → 0.18.0
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/CHANGELOG.md +19 -0
- package/dist/cjs/errors.d.ts +41 -0
- package/dist/cjs/errors.js +60 -2
- package/dist/cjs/index.d.ts +2 -2
- package/dist/cjs/index.js +11 -9
- package/dist/cjs/protocol.d.ts +1 -0
- package/dist/cjs/protocol.js +10 -2
- package/dist/errors.d.ts +41 -0
- package/dist/errors.js +58 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -10
- package/dist/protocol.d.ts +1 -0
- package/dist/protocol.js +10 -2
- package/package.json +10 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.0 - 2026-07-20
|
|
4
|
+
|
|
5
|
+
- Version-alignment release in lockstep with workspace v0.18.0 (nested
|
|
6
|
+
projections: a PowQL projection field can embed a correlated child query and
|
|
7
|
+
return a native JSON array of shaped child objects per parent row). The
|
|
8
|
+
nested column arrives as an ordinary JSON value, so existing JSON handling
|
|
9
|
+
applies unchanged. No TypeScript API changes.
|
|
10
|
+
|
|
11
|
+
## 0.17.0 - 2026-07-19
|
|
12
|
+
|
|
13
|
+
- **Typed wire error codes.** Servers >= 0.17.0 append a stable one-byte error
|
|
14
|
+
class to error frames; the client maps it onto `PowDBErrorCode` (`timeout`,
|
|
15
|
+
`size_exceeded`, `auth_failed`, ...) instead of collapsing every server
|
|
16
|
+
error to `query_failed`, and exposes the raw class as
|
|
17
|
+
`PowDBError.wireErrorClass`. Fully backward compatible: classless frames
|
|
18
|
+
from older servers behave exactly as before, and unknown future classes
|
|
19
|
+
fall back to `query_failed`. See the repo's `docs/errors.md` for the code
|
|
20
|
+
table.
|
|
21
|
+
|
|
3
22
|
## 0.16.0 - 2026-07-18
|
|
4
23
|
|
|
5
24
|
- Version-alignment release in lockstep with workspace v0.16.0 (NUL-safe
|
package/dist/cjs/errors.d.ts
CHANGED
|
@@ -26,6 +26,39 @@ export type PowDBErrorCode =
|
|
|
26
26
|
| "timeout"
|
|
27
27
|
/** Type coercion on a row failed (queryTyped). */
|
|
28
28
|
| "type_coercion_failed";
|
|
29
|
+
/**
|
|
30
|
+
* Stable wire error classes appended by 0.17+ servers to Error frames
|
|
31
|
+
* (see docs/errors.md in the PowDB repo). These numeric values never change;
|
|
32
|
+
* new classes are only appended. Treat unknown values as `internal`.
|
|
33
|
+
*/
|
|
34
|
+
export declare const WIRE_ERROR_CLASS: {
|
|
35
|
+
/** Unclassified or internal server error. */
|
|
36
|
+
readonly internal: 0;
|
|
37
|
+
/** The query text failed to lex or parse. */
|
|
38
|
+
readonly parse: 1;
|
|
39
|
+
/** Planning or execution failed (unknown table/column, type mismatch, ...). */
|
|
40
|
+
readonly execution: 2;
|
|
41
|
+
/** A time budget elapsed (query timeout, gate wait, idle timeout). */
|
|
42
|
+
readonly timeout: 3;
|
|
43
|
+
/** A memory or size limit was exceeded. */
|
|
44
|
+
readonly limit_exceeded: 4;
|
|
45
|
+
/** The server is read-only and the statement requires a writer. */
|
|
46
|
+
readonly readonly_refused: 5;
|
|
47
|
+
/** Authentication or database selection failed at CONNECT time. */
|
|
48
|
+
readonly auth_failed: 6;
|
|
49
|
+
/** Too many failed authentication attempts. */
|
|
50
|
+
readonly rate_limited: 7;
|
|
51
|
+
/** A constraint (e.g. unique index) rejected the write. */
|
|
52
|
+
readonly constraint_violation: 8;
|
|
53
|
+
/** Execution was cancelled cooperatively (client disconnect). */
|
|
54
|
+
readonly cancelled: 9;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Map a server wire error class to the client's `PowDBErrorCode` taxonomy.
|
|
58
|
+
* `undefined` (legacy server, no class byte) and unknown future bytes fall
|
|
59
|
+
* back to `"query_failed"`, preserving pre-class behavior.
|
|
60
|
+
*/
|
|
61
|
+
export declare function errorCodeForWireClass(errorClass: number | undefined): PowDBErrorCode;
|
|
29
62
|
/**
|
|
30
63
|
* All errors thrown by `@zvndev/powdb-client` are instances of this class.
|
|
31
64
|
* Use `err.code` to branch; `err.cause` optionally carries the underlying
|
|
@@ -33,8 +66,16 @@ export type PowDBErrorCode =
|
|
|
33
66
|
*/
|
|
34
67
|
export declare class PowDBError extends Error {
|
|
35
68
|
readonly code: PowDBErrorCode;
|
|
69
|
+
/**
|
|
70
|
+
* The raw server wire error class (see `WIRE_ERROR_CLASS`), when the error
|
|
71
|
+
* came from a server Error frame that carried one. Finer-grained than
|
|
72
|
+
* `code` (e.g. it distinguishes readonly refusals and constraint
|
|
73
|
+
* violations); `undefined` for client-side errors and legacy servers.
|
|
74
|
+
*/
|
|
75
|
+
readonly wireErrorClass?: number;
|
|
36
76
|
constructor(message: string, code: PowDBErrorCode, options?: {
|
|
37
77
|
cause?: unknown;
|
|
78
|
+
wireErrorClass?: number;
|
|
38
79
|
});
|
|
39
80
|
}
|
|
40
81
|
/**
|
package/dist/cjs/errors.js
CHANGED
|
@@ -8,9 +8,55 @@
|
|
|
8
8
|
* legitimate reason to handle them differently.
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
-
exports.PowDBScriptError = exports.PowDBError = void 0;
|
|
11
|
+
exports.PowDBScriptError = exports.PowDBError = exports.WIRE_ERROR_CLASS = void 0;
|
|
12
|
+
exports.errorCodeForWireClass = errorCodeForWireClass;
|
|
12
13
|
exports.isPowDBError = isPowDBError;
|
|
13
14
|
exports.isPowDBScriptError = isPowDBScriptError;
|
|
15
|
+
/**
|
|
16
|
+
* Stable wire error classes appended by 0.17+ servers to Error frames
|
|
17
|
+
* (see docs/errors.md in the PowDB repo). These numeric values never change;
|
|
18
|
+
* new classes are only appended. Treat unknown values as `internal`.
|
|
19
|
+
*/
|
|
20
|
+
exports.WIRE_ERROR_CLASS = {
|
|
21
|
+
/** Unclassified or internal server error. */
|
|
22
|
+
internal: 0,
|
|
23
|
+
/** The query text failed to lex or parse. */
|
|
24
|
+
parse: 1,
|
|
25
|
+
/** Planning or execution failed (unknown table/column, type mismatch, ...). */
|
|
26
|
+
execution: 2,
|
|
27
|
+
/** A time budget elapsed (query timeout, gate wait, idle timeout). */
|
|
28
|
+
timeout: 3,
|
|
29
|
+
/** A memory or size limit was exceeded. */
|
|
30
|
+
limit_exceeded: 4,
|
|
31
|
+
/** The server is read-only and the statement requires a writer. */
|
|
32
|
+
readonly_refused: 5,
|
|
33
|
+
/** Authentication or database selection failed at CONNECT time. */
|
|
34
|
+
auth_failed: 6,
|
|
35
|
+
/** Too many failed authentication attempts. */
|
|
36
|
+
rate_limited: 7,
|
|
37
|
+
/** A constraint (e.g. unique index) rejected the write. */
|
|
38
|
+
constraint_violation: 8,
|
|
39
|
+
/** Execution was cancelled cooperatively (client disconnect). */
|
|
40
|
+
cancelled: 9,
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Map a server wire error class to the client's `PowDBErrorCode` taxonomy.
|
|
44
|
+
* `undefined` (legacy server, no class byte) and unknown future bytes fall
|
|
45
|
+
* back to `"query_failed"`, preserving pre-class behavior.
|
|
46
|
+
*/
|
|
47
|
+
function errorCodeForWireClass(errorClass) {
|
|
48
|
+
switch (errorClass) {
|
|
49
|
+
case exports.WIRE_ERROR_CLASS.timeout:
|
|
50
|
+
return "timeout";
|
|
51
|
+
case exports.WIRE_ERROR_CLASS.limit_exceeded:
|
|
52
|
+
return "size_exceeded";
|
|
53
|
+
case exports.WIRE_ERROR_CLASS.auth_failed:
|
|
54
|
+
case exports.WIRE_ERROR_CLASS.rate_limited:
|
|
55
|
+
return "auth_failed";
|
|
56
|
+
default:
|
|
57
|
+
return "query_failed";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
14
60
|
/**
|
|
15
61
|
* All errors thrown by `@zvndev/powdb-client` are instances of this class.
|
|
16
62
|
* Use `err.code` to branch; `err.cause` optionally carries the underlying
|
|
@@ -18,11 +64,23 @@ exports.isPowDBScriptError = isPowDBScriptError;
|
|
|
18
64
|
*/
|
|
19
65
|
class PowDBError extends Error {
|
|
20
66
|
code;
|
|
67
|
+
/**
|
|
68
|
+
* The raw server wire error class (see `WIRE_ERROR_CLASS`), when the error
|
|
69
|
+
* came from a server Error frame that carried one. Finer-grained than
|
|
70
|
+
* `code` (e.g. it distinguishes readonly refusals and constraint
|
|
71
|
+
* violations); `undefined` for client-side errors and legacy servers.
|
|
72
|
+
*/
|
|
73
|
+
wireErrorClass;
|
|
21
74
|
constructor(message, code, options) {
|
|
22
75
|
// ErrorOptions.cause is supported in Node 16.9+; we require Node 18+.
|
|
23
|
-
|
|
76
|
+
// Only forward `cause` when the caller supplied one, so a bare options
|
|
77
|
+
// object never materializes an own `cause: undefined` property.
|
|
78
|
+
super(message, options && "cause" in options
|
|
79
|
+
? { cause: options.cause }
|
|
80
|
+
: undefined);
|
|
24
81
|
this.name = "PowDBError";
|
|
25
82
|
this.code = code;
|
|
83
|
+
this.wireErrorClass = options?.wireErrorClass;
|
|
26
84
|
// Preserve the prototype chain across `target: es2020` and friends.
|
|
27
85
|
Object.setPrototypeOf(this, PowDBError.prototype);
|
|
28
86
|
}
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { EventEmitter } from "node:events";
|
|
|
19
19
|
import { type NativeJson, type SyncRepairAction, type WireRetainedUnit, type WireSyncStatus, type WireValue } from "./protocol.js";
|
|
20
20
|
import { type TypedRow, type TypedSchema } from "./typed.js";
|
|
21
21
|
/** Client library version. Compared to the server's reported version. */
|
|
22
|
-
export declare const CLIENT_VERSION = "0.
|
|
22
|
+
export declare const CLIENT_VERSION = "0.18.0";
|
|
23
23
|
/**
|
|
24
24
|
* The maximum catalog format version this client can read. State this as the
|
|
25
25
|
* `catalogVersion` in sync pull requests: the server accepts any replica whose
|
|
@@ -471,7 +471,7 @@ export { escapeLiteral, escapeIdent, ident, powql, PowqlIdent, } from "./escape.
|
|
|
471
471
|
export { Pool } from "./pool.js";
|
|
472
472
|
export type { PoolOptions } from "./pool.js";
|
|
473
473
|
export { splitStatements } from "./script.js";
|
|
474
|
-
export { PowDBError, isPowDBError, PowDBScriptError, isPowDBScriptError, } from "./errors.js";
|
|
474
|
+
export { errorCodeForWireClass, PowDBError, isPowDBError, PowDBScriptError, isPowDBScriptError, WIRE_ERROR_CLASS, } from "./errors.js";
|
|
475
475
|
export type { PowDBErrorCode } from "./errors.js";
|
|
476
476
|
export { coerceValue, coerceRow, coerceRows, } from "./typed.js";
|
|
477
477
|
export type { ColumnType, TypedSchema, TypedRow, Coerced, JsonValue, } from "./typed.js";
|
package/dist/cjs/index.js
CHANGED
|
@@ -49,7 +49,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
49
49
|
};
|
|
50
50
|
})();
|
|
51
51
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
-
exports.coerceRows = exports.coerceRow = exports.coerceValue = exports.isPowDBScriptError = exports.PowDBScriptError = exports.isPowDBError = exports.PowDBError = exports.splitStatements = exports.Pool = exports.PowqlIdent = exports.powql = exports.ident = exports.escapeIdent = exports.escapeLiteral = exports.MAX_SYNC_PULL_BYTES = exports.MAX_SYNC_PULL_UNITS = exports.MAX_SYNC_UNITS = exports.MAX_PARAMS = exports.MAX_COLUMNS = exports.MAX_ROWS = exports.MAX_PAYLOAD_SIZE = exports.tryDecode = exports.encode = exports.Client = exports.SUPPORTED_CATALOG_VERSION = exports.CLIENT_VERSION = void 0;
|
|
52
|
+
exports.coerceRows = exports.coerceRow = exports.coerceValue = exports.WIRE_ERROR_CLASS = exports.isPowDBScriptError = exports.PowDBScriptError = exports.isPowDBError = exports.PowDBError = exports.errorCodeForWireClass = exports.splitStatements = exports.Pool = exports.PowqlIdent = exports.powql = exports.ident = exports.escapeIdent = exports.escapeLiteral = exports.MAX_SYNC_PULL_BYTES = exports.MAX_SYNC_PULL_UNITS = exports.MAX_SYNC_UNITS = exports.MAX_PARAMS = exports.MAX_COLUMNS = exports.MAX_ROWS = exports.MAX_PAYLOAD_SIZE = exports.tryDecode = exports.encode = exports.Client = exports.SUPPORTED_CATALOG_VERSION = exports.CLIENT_VERSION = void 0;
|
|
53
53
|
exports.assertServerCatalogVersionSupported = assertServerCatalogVersionSupported;
|
|
54
54
|
const net = __importStar(require("node:net"));
|
|
55
55
|
const tls = __importStar(require("node:tls"));
|
|
@@ -59,7 +59,7 @@ const errors_js_1 = require("./errors.js");
|
|
|
59
59
|
const script_js_1 = require("./script.js");
|
|
60
60
|
const typed_js_1 = require("./typed.js");
|
|
61
61
|
/** Client library version. Compared to the server's reported version. */
|
|
62
|
-
exports.CLIENT_VERSION = "0.
|
|
62
|
+
exports.CLIENT_VERSION = "0.18.0";
|
|
63
63
|
/**
|
|
64
64
|
* The maximum catalog format version this client can read. State this as the
|
|
65
65
|
* `catalogVersion` in sync pull requests: the server accepts any replica whose
|
|
@@ -152,7 +152,7 @@ function nativeQueryResult(reply) {
|
|
|
152
152
|
case "ResultMessage":
|
|
153
153
|
return { kind: "message", message: reply.message };
|
|
154
154
|
case "Error":
|
|
155
|
-
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`,
|
|
155
|
+
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`, (0, errors_js_1.errorCodeForWireClass)(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
156
156
|
default:
|
|
157
157
|
throw new errors_js_1.PowDBError(`unexpected reply to native query: ${reply.type}`, "protocol_error");
|
|
158
158
|
}
|
|
@@ -168,7 +168,7 @@ function rawNativeQueryResult(reply) {
|
|
|
168
168
|
case "ResultMessage":
|
|
169
169
|
return { kind: "message", message: reply.message };
|
|
170
170
|
case "Error":
|
|
171
|
-
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`,
|
|
171
|
+
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`, (0, errors_js_1.errorCodeForWireClass)(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
172
172
|
default:
|
|
173
173
|
throw new errors_js_1.PowDBError(`unexpected reply to native query: ${reply.type}`, "protocol_error");
|
|
174
174
|
}
|
|
@@ -386,7 +386,7 @@ class Client extends node_events_1.EventEmitter {
|
|
|
386
386
|
result = { kind: "message", message: reply.message };
|
|
387
387
|
break;
|
|
388
388
|
case "Error":
|
|
389
|
-
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`,
|
|
389
|
+
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`, (0, errors_js_1.errorCodeForWireClass)(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
390
390
|
default:
|
|
391
391
|
throw new errors_js_1.PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
392
392
|
}
|
|
@@ -515,7 +515,7 @@ class Client extends node_events_1.EventEmitter {
|
|
|
515
515
|
result = { kind: "message", message: reply.message };
|
|
516
516
|
break;
|
|
517
517
|
case "Error":
|
|
518
|
-
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`,
|
|
518
|
+
throw new errors_js_1.PowDBError(`query failed: ${reply.message}`, (0, errors_js_1.errorCodeForWireClass)(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
519
519
|
default:
|
|
520
520
|
throw new errors_js_1.PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
521
521
|
}
|
|
@@ -572,7 +572,7 @@ class Client extends node_events_1.EventEmitter {
|
|
|
572
572
|
try {
|
|
573
573
|
const reply = await this.send({ type: "SyncStatus", replicaId }, opts);
|
|
574
574
|
if (reply.type === "Error") {
|
|
575
|
-
throw new errors_js_1.PowDBError(`sync status failed: ${reply.message}`,
|
|
575
|
+
throw new errors_js_1.PowDBError(`sync status failed: ${reply.message}`, (0, errors_js_1.errorCodeForWireClass)(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
576
576
|
}
|
|
577
577
|
if (reply.type !== "SyncStatusResult") {
|
|
578
578
|
throw new errors_js_1.PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
@@ -622,7 +622,7 @@ class Client extends node_events_1.EventEmitter {
|
|
|
622
622
|
segmentFormatVersion: toU16(request.segmentFormatVersion, "segmentFormatVersion"),
|
|
623
623
|
}, opts);
|
|
624
624
|
if (reply.type === "Error") {
|
|
625
|
-
throw new errors_js_1.PowDBError(`sync pull failed: ${reply.message}`,
|
|
625
|
+
throw new errors_js_1.PowDBError(`sync pull failed: ${reply.message}`, (0, errors_js_1.errorCodeForWireClass)(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
626
626
|
}
|
|
627
627
|
if (reply.type !== "SyncPullResult") {
|
|
628
628
|
throw new errors_js_1.PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
@@ -665,7 +665,7 @@ class Client extends node_events_1.EventEmitter {
|
|
|
665
665
|
remoteLsn: toU64(request.remoteLsn, "remoteLsn"),
|
|
666
666
|
}, opts);
|
|
667
667
|
if (reply.type === "Error") {
|
|
668
|
-
throw new errors_js_1.PowDBError(`sync ack failed: ${reply.message}`,
|
|
668
|
+
throw new errors_js_1.PowDBError(`sync ack failed: ${reply.message}`, (0, errors_js_1.errorCodeForWireClass)(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
669
669
|
}
|
|
670
670
|
if (reply.type !== "SyncAckResult") {
|
|
671
671
|
throw new errors_js_1.PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
@@ -1226,10 +1226,12 @@ Object.defineProperty(exports, "Pool", { enumerable: true, get: function () { re
|
|
|
1226
1226
|
var script_js_2 = require("./script.js");
|
|
1227
1227
|
Object.defineProperty(exports, "splitStatements", { enumerable: true, get: function () { return script_js_2.splitStatements; } });
|
|
1228
1228
|
var errors_js_2 = require("./errors.js");
|
|
1229
|
+
Object.defineProperty(exports, "errorCodeForWireClass", { enumerable: true, get: function () { return errors_js_2.errorCodeForWireClass; } });
|
|
1229
1230
|
Object.defineProperty(exports, "PowDBError", { enumerable: true, get: function () { return errors_js_2.PowDBError; } });
|
|
1230
1231
|
Object.defineProperty(exports, "isPowDBError", { enumerable: true, get: function () { return errors_js_2.isPowDBError; } });
|
|
1231
1232
|
Object.defineProperty(exports, "PowDBScriptError", { enumerable: true, get: function () { return errors_js_2.PowDBScriptError; } });
|
|
1232
1233
|
Object.defineProperty(exports, "isPowDBScriptError", { enumerable: true, get: function () { return errors_js_2.isPowDBScriptError; } });
|
|
1234
|
+
Object.defineProperty(exports, "WIRE_ERROR_CLASS", { enumerable: true, get: function () { return errors_js_2.WIRE_ERROR_CLASS; } });
|
|
1233
1235
|
var typed_js_2 = require("./typed.js");
|
|
1234
1236
|
Object.defineProperty(exports, "coerceValue", { enumerable: true, get: function () { return typed_js_2.coerceValue; } });
|
|
1235
1237
|
Object.defineProperty(exports, "coerceRow", { enumerable: true, get: function () { return typed_js_2.coerceRow; } });
|
package/dist/cjs/protocol.d.ts
CHANGED
package/dist/cjs/protocol.js
CHANGED
|
@@ -544,8 +544,16 @@ function decodePayload(msgType, payload) {
|
|
|
544
544
|
}
|
|
545
545
|
case exports.MSG_RESULT_MSG:
|
|
546
546
|
return { type: "ResultMessage", message: decodeString(payload, cursor) };
|
|
547
|
-
case exports.MSG_ERROR:
|
|
548
|
-
|
|
547
|
+
case exports.MSG_ERROR: {
|
|
548
|
+
const message = decodeString(payload, cursor);
|
|
549
|
+
// 0.17+ servers append one stable error-class byte after the
|
|
550
|
+
// length-prefixed message (see docs/errors.md). Old servers send only
|
|
551
|
+
// the string, so absence means "no class".
|
|
552
|
+
if (cursor.pos < payload.length) {
|
|
553
|
+
return { type: "Error", message, errorClass: payload[cursor.pos] };
|
|
554
|
+
}
|
|
555
|
+
return { type: "Error", message };
|
|
556
|
+
}
|
|
549
557
|
case exports.MSG_DISCONNECT:
|
|
550
558
|
return { type: "Disconnect" };
|
|
551
559
|
case exports.MSG_PING:
|
package/dist/errors.d.ts
CHANGED
|
@@ -26,6 +26,39 @@ export type PowDBErrorCode =
|
|
|
26
26
|
| "timeout"
|
|
27
27
|
/** Type coercion on a row failed (queryTyped). */
|
|
28
28
|
| "type_coercion_failed";
|
|
29
|
+
/**
|
|
30
|
+
* Stable wire error classes appended by 0.17+ servers to Error frames
|
|
31
|
+
* (see docs/errors.md in the PowDB repo). These numeric values never change;
|
|
32
|
+
* new classes are only appended. Treat unknown values as `internal`.
|
|
33
|
+
*/
|
|
34
|
+
export declare const WIRE_ERROR_CLASS: {
|
|
35
|
+
/** Unclassified or internal server error. */
|
|
36
|
+
readonly internal: 0;
|
|
37
|
+
/** The query text failed to lex or parse. */
|
|
38
|
+
readonly parse: 1;
|
|
39
|
+
/** Planning or execution failed (unknown table/column, type mismatch, ...). */
|
|
40
|
+
readonly execution: 2;
|
|
41
|
+
/** A time budget elapsed (query timeout, gate wait, idle timeout). */
|
|
42
|
+
readonly timeout: 3;
|
|
43
|
+
/** A memory or size limit was exceeded. */
|
|
44
|
+
readonly limit_exceeded: 4;
|
|
45
|
+
/** The server is read-only and the statement requires a writer. */
|
|
46
|
+
readonly readonly_refused: 5;
|
|
47
|
+
/** Authentication or database selection failed at CONNECT time. */
|
|
48
|
+
readonly auth_failed: 6;
|
|
49
|
+
/** Too many failed authentication attempts. */
|
|
50
|
+
readonly rate_limited: 7;
|
|
51
|
+
/** A constraint (e.g. unique index) rejected the write. */
|
|
52
|
+
readonly constraint_violation: 8;
|
|
53
|
+
/** Execution was cancelled cooperatively (client disconnect). */
|
|
54
|
+
readonly cancelled: 9;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Map a server wire error class to the client's `PowDBErrorCode` taxonomy.
|
|
58
|
+
* `undefined` (legacy server, no class byte) and unknown future bytes fall
|
|
59
|
+
* back to `"query_failed"`, preserving pre-class behavior.
|
|
60
|
+
*/
|
|
61
|
+
export declare function errorCodeForWireClass(errorClass: number | undefined): PowDBErrorCode;
|
|
29
62
|
/**
|
|
30
63
|
* All errors thrown by `@zvndev/powdb-client` are instances of this class.
|
|
31
64
|
* Use `err.code` to branch; `err.cause` optionally carries the underlying
|
|
@@ -33,8 +66,16 @@ export type PowDBErrorCode =
|
|
|
33
66
|
*/
|
|
34
67
|
export declare class PowDBError extends Error {
|
|
35
68
|
readonly code: PowDBErrorCode;
|
|
69
|
+
/**
|
|
70
|
+
* The raw server wire error class (see `WIRE_ERROR_CLASS`), when the error
|
|
71
|
+
* came from a server Error frame that carried one. Finer-grained than
|
|
72
|
+
* `code` (e.g. it distinguishes readonly refusals and constraint
|
|
73
|
+
* violations); `undefined` for client-side errors and legacy servers.
|
|
74
|
+
*/
|
|
75
|
+
readonly wireErrorClass?: number;
|
|
36
76
|
constructor(message: string, code: PowDBErrorCode, options?: {
|
|
37
77
|
cause?: unknown;
|
|
78
|
+
wireErrorClass?: number;
|
|
38
79
|
});
|
|
39
80
|
}
|
|
40
81
|
/**
|
package/dist/errors.js
CHANGED
|
@@ -6,6 +6,51 @@
|
|
|
6
6
|
* is intentionally small — new codes are added only when a caller has a
|
|
7
7
|
* legitimate reason to handle them differently.
|
|
8
8
|
*/
|
|
9
|
+
/**
|
|
10
|
+
* Stable wire error classes appended by 0.17+ servers to Error frames
|
|
11
|
+
* (see docs/errors.md in the PowDB repo). These numeric values never change;
|
|
12
|
+
* new classes are only appended. Treat unknown values as `internal`.
|
|
13
|
+
*/
|
|
14
|
+
export const WIRE_ERROR_CLASS = {
|
|
15
|
+
/** Unclassified or internal server error. */
|
|
16
|
+
internal: 0,
|
|
17
|
+
/** The query text failed to lex or parse. */
|
|
18
|
+
parse: 1,
|
|
19
|
+
/** Planning or execution failed (unknown table/column, type mismatch, ...). */
|
|
20
|
+
execution: 2,
|
|
21
|
+
/** A time budget elapsed (query timeout, gate wait, idle timeout). */
|
|
22
|
+
timeout: 3,
|
|
23
|
+
/** A memory or size limit was exceeded. */
|
|
24
|
+
limit_exceeded: 4,
|
|
25
|
+
/** The server is read-only and the statement requires a writer. */
|
|
26
|
+
readonly_refused: 5,
|
|
27
|
+
/** Authentication or database selection failed at CONNECT time. */
|
|
28
|
+
auth_failed: 6,
|
|
29
|
+
/** Too many failed authentication attempts. */
|
|
30
|
+
rate_limited: 7,
|
|
31
|
+
/** A constraint (e.g. unique index) rejected the write. */
|
|
32
|
+
constraint_violation: 8,
|
|
33
|
+
/** Execution was cancelled cooperatively (client disconnect). */
|
|
34
|
+
cancelled: 9,
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Map a server wire error class to the client's `PowDBErrorCode` taxonomy.
|
|
38
|
+
* `undefined` (legacy server, no class byte) and unknown future bytes fall
|
|
39
|
+
* back to `"query_failed"`, preserving pre-class behavior.
|
|
40
|
+
*/
|
|
41
|
+
export function errorCodeForWireClass(errorClass) {
|
|
42
|
+
switch (errorClass) {
|
|
43
|
+
case WIRE_ERROR_CLASS.timeout:
|
|
44
|
+
return "timeout";
|
|
45
|
+
case WIRE_ERROR_CLASS.limit_exceeded:
|
|
46
|
+
return "size_exceeded";
|
|
47
|
+
case WIRE_ERROR_CLASS.auth_failed:
|
|
48
|
+
case WIRE_ERROR_CLASS.rate_limited:
|
|
49
|
+
return "auth_failed";
|
|
50
|
+
default:
|
|
51
|
+
return "query_failed";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
9
54
|
/**
|
|
10
55
|
* All errors thrown by `@zvndev/powdb-client` are instances of this class.
|
|
11
56
|
* Use `err.code` to branch; `err.cause` optionally carries the underlying
|
|
@@ -13,11 +58,23 @@
|
|
|
13
58
|
*/
|
|
14
59
|
export class PowDBError extends Error {
|
|
15
60
|
code;
|
|
61
|
+
/**
|
|
62
|
+
* The raw server wire error class (see `WIRE_ERROR_CLASS`), when the error
|
|
63
|
+
* came from a server Error frame that carried one. Finer-grained than
|
|
64
|
+
* `code` (e.g. it distinguishes readonly refusals and constraint
|
|
65
|
+
* violations); `undefined` for client-side errors and legacy servers.
|
|
66
|
+
*/
|
|
67
|
+
wireErrorClass;
|
|
16
68
|
constructor(message, code, options) {
|
|
17
69
|
// ErrorOptions.cause is supported in Node 16.9+; we require Node 18+.
|
|
18
|
-
|
|
70
|
+
// Only forward `cause` when the caller supplied one, so a bare options
|
|
71
|
+
// object never materializes an own `cause: undefined` property.
|
|
72
|
+
super(message, options && "cause" in options
|
|
73
|
+
? { cause: options.cause }
|
|
74
|
+
: undefined);
|
|
19
75
|
this.name = "PowDBError";
|
|
20
76
|
this.code = code;
|
|
77
|
+
this.wireErrorClass = options?.wireErrorClass;
|
|
21
78
|
// Preserve the prototype chain across `target: es2020` and friends.
|
|
22
79
|
Object.setPrototypeOf(this, PowDBError.prototype);
|
|
23
80
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { EventEmitter } from "node:events";
|
|
|
19
19
|
import { type NativeJson, type SyncRepairAction, type WireRetainedUnit, type WireSyncStatus, type WireValue } from "./protocol.js";
|
|
20
20
|
import { type TypedRow, type TypedSchema } from "./typed.js";
|
|
21
21
|
/** Client library version. Compared to the server's reported version. */
|
|
22
|
-
export declare const CLIENT_VERSION = "0.
|
|
22
|
+
export declare const CLIENT_VERSION = "0.18.0";
|
|
23
23
|
/**
|
|
24
24
|
* The maximum catalog format version this client can read. State this as the
|
|
25
25
|
* `catalogVersion` in sync pull requests: the server accepts any replica whose
|
|
@@ -471,7 +471,7 @@ export { escapeLiteral, escapeIdent, ident, powql, PowqlIdent, } from "./escape.
|
|
|
471
471
|
export { Pool } from "./pool.js";
|
|
472
472
|
export type { PoolOptions } from "./pool.js";
|
|
473
473
|
export { splitStatements } from "./script.js";
|
|
474
|
-
export { PowDBError, isPowDBError, PowDBScriptError, isPowDBScriptError, } from "./errors.js";
|
|
474
|
+
export { errorCodeForWireClass, PowDBError, isPowDBError, PowDBScriptError, isPowDBScriptError, WIRE_ERROR_CLASS, } from "./errors.js";
|
|
475
475
|
export type { PowDBErrorCode } from "./errors.js";
|
|
476
476
|
export { coerceValue, coerceRow, coerceRows, } from "./typed.js";
|
|
477
477
|
export type { ColumnType, TypedSchema, TypedRow, Coerced, JsonValue, } from "./typed.js";
|
package/dist/index.js
CHANGED
|
@@ -18,11 +18,11 @@ import * as net from "node:net";
|
|
|
18
18
|
import * as tls from "node:tls";
|
|
19
19
|
import { EventEmitter } from "node:events";
|
|
20
20
|
import { encode, tryDecode, MAX_SYNC_PULL_BYTES, MAX_SYNC_PULL_UNITS, } from "./protocol.js";
|
|
21
|
-
import { PowDBError, PowDBScriptError,
|
|
21
|
+
import { errorCodeForWireClass, isPowDBError, PowDBError, PowDBScriptError, } from "./errors.js";
|
|
22
22
|
import { splitStatements } from "./script.js";
|
|
23
23
|
import { coerceRows, } from "./typed.js";
|
|
24
24
|
/** Client library version. Compared to the server's reported version. */
|
|
25
|
-
export const CLIENT_VERSION = "0.
|
|
25
|
+
export const CLIENT_VERSION = "0.18.0";
|
|
26
26
|
/**
|
|
27
27
|
* The maximum catalog format version this client can read. State this as the
|
|
28
28
|
* `catalogVersion` in sync pull requests: the server accepts any replica whose
|
|
@@ -115,7 +115,7 @@ function nativeQueryResult(reply) {
|
|
|
115
115
|
case "ResultMessage":
|
|
116
116
|
return { kind: "message", message: reply.message };
|
|
117
117
|
case "Error":
|
|
118
|
-
throw new PowDBError(`query failed: ${reply.message}`,
|
|
118
|
+
throw new PowDBError(`query failed: ${reply.message}`, errorCodeForWireClass(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
119
119
|
default:
|
|
120
120
|
throw new PowDBError(`unexpected reply to native query: ${reply.type}`, "protocol_error");
|
|
121
121
|
}
|
|
@@ -131,7 +131,7 @@ function rawNativeQueryResult(reply) {
|
|
|
131
131
|
case "ResultMessage":
|
|
132
132
|
return { kind: "message", message: reply.message };
|
|
133
133
|
case "Error":
|
|
134
|
-
throw new PowDBError(`query failed: ${reply.message}`,
|
|
134
|
+
throw new PowDBError(`query failed: ${reply.message}`, errorCodeForWireClass(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
135
135
|
default:
|
|
136
136
|
throw new PowDBError(`unexpected reply to native query: ${reply.type}`, "protocol_error");
|
|
137
137
|
}
|
|
@@ -349,7 +349,7 @@ export class Client extends EventEmitter {
|
|
|
349
349
|
result = { kind: "message", message: reply.message };
|
|
350
350
|
break;
|
|
351
351
|
case "Error":
|
|
352
|
-
throw new PowDBError(`query failed: ${reply.message}`,
|
|
352
|
+
throw new PowDBError(`query failed: ${reply.message}`, errorCodeForWireClass(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
353
353
|
default:
|
|
354
354
|
throw new PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
355
355
|
}
|
|
@@ -478,7 +478,7 @@ export class Client extends EventEmitter {
|
|
|
478
478
|
result = { kind: "message", message: reply.message };
|
|
479
479
|
break;
|
|
480
480
|
case "Error":
|
|
481
|
-
throw new PowDBError(`query failed: ${reply.message}`,
|
|
481
|
+
throw new PowDBError(`query failed: ${reply.message}`, errorCodeForWireClass(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
482
482
|
default:
|
|
483
483
|
throw new PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
484
484
|
}
|
|
@@ -535,7 +535,7 @@ export class Client extends EventEmitter {
|
|
|
535
535
|
try {
|
|
536
536
|
const reply = await this.send({ type: "SyncStatus", replicaId }, opts);
|
|
537
537
|
if (reply.type === "Error") {
|
|
538
|
-
throw new PowDBError(`sync status failed: ${reply.message}`,
|
|
538
|
+
throw new PowDBError(`sync status failed: ${reply.message}`, errorCodeForWireClass(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
539
539
|
}
|
|
540
540
|
if (reply.type !== "SyncStatusResult") {
|
|
541
541
|
throw new PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
@@ -585,7 +585,7 @@ export class Client extends EventEmitter {
|
|
|
585
585
|
segmentFormatVersion: toU16(request.segmentFormatVersion, "segmentFormatVersion"),
|
|
586
586
|
}, opts);
|
|
587
587
|
if (reply.type === "Error") {
|
|
588
|
-
throw new PowDBError(`sync pull failed: ${reply.message}`,
|
|
588
|
+
throw new PowDBError(`sync pull failed: ${reply.message}`, errorCodeForWireClass(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
589
589
|
}
|
|
590
590
|
if (reply.type !== "SyncPullResult") {
|
|
591
591
|
throw new PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
@@ -628,7 +628,7 @@ export class Client extends EventEmitter {
|
|
|
628
628
|
remoteLsn: toU64(request.remoteLsn, "remoteLsn"),
|
|
629
629
|
}, opts);
|
|
630
630
|
if (reply.type === "Error") {
|
|
631
|
-
throw new PowDBError(`sync ack failed: ${reply.message}`,
|
|
631
|
+
throw new PowDBError(`sync ack failed: ${reply.message}`, errorCodeForWireClass(reply.errorClass), { wireErrorClass: reply.errorClass });
|
|
632
632
|
}
|
|
633
633
|
if (reply.type !== "SyncAckResult") {
|
|
634
634
|
throw new PowDBError(`unexpected reply: ${reply.type}`, "protocol_error");
|
|
@@ -1171,5 +1171,5 @@ export { MAX_PAYLOAD_SIZE, MAX_ROWS, MAX_COLUMNS, MAX_PARAMS, MAX_SYNC_UNITS, MA
|
|
|
1171
1171
|
export { escapeLiteral, escapeIdent, ident, powql, PowqlIdent, } from "./escape.js";
|
|
1172
1172
|
export { Pool } from "./pool.js";
|
|
1173
1173
|
export { splitStatements } from "./script.js";
|
|
1174
|
-
export { PowDBError, isPowDBError, PowDBScriptError, isPowDBScriptError, } from "./errors.js";
|
|
1174
|
+
export { errorCodeForWireClass, PowDBError, isPowDBError, PowDBScriptError, isPowDBScriptError, WIRE_ERROR_CLASS, } from "./errors.js";
|
|
1175
1175
|
export { coerceValue, coerceRow, coerceRows, } from "./typed.js";
|
package/dist/protocol.d.ts
CHANGED
package/dist/protocol.js
CHANGED
|
@@ -539,8 +539,16 @@ function decodePayload(msgType, payload) {
|
|
|
539
539
|
}
|
|
540
540
|
case MSG_RESULT_MSG:
|
|
541
541
|
return { type: "ResultMessage", message: decodeString(payload, cursor) };
|
|
542
|
-
case MSG_ERROR:
|
|
543
|
-
|
|
542
|
+
case MSG_ERROR: {
|
|
543
|
+
const message = decodeString(payload, cursor);
|
|
544
|
+
// 0.17+ servers append one stable error-class byte after the
|
|
545
|
+
// length-prefixed message (see docs/errors.md). Old servers send only
|
|
546
|
+
// the string, so absence means "no class".
|
|
547
|
+
if (cursor.pos < payload.length) {
|
|
548
|
+
return { type: "Error", message, errorClass: payload[cursor.pos] };
|
|
549
|
+
}
|
|
550
|
+
return { type: "Error", message };
|
|
551
|
+
}
|
|
544
552
|
case MSG_DISCONNECT:
|
|
545
553
|
return { type: "Disconnect" };
|
|
546
554
|
case MSG_PING:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zvndev/powdb-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "TypeScript client for PowDB (PowQL wire protocol)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.29.3",
|
|
@@ -19,7 +19,12 @@
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
|
-
"files": [
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md",
|
|
25
|
+
"LICENSE",
|
|
26
|
+
"CHANGELOG.md"
|
|
27
|
+
],
|
|
23
28
|
"license": "MIT",
|
|
24
29
|
"repository": {
|
|
25
30
|
"type": "git",
|
|
@@ -51,7 +56,9 @@
|
|
|
51
56
|
"@types/node": ">=18"
|
|
52
57
|
},
|
|
53
58
|
"peerDependenciesMeta": {
|
|
54
|
-
"@types/node": {
|
|
59
|
+
"@types/node": {
|
|
60
|
+
"optional": true
|
|
61
|
+
}
|
|
55
62
|
},
|
|
56
63
|
"scripts": {
|
|
57
64
|
"build": "npm run build:esm && npm run build:cjs",
|