@zvndev/powdb-client 0.8.0 → 0.8.1
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/README.md +18 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +28 -17
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -322,11 +322,12 @@ try {
|
|
|
322
322
|
}
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
`PowDBError`
|
|
325
|
+
A plain `ctrl.abort()` throws a `PowDBError` with `code === "aborted"`. If you
|
|
326
|
+
abort with a custom `Error` reason (`ctrl.abort(myError)`), that error is thrown
|
|
327
|
+
as-is; any non-`Error` reason is wrapped in a `PowDBError` (`code === "aborted"`).
|
|
328
328
|
|
|
329
|
-
The socket stays open — the
|
|
329
|
+
The socket stays open — the aborted query's reply is silently discarded when it
|
|
330
|
+
arrives, and every other in-flight query still receives its own result.
|
|
330
331
|
|
|
331
332
|
## API
|
|
332
333
|
|
|
@@ -361,6 +362,19 @@ Sends a PowQL query and returns a `Promise<QueryResult>`:
|
|
|
361
362
|
|
|
362
363
|
Throws a `PowDBError` (see Structured errors above) on any failure.
|
|
363
364
|
|
|
365
|
+
### `client.querySql(query, opts?)`
|
|
366
|
+
|
|
367
|
+
Runs a statement through the server's **SQL frontend** and returns a
|
|
368
|
+
`Promise<QueryResult>` — the same result shape as `query()`. The plain
|
|
369
|
+
`query()` method stays PowQL for wire compatibility; `querySql()` sends the
|
|
370
|
+
dedicated `QuerySql` wire message. Requires server ≥0.5.0 (the SQL frontend was
|
|
371
|
+
added in 0.5.0); see `docs/SQL.md` for the supported subset. `opts.signal?:
|
|
372
|
+
AbortSignal` cancels the query (see Cancellation above).
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
const result = await client.querySql("SELECT name, age FROM User WHERE age > 27");
|
|
376
|
+
```
|
|
377
|
+
|
|
364
378
|
### `client.queryTyped(query, schema, opts?)`
|
|
365
379
|
|
|
366
380
|
Like `query()`, but coerces each row's string values to JS types using the
|
package/dist/index.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { EventEmitter } from "node:events";
|
|
|
19
19
|
import { type SyncRepairAction, type WireRetainedUnit, type WireSyncStatus } 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.8.
|
|
22
|
+
export declare const CLIENT_VERSION = "0.8.1";
|
|
23
23
|
export type QueryResult = {
|
|
24
24
|
kind: "rows";
|
|
25
25
|
columns: string[];
|
package/dist/index.js
CHANGED
|
@@ -21,7 +21,7 @@ import { encode, tryDecode, MAX_SYNC_PULL_BYTES, MAX_SYNC_PULL_UNITS, } from "./
|
|
|
21
21
|
import { PowDBError } from "./errors.js";
|
|
22
22
|
import { coerceRows, } from "./typed.js";
|
|
23
23
|
/** Client library version. Compared to the server's reported version. */
|
|
24
|
-
export const CLIENT_VERSION = "0.8.
|
|
24
|
+
export const CLIENT_VERSION = "0.8.1";
|
|
25
25
|
function socketChunkToBuffer(chunk) {
|
|
26
26
|
return typeof chunk === "string" ? Buffer.from(chunk) : chunk;
|
|
27
27
|
}
|
|
@@ -98,16 +98,19 @@ function majorOf(version) {
|
|
|
98
98
|
return dot === -1 ? version : version.slice(0, dot);
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
101
|
-
* Build an AbortError.
|
|
102
|
-
*
|
|
103
|
-
* `
|
|
101
|
+
* Build an AbortError. A caller-supplied custom `Error` reason
|
|
102
|
+
* (`ctrl.abort(myError)`) passes through as-is to match DOM semantics. The
|
|
103
|
+
* default abort reason — Node's `DOMException` named `"AbortError"` — and any
|
|
104
|
+
* non-Error reason are wrapped in a `PowDBError` with code `"aborted"` so the
|
|
105
|
+
* common `ctrl.abort()` case branches uniformly on `err.code === "aborted"`.
|
|
104
106
|
*/
|
|
105
107
|
function abortError(signal) {
|
|
106
108
|
if (signal && signal.reason !== undefined) {
|
|
107
109
|
const r = signal.reason;
|
|
108
|
-
|
|
110
|
+
const isDefaultAbort = r instanceof DOMException && r.name === "AbortError";
|
|
111
|
+
if (r instanceof Error && !isDefaultAbort)
|
|
109
112
|
return r;
|
|
110
|
-
return new PowDBError(String(r), "aborted");
|
|
113
|
+
return new PowDBError(isDefaultAbort ? "query was aborted" : String(r), "aborted");
|
|
111
114
|
}
|
|
112
115
|
return new PowDBError("query was aborted", "aborted");
|
|
113
116
|
}
|
|
@@ -527,8 +530,17 @@ export class Client extends EventEmitter {
|
|
|
527
530
|
* timeout so an unresponsive peer cannot make `close()` hang forever.
|
|
528
531
|
*/
|
|
529
532
|
async close() {
|
|
530
|
-
if (this.closed)
|
|
533
|
+
if (this.closed) {
|
|
534
|
+
// Already torn down (e.g. an error in onData/onClose closed the client
|
|
535
|
+
// without destroying the socket). Ensure the socket is released so a
|
|
536
|
+
// post-teardown close() resolves instead of keeping the event loop
|
|
537
|
+
// alive. `writableEnded` distinguishes that case from a concurrent
|
|
538
|
+
// close() mid-graceful-shutdown, which must not be force-destroyed.
|
|
539
|
+
if (!this.socket.destroyed && !this.socket.writableEnded) {
|
|
540
|
+
this.socket.destroy();
|
|
541
|
+
}
|
|
531
542
|
return;
|
|
543
|
+
}
|
|
532
544
|
try {
|
|
533
545
|
this.socket.write(encode({ type: "Disconnect" }));
|
|
534
546
|
}
|
|
@@ -682,19 +694,18 @@ export class Client extends EventEmitter {
|
|
|
682
694
|
this.socket.write(encode({ type: "Pong" }));
|
|
683
695
|
continue;
|
|
684
696
|
}
|
|
685
|
-
//
|
|
686
|
-
//
|
|
687
|
-
// reply is arriving now
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
if (!entry) {
|
|
693
|
-
// Server sent an unsolicited frame (or we got extra after aborts
|
|
694
|
-
// with no replacement). Treat as protocol error.
|
|
697
|
+
// Replies are strictly FIFO: this frame belongs to exactly one pending
|
|
698
|
+
// entry — the head. Consume one entry per frame. If it was aborted
|
|
699
|
+
// (settled), its reply is arriving now; drop the frame and keep decoding
|
|
700
|
+
// rather than delivering it to a later, live query.
|
|
701
|
+
const entry = this.pending.shift();
|
|
702
|
+
if (entry === undefined) {
|
|
703
|
+
// No pending entry at all — the server sent an unsolicited frame.
|
|
695
704
|
this.onClose(new PowDBError("received unexpected frame from server", "protocol_error"));
|
|
696
705
|
return;
|
|
697
706
|
}
|
|
707
|
+
if (entry.settled)
|
|
708
|
+
continue;
|
|
698
709
|
entry.resolve(decoded.msg);
|
|
699
710
|
}
|
|
700
711
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zvndev/powdb-client",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "TypeScript client for PowDB (PowQL wire protocol)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@10.29.3",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"prepublishOnly": "npm run build"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
|
-
"@types/node": "^
|
|
64
|
+
"@types/node": "^26",
|
|
65
65
|
"tsx": "^4",
|
|
66
66
|
"typescript": "^6.0"
|
|
67
67
|
}
|