@powerdata/pd4 0.1.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/dist/index.cjs +356 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +185 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.js +324 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +523 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +198 -0
- package/dist/react/index.d.ts +198 -0
- package/dist/react/index.js +492 -0
- package/dist/react/index.js.map +1 -0
- package/package.json +38 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var src_exports = {};
|
|
22
|
+
__export(src_exports, {
|
|
23
|
+
PD4Buffer: () => PD4Buffer,
|
|
24
|
+
PD4Client: () => PD4Client,
|
|
25
|
+
PD4Error: () => PD4Error,
|
|
26
|
+
flattenRow: () => flattenRow,
|
|
27
|
+
toColumnValues: () => toColumnValues,
|
|
28
|
+
toColumnar: () => toColumnar
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(src_exports);
|
|
31
|
+
|
|
32
|
+
// src/errors.ts
|
|
33
|
+
var PD4Error = class extends Error {
|
|
34
|
+
constructor(message, status, url) {
|
|
35
|
+
super(message);
|
|
36
|
+
this.name = "PD4Error";
|
|
37
|
+
this.status = status;
|
|
38
|
+
this.url = url;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/utils.ts
|
|
43
|
+
function flattenRow(row) {
|
|
44
|
+
const flat = { _pk: row.key };
|
|
45
|
+
for (const cv of row.values) {
|
|
46
|
+
flat[cv.column] = cv.value;
|
|
47
|
+
}
|
|
48
|
+
return flat;
|
|
49
|
+
}
|
|
50
|
+
function toColumnar(flatRows, columnNames) {
|
|
51
|
+
if (flatRows.length === 0) return { columns: [], rows: [] };
|
|
52
|
+
const cols = columnNames ?? Object.keys(flatRows[0]).filter((k) => k !== "_pk");
|
|
53
|
+
const rows = flatRows.map((row) => cols.map((c) => row[c] ?? null));
|
|
54
|
+
return { columns: cols, rows };
|
|
55
|
+
}
|
|
56
|
+
function toColumnValues(flat) {
|
|
57
|
+
return Object.entries(flat).filter(([k]) => k !== "_pk").map(([column, value]) => ({ column, value }));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/buffer.ts
|
|
61
|
+
var PD4Buffer = class {
|
|
62
|
+
constructor(client, handle, table) {
|
|
63
|
+
this.client = client;
|
|
64
|
+
this.handle = handle;
|
|
65
|
+
this.table = table;
|
|
66
|
+
}
|
|
67
|
+
/** Update a row within the buffer (not visible to others until commit). */
|
|
68
|
+
async update(key, values) {
|
|
69
|
+
const pairs = toColumnValues(values);
|
|
70
|
+
await this._request(`views/${this.handle}/rows/update`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
body: JSON.stringify({ key, values: pairs })
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/** Fetch rows from the buffer (sees uncommitted changes). */
|
|
76
|
+
async fetch(offset = 0, limit = 100) {
|
|
77
|
+
const data = await this._request(
|
|
78
|
+
`views/${this.handle}/rows?offset=${offset}&limit=${limit}`
|
|
79
|
+
);
|
|
80
|
+
return {
|
|
81
|
+
rows: data.rows.map(flattenRow),
|
|
82
|
+
total: data.total
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Commit all buffered writes atomically. Fires SSE events. */
|
|
86
|
+
async commit() {
|
|
87
|
+
await this._request(`views/${this.handle}/commit`, { method: "POST" });
|
|
88
|
+
}
|
|
89
|
+
/** Rollback all buffered writes (discard pending changes). */
|
|
90
|
+
async rollback() {
|
|
91
|
+
await this._request(`views/${this.handle}/rollback`, { method: "POST" });
|
|
92
|
+
}
|
|
93
|
+
// --- Internal ----------------------------------------------------------
|
|
94
|
+
async _request(path, init) {
|
|
95
|
+
const url = `${this.client.url}/v1/${this.client.db}/${path}`;
|
|
96
|
+
const res = await fetch(url, {
|
|
97
|
+
...init,
|
|
98
|
+
headers: { "Content-Type": "application/json", ...init?.headers }
|
|
99
|
+
});
|
|
100
|
+
if (!res.ok) {
|
|
101
|
+
const text = await res.text();
|
|
102
|
+
throw new Error(`PD4 Buffer ${init?.method ?? "GET"} ${url}: ${res.status} ${text}`);
|
|
103
|
+
}
|
|
104
|
+
if (res.status === 204) return void 0;
|
|
105
|
+
return res.json();
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// src/client.ts
|
|
110
|
+
var PD4Client = class {
|
|
111
|
+
constructor(url, db, options) {
|
|
112
|
+
this.eventSource = null;
|
|
113
|
+
this.handlers = /* @__PURE__ */ new Map();
|
|
114
|
+
this.statusHandlers = [];
|
|
115
|
+
this._status = "connecting";
|
|
116
|
+
this.url = url.replace(/\/$/, "");
|
|
117
|
+
this.db = db;
|
|
118
|
+
this.EventSourceCtor = options?.EventSource ?? (typeof globalThis !== "undefined" && globalThis.EventSource ? globalThis.EventSource : null);
|
|
119
|
+
}
|
|
120
|
+
// --- URL helpers -------------------------------------------------------
|
|
121
|
+
get v1() {
|
|
122
|
+
return `${this.url}/v1/${this.db}`;
|
|
123
|
+
}
|
|
124
|
+
get api() {
|
|
125
|
+
return `${this.url}/api/${this.db}`;
|
|
126
|
+
}
|
|
127
|
+
// --- HTTP helper -------------------------------------------------------
|
|
128
|
+
async request(url, init) {
|
|
129
|
+
const res = await fetch(url, {
|
|
130
|
+
...init,
|
|
131
|
+
headers: { "Content-Type": "application/json", ...init?.headers }
|
|
132
|
+
});
|
|
133
|
+
if (!res.ok) {
|
|
134
|
+
const text = await res.text();
|
|
135
|
+
throw new PD4Error(
|
|
136
|
+
`PD4 ${init?.method ?? "GET"} ${url}: ${res.status} ${text}`,
|
|
137
|
+
res.status,
|
|
138
|
+
url
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
if (res.status === 204) return void 0;
|
|
142
|
+
return res.json();
|
|
143
|
+
}
|
|
144
|
+
// --- Health ------------------------------------------------------------
|
|
145
|
+
/** Check if PD4 is reachable */
|
|
146
|
+
async ping() {
|
|
147
|
+
try {
|
|
148
|
+
const res = await fetch(`${this.url}/health`);
|
|
149
|
+
return res.ok;
|
|
150
|
+
} catch {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// --- Database ----------------------------------------------------------
|
|
155
|
+
/** Ensure the database is open */
|
|
156
|
+
async ensureDatabase() {
|
|
157
|
+
await this.request(`${this.url}/v1/db`, {
|
|
158
|
+
method: "POST",
|
|
159
|
+
body: JSON.stringify({ name: this.db })
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
// --- Tables ------------------------------------------------------------
|
|
163
|
+
/** List all table names */
|
|
164
|
+
async listTables() {
|
|
165
|
+
const data = await this.request(`${this.v1}/tables`);
|
|
166
|
+
return data.tables;
|
|
167
|
+
}
|
|
168
|
+
/** Get table info */
|
|
169
|
+
async getTable(name) {
|
|
170
|
+
return this.request(`${this.v1}/tables/${name}`);
|
|
171
|
+
}
|
|
172
|
+
/** Create a table (with auto_pk) */
|
|
173
|
+
async createTable(name) {
|
|
174
|
+
await this.request(`${this.v1}/tables`, {
|
|
175
|
+
method: "POST",
|
|
176
|
+
body: JSON.stringify({ name, auto_pk: true })
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/** Drop a table */
|
|
180
|
+
async dropTable(name) {
|
|
181
|
+
await this.request(`${this.v1}/tables/${name}`, { method: "DELETE" });
|
|
182
|
+
}
|
|
183
|
+
/** Add a column to a table */
|
|
184
|
+
async addColumn(table, name, dtype) {
|
|
185
|
+
await this.request(`${this.v1}/tables/${table}/columns`, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
body: JSON.stringify({ name, dtype })
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
// --- Rows (flat objects in, flat objects out) ---------------------------
|
|
191
|
+
/** Insert one or more rows (flat objects). Returns keys and count. */
|
|
192
|
+
async insert(table, rows) {
|
|
193
|
+
const arr = Array.isArray(rows) ? rows : [rows];
|
|
194
|
+
const { columns, rows: colRows } = toColumnar(arr);
|
|
195
|
+
return this.request(`${this.v1}/tables/${table}/rows`, {
|
|
196
|
+
method: "POST",
|
|
197
|
+
body: JSON.stringify({ columns, rows: colRows })
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/** Update a single row by key with a flat object of changed columns. */
|
|
201
|
+
async update(table, key, values) {
|
|
202
|
+
const pairs = toColumnValues(values);
|
|
203
|
+
await this.request(`${this.v1}/views/${table}/rows/update`, {
|
|
204
|
+
method: "POST",
|
|
205
|
+
body: JSON.stringify({ key, values: pairs })
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
/** Delete rows by keys. */
|
|
209
|
+
async delete(table, keys) {
|
|
210
|
+
const arr = Array.isArray(keys) ? keys : [keys];
|
|
211
|
+
await this.request(`${this.v1}/views/${table}/rows/delete`, {
|
|
212
|
+
method: "POST",
|
|
213
|
+
body: JSON.stringify({ keys: arr })
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
/** Fetch rows from a table/view. Returns flat Row objects. */
|
|
217
|
+
async fetch(table, opts) {
|
|
218
|
+
const offset = opts?.offset ?? 0;
|
|
219
|
+
const limit = opts?.limit ?? 1e3;
|
|
220
|
+
const data = await this.request(
|
|
221
|
+
`${this.v1}/views/${table}/rows?offset=${offset}&limit=${limit}`
|
|
222
|
+
);
|
|
223
|
+
return {
|
|
224
|
+
rows: data.rows.map(flattenRow),
|
|
225
|
+
total: data.total
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
// --- Raw row access (PD4 wire format) ----------------------------------
|
|
229
|
+
/** Insert rows in columnar format (low-level). */
|
|
230
|
+
async insertColumnar(table, columns, rows) {
|
|
231
|
+
return this.request(`${this.v1}/tables/${table}/rows`, {
|
|
232
|
+
method: "POST",
|
|
233
|
+
body: JSON.stringify({ columns, rows })
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
/** Update a row by key with column-value pairs (low-level). */
|
|
237
|
+
async updateRaw(table, key, values) {
|
|
238
|
+
await this.request(`${this.v1}/views/${table}/rows/update`, {
|
|
239
|
+
method: "POST",
|
|
240
|
+
body: JSON.stringify({ key, values })
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/** Fetch rows in PD4 wire format (low-level). */
|
|
244
|
+
async fetchRaw(table, offset = 0, limit = 1e3) {
|
|
245
|
+
return this.request(`${this.v1}/views/${table}/rows?offset=${offset}&limit=${limit}`);
|
|
246
|
+
}
|
|
247
|
+
// --- Buffer ------------------------------------------------------------
|
|
248
|
+
/** Create a buffered view wrapping a table. */
|
|
249
|
+
async buffer(table) {
|
|
250
|
+
const info = await this.request(
|
|
251
|
+
`${this.v1}/views/${table}/buffer`,
|
|
252
|
+
{ method: "POST" }
|
|
253
|
+
);
|
|
254
|
+
return new PD4Buffer(this, info.handle, table);
|
|
255
|
+
}
|
|
256
|
+
// --- SSE ---------------------------------------------------------------
|
|
257
|
+
/** Get current SSE connection status. */
|
|
258
|
+
get status() {
|
|
259
|
+
return this._status;
|
|
260
|
+
}
|
|
261
|
+
/** Connect to the SSE event stream. Called automatically on first on(). */
|
|
262
|
+
connect() {
|
|
263
|
+
if (this.eventSource) return;
|
|
264
|
+
if (!this.EventSourceCtor) {
|
|
265
|
+
throw new Error(
|
|
266
|
+
'EventSource is not available. In Node.js, pass { EventSource } from the "eventsource" package to the PD4Client constructor.'
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
this._setStatus("connecting");
|
|
270
|
+
const sse = new this.EventSourceCtor(`${this.api}/events`);
|
|
271
|
+
this.eventSource = sse;
|
|
272
|
+
sse.addEventListener("session", () => {
|
|
273
|
+
this._setStatus("connected");
|
|
274
|
+
});
|
|
275
|
+
sse.addEventListener("insert", (e) => {
|
|
276
|
+
const data = JSON.parse(e.data);
|
|
277
|
+
const table = data.handle;
|
|
278
|
+
const keys = data.keys ?? [];
|
|
279
|
+
const newValues = data.new_values ?? [];
|
|
280
|
+
this._dispatch(table, "insert", keys, newValues, []);
|
|
281
|
+
});
|
|
282
|
+
sse.addEventListener("update", (e) => {
|
|
283
|
+
const data = JSON.parse(e.data);
|
|
284
|
+
const table = data.handle;
|
|
285
|
+
const keys = data.keys ?? [];
|
|
286
|
+
const newValues = data.new_values ?? [];
|
|
287
|
+
const oldValues = data.old_values ?? [];
|
|
288
|
+
this._dispatch(table, "update", keys, newValues, oldValues);
|
|
289
|
+
});
|
|
290
|
+
sse.addEventListener("delete", (e) => {
|
|
291
|
+
const data = JSON.parse(e.data);
|
|
292
|
+
const table = data.handle;
|
|
293
|
+
const keys = data.keys ?? [];
|
|
294
|
+
this._dispatch(table, "delete", keys, [], []);
|
|
295
|
+
});
|
|
296
|
+
sse.onerror = () => {
|
|
297
|
+
this._setStatus("error");
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/** Disconnect from the SSE event stream. */
|
|
301
|
+
disconnect() {
|
|
302
|
+
this.eventSource?.close();
|
|
303
|
+
this.eventSource = null;
|
|
304
|
+
this._setStatus("connecting");
|
|
305
|
+
}
|
|
306
|
+
on(table, event, handler) {
|
|
307
|
+
if (!this.eventSource) this.connect();
|
|
308
|
+
let tableHandlers = this.handlers.get(table);
|
|
309
|
+
if (!tableHandlers) {
|
|
310
|
+
tableHandlers = { insert: [], update: [], delete: [] };
|
|
311
|
+
this.handlers.set(table, tableHandlers);
|
|
312
|
+
}
|
|
313
|
+
const list = tableHandlers[event];
|
|
314
|
+
list.push(handler);
|
|
315
|
+
return () => {
|
|
316
|
+
const idx = list.indexOf(handler);
|
|
317
|
+
if (idx >= 0) list.splice(idx, 1);
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
/** Subscribe to connection status changes. Returns an unsubscribe function. */
|
|
321
|
+
onStatus(handler) {
|
|
322
|
+
this.statusHandlers.push(handler);
|
|
323
|
+
return () => {
|
|
324
|
+
const idx = this.statusHandlers.indexOf(handler);
|
|
325
|
+
if (idx >= 0) this.statusHandlers.splice(idx, 1);
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
// --- SSE internals -----------------------------------------------------
|
|
329
|
+
_setStatus(status) {
|
|
330
|
+
this._status = status;
|
|
331
|
+
for (const handler of this.statusHandlers) {
|
|
332
|
+
handler(status);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
_dispatch(table, event, keys, newValues, oldValues) {
|
|
336
|
+
const tableHandlers = this.handlers.get(table);
|
|
337
|
+
if (!tableHandlers) return;
|
|
338
|
+
if (event === "insert") {
|
|
339
|
+
for (const h of tableHandlers.insert) h(keys, newValues);
|
|
340
|
+
} else if (event === "update") {
|
|
341
|
+
for (const h of tableHandlers.update) h(keys, newValues, oldValues);
|
|
342
|
+
} else {
|
|
343
|
+
for (const h of tableHandlers.delete) h(keys);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
348
|
+
0 && (module.exports = {
|
|
349
|
+
PD4Buffer,
|
|
350
|
+
PD4Client,
|
|
351
|
+
PD4Error,
|
|
352
|
+
flattenRow,
|
|
353
|
+
toColumnValues,
|
|
354
|
+
toColumnar
|
|
355
|
+
});
|
|
356
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/utils.ts","../src/buffer.ts","../src/client.ts"],"sourcesContent":["export { PD4Client } from './client'\nexport { PD4Buffer } from './buffer'\nexport { PD4Error } from './errors'\nexport { flattenRow, toColumnar, toColumnValues } from './utils'\nexport type {\n ColumnInfo,\n TableInfo,\n ColumnValue,\n PD4Row,\n Row,\n SseEventType,\n ConnectionStatus,\n InsertHandler,\n UpdateHandler,\n DeleteHandler,\n StatusHandler,\n FetchOptions,\n FetchResult,\n InsertResult,\n BufferInfo,\n ViewInfo,\n PD4ClientOptions,\n} from './types'\n","/** Base error class for PD4 client errors */\nexport class PD4Error extends Error {\n readonly status: number | undefined\n readonly url: string | undefined\n\n constructor(message: string, status?: number, url?: string) {\n super(message)\n this.name = 'PD4Error'\n this.status = status\n this.url = url\n }\n}\n","import type { PD4Row, Row } from './types'\n\n/** Convert PD4 row format to flat record */\nexport function flattenRow(row: PD4Row): Row {\n const flat: Row = { _pk: row.key }\n for (const cv of row.values) {\n flat[cv.column] = cv.value\n }\n return flat\n}\n\n/**\n * Convert flat row objects to PD4's columnar insert format.\n * Returns { columns, rows } suitable for the insert endpoint.\n */\nexport function toColumnar(\n flatRows: Row[],\n columnNames?: string[],\n): { columns: string[]; rows: (string | number | boolean | null)[][] } {\n if (flatRows.length === 0) return { columns: [], rows: [] }\n const cols = columnNames ?? Object.keys(flatRows[0]).filter((k) => k !== '_pk')\n const rows = flatRows.map((row) => cols.map((c) => row[c] ?? null))\n return { columns: cols, rows }\n}\n\n/**\n * Convert a flat row object to PD4's column-value pairs for update.\n * Filters out the _pk field.\n */\nexport function toColumnValues(\n flat: Row,\n): { column: string; value: string | number | boolean | null }[] {\n return Object.entries(flat)\n .filter(([k]) => k !== '_pk')\n .map(([column, value]) => ({ column, value }))\n}\n","import type { PD4Client } from './client'\nimport { flattenRow, toColumnValues } from './utils'\nimport type { Row, FetchResult, PD4Row } from './types'\n\n/**\n * A buffered view wrapping a PD4 table.\n * Changes are accumulated locally and only become visible\n * to other clients after commit().\n */\nexport class PD4Buffer {\n private client: PD4Client\n readonly handle: string\n readonly table: string\n\n constructor(client: PD4Client, handle: string, table: string) {\n this.client = client\n this.handle = handle\n this.table = table\n }\n\n /** Update a row within the buffer (not visible to others until commit). */\n async update(key: number, values: Row): Promise<void> {\n const pairs = toColumnValues(values)\n await this._request(`views/${this.handle}/rows/update`, {\n method: 'POST',\n body: JSON.stringify({ key, values: pairs }),\n })\n }\n\n /** Fetch rows from the buffer (sees uncommitted changes). */\n async fetch(offset = 0, limit = 100): Promise<FetchResult> {\n const data = await this._request<{ rows: PD4Row[]; total: number }>(\n `views/${this.handle}/rows?offset=${offset}&limit=${limit}`,\n )\n return {\n rows: data.rows.map(flattenRow),\n total: data.total,\n }\n }\n\n /** Commit all buffered writes atomically. Fires SSE events. */\n async commit(): Promise<void> {\n await this._request(`views/${this.handle}/commit`, { method: 'POST' })\n }\n\n /** Rollback all buffered writes (discard pending changes). */\n async rollback(): Promise<void> {\n await this._request(`views/${this.handle}/rollback`, { method: 'POST' })\n }\n\n // --- Internal ----------------------------------------------------------\n\n private async _request<T>(path: string, init?: RequestInit): Promise<T> {\n const url = `${this.client.url}/v1/${this.client.db}/${path}`\n const res = await fetch(url, {\n ...init,\n headers: { 'Content-Type': 'application/json', ...init?.headers },\n })\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`PD4 Buffer ${init?.method ?? 'GET'} ${url}: ${res.status} ${text}`)\n }\n if (res.status === 204) return undefined as T\n return res.json()\n }\n}\n","import { PD4Error } from './errors'\nimport { flattenRow, toColumnar, toColumnValues } from './utils'\nimport { PD4Buffer } from './buffer'\nimport type {\n ColumnInfo,\n TableInfo,\n PD4Row,\n Row,\n FetchOptions,\n FetchResult,\n InsertResult,\n ConnectionStatus,\n InsertHandler,\n UpdateHandler,\n DeleteHandler,\n StatusHandler,\n PD4ClientOptions,\n} from './types'\n\n// ---------------------------------------------------------------------------\n// Internal types for SSE handler registry\n// ---------------------------------------------------------------------------\n\ninterface TableHandlers {\n insert: InsertHandler[]\n update: UpdateHandler[]\n delete: DeleteHandler[]\n}\n\n// ---------------------------------------------------------------------------\n// PD4Client\n// ---------------------------------------------------------------------------\n\nexport class PD4Client {\n readonly url: string\n readonly db: string\n\n private EventSourceCtor: (new (url: string) => EventSource) | null\n private eventSource: EventSource | null = null\n private handlers = new Map<string, TableHandlers>()\n private statusHandlers: StatusHandler[] = []\n private _status: ConnectionStatus = 'connecting'\n\n constructor(url: string, db: string, options?: PD4ClientOptions) {\n this.url = url.replace(/\\/$/, '')\n this.db = db\n this.EventSourceCtor = options?.EventSource\n ?? (typeof globalThis !== 'undefined' && globalThis.EventSource\n ? globalThis.EventSource\n : null)\n }\n\n // --- URL helpers -------------------------------------------------------\n\n private get v1() {\n return `${this.url}/v1/${this.db}`\n }\n\n private get api() {\n return `${this.url}/api/${this.db}`\n }\n\n // --- HTTP helper -------------------------------------------------------\n\n private async request<T>(url: string, init?: RequestInit): Promise<T> {\n const res = await fetch(url, {\n ...init,\n headers: { 'Content-Type': 'application/json', ...init?.headers },\n })\n if (!res.ok) {\n const text = await res.text()\n throw new PD4Error(\n `PD4 ${init?.method ?? 'GET'} ${url}: ${res.status} ${text}`,\n res.status,\n url,\n )\n }\n if (res.status === 204) return undefined as T\n return res.json()\n }\n\n // --- Health ------------------------------------------------------------\n\n /** Check if PD4 is reachable */\n async ping(): Promise<boolean> {\n try {\n const res = await fetch(`${this.url}/health`)\n return res.ok\n } catch {\n return false\n }\n }\n\n // --- Database ----------------------------------------------------------\n\n /** Ensure the database is open */\n async ensureDatabase(): Promise<void> {\n await this.request(`${this.url}/v1/db`, {\n method: 'POST',\n body: JSON.stringify({ name: this.db }),\n })\n }\n\n // --- Tables ------------------------------------------------------------\n\n /** List all table names */\n async listTables(): Promise<string[]> {\n const data = await this.request<{ tables: string[] }>(`${this.v1}/tables`)\n return data.tables\n }\n\n /** Get table info */\n async getTable(name: string): Promise<TableInfo> {\n return this.request<TableInfo>(`${this.v1}/tables/${name}`)\n }\n\n /** Create a table (with auto_pk) */\n async createTable(name: string): Promise<void> {\n await this.request(`${this.v1}/tables`, {\n method: 'POST',\n body: JSON.stringify({ name, auto_pk: true }),\n })\n }\n\n /** Drop a table */\n async dropTable(name: string): Promise<void> {\n await this.request(`${this.v1}/tables/${name}`, { method: 'DELETE' })\n }\n\n /** Add a column to a table */\n async addColumn(table: string, name: string, dtype: string): Promise<void> {\n await this.request(`${this.v1}/tables/${table}/columns`, {\n method: 'POST',\n body: JSON.stringify({ name, dtype }),\n })\n }\n\n // --- Rows (flat objects in, flat objects out) ---------------------------\n\n /** Insert one or more rows (flat objects). Returns keys and count. */\n async insert(table: string, rows: Row | Row[]): Promise<InsertResult> {\n const arr = Array.isArray(rows) ? rows : [rows]\n const { columns, rows: colRows } = toColumnar(arr)\n return this.request<InsertResult>(`${this.v1}/tables/${table}/rows`, {\n method: 'POST',\n body: JSON.stringify({ columns, rows: colRows }),\n })\n }\n\n /** Update a single row by key with a flat object of changed columns. */\n async update(table: string, key: number, values: Row): Promise<void> {\n const pairs = toColumnValues(values)\n await this.request(`${this.v1}/views/${table}/rows/update`, {\n method: 'POST',\n body: JSON.stringify({ key, values: pairs }),\n })\n }\n\n /** Delete rows by keys. */\n async delete(table: string, keys: number | number[]): Promise<void> {\n const arr = Array.isArray(keys) ? keys : [keys]\n await this.request(`${this.v1}/views/${table}/rows/delete`, {\n method: 'POST',\n body: JSON.stringify({ keys: arr }),\n })\n }\n\n /** Fetch rows from a table/view. Returns flat Row objects. */\n async fetch(table: string, opts?: FetchOptions): Promise<FetchResult> {\n const offset = opts?.offset ?? 0\n const limit = opts?.limit ?? 1000\n const data = await this.request<{ rows: PD4Row[]; total: number }>(\n `${this.v1}/views/${table}/rows?offset=${offset}&limit=${limit}`,\n )\n return {\n rows: data.rows.map(flattenRow),\n total: data.total,\n }\n }\n\n // --- Raw row access (PD4 wire format) ----------------------------------\n\n /** Insert rows in columnar format (low-level). */\n async insertColumnar(\n table: string,\n columns: string[],\n rows: (string | number | boolean | null)[][],\n ): Promise<InsertResult> {\n return this.request<InsertResult>(`${this.v1}/tables/${table}/rows`, {\n method: 'POST',\n body: JSON.stringify({ columns, rows }),\n })\n }\n\n /** Update a row by key with column-value pairs (low-level). */\n async updateRaw(\n table: string,\n key: number,\n values: { column: string; value: string | number | boolean | null }[],\n ): Promise<void> {\n await this.request(`${this.v1}/views/${table}/rows/update`, {\n method: 'POST',\n body: JSON.stringify({ key, values }),\n })\n }\n\n /** Fetch rows in PD4 wire format (low-level). */\n async fetchRaw(\n table: string,\n offset = 0,\n limit = 1000,\n ): Promise<{ rows: PD4Row[]; total: number }> {\n return this.request(`${this.v1}/views/${table}/rows?offset=${offset}&limit=${limit}`)\n }\n\n // --- Buffer ------------------------------------------------------------\n\n /** Create a buffered view wrapping a table. */\n async buffer(table: string): Promise<PD4Buffer> {\n const info = await this.request<{ handle: string; source: string; row_count: number }>(\n `${this.v1}/views/${table}/buffer`,\n { method: 'POST' },\n )\n return new PD4Buffer(this, info.handle, table)\n }\n\n // --- SSE ---------------------------------------------------------------\n\n /** Get current SSE connection status. */\n get status(): ConnectionStatus {\n return this._status\n }\n\n /** Connect to the SSE event stream. Called automatically on first on(). */\n connect(): void {\n if (this.eventSource) return\n if (!this.EventSourceCtor) {\n throw new Error(\n 'EventSource is not available. In Node.js, pass { EventSource } from the \"eventsource\" package to the PD4Client constructor.',\n )\n }\n\n this._setStatus('connecting')\n const sse = new this.EventSourceCtor(`${this.api}/events`)\n this.eventSource = sse\n\n sse.addEventListener('session', () => {\n this._setStatus('connected')\n })\n\n sse.addEventListener('insert', (e: MessageEvent) => {\n const data = JSON.parse(e.data)\n const table = data.handle as string\n const keys: number[] = data.keys ?? []\n const newValues: Row[] = data.new_values ?? []\n this._dispatch(table, 'insert', keys, newValues, [])\n })\n\n sse.addEventListener('update', (e: MessageEvent) => {\n const data = JSON.parse(e.data)\n const table = data.handle as string\n const keys: number[] = data.keys ?? []\n const newValues: Row[] = data.new_values ?? []\n const oldValues: Row[] = data.old_values ?? []\n this._dispatch(table, 'update', keys, newValues, oldValues)\n })\n\n sse.addEventListener('delete', (e: MessageEvent) => {\n const data = JSON.parse(e.data)\n const table = data.handle as string\n const keys: number[] = data.keys ?? []\n this._dispatch(table, 'delete', keys, [], [])\n })\n\n sse.onerror = () => {\n this._setStatus('error')\n }\n }\n\n /** Disconnect from the SSE event stream. */\n disconnect(): void {\n this.eventSource?.close()\n this.eventSource = null\n this._setStatus('connecting')\n }\n\n /**\n * Subscribe to SSE events for a table.\n * Auto-connects on first call. Returns an unsubscribe function.\n */\n on(table: string, event: 'insert', handler: InsertHandler): () => void\n on(table: string, event: 'update', handler: UpdateHandler): () => void\n on(table: string, event: 'delete', handler: DeleteHandler): () => void\n on(\n table: string,\n event: 'insert' | 'update' | 'delete',\n handler: InsertHandler | UpdateHandler | DeleteHandler,\n ): () => void {\n // Auto-connect\n if (!this.eventSource) this.connect()\n\n let tableHandlers = this.handlers.get(table)\n if (!tableHandlers) {\n tableHandlers = { insert: [], update: [], delete: [] }\n this.handlers.set(table, tableHandlers)\n }\n\n const list = tableHandlers[event] as unknown[]\n list.push(handler)\n\n return () => {\n const idx = list.indexOf(handler)\n if (idx >= 0) list.splice(idx, 1)\n }\n }\n\n /** Subscribe to connection status changes. Returns an unsubscribe function. */\n onStatus(handler: StatusHandler): () => void {\n this.statusHandlers.push(handler)\n return () => {\n const idx = this.statusHandlers.indexOf(handler)\n if (idx >= 0) this.statusHandlers.splice(idx, 1)\n }\n }\n\n // --- SSE internals -----------------------------------------------------\n\n private _setStatus(status: ConnectionStatus) {\n this._status = status\n for (const handler of this.statusHandlers) {\n handler(status)\n }\n }\n\n private _dispatch(\n table: string,\n event: 'insert' | 'update' | 'delete',\n keys: number[],\n newValues: Row[],\n oldValues: Row[],\n ) {\n const tableHandlers = this.handlers.get(table)\n if (!tableHandlers) return\n\n if (event === 'insert') {\n for (const h of tableHandlers.insert) h(keys, newValues)\n } else if (event === 'update') {\n for (const h of tableHandlers.update) h(keys, newValues, oldValues)\n } else {\n for (const h of tableHandlers.delete) h(keys)\n }\n }\n}\n\n// Re-export for convenience\nexport type { ColumnInfo, TableInfo, PD4Row, Row, FetchOptions, FetchResult, InsertResult }\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCO,IAAM,WAAN,cAAuB,MAAM;AAAA,EAIlC,YAAY,SAAiB,QAAiB,KAAc;AAC1D,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,MAAM;AAAA,EACb;AACF;;;ACRO,SAAS,WAAW,KAAkB;AAC3C,QAAM,OAAY,EAAE,KAAK,IAAI,IAAI;AACjC,aAAW,MAAM,IAAI,QAAQ;AAC3B,SAAK,GAAG,MAAM,IAAI,GAAG;AAAA,EACvB;AACA,SAAO;AACT;AAMO,SAAS,WACd,UACA,aACqE;AACrE,MAAI,SAAS,WAAW,EAAG,QAAO,EAAE,SAAS,CAAC,GAAG,MAAM,CAAC,EAAE;AAC1D,QAAM,OAAO,eAAe,OAAO,KAAK,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,MAAM,MAAM,KAAK;AAC9E,QAAM,OAAO,SAAS,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,IAAI,CAAC;AAClE,SAAO,EAAE,SAAS,MAAM,KAAK;AAC/B;AAMO,SAAS,eACd,MAC+D;AAC/D,SAAO,OAAO,QAAQ,IAAI,EACvB,OAAO,CAAC,CAAC,CAAC,MAAM,MAAM,KAAK,EAC3B,IAAI,CAAC,CAAC,QAAQ,KAAK,OAAO,EAAE,QAAQ,MAAM,EAAE;AACjD;;;AC1BO,IAAM,YAAN,MAAgB;AAAA,EAKrB,YAAY,QAAmB,QAAgB,OAAe;AAC5D,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA,EAGA,MAAM,OAAO,KAAa,QAA4B;AACpD,UAAM,QAAQ,eAAe,MAAM;AACnC,UAAM,KAAK,SAAS,SAAS,KAAK,MAAM,gBAAgB;AAAA,MACtD,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,KAAK,QAAQ,MAAM,CAAC;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,MAAM,SAAS,GAAG,QAAQ,KAA2B;AACzD,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB,SAAS,KAAK,MAAM,gBAAgB,MAAM,UAAU,KAAK;AAAA,IAC3D;AACA,WAAO;AAAA,MACL,MAAM,KAAK,KAAK,IAAI,UAAU;AAAA,MAC9B,OAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,SAAwB;AAC5B,UAAM,KAAK,SAAS,SAAS,KAAK,MAAM,WAAW,EAAE,QAAQ,OAAO,CAAC;AAAA,EACvE;AAAA;AAAA,EAGA,MAAM,WAA0B;AAC9B,UAAM,KAAK,SAAS,SAAS,KAAK,MAAM,aAAa,EAAE,QAAQ,OAAO,CAAC;AAAA,EACzE;AAAA;AAAA,EAIA,MAAc,SAAY,MAAc,MAAgC;AACtE,UAAM,MAAM,GAAG,KAAK,OAAO,GAAG,OAAO,KAAK,OAAO,EAAE,IAAI,IAAI;AAC3D,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,GAAG;AAAA,MACH,SAAS,EAAE,gBAAgB,oBAAoB,GAAG,MAAM,QAAQ;AAAA,IAClE,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,YAAM,IAAI,MAAM,cAAc,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE;AAAA,IACrF;AACA,QAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,WAAO,IAAI,KAAK;AAAA,EAClB;AACF;;;AChCO,IAAM,YAAN,MAAgB;AAAA,EAUrB,YAAY,KAAa,IAAY,SAA4B;AALjE,SAAQ,cAAkC;AAC1C,SAAQ,WAAW,oBAAI,IAA2B;AAClD,SAAQ,iBAAkC,CAAC;AAC3C,SAAQ,UAA4B;AAGlC,SAAK,MAAM,IAAI,QAAQ,OAAO,EAAE;AAChC,SAAK,KAAK;AACV,SAAK,kBAAkB,SAAS,gBAC1B,OAAO,eAAe,eAAe,WAAW,cAChD,WAAW,cACX;AAAA,EACR;AAAA;AAAA,EAIA,IAAY,KAAK;AACf,WAAO,GAAG,KAAK,GAAG,OAAO,KAAK,EAAE;AAAA,EAClC;AAAA,EAEA,IAAY,MAAM;AAChB,WAAO,GAAG,KAAK,GAAG,QAAQ,KAAK,EAAE;AAAA,EACnC;AAAA;AAAA,EAIA,MAAc,QAAW,KAAa,MAAgC;AACpE,UAAM,MAAM,MAAM,MAAM,KAAK;AAAA,MAC3B,GAAG;AAAA,MACH,SAAS,EAAE,gBAAgB,oBAAoB,GAAG,MAAM,QAAQ;AAAA,IAClE,CAAC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,YAAM,IAAI;AAAA,QACR,OAAO,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,IAAI,IAAI;AAAA,QAC1D,IAAI;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AACA,QAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,WAAO,IAAI,KAAK;AAAA,EAClB;AAAA;AAAA;AAAA,EAKA,MAAM,OAAyB;AAC7B,QAAI;AACF,YAAM,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,SAAS;AAC5C,aAAO,IAAI;AAAA,IACb,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAgC;AACpC,UAAM,KAAK,QAAQ,GAAG,KAAK,GAAG,UAAU;AAAA,MACtC,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,MAAM,KAAK,GAAG,CAAC;AAAA,IACxC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAKA,MAAM,aAAgC;AACpC,UAAM,OAAO,MAAM,KAAK,QAA8B,GAAG,KAAK,EAAE,SAAS;AACzE,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,SAAS,MAAkC;AAC/C,WAAO,KAAK,QAAmB,GAAG,KAAK,EAAE,WAAW,IAAI,EAAE;AAAA,EAC5D;AAAA;AAAA,EAGA,MAAM,YAAY,MAA6B;AAC7C,UAAM,KAAK,QAAQ,GAAG,KAAK,EAAE,WAAW;AAAA,MACtC,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,MAAM,SAAS,KAAK,CAAC;AAAA,IAC9C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,UAAU,MAA6B;AAC3C,UAAM,KAAK,QAAQ,GAAG,KAAK,EAAE,WAAW,IAAI,IAAI,EAAE,QAAQ,SAAS,CAAC;AAAA,EACtE;AAAA;AAAA,EAGA,MAAM,UAAU,OAAe,MAAc,OAA8B;AACzE,UAAM,KAAK,QAAQ,GAAG,KAAK,EAAE,WAAW,KAAK,YAAY;AAAA,MACvD,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAAA,IACtC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,OAAe,MAA0C;AACpE,UAAM,MAAM,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAC9C,UAAM,EAAE,SAAS,MAAM,QAAQ,IAAI,WAAW,GAAG;AACjD,WAAO,KAAK,QAAsB,GAAG,KAAK,EAAE,WAAW,KAAK,SAAS;AAAA,MACnE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,SAAS,MAAM,QAAQ,CAAC;AAAA,IACjD,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,OAAO,OAAe,KAAa,QAA4B;AACnE,UAAM,QAAQ,eAAe,MAAM;AACnC,UAAM,KAAK,QAAQ,GAAG,KAAK,EAAE,UAAU,KAAK,gBAAgB;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,KAAK,QAAQ,MAAM,CAAC;AAAA,IAC7C,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,OAAO,OAAe,MAAwC;AAClE,UAAM,MAAM,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AAC9C,UAAM,KAAK,QAAQ,GAAG,KAAK,EAAE,UAAU,KAAK,gBAAgB;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,MAAM,IAAI,CAAC;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,MAAM,OAAe,MAA2C;AACpE,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB,GAAG,KAAK,EAAE,UAAU,KAAK,gBAAgB,MAAM,UAAU,KAAK;AAAA,IAChE;AACA,WAAO;AAAA,MACL,MAAM,KAAK,KAAK,IAAI,UAAU;AAAA,MAC9B,OAAO,KAAK;AAAA,IACd;AAAA,EACF;AAAA;AAAA;AAAA,EAKA,MAAM,eACJ,OACA,SACA,MACuB;AACvB,WAAO,KAAK,QAAsB,GAAG,KAAK,EAAE,WAAW,KAAK,SAAS;AAAA,MACnE,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,IACxC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,UACJ,OACA,KACA,QACe;AACf,UAAM,KAAK,QAAQ,GAAG,KAAK,EAAE,UAAU,KAAK,gBAAgB;AAAA,MAC1D,QAAQ;AAAA,MACR,MAAM,KAAK,UAAU,EAAE,KAAK,OAAO,CAAC;AAAA,IACtC,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,SACJ,OACA,SAAS,GACT,QAAQ,KACoC;AAC5C,WAAO,KAAK,QAAQ,GAAG,KAAK,EAAE,UAAU,KAAK,gBAAgB,MAAM,UAAU,KAAK,EAAE;AAAA,EACtF;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,OAAmC;AAC9C,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB,GAAG,KAAK,EAAE,UAAU,KAAK;AAAA,MACzB,EAAE,QAAQ,OAAO;AAAA,IACnB;AACA,WAAO,IAAI,UAAU,MAAM,KAAK,QAAQ,KAAK;AAAA,EAC/C;AAAA;AAAA;AAAA,EAKA,IAAI,SAA2B;AAC7B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,UAAgB;AACd,QAAI,KAAK,YAAa;AACtB,QAAI,CAAC,KAAK,iBAAiB;AACzB,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,SAAK,WAAW,YAAY;AAC5B,UAAM,MAAM,IAAI,KAAK,gBAAgB,GAAG,KAAK,GAAG,SAAS;AACzD,SAAK,cAAc;AAEnB,QAAI,iBAAiB,WAAW,MAAM;AACpC,WAAK,WAAW,WAAW;AAAA,IAC7B,CAAC;AAED,QAAI,iBAAiB,UAAU,CAAC,MAAoB;AAClD,YAAM,OAAO,KAAK,MAAM,EAAE,IAAI;AAC9B,YAAM,QAAQ,KAAK;AACnB,YAAM,OAAiB,KAAK,QAAQ,CAAC;AACrC,YAAM,YAAmB,KAAK,cAAc,CAAC;AAC7C,WAAK,UAAU,OAAO,UAAU,MAAM,WAAW,CAAC,CAAC;AAAA,IACrD,CAAC;AAED,QAAI,iBAAiB,UAAU,CAAC,MAAoB;AAClD,YAAM,OAAO,KAAK,MAAM,EAAE,IAAI;AAC9B,YAAM,QAAQ,KAAK;AACnB,YAAM,OAAiB,KAAK,QAAQ,CAAC;AACrC,YAAM,YAAmB,KAAK,cAAc,CAAC;AAC7C,YAAM,YAAmB,KAAK,cAAc,CAAC;AAC7C,WAAK,UAAU,OAAO,UAAU,MAAM,WAAW,SAAS;AAAA,IAC5D,CAAC;AAED,QAAI,iBAAiB,UAAU,CAAC,MAAoB;AAClD,YAAM,OAAO,KAAK,MAAM,EAAE,IAAI;AAC9B,YAAM,QAAQ,KAAK;AACnB,YAAM,OAAiB,KAAK,QAAQ,CAAC;AACrC,WAAK,UAAU,OAAO,UAAU,MAAM,CAAC,GAAG,CAAC,CAAC;AAAA,IAC9C,CAAC;AAED,QAAI,UAAU,MAAM;AAClB,WAAK,WAAW,OAAO;AAAA,IACzB;AAAA,EACF;AAAA;AAAA,EAGA,aAAmB;AACjB,SAAK,aAAa,MAAM;AACxB,SAAK,cAAc;AACnB,SAAK,WAAW,YAAY;AAAA,EAC9B;AAAA,EASA,GACE,OACA,OACA,SACY;AAEZ,QAAI,CAAC,KAAK,YAAa,MAAK,QAAQ;AAEpC,QAAI,gBAAgB,KAAK,SAAS,IAAI,KAAK;AAC3C,QAAI,CAAC,eAAe;AAClB,sBAAgB,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE;AACrD,WAAK,SAAS,IAAI,OAAO,aAAa;AAAA,IACxC;AAEA,UAAM,OAAO,cAAc,KAAK;AAChC,SAAK,KAAK,OAAO;AAEjB,WAAO,MAAM;AACX,YAAM,MAAM,KAAK,QAAQ,OAAO;AAChC,UAAI,OAAO,EAAG,MAAK,OAAO,KAAK,CAAC;AAAA,IAClC;AAAA,EACF;AAAA;AAAA,EAGA,SAAS,SAAoC;AAC3C,SAAK,eAAe,KAAK,OAAO;AAChC,WAAO,MAAM;AACX,YAAM,MAAM,KAAK,eAAe,QAAQ,OAAO;AAC/C,UAAI,OAAO,EAAG,MAAK,eAAe,OAAO,KAAK,CAAC;AAAA,IACjD;AAAA,EACF;AAAA;AAAA,EAIQ,WAAW,QAA0B;AAC3C,SAAK,UAAU;AACf,eAAW,WAAW,KAAK,gBAAgB;AACzC,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,UACN,OACA,OACA,MACA,WACA,WACA;AACA,UAAM,gBAAgB,KAAK,SAAS,IAAI,KAAK;AAC7C,QAAI,CAAC,cAAe;AAEpB,QAAI,UAAU,UAAU;AACtB,iBAAW,KAAK,cAAc,OAAQ,GAAE,MAAM,SAAS;AAAA,IACzD,WAAW,UAAU,UAAU;AAC7B,iBAAW,KAAK,cAAc,OAAQ,GAAE,MAAM,WAAW,SAAS;AAAA,IACpE,OAAO;AACL,iBAAW,KAAK,cAAc,OAAQ,GAAE,IAAI;AAAA,IAC9C;AAAA,EACF;AACF;","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/** PD4 column info from table details */
|
|
2
|
+
interface ColumnInfo {
|
|
3
|
+
name: string;
|
|
4
|
+
dtype: string;
|
|
5
|
+
}
|
|
6
|
+
/** PD4 table info returned by GET /v1/tables/:name */
|
|
7
|
+
interface TableInfo {
|
|
8
|
+
name: string;
|
|
9
|
+
columns: ColumnInfo[];
|
|
10
|
+
row_count: number;
|
|
11
|
+
}
|
|
12
|
+
/** A column-value pair in PD4's row format */
|
|
13
|
+
interface ColumnValue {
|
|
14
|
+
column: string;
|
|
15
|
+
value: string | number | boolean | null;
|
|
16
|
+
}
|
|
17
|
+
/** A row as returned by PD4 */
|
|
18
|
+
interface PD4Row {
|
|
19
|
+
key: number;
|
|
20
|
+
values: ColumnValue[];
|
|
21
|
+
}
|
|
22
|
+
/** Flat row for display: column name -> value, plus _pk */
|
|
23
|
+
type Row = Record<string, string | number | boolean | null>;
|
|
24
|
+
/** SSE event types */
|
|
25
|
+
type SseEventType = 'insert' | 'update' | 'delete';
|
|
26
|
+
/** SSE connection status */
|
|
27
|
+
type ConnectionStatus = 'connecting' | 'connected' | 'error';
|
|
28
|
+
/** Callback for insert events: (keys, rows) */
|
|
29
|
+
type InsertHandler = (keys: number[], rows: Row[]) => void;
|
|
30
|
+
/** Callback for update events: (keys, newValues, oldValues) */
|
|
31
|
+
type UpdateHandler = (keys: number[], newValues: Row[], oldValues: Row[]) => void;
|
|
32
|
+
/** Callback for delete events: (keys) */
|
|
33
|
+
type DeleteHandler = (keys: number[]) => void;
|
|
34
|
+
/** Callback for status changes */
|
|
35
|
+
type StatusHandler = (status: ConnectionStatus) => void;
|
|
36
|
+
/** Options for fetch */
|
|
37
|
+
interface FetchOptions {
|
|
38
|
+
offset?: number;
|
|
39
|
+
limit?: number;
|
|
40
|
+
}
|
|
41
|
+
/** Result from fetch */
|
|
42
|
+
interface FetchResult {
|
|
43
|
+
rows: Row[];
|
|
44
|
+
total: number;
|
|
45
|
+
}
|
|
46
|
+
/** Result from insert */
|
|
47
|
+
interface InsertResult {
|
|
48
|
+
keys: number[];
|
|
49
|
+
count: number;
|
|
50
|
+
}
|
|
51
|
+
/** Buffer info returned when opening a buffer */
|
|
52
|
+
interface BufferInfo {
|
|
53
|
+
handle: string;
|
|
54
|
+
source: string;
|
|
55
|
+
row_count: number;
|
|
56
|
+
}
|
|
57
|
+
/** View info returned when opening a session view */
|
|
58
|
+
interface ViewInfo {
|
|
59
|
+
handle: string;
|
|
60
|
+
row_count: number;
|
|
61
|
+
}
|
|
62
|
+
/** Constructor options for PD4Client */
|
|
63
|
+
interface PD4ClientOptions {
|
|
64
|
+
/**
|
|
65
|
+
* Custom EventSource constructor for environments without a global EventSource
|
|
66
|
+
* (e.g. Node.js). Pass the `EventSource` class from the `eventsource` npm package.
|
|
67
|
+
*/
|
|
68
|
+
EventSource?: new (url: string) => EventSource;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* A buffered view wrapping a PD4 table.
|
|
73
|
+
* Changes are accumulated locally and only become visible
|
|
74
|
+
* to other clients after commit().
|
|
75
|
+
*/
|
|
76
|
+
declare class PD4Buffer {
|
|
77
|
+
private client;
|
|
78
|
+
readonly handle: string;
|
|
79
|
+
readonly table: string;
|
|
80
|
+
constructor(client: PD4Client, handle: string, table: string);
|
|
81
|
+
/** Update a row within the buffer (not visible to others until commit). */
|
|
82
|
+
update(key: number, values: Row): Promise<void>;
|
|
83
|
+
/** Fetch rows from the buffer (sees uncommitted changes). */
|
|
84
|
+
fetch(offset?: number, limit?: number): Promise<FetchResult>;
|
|
85
|
+
/** Commit all buffered writes atomically. Fires SSE events. */
|
|
86
|
+
commit(): Promise<void>;
|
|
87
|
+
/** Rollback all buffered writes (discard pending changes). */
|
|
88
|
+
rollback(): Promise<void>;
|
|
89
|
+
private _request;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
declare class PD4Client {
|
|
93
|
+
readonly url: string;
|
|
94
|
+
readonly db: string;
|
|
95
|
+
private EventSourceCtor;
|
|
96
|
+
private eventSource;
|
|
97
|
+
private handlers;
|
|
98
|
+
private statusHandlers;
|
|
99
|
+
private _status;
|
|
100
|
+
constructor(url: string, db: string, options?: PD4ClientOptions);
|
|
101
|
+
private get v1();
|
|
102
|
+
private get api();
|
|
103
|
+
private request;
|
|
104
|
+
/** Check if PD4 is reachable */
|
|
105
|
+
ping(): Promise<boolean>;
|
|
106
|
+
/** Ensure the database is open */
|
|
107
|
+
ensureDatabase(): Promise<void>;
|
|
108
|
+
/** List all table names */
|
|
109
|
+
listTables(): Promise<string[]>;
|
|
110
|
+
/** Get table info */
|
|
111
|
+
getTable(name: string): Promise<TableInfo>;
|
|
112
|
+
/** Create a table (with auto_pk) */
|
|
113
|
+
createTable(name: string): Promise<void>;
|
|
114
|
+
/** Drop a table */
|
|
115
|
+
dropTable(name: string): Promise<void>;
|
|
116
|
+
/** Add a column to a table */
|
|
117
|
+
addColumn(table: string, name: string, dtype: string): Promise<void>;
|
|
118
|
+
/** Insert one or more rows (flat objects). Returns keys and count. */
|
|
119
|
+
insert(table: string, rows: Row | Row[]): Promise<InsertResult>;
|
|
120
|
+
/** Update a single row by key with a flat object of changed columns. */
|
|
121
|
+
update(table: string, key: number, values: Row): Promise<void>;
|
|
122
|
+
/** Delete rows by keys. */
|
|
123
|
+
delete(table: string, keys: number | number[]): Promise<void>;
|
|
124
|
+
/** Fetch rows from a table/view. Returns flat Row objects. */
|
|
125
|
+
fetch(table: string, opts?: FetchOptions): Promise<FetchResult>;
|
|
126
|
+
/** Insert rows in columnar format (low-level). */
|
|
127
|
+
insertColumnar(table: string, columns: string[], rows: (string | number | boolean | null)[][]): Promise<InsertResult>;
|
|
128
|
+
/** Update a row by key with column-value pairs (low-level). */
|
|
129
|
+
updateRaw(table: string, key: number, values: {
|
|
130
|
+
column: string;
|
|
131
|
+
value: string | number | boolean | null;
|
|
132
|
+
}[]): Promise<void>;
|
|
133
|
+
/** Fetch rows in PD4 wire format (low-level). */
|
|
134
|
+
fetchRaw(table: string, offset?: number, limit?: number): Promise<{
|
|
135
|
+
rows: PD4Row[];
|
|
136
|
+
total: number;
|
|
137
|
+
}>;
|
|
138
|
+
/** Create a buffered view wrapping a table. */
|
|
139
|
+
buffer(table: string): Promise<PD4Buffer>;
|
|
140
|
+
/** Get current SSE connection status. */
|
|
141
|
+
get status(): ConnectionStatus;
|
|
142
|
+
/** Connect to the SSE event stream. Called automatically on first on(). */
|
|
143
|
+
connect(): void;
|
|
144
|
+
/** Disconnect from the SSE event stream. */
|
|
145
|
+
disconnect(): void;
|
|
146
|
+
/**
|
|
147
|
+
* Subscribe to SSE events for a table.
|
|
148
|
+
* Auto-connects on first call. Returns an unsubscribe function.
|
|
149
|
+
*/
|
|
150
|
+
on(table: string, event: 'insert', handler: InsertHandler): () => void;
|
|
151
|
+
on(table: string, event: 'update', handler: UpdateHandler): () => void;
|
|
152
|
+
on(table: string, event: 'delete', handler: DeleteHandler): () => void;
|
|
153
|
+
/** Subscribe to connection status changes. Returns an unsubscribe function. */
|
|
154
|
+
onStatus(handler: StatusHandler): () => void;
|
|
155
|
+
private _setStatus;
|
|
156
|
+
private _dispatch;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Base error class for PD4 client errors */
|
|
160
|
+
declare class PD4Error extends Error {
|
|
161
|
+
readonly status: number | undefined;
|
|
162
|
+
readonly url: string | undefined;
|
|
163
|
+
constructor(message: string, status?: number, url?: string);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** Convert PD4 row format to flat record */
|
|
167
|
+
declare function flattenRow(row: PD4Row): Row;
|
|
168
|
+
/**
|
|
169
|
+
* Convert flat row objects to PD4's columnar insert format.
|
|
170
|
+
* Returns { columns, rows } suitable for the insert endpoint.
|
|
171
|
+
*/
|
|
172
|
+
declare function toColumnar(flatRows: Row[], columnNames?: string[]): {
|
|
173
|
+
columns: string[];
|
|
174
|
+
rows: (string | number | boolean | null)[][];
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Convert a flat row object to PD4's column-value pairs for update.
|
|
178
|
+
* Filters out the _pk field.
|
|
179
|
+
*/
|
|
180
|
+
declare function toColumnValues(flat: Row): {
|
|
181
|
+
column: string;
|
|
182
|
+
value: string | number | boolean | null;
|
|
183
|
+
}[];
|
|
184
|
+
|
|
185
|
+
export { type BufferInfo, type ColumnInfo, type ColumnValue, type ConnectionStatus, type DeleteHandler, type FetchOptions, type FetchResult, type InsertHandler, type InsertResult, PD4Buffer, PD4Client, type PD4ClientOptions, PD4Error, type PD4Row, type Row, type SseEventType, type StatusHandler, type TableInfo, type UpdateHandler, type ViewInfo, flattenRow, toColumnValues, toColumnar };
|