stitchdb 1.1.0 → 1.2.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.d.mts +18 -12
- package/dist/index.d.ts +18 -12
- package/dist/index.js +33 -121
- package/dist/index.mjs +33 -121
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -32,22 +32,24 @@ declare class StitchDBError extends Error {
|
|
|
32
32
|
status: number;
|
|
33
33
|
constructor(message: string, status?: number);
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* StitchDB client.
|
|
37
|
+
*
|
|
38
|
+
* Uses HTTP/2 with persistent connections (via fetch keep-alive).
|
|
39
|
+
* All requests share one TCP connection — no repeated TLS handshakes.
|
|
40
|
+
* Batch API sends multiple queries in one request.
|
|
41
|
+
*/
|
|
35
42
|
declare class StitchDB {
|
|
36
43
|
private url;
|
|
37
|
-
private wsUrl;
|
|
38
44
|
private apiKey;
|
|
39
|
-
private
|
|
40
|
-
private pending;
|
|
41
|
-
private msgId;
|
|
42
|
-
private connecting;
|
|
43
|
-
private useWebSocket;
|
|
45
|
+
private headers;
|
|
44
46
|
constructor(config: StitchDBConfig);
|
|
45
|
-
private connect;
|
|
46
|
-
private wsSend;
|
|
47
|
-
private httpQuery;
|
|
48
47
|
/** Run a SQL query with parameterized bindings. */
|
|
49
48
|
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
50
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Run multiple queries in a single HTTP request.
|
|
51
|
+
* All queries execute atomically. One Worker invocation for N queries.
|
|
52
|
+
*/
|
|
51
53
|
batch(queries: {
|
|
52
54
|
sql: string;
|
|
53
55
|
params?: unknown[];
|
|
@@ -56,6 +58,11 @@ declare class StitchDB {
|
|
|
56
58
|
run(sql: string): Promise<ExecResult>;
|
|
57
59
|
/** Insert a row. */
|
|
58
60
|
insert(table: string, data: Record<string, unknown>): Promise<QueryResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Insert multiple rows in a single request using batch API.
|
|
63
|
+
* One Worker invocation regardless of how many rows.
|
|
64
|
+
*/
|
|
65
|
+
insertMany(table: string, rows: Record<string, unknown>[]): Promise<BatchResult>;
|
|
59
66
|
/** Update rows matching a WHERE clause. */
|
|
60
67
|
update(table: string, data: Record<string, unknown>, where: string, whereParams?: unknown[]): Promise<QueryResult>;
|
|
61
68
|
/** Delete rows matching a WHERE clause. */
|
|
@@ -68,8 +75,7 @@ declare class StitchDB {
|
|
|
68
75
|
limit?: number;
|
|
69
76
|
offset?: number;
|
|
70
77
|
}): Promise<T[]>;
|
|
71
|
-
|
|
72
|
-
close(): void;
|
|
78
|
+
private post;
|
|
73
79
|
}
|
|
74
80
|
/** Create a StitchDB client. */
|
|
75
81
|
declare function createClient(config: StitchDBConfig): StitchDB;
|
package/dist/index.d.ts
CHANGED
|
@@ -32,22 +32,24 @@ declare class StitchDBError extends Error {
|
|
|
32
32
|
status: number;
|
|
33
33
|
constructor(message: string, status?: number);
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* StitchDB client.
|
|
37
|
+
*
|
|
38
|
+
* Uses HTTP/2 with persistent connections (via fetch keep-alive).
|
|
39
|
+
* All requests share one TCP connection — no repeated TLS handshakes.
|
|
40
|
+
* Batch API sends multiple queries in one request.
|
|
41
|
+
*/
|
|
35
42
|
declare class StitchDB {
|
|
36
43
|
private url;
|
|
37
|
-
private wsUrl;
|
|
38
44
|
private apiKey;
|
|
39
|
-
private
|
|
40
|
-
private pending;
|
|
41
|
-
private msgId;
|
|
42
|
-
private connecting;
|
|
43
|
-
private useWebSocket;
|
|
45
|
+
private headers;
|
|
44
46
|
constructor(config: StitchDBConfig);
|
|
45
|
-
private connect;
|
|
46
|
-
private wsSend;
|
|
47
|
-
private httpQuery;
|
|
48
47
|
/** Run a SQL query with parameterized bindings. */
|
|
49
48
|
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
50
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Run multiple queries in a single HTTP request.
|
|
51
|
+
* All queries execute atomically. One Worker invocation for N queries.
|
|
52
|
+
*/
|
|
51
53
|
batch(queries: {
|
|
52
54
|
sql: string;
|
|
53
55
|
params?: unknown[];
|
|
@@ -56,6 +58,11 @@ declare class StitchDB {
|
|
|
56
58
|
run(sql: string): Promise<ExecResult>;
|
|
57
59
|
/** Insert a row. */
|
|
58
60
|
insert(table: string, data: Record<string, unknown>): Promise<QueryResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Insert multiple rows in a single request using batch API.
|
|
63
|
+
* One Worker invocation regardless of how many rows.
|
|
64
|
+
*/
|
|
65
|
+
insertMany(table: string, rows: Record<string, unknown>[]): Promise<BatchResult>;
|
|
59
66
|
/** Update rows matching a WHERE clause. */
|
|
60
67
|
update(table: string, data: Record<string, unknown>, where: string, whereParams?: unknown[]): Promise<QueryResult>;
|
|
61
68
|
/** Delete rows matching a WHERE clause. */
|
|
@@ -68,8 +75,7 @@ declare class StitchDB {
|
|
|
68
75
|
limit?: number;
|
|
69
76
|
offset?: number;
|
|
70
77
|
}): Promise<T[]>;
|
|
71
|
-
|
|
72
|
-
close(): void;
|
|
78
|
+
private post;
|
|
73
79
|
}
|
|
74
80
|
/** Create a StitchDB client. */
|
|
75
81
|
declare function createClient(config: StitchDBConfig): StitchDB;
|
package/dist/index.js
CHANGED
|
@@ -35,132 +35,27 @@ var StitchDBError = class extends Error {
|
|
|
35
35
|
};
|
|
36
36
|
var StitchDB = class {
|
|
37
37
|
constructor(config) {
|
|
38
|
-
this.ws = null;
|
|
39
|
-
this.pending = /* @__PURE__ */ new Map();
|
|
40
|
-
this.msgId = 0;
|
|
41
|
-
this.connecting = null;
|
|
42
38
|
this.url = (config.url || "https://db.stitchdb.com").replace(/\/$/, "");
|
|
43
|
-
this.wsUrl = this.url.replace("https://", "wss://").replace("http://", "ws://");
|
|
44
39
|
this.apiKey = config.apiKey;
|
|
45
|
-
this.
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
if (this.connecting) return this.connecting;
|
|
50
|
-
this.connecting = new Promise((resolve, reject) => {
|
|
51
|
-
try {
|
|
52
|
-
const ws = new WebSocket(`${this.wsUrl}/ws/query?key=${this.apiKey}`);
|
|
53
|
-
ws.onopen = () => {
|
|
54
|
-
this.ws = ws;
|
|
55
|
-
this.connecting = null;
|
|
56
|
-
resolve();
|
|
57
|
-
};
|
|
58
|
-
ws.onmessage = (event) => {
|
|
59
|
-
try {
|
|
60
|
-
const data = JSON.parse(typeof event.data === "string" ? event.data : "");
|
|
61
|
-
const pending = this.pending.get(data.id);
|
|
62
|
-
if (pending) {
|
|
63
|
-
this.pending.delete(data.id);
|
|
64
|
-
if (data.error) {
|
|
65
|
-
pending.reject(new StitchDBError(data.error));
|
|
66
|
-
} else {
|
|
67
|
-
pending.resolve(data);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
} catch {
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
ws.onclose = () => {
|
|
74
|
-
this.ws = null;
|
|
75
|
-
this.connecting = null;
|
|
76
|
-
for (const [id, p] of this.pending) {
|
|
77
|
-
p.reject(new StitchDBError("Connection closed"));
|
|
78
|
-
this.pending.delete(id);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
ws.onerror = () => {
|
|
82
|
-
this.ws = null;
|
|
83
|
-
this.connecting = null;
|
|
84
|
-
reject(new StitchDBError("WebSocket connection failed"));
|
|
85
|
-
};
|
|
86
|
-
} catch {
|
|
87
|
-
this.connecting = null;
|
|
88
|
-
this.useWebSocket = false;
|
|
89
|
-
resolve();
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
return this.connecting;
|
|
93
|
-
}
|
|
94
|
-
async wsSend(msg) {
|
|
95
|
-
await this.connect();
|
|
96
|
-
if (!this.ws || this.ws.readyState !== 1) {
|
|
97
|
-
this.useWebSocket = false;
|
|
98
|
-
return this.httpQuery(msg);
|
|
99
|
-
}
|
|
100
|
-
const id = String(++this.msgId);
|
|
101
|
-
msg.id = id;
|
|
102
|
-
return new Promise((resolve, reject) => {
|
|
103
|
-
const timeout = setTimeout(() => {
|
|
104
|
-
this.pending.delete(id);
|
|
105
|
-
reject(new StitchDBError("Query timeout"));
|
|
106
|
-
}, 3e4);
|
|
107
|
-
this.pending.set(id, {
|
|
108
|
-
resolve: (v) => {
|
|
109
|
-
clearTimeout(timeout);
|
|
110
|
-
resolve(v);
|
|
111
|
-
},
|
|
112
|
-
reject: (e) => {
|
|
113
|
-
clearTimeout(timeout);
|
|
114
|
-
reject(e);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
this.ws.send(JSON.stringify(msg));
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
async httpQuery(msg) {
|
|
121
|
-
let path = "/v1/query";
|
|
122
|
-
let body = { sql: msg.sql, params: msg.params };
|
|
123
|
-
if (msg.action === "batch") {
|
|
124
|
-
path = "/v1/batch";
|
|
125
|
-
body = { queries: msg.queries };
|
|
126
|
-
} else if (msg.action === "exec") {
|
|
127
|
-
path = "/v1/exec";
|
|
128
|
-
body = { sql: msg.sql };
|
|
129
|
-
}
|
|
130
|
-
const res = await fetch(`${this.url}${path}`, {
|
|
131
|
-
method: "POST",
|
|
132
|
-
headers: {
|
|
133
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
134
|
-
"Content-Type": "application/json"
|
|
135
|
-
},
|
|
136
|
-
body: JSON.stringify(body)
|
|
137
|
-
});
|
|
138
|
-
const data = await res.json();
|
|
139
|
-
if (!res.ok || data.error) {
|
|
140
|
-
throw new StitchDBError(data.error || `Request failed: ${res.status}`, res.status);
|
|
141
|
-
}
|
|
142
|
-
return data;
|
|
40
|
+
this.headers = {
|
|
41
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
42
|
+
"Content-Type": "application/json"
|
|
43
|
+
};
|
|
143
44
|
}
|
|
144
45
|
/** Run a SQL query with parameterized bindings. */
|
|
145
46
|
async query(sql, params) {
|
|
146
|
-
|
|
147
|
-
return this.wsSend({ action: "query", sql, params });
|
|
148
|
-
}
|
|
149
|
-
return this.httpQuery({ action: "query", sql, params });
|
|
47
|
+
return this.post("/v1/query", { sql, params });
|
|
150
48
|
}
|
|
151
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* Run multiple queries in a single HTTP request.
|
|
51
|
+
* All queries execute atomically. One Worker invocation for N queries.
|
|
52
|
+
*/
|
|
152
53
|
async batch(queries) {
|
|
153
|
-
|
|
154
|
-
return this.wsSend({ action: "batch", queries });
|
|
155
|
-
}
|
|
156
|
-
return this.httpQuery({ action: "batch", queries });
|
|
54
|
+
return this.post("/v1/batch", { queries });
|
|
157
55
|
}
|
|
158
56
|
/** Run a DDL statement (CREATE TABLE, ALTER TABLE, DROP TABLE, etc.) */
|
|
159
57
|
async run(sql) {
|
|
160
|
-
|
|
161
|
-
return this.wsSend({ action: "exec", sql });
|
|
162
|
-
}
|
|
163
|
-
return this.httpQuery({ action: "exec", sql });
|
|
58
|
+
return this.post("/v1/exec", { sql });
|
|
164
59
|
}
|
|
165
60
|
/** Insert a row. */
|
|
166
61
|
async insert(table, data) {
|
|
@@ -168,6 +63,16 @@ var StitchDB = class {
|
|
|
168
63
|
const sql = `INSERT INTO "${table}" (${cols.map((c) => `"${c}"`).join(", ")}) VALUES (${cols.map(() => "?").join(", ")})`;
|
|
169
64
|
return this.query(sql, Object.values(data));
|
|
170
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Insert multiple rows in a single request using batch API.
|
|
68
|
+
* One Worker invocation regardless of how many rows.
|
|
69
|
+
*/
|
|
70
|
+
async insertMany(table, rows) {
|
|
71
|
+
if (rows.length === 0) return { results: [], meta: { rows_read: 0, rows_written: 0, duration_ms: 0, queries_count: 0 } };
|
|
72
|
+
const cols = Object.keys(rows[0]);
|
|
73
|
+
const sql = `INSERT INTO "${table}" (${cols.map((c) => `"${c}"`).join(", ")}) VALUES (${cols.map(() => "?").join(", ")})`;
|
|
74
|
+
return this.batch(rows.map((row) => ({ sql, params: cols.map((c) => row[c]) })));
|
|
75
|
+
}
|
|
171
76
|
/** Update rows matching a WHERE clause. */
|
|
172
77
|
async update(table, data, where, whereParams) {
|
|
173
78
|
const set = Object.keys(data).map((c) => `"${c}" = ?`).join(", ");
|
|
@@ -192,12 +97,19 @@ var StitchDB = class {
|
|
|
192
97
|
const { results } = await this.query(sql, params);
|
|
193
98
|
return results;
|
|
194
99
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this.
|
|
199
|
-
|
|
100
|
+
async post(path, body) {
|
|
101
|
+
const res = await fetch(`${this.url}${path}`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers: this.headers,
|
|
104
|
+
body: JSON.stringify(body),
|
|
105
|
+
// @ts-ignore — keepalive hint for HTTP/2 connection reuse
|
|
106
|
+
keepalive: true
|
|
107
|
+
});
|
|
108
|
+
const data = await res.json();
|
|
109
|
+
if (!res.ok || data.error) {
|
|
110
|
+
throw new StitchDBError(data.error || `Request failed: ${res.status}`, res.status);
|
|
200
111
|
}
|
|
112
|
+
return data;
|
|
201
113
|
}
|
|
202
114
|
};
|
|
203
115
|
function createClient(config) {
|
package/dist/index.mjs
CHANGED
|
@@ -8,132 +8,27 @@ var StitchDBError = class extends Error {
|
|
|
8
8
|
};
|
|
9
9
|
var StitchDB = class {
|
|
10
10
|
constructor(config) {
|
|
11
|
-
this.ws = null;
|
|
12
|
-
this.pending = /* @__PURE__ */ new Map();
|
|
13
|
-
this.msgId = 0;
|
|
14
|
-
this.connecting = null;
|
|
15
11
|
this.url = (config.url || "https://db.stitchdb.com").replace(/\/$/, "");
|
|
16
|
-
this.wsUrl = this.url.replace("https://", "wss://").replace("http://", "ws://");
|
|
17
12
|
this.apiKey = config.apiKey;
|
|
18
|
-
this.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (this.connecting) return this.connecting;
|
|
23
|
-
this.connecting = new Promise((resolve, reject) => {
|
|
24
|
-
try {
|
|
25
|
-
const ws = new WebSocket(`${this.wsUrl}/ws/query?key=${this.apiKey}`);
|
|
26
|
-
ws.onopen = () => {
|
|
27
|
-
this.ws = ws;
|
|
28
|
-
this.connecting = null;
|
|
29
|
-
resolve();
|
|
30
|
-
};
|
|
31
|
-
ws.onmessage = (event) => {
|
|
32
|
-
try {
|
|
33
|
-
const data = JSON.parse(typeof event.data === "string" ? event.data : "");
|
|
34
|
-
const pending = this.pending.get(data.id);
|
|
35
|
-
if (pending) {
|
|
36
|
-
this.pending.delete(data.id);
|
|
37
|
-
if (data.error) {
|
|
38
|
-
pending.reject(new StitchDBError(data.error));
|
|
39
|
-
} else {
|
|
40
|
-
pending.resolve(data);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
} catch {
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
ws.onclose = () => {
|
|
47
|
-
this.ws = null;
|
|
48
|
-
this.connecting = null;
|
|
49
|
-
for (const [id, p] of this.pending) {
|
|
50
|
-
p.reject(new StitchDBError("Connection closed"));
|
|
51
|
-
this.pending.delete(id);
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
ws.onerror = () => {
|
|
55
|
-
this.ws = null;
|
|
56
|
-
this.connecting = null;
|
|
57
|
-
reject(new StitchDBError("WebSocket connection failed"));
|
|
58
|
-
};
|
|
59
|
-
} catch {
|
|
60
|
-
this.connecting = null;
|
|
61
|
-
this.useWebSocket = false;
|
|
62
|
-
resolve();
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
return this.connecting;
|
|
66
|
-
}
|
|
67
|
-
async wsSend(msg) {
|
|
68
|
-
await this.connect();
|
|
69
|
-
if (!this.ws || this.ws.readyState !== 1) {
|
|
70
|
-
this.useWebSocket = false;
|
|
71
|
-
return this.httpQuery(msg);
|
|
72
|
-
}
|
|
73
|
-
const id = String(++this.msgId);
|
|
74
|
-
msg.id = id;
|
|
75
|
-
return new Promise((resolve, reject) => {
|
|
76
|
-
const timeout = setTimeout(() => {
|
|
77
|
-
this.pending.delete(id);
|
|
78
|
-
reject(new StitchDBError("Query timeout"));
|
|
79
|
-
}, 3e4);
|
|
80
|
-
this.pending.set(id, {
|
|
81
|
-
resolve: (v) => {
|
|
82
|
-
clearTimeout(timeout);
|
|
83
|
-
resolve(v);
|
|
84
|
-
},
|
|
85
|
-
reject: (e) => {
|
|
86
|
-
clearTimeout(timeout);
|
|
87
|
-
reject(e);
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
this.ws.send(JSON.stringify(msg));
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
async httpQuery(msg) {
|
|
94
|
-
let path = "/v1/query";
|
|
95
|
-
let body = { sql: msg.sql, params: msg.params };
|
|
96
|
-
if (msg.action === "batch") {
|
|
97
|
-
path = "/v1/batch";
|
|
98
|
-
body = { queries: msg.queries };
|
|
99
|
-
} else if (msg.action === "exec") {
|
|
100
|
-
path = "/v1/exec";
|
|
101
|
-
body = { sql: msg.sql };
|
|
102
|
-
}
|
|
103
|
-
const res = await fetch(`${this.url}${path}`, {
|
|
104
|
-
method: "POST",
|
|
105
|
-
headers: {
|
|
106
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
107
|
-
"Content-Type": "application/json"
|
|
108
|
-
},
|
|
109
|
-
body: JSON.stringify(body)
|
|
110
|
-
});
|
|
111
|
-
const data = await res.json();
|
|
112
|
-
if (!res.ok || data.error) {
|
|
113
|
-
throw new StitchDBError(data.error || `Request failed: ${res.status}`, res.status);
|
|
114
|
-
}
|
|
115
|
-
return data;
|
|
13
|
+
this.headers = {
|
|
14
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
15
|
+
"Content-Type": "application/json"
|
|
16
|
+
};
|
|
116
17
|
}
|
|
117
18
|
/** Run a SQL query with parameterized bindings. */
|
|
118
19
|
async query(sql, params) {
|
|
119
|
-
|
|
120
|
-
return this.wsSend({ action: "query", sql, params });
|
|
121
|
-
}
|
|
122
|
-
return this.httpQuery({ action: "query", sql, params });
|
|
20
|
+
return this.post("/v1/query", { sql, params });
|
|
123
21
|
}
|
|
124
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Run multiple queries in a single HTTP request.
|
|
24
|
+
* All queries execute atomically. One Worker invocation for N queries.
|
|
25
|
+
*/
|
|
125
26
|
async batch(queries) {
|
|
126
|
-
|
|
127
|
-
return this.wsSend({ action: "batch", queries });
|
|
128
|
-
}
|
|
129
|
-
return this.httpQuery({ action: "batch", queries });
|
|
27
|
+
return this.post("/v1/batch", { queries });
|
|
130
28
|
}
|
|
131
29
|
/** Run a DDL statement (CREATE TABLE, ALTER TABLE, DROP TABLE, etc.) */
|
|
132
30
|
async run(sql) {
|
|
133
|
-
|
|
134
|
-
return this.wsSend({ action: "exec", sql });
|
|
135
|
-
}
|
|
136
|
-
return this.httpQuery({ action: "exec", sql });
|
|
31
|
+
return this.post("/v1/exec", { sql });
|
|
137
32
|
}
|
|
138
33
|
/** Insert a row. */
|
|
139
34
|
async insert(table, data) {
|
|
@@ -141,6 +36,16 @@ var StitchDB = class {
|
|
|
141
36
|
const sql = `INSERT INTO "${table}" (${cols.map((c) => `"${c}"`).join(", ")}) VALUES (${cols.map(() => "?").join(", ")})`;
|
|
142
37
|
return this.query(sql, Object.values(data));
|
|
143
38
|
}
|
|
39
|
+
/**
|
|
40
|
+
* Insert multiple rows in a single request using batch API.
|
|
41
|
+
* One Worker invocation regardless of how many rows.
|
|
42
|
+
*/
|
|
43
|
+
async insertMany(table, rows) {
|
|
44
|
+
if (rows.length === 0) return { results: [], meta: { rows_read: 0, rows_written: 0, duration_ms: 0, queries_count: 0 } };
|
|
45
|
+
const cols = Object.keys(rows[0]);
|
|
46
|
+
const sql = `INSERT INTO "${table}" (${cols.map((c) => `"${c}"`).join(", ")}) VALUES (${cols.map(() => "?").join(", ")})`;
|
|
47
|
+
return this.batch(rows.map((row) => ({ sql, params: cols.map((c) => row[c]) })));
|
|
48
|
+
}
|
|
144
49
|
/** Update rows matching a WHERE clause. */
|
|
145
50
|
async update(table, data, where, whereParams) {
|
|
146
51
|
const set = Object.keys(data).map((c) => `"${c}" = ?`).join(", ");
|
|
@@ -165,12 +70,19 @@ var StitchDB = class {
|
|
|
165
70
|
const { results } = await this.query(sql, params);
|
|
166
71
|
return results;
|
|
167
72
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
this.
|
|
172
|
-
|
|
73
|
+
async post(path, body) {
|
|
74
|
+
const res = await fetch(`${this.url}${path}`, {
|
|
75
|
+
method: "POST",
|
|
76
|
+
headers: this.headers,
|
|
77
|
+
body: JSON.stringify(body),
|
|
78
|
+
// @ts-ignore — keepalive hint for HTTP/2 connection reuse
|
|
79
|
+
keepalive: true
|
|
80
|
+
});
|
|
81
|
+
const data = await res.json();
|
|
82
|
+
if (!res.ok || data.error) {
|
|
83
|
+
throw new StitchDBError(data.error || `Request failed: ${res.status}`, res.status);
|
|
173
84
|
}
|
|
85
|
+
return data;
|
|
174
86
|
}
|
|
175
87
|
};
|
|
176
88
|
function createClient(config) {
|