hydrousdb 2.0.1 → 2.0.3
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/LICENSE +1 -1
- package/README.md +976 -421
- package/dist/index.d.mts +226 -383
- package/dist/index.d.ts +226 -383
- package/dist/index.js +343 -593
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +339 -592
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -27
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// src/utils/errors.ts
|
|
2
|
-
var
|
|
2
|
+
var HydrousDBError = class extends Error {
|
|
3
3
|
constructor(message, code = "SDK_ERROR", status) {
|
|
4
4
|
super(message);
|
|
5
|
-
this.name = "
|
|
5
|
+
this.name = "HydrousDBError";
|
|
6
6
|
this.code = code;
|
|
7
7
|
this.status = status;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
10
|
function toHydrousError(err) {
|
|
11
|
-
if (err instanceof
|
|
11
|
+
if (err instanceof HydrousDBError) {
|
|
12
12
|
return { message: err.message, code: err.code, status: err.status };
|
|
13
13
|
}
|
|
14
14
|
if (err instanceof Error) {
|
|
@@ -17,7 +17,7 @@ function toHydrousError(err) {
|
|
|
17
17
|
return { message: String(err), code: "UNKNOWN_ERROR" };
|
|
18
18
|
}
|
|
19
19
|
function isHydrousError(err) {
|
|
20
|
-
return err instanceof
|
|
20
|
+
return err instanceof HydrousDBError;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// src/utils/http.ts
|
|
@@ -26,16 +26,14 @@ async function parseResponse(res) {
|
|
|
26
26
|
try {
|
|
27
27
|
body = await res.json();
|
|
28
28
|
} catch (e) {
|
|
29
|
-
if (!res.ok) {
|
|
30
|
-
throw new HydrousSDKError(`HTTP ${res.status}`, "HTTP_ERROR", res.status);
|
|
31
|
-
}
|
|
29
|
+
if (!res.ok) throw new HydrousDBError(`HTTP ${res.status}`, "HTTP_ERROR", res.status);
|
|
32
30
|
return void 0;
|
|
33
31
|
}
|
|
34
32
|
if (!res.ok) {
|
|
35
|
-
const
|
|
36
|
-
throw new
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
const e = body;
|
|
34
|
+
throw new HydrousDBError(
|
|
35
|
+
e.error || e.message || `HTTP ${res.status}`,
|
|
36
|
+
e.code || "HTTP_ERROR",
|
|
39
37
|
res.status
|
|
40
38
|
);
|
|
41
39
|
}
|
|
@@ -45,15 +43,13 @@ function buildUrl(base, path, params) {
|
|
|
45
43
|
const url = new URL(path, base.endsWith("/") ? base : base + "/");
|
|
46
44
|
if (params) {
|
|
47
45
|
for (const [k, v] of Object.entries(params)) {
|
|
48
|
-
if (v !== void 0 && v !== null)
|
|
49
|
-
url.searchParams.set(k, String(v));
|
|
50
|
-
}
|
|
46
|
+
if (v !== void 0 && v !== null) url.searchParams.set(k, String(v));
|
|
51
47
|
}
|
|
52
48
|
}
|
|
53
49
|
return url.toString();
|
|
54
50
|
}
|
|
55
|
-
function mergeHeaders(
|
|
56
|
-
return { ...
|
|
51
|
+
function mergeHeaders(a, b) {
|
|
52
|
+
return { ...a, ...b };
|
|
57
53
|
}
|
|
58
54
|
async function readSSEStream(response, onEvent) {
|
|
59
55
|
if (!response.body) return;
|
|
@@ -87,17 +83,32 @@ async function readSSEStream(response, onEvent) {
|
|
|
87
83
|
}
|
|
88
84
|
if (buf.trim()) flush("");
|
|
89
85
|
}
|
|
90
|
-
function
|
|
86
|
+
function parseSSEText(text, onEvent) {
|
|
87
|
+
const blocks = text.split("\n\n");
|
|
88
|
+
for (const block of blocks) {
|
|
89
|
+
if (!block.trim()) continue;
|
|
90
|
+
let eventType = "message";
|
|
91
|
+
let dataLine = null;
|
|
92
|
+
for (const line of block.split("\n")) {
|
|
93
|
+
if (line.startsWith("event:")) eventType = line.slice(6).trim();
|
|
94
|
+
if (line.startsWith("data:")) dataLine = line.slice(5).trim();
|
|
95
|
+
}
|
|
96
|
+
if (dataLine === null) continue;
|
|
97
|
+
try {
|
|
98
|
+
onEvent(eventType, JSON.parse(dataLine));
|
|
99
|
+
} catch (e) {
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function xhrUpload(url, body, headers, onProgress) {
|
|
91
104
|
return new Promise((resolve, reject) => {
|
|
92
105
|
const xhr = new XMLHttpRequest();
|
|
93
106
|
xhr.open("POST", url);
|
|
94
|
-
for (const [
|
|
95
|
-
xhr.setRequestHeader(key, val);
|
|
96
|
-
}
|
|
107
|
+
for (const [k, v] of Object.entries(headers)) xhr.setRequestHeader(k, v);
|
|
97
108
|
xhr.responseType = "text";
|
|
98
|
-
if (
|
|
109
|
+
if (onProgress) {
|
|
99
110
|
xhr.upload.onprogress = (e) => {
|
|
100
|
-
if (e.lengthComputable)
|
|
111
|
+
if (e.lengthComputable) onProgress(e.loaded, e.total);
|
|
101
112
|
};
|
|
102
113
|
}
|
|
103
114
|
xhr.onload = () => {
|
|
@@ -107,35 +118,18 @@ function xhrUpload(url, body, headers, onXhrProgress) {
|
|
|
107
118
|
} else {
|
|
108
119
|
try {
|
|
109
120
|
const d = JSON.parse(xhr.responseText);
|
|
110
|
-
reject(new
|
|
121
|
+
reject(new HydrousDBError((_a = d.error) != null ? _a : `HTTP ${xhr.status}`, "HTTP_ERROR", xhr.status));
|
|
111
122
|
} catch (e) {
|
|
112
|
-
reject(new
|
|
123
|
+
reject(new HydrousDBError(`HTTP ${xhr.status}`, "HTTP_ERROR", xhr.status));
|
|
113
124
|
}
|
|
114
125
|
}
|
|
115
126
|
};
|
|
116
|
-
xhr.onerror = () => reject(new
|
|
117
|
-
xhr.onabort = () => reject(new
|
|
118
|
-
xhr.ontimeout = () => reject(new
|
|
127
|
+
xhr.onerror = () => reject(new HydrousDBError("Network error", "NETWORK_ERROR"));
|
|
128
|
+
xhr.onabort = () => reject(new HydrousDBError("Upload aborted", "UPLOAD_ABORTED"));
|
|
129
|
+
xhr.ontimeout = () => reject(new HydrousDBError("Upload timed out", "UPLOAD_TIMEOUT"));
|
|
119
130
|
xhr.send(body);
|
|
120
131
|
});
|
|
121
132
|
}
|
|
122
|
-
function parseSSEText(text, onEvent) {
|
|
123
|
-
const blocks = text.split("\n\n");
|
|
124
|
-
for (const block of blocks) {
|
|
125
|
-
if (!block.trim()) continue;
|
|
126
|
-
let eventType = "message";
|
|
127
|
-
let dataLine = null;
|
|
128
|
-
for (const line of block.split("\n")) {
|
|
129
|
-
if (line.startsWith("event:")) eventType = line.slice(6).trim();
|
|
130
|
-
if (line.startsWith("data:")) dataLine = line.slice(5).trim();
|
|
131
|
-
}
|
|
132
|
-
if (dataLine === null) continue;
|
|
133
|
-
try {
|
|
134
|
-
onEvent(eventType, JSON.parse(dataLine));
|
|
135
|
-
} catch (e) {
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
133
|
|
|
140
134
|
// src/auth/client.ts
|
|
141
135
|
var AuthClient = class {
|
|
@@ -144,23 +138,13 @@ var AuthClient = class {
|
|
|
144
138
|
this.baseUrl = config.url;
|
|
145
139
|
this.headers = {
|
|
146
140
|
"Content-Type": "application/json",
|
|
147
|
-
"Authorization": `Bearer ${config.
|
|
141
|
+
"Authorization": `Bearer ${config.authKey}`
|
|
148
142
|
};
|
|
149
143
|
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Create a new user account and return a session.
|
|
153
|
-
*
|
|
154
|
-
* @example
|
|
155
|
-
* const { data, error } = await hydrous.auth.signUp({
|
|
156
|
-
* email: 'user@example.com',
|
|
157
|
-
* password: 'supersecret',
|
|
158
|
-
* });
|
|
159
|
-
*/
|
|
144
|
+
/** Create a new user account */
|
|
160
145
|
async signUp(options) {
|
|
161
146
|
try {
|
|
162
|
-
const
|
|
163
|
-
const res = await fetch(url, {
|
|
147
|
+
const res = await fetch(buildUrl(this.baseUrl, "auth/signup"), {
|
|
164
148
|
method: "POST",
|
|
165
149
|
headers: this.headers,
|
|
166
150
|
body: JSON.stringify(options)
|
|
@@ -172,21 +156,10 @@ var AuthClient = class {
|
|
|
172
156
|
return { data: null, error: toHydrousError(err) };
|
|
173
157
|
}
|
|
174
158
|
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Sign in with email and password.
|
|
178
|
-
*
|
|
179
|
-
* @example
|
|
180
|
-
* const { data, error } = await hydrous.auth.signIn({
|
|
181
|
-
* email: 'user@example.com',
|
|
182
|
-
* password: 'supersecret',
|
|
183
|
-
* });
|
|
184
|
-
* if (data) console.log('Signed in as', data.user.email);
|
|
185
|
-
*/
|
|
159
|
+
/** Sign in with email and password */
|
|
186
160
|
async signIn(options) {
|
|
187
161
|
try {
|
|
188
|
-
const
|
|
189
|
-
const res = await fetch(url, {
|
|
162
|
+
const res = await fetch(buildUrl(this.baseUrl, "auth/signin"), {
|
|
190
163
|
method: "POST",
|
|
191
164
|
headers: this.headers,
|
|
192
165
|
body: JSON.stringify(options)
|
|
@@ -198,14 +171,10 @@ var AuthClient = class {
|
|
|
198
171
|
return { data: null, error: toHydrousError(err) };
|
|
199
172
|
}
|
|
200
173
|
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Sign out the current user and invalidate their session.
|
|
204
|
-
*/
|
|
174
|
+
/** Sign out and invalidate the current session */
|
|
205
175
|
async signOut() {
|
|
206
176
|
try {
|
|
207
|
-
const
|
|
208
|
-
const res = await fetch(url, {
|
|
177
|
+
const res = await fetch(buildUrl(this.baseUrl, "auth/signout"), {
|
|
209
178
|
method: "POST",
|
|
210
179
|
headers: mergeHeaders(this.headers, this._sessionHeader())
|
|
211
180
|
});
|
|
@@ -216,12 +185,10 @@ var AuthClient = class {
|
|
|
216
185
|
return { data: null, error: toHydrousError(err) };
|
|
217
186
|
}
|
|
218
187
|
}
|
|
219
|
-
|
|
220
|
-
/** Return the currently authenticated user, or null if not signed in. */
|
|
188
|
+
/** Get the currently authenticated user */
|
|
221
189
|
async getUser() {
|
|
222
190
|
try {
|
|
223
|
-
const
|
|
224
|
-
const res = await fetch(url, {
|
|
191
|
+
const res = await fetch(buildUrl(this.baseUrl, "auth/user"), {
|
|
225
192
|
headers: mergeHeaders(this.headers, this._sessionHeader())
|
|
226
193
|
});
|
|
227
194
|
const json = await parseResponse(res);
|
|
@@ -230,19 +197,14 @@ var AuthClient = class {
|
|
|
230
197
|
return { data: null, error: toHydrousError(err) };
|
|
231
198
|
}
|
|
232
199
|
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Refresh the access token using the stored refresh token.
|
|
236
|
-
* Called automatically by the SDK when a 401 is received.
|
|
237
|
-
*/
|
|
200
|
+
/** Refresh the access token using the stored refresh token */
|
|
238
201
|
async refreshSession() {
|
|
239
202
|
var _a;
|
|
240
203
|
if (!((_a = this.session) == null ? void 0 : _a.refreshToken)) {
|
|
241
|
-
return { data: null, error: { message: "No session", code: "NO_SESSION" } };
|
|
204
|
+
return { data: null, error: { message: "No active session", code: "NO_SESSION" } };
|
|
242
205
|
}
|
|
243
206
|
try {
|
|
244
|
-
const
|
|
245
|
-
const res = await fetch(url, {
|
|
207
|
+
const res = await fetch(buildUrl(this.baseUrl, "auth/refresh"), {
|
|
246
208
|
method: "POST",
|
|
247
209
|
headers: this.headers,
|
|
248
210
|
body: JSON.stringify({ refreshToken: this.session.refreshToken })
|
|
@@ -254,7 +216,7 @@ var AuthClient = class {
|
|
|
254
216
|
return { data: null, error: toHydrousError(err) };
|
|
255
217
|
}
|
|
256
218
|
}
|
|
257
|
-
/** Return the current in-memory session (may be null)
|
|
219
|
+
/** Return the current in-memory session (may be null) */
|
|
258
220
|
getSession() {
|
|
259
221
|
return this.session;
|
|
260
222
|
}
|
|
@@ -270,34 +232,22 @@ function serialiseQuery(opts = {}) {
|
|
|
270
232
|
const params = {};
|
|
271
233
|
if (opts.limit !== void 0) params["limit"] = String(opts.limit);
|
|
272
234
|
if (opts.offset !== void 0) params["offset"] = String(opts.offset);
|
|
273
|
-
if (opts.select && opts.select.length > 0)
|
|
274
|
-
params["select"] = opts.select.join(",");
|
|
275
|
-
}
|
|
235
|
+
if (opts.select && opts.select.length > 0) params["select"] = opts.select.join(",");
|
|
276
236
|
if (opts.orderBy) {
|
|
277
237
|
params["orderBy"] = opts.orderBy.field;
|
|
278
238
|
params["direction"] = (_a = opts.orderBy.direction) != null ? _a : "asc";
|
|
279
239
|
}
|
|
280
240
|
const filters = opts.where ? Array.isArray(opts.where) ? opts.where : [opts.where] : [];
|
|
281
|
-
if (filters.length > 0)
|
|
282
|
-
params["where"] = JSON.stringify(filters);
|
|
283
|
-
}
|
|
241
|
+
if (filters.length > 0) params["where"] = JSON.stringify(filters);
|
|
284
242
|
return params;
|
|
285
243
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return { field, operator: "gt", value };
|
|
294
|
-
}
|
|
295
|
-
function lt(field, value) {
|
|
296
|
-
return { field, operator: "lt", value };
|
|
297
|
-
}
|
|
298
|
-
function inArray(field, value) {
|
|
299
|
-
return { field, operator: "in", value };
|
|
300
|
-
}
|
|
244
|
+
var eq = (field, value) => ({ field, operator: "eq", value });
|
|
245
|
+
var neq = (field, value) => ({ field, operator: "neq", value });
|
|
246
|
+
var gt = (field, value) => ({ field, operator: "gt", value });
|
|
247
|
+
var lt = (field, value) => ({ field, operator: "lt", value });
|
|
248
|
+
var gte = (field, value) => ({ field, operator: "gte", value });
|
|
249
|
+
var lte = (field, value) => ({ field, operator: "lte", value });
|
|
250
|
+
var inArray = (field, value) => ({ field, operator: "in", value });
|
|
301
251
|
|
|
302
252
|
// src/records/client.ts
|
|
303
253
|
var RecordsClient = class {
|
|
@@ -305,27 +255,13 @@ var RecordsClient = class {
|
|
|
305
255
|
this.baseUrl = config.url;
|
|
306
256
|
this.headers = {
|
|
307
257
|
"Content-Type": "application/json",
|
|
308
|
-
"Authorization": `Bearer ${config.
|
|
258
|
+
"Authorization": `Bearer ${config.bucketSecurityKey}`
|
|
309
259
|
};
|
|
310
260
|
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Query records from a collection.
|
|
314
|
-
*
|
|
315
|
-
* @param collection - Collection name (e.g. "users")
|
|
316
|
-
* @param options - Filters, ordering, pagination
|
|
317
|
-
*
|
|
318
|
-
* @example
|
|
319
|
-
* const { data, error } = await hydrous.records.select('users', {
|
|
320
|
-
* where: { field: 'role', operator: 'eq', value: 'admin' },
|
|
321
|
-
* orderBy: { field: 'createdAt', direction: 'desc' },
|
|
322
|
-
* limit: 20,
|
|
323
|
-
* });
|
|
324
|
-
*/
|
|
261
|
+
/** Query records from a collection */
|
|
325
262
|
async select(collection, options = {}) {
|
|
326
263
|
try {
|
|
327
|
-
const
|
|
328
|
-
const url = buildUrl(this.baseUrl, `records/${collection}`, params);
|
|
264
|
+
const url = buildUrl(this.baseUrl, `records/${collection}`, serialiseQuery(options));
|
|
329
265
|
const res = await fetch(url, { headers: this.headers });
|
|
330
266
|
const json = await parseResponse(res);
|
|
331
267
|
return { data: json.data, count: json.count, error: null };
|
|
@@ -333,45 +269,20 @@ var RecordsClient = class {
|
|
|
333
269
|
return { data: [], count: 0, error: toHydrousError(err) };
|
|
334
270
|
}
|
|
335
271
|
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Fetch a single record by its ID.
|
|
339
|
-
*
|
|
340
|
-
* @example
|
|
341
|
-
* const { data, error } = await hydrous.records.get('users', 'user_abc123');
|
|
342
|
-
*/
|
|
272
|
+
/** Fetch a single record by ID */
|
|
343
273
|
async get(collection, id) {
|
|
344
274
|
try {
|
|
345
|
-
const
|
|
346
|
-
const res = await fetch(url, { headers: this.headers });
|
|
275
|
+
const res = await fetch(buildUrl(this.baseUrl, `records/${collection}/${id}`), { headers: this.headers });
|
|
347
276
|
const json = await parseResponse(res);
|
|
348
277
|
return { data: json.data, error: null };
|
|
349
278
|
} catch (err) {
|
|
350
279
|
return { data: null, error: toHydrousError(err) };
|
|
351
280
|
}
|
|
352
281
|
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Insert one or more records into a collection.
|
|
356
|
-
*
|
|
357
|
-
* @param collection - Collection name
|
|
358
|
-
* @param payload - A single record object or an array of record objects
|
|
359
|
-
*
|
|
360
|
-
* @example
|
|
361
|
-
* // Single insert
|
|
362
|
-
* const { data, error } = await hydrous.records.insert('users', {
|
|
363
|
-
* name: 'Alice', email: 'alice@example.com'
|
|
364
|
-
* });
|
|
365
|
-
*
|
|
366
|
-
* // Bulk insert
|
|
367
|
-
* const { data, error } = await hydrous.records.insert('users', [
|
|
368
|
-
* { name: 'Alice' }, { name: 'Bob' }
|
|
369
|
-
* ]);
|
|
370
|
-
*/
|
|
282
|
+
/** Insert one or more records */
|
|
371
283
|
async insert(collection, payload) {
|
|
372
284
|
try {
|
|
373
|
-
const
|
|
374
|
-
const res = await fetch(url, {
|
|
285
|
+
const res = await fetch(buildUrl(this.baseUrl, `records/${collection}`), {
|
|
375
286
|
method: "POST",
|
|
376
287
|
headers: this.headers,
|
|
377
288
|
body: JSON.stringify(payload)
|
|
@@ -382,19 +293,10 @@ var RecordsClient = class {
|
|
|
382
293
|
return { data: [], count: 0, error: toHydrousError(err) };
|
|
383
294
|
}
|
|
384
295
|
}
|
|
385
|
-
|
|
386
|
-
/**
|
|
387
|
-
* Update a record by ID.
|
|
388
|
-
*
|
|
389
|
-
* @example
|
|
390
|
-
* const { data, error } = await hydrous.records.update('users', 'user_abc123', {
|
|
391
|
-
* name: 'Alice Smith'
|
|
392
|
-
* });
|
|
393
|
-
*/
|
|
296
|
+
/** Update a record by ID */
|
|
394
297
|
async update(collection, id, payload) {
|
|
395
298
|
try {
|
|
396
|
-
const
|
|
397
|
-
const res = await fetch(url, {
|
|
299
|
+
const res = await fetch(buildUrl(this.baseUrl, `records/${collection}/${id}`), {
|
|
398
300
|
method: "PATCH",
|
|
399
301
|
headers: this.headers,
|
|
400
302
|
body: JSON.stringify(payload)
|
|
@@ -405,17 +307,13 @@ var RecordsClient = class {
|
|
|
405
307
|
return { data: null, error: toHydrousError(err) };
|
|
406
308
|
}
|
|
407
309
|
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Delete a record by ID.
|
|
411
|
-
*
|
|
412
|
-
* @example
|
|
413
|
-
* const { error } = await hydrous.records.delete('users', 'user_abc123');
|
|
414
|
-
*/
|
|
310
|
+
/** Delete a record by ID */
|
|
415
311
|
async delete(collection, id) {
|
|
416
312
|
try {
|
|
417
|
-
const
|
|
418
|
-
|
|
313
|
+
const res = await fetch(buildUrl(this.baseUrl, `records/${collection}/${id}`), {
|
|
314
|
+
method: "DELETE",
|
|
315
|
+
headers: this.headers
|
|
316
|
+
});
|
|
419
317
|
await parseResponse(res);
|
|
420
318
|
return { data: void 0, error: null };
|
|
421
319
|
} catch (err) {
|
|
@@ -430,31 +328,17 @@ var AnalyticsClient = class {
|
|
|
430
328
|
this.baseUrl = config.url;
|
|
431
329
|
this.headers = {
|
|
432
330
|
"Content-Type": "application/json",
|
|
433
|
-
"Authorization": `Bearer ${config.
|
|
331
|
+
"Authorization": `Bearer ${config.bucketSecurityKey}`
|
|
434
332
|
};
|
|
435
333
|
}
|
|
436
|
-
|
|
437
|
-
/**
|
|
438
|
-
* Track an analytics event.
|
|
439
|
-
*
|
|
440
|
-
* @example
|
|
441
|
-
* await hydrous.analytics.track({
|
|
442
|
-
* event: 'page_view',
|
|
443
|
-
* properties: { page: '/home', referrer: 'google.com' },
|
|
444
|
-
* userId: 'user_abc123',
|
|
445
|
-
* });
|
|
446
|
-
*/
|
|
334
|
+
/** Track a single analytics event */
|
|
447
335
|
async track(options) {
|
|
448
336
|
var _a;
|
|
449
337
|
try {
|
|
450
|
-
const
|
|
451
|
-
const res = await fetch(url, {
|
|
338
|
+
const res = await fetch(buildUrl(this.baseUrl, "analytics/track"), {
|
|
452
339
|
method: "POST",
|
|
453
340
|
headers: this.headers,
|
|
454
|
-
body: JSON.stringify({
|
|
455
|
-
...options,
|
|
456
|
-
timestamp: (_a = options.timestamp) != null ? _a : Date.now()
|
|
457
|
-
})
|
|
341
|
+
body: JSON.stringify({ ...options, timestamp: (_a = options.timestamp) != null ? _a : Date.now() })
|
|
458
342
|
});
|
|
459
343
|
await parseResponse(res);
|
|
460
344
|
return { data: void 0, error: null };
|
|
@@ -462,18 +346,25 @@ var AnalyticsClient = class {
|
|
|
462
346
|
return { data: null, error: toHydrousError(err) };
|
|
463
347
|
}
|
|
464
348
|
}
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
349
|
+
/** Track many events in one request */
|
|
350
|
+
async trackBatch(events) {
|
|
351
|
+
try {
|
|
352
|
+
const stamped = events.map((e) => {
|
|
353
|
+
var _a;
|
|
354
|
+
return { ...e, timestamp: (_a = e.timestamp) != null ? _a : Date.now() };
|
|
355
|
+
});
|
|
356
|
+
const res = await fetch(buildUrl(this.baseUrl, "analytics/track/batch"), {
|
|
357
|
+
method: "POST",
|
|
358
|
+
headers: this.headers,
|
|
359
|
+
body: JSON.stringify({ events: stamped })
|
|
360
|
+
});
|
|
361
|
+
await parseResponse(res);
|
|
362
|
+
return { data: void 0, error: null };
|
|
363
|
+
} catch (err) {
|
|
364
|
+
return { data: null, error: toHydrousError(err) };
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/** Query recorded analytics events */
|
|
477
368
|
async query(options = {}) {
|
|
478
369
|
try {
|
|
479
370
|
const params = {};
|
|
@@ -490,56 +381,23 @@ var AnalyticsClient = class {
|
|
|
490
381
|
return { data: [], count: 0, error: toHydrousError(err) };
|
|
491
382
|
}
|
|
492
383
|
}
|
|
493
|
-
// ─── BATCH TRACK ─────────────────────────────────────────────────────────
|
|
494
|
-
/**
|
|
495
|
-
* Track multiple events in a single request (more efficient than
|
|
496
|
-
* calling `track` in a loop).
|
|
497
|
-
*
|
|
498
|
-
* @example
|
|
499
|
-
* await hydrous.analytics.trackBatch([
|
|
500
|
-
* { event: 'signup', userId: 'u1' },
|
|
501
|
-
* { event: 'onboarded', userId: 'u1' },
|
|
502
|
-
* ]);
|
|
503
|
-
*/
|
|
504
|
-
async trackBatch(events) {
|
|
505
|
-
try {
|
|
506
|
-
const url = buildUrl(this.baseUrl, "analytics/track/batch");
|
|
507
|
-
const stamped = events.map((e) => {
|
|
508
|
-
var _a;
|
|
509
|
-
return {
|
|
510
|
-
...e,
|
|
511
|
-
timestamp: (_a = e.timestamp) != null ? _a : Date.now()
|
|
512
|
-
};
|
|
513
|
-
});
|
|
514
|
-
const res = await fetch(url, {
|
|
515
|
-
method: "POST",
|
|
516
|
-
headers: this.headers,
|
|
517
|
-
body: JSON.stringify({ events: stamped })
|
|
518
|
-
});
|
|
519
|
-
await parseResponse(res);
|
|
520
|
-
return { data: void 0, error: null };
|
|
521
|
-
} catch (err) {
|
|
522
|
-
return { data: null, error: toHydrousError(err) };
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
384
|
};
|
|
526
385
|
|
|
527
|
-
// src/storage/
|
|
386
|
+
// src/storage/scoped.ts
|
|
528
387
|
var isBrowser = typeof window !== "undefined" && typeof XMLHttpRequest !== "undefined";
|
|
529
|
-
function
|
|
530
|
-
return encodeURIComponent(
|
|
531
|
-
}
|
|
532
|
-
function storageUrl(base, bucketKey, path) {
|
|
533
|
-
const bucket = bucketFromKey(bucketKey);
|
|
534
|
-
return `${base.replace(/\/$/, "")}/storage/${bucket}/${path.replace(/^\//, "")}`;
|
|
388
|
+
function storageBase(url, bucketKey) {
|
|
389
|
+
return `${url.replace(/\/$/, "")}/storage/${encodeURIComponent(bucketKey)}`;
|
|
535
390
|
}
|
|
536
391
|
function storageHeaders(bucketKey) {
|
|
537
392
|
return { "X-Storage-Key": bucketKey };
|
|
538
393
|
}
|
|
539
|
-
function
|
|
394
|
+
function jsonHeaders(bucketKey) {
|
|
395
|
+
return { "X-Storage-Key": bucketKey, "Content-Type": "application/json" };
|
|
396
|
+
}
|
|
397
|
+
function drainSSE(raw, onProgress) {
|
|
540
398
|
const results = [];
|
|
541
399
|
const errors = [];
|
|
542
|
-
parseSSEText(
|
|
400
|
+
parseSSEText(raw, (eventType, data) => {
|
|
543
401
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
|
|
544
402
|
const d = data;
|
|
545
403
|
if (eventType === "progress" && onProgress) {
|
|
@@ -561,11 +419,9 @@ function drainSSEProgress(rawText, onProgress) {
|
|
|
561
419
|
if (eventType === "done") {
|
|
562
420
|
if (d["path"]) {
|
|
563
421
|
results.push(d);
|
|
564
|
-
} else if (Array.isArray(d["
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
results.push(...succeeded);
|
|
568
|
-
errors.push(...errs);
|
|
422
|
+
} else if (Array.isArray(d["succeeded"])) {
|
|
423
|
+
results.push(...d["succeeded"]);
|
|
424
|
+
errors.push(...(_j = d["errors"]) != null ? _j : []);
|
|
569
425
|
}
|
|
570
426
|
}
|
|
571
427
|
if (eventType === "error") {
|
|
@@ -578,51 +434,44 @@ function drainSSEProgress(rawText, onProgress) {
|
|
|
578
434
|
});
|
|
579
435
|
return { results, errors };
|
|
580
436
|
}
|
|
581
|
-
var
|
|
582
|
-
constructor(
|
|
583
|
-
this.
|
|
437
|
+
var ScopedStorageClient = class {
|
|
438
|
+
constructor(baseUrl, keyName, bucketKey) {
|
|
439
|
+
this.base = storageBase(baseUrl, bucketKey);
|
|
440
|
+
this.key = bucketKey;
|
|
441
|
+
this.keyName = keyName;
|
|
584
442
|
}
|
|
585
443
|
// ══════════════════════════════════════════════════════════════════════════
|
|
586
|
-
// UPLOAD
|
|
444
|
+
// UPLOAD — single file
|
|
587
445
|
// ══════════════════════════════════════════════════════════════════════════
|
|
588
446
|
/**
|
|
589
|
-
* Upload a single file
|
|
447
|
+
* Upload a single file.
|
|
590
448
|
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
593
|
-
* bytes transferred, speed (bytes/sec), ETA, and lifecycle stage.
|
|
449
|
+
* Supply `onProgress` to receive live upload ticks including bytes
|
|
450
|
+
* transferred, speed (bytes/sec), ETA, and lifecycle stage.
|
|
594
451
|
*
|
|
595
|
-
*
|
|
596
|
-
*
|
|
597
|
-
* |-------------|------------------------------------------|
|
|
598
|
-
* | `pending` | Queued, not yet started |
|
|
599
|
-
* | `compressing` | Server is compressing the file |
|
|
600
|
-
* | `uploading` | Bytes flowing to cloud storage |
|
|
601
|
-
* | `done` | Confirmed written to cloud storage |
|
|
602
|
-
* | `error` | Something went wrong |
|
|
452
|
+
* **Stage sequence:**
|
|
453
|
+
* `pending → compressing → uploading → done | error`
|
|
603
454
|
*
|
|
604
|
-
*
|
|
605
|
-
*
|
|
606
|
-
*
|
|
455
|
+
* In browsers the progress is tracked at the network level via XHR, so
|
|
456
|
+
* `percent` reflects actual bytes leaving the device. `done` only fires
|
|
457
|
+
* after the server confirms the write to cloud storage, so 100% is real.
|
|
607
458
|
*
|
|
608
459
|
* @example
|
|
609
|
-
* const { data, error } = await
|
|
610
|
-
* '
|
|
611
|
-
*
|
|
612
|
-
* {
|
|
613
|
-
*
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
* }
|
|
619
|
-
* );
|
|
460
|
+
* const { data, error } = await db.storage('avatars').upload(file, {
|
|
461
|
+
* path: 'users/alice.jpg',
|
|
462
|
+
* overwrite: true,
|
|
463
|
+
* onProgress: (p) => {
|
|
464
|
+
* setProgress(p.percent); // e.g. drive a <progress> bar
|
|
465
|
+
* setSpeed(`${p.bytesPerSecond} B/s`);
|
|
466
|
+
* setEta(`${p.eta}s remaining`);
|
|
467
|
+
* },
|
|
468
|
+
* });
|
|
620
469
|
*/
|
|
621
|
-
async upload(
|
|
470
|
+
async upload(file, options = {}) {
|
|
622
471
|
var _a, _b;
|
|
623
472
|
const { path, overwrite = false, onProgress } = options;
|
|
624
473
|
try {
|
|
625
|
-
const url =
|
|
474
|
+
const url = `${this.base}/upload`;
|
|
626
475
|
const form = new FormData();
|
|
627
476
|
if (file instanceof Uint8Array) {
|
|
628
477
|
form.append("file", new Blob([file.buffer]), path != null ? path : "file");
|
|
@@ -633,25 +482,23 @@ var StorageClient = class {
|
|
|
633
482
|
}
|
|
634
483
|
if (path) form.append("path", path);
|
|
635
484
|
if (overwrite) form.append("overwrite", "true");
|
|
636
|
-
const headers = storageHeaders(
|
|
485
|
+
const headers = storageHeaders(this.key);
|
|
637
486
|
if (isBrowser) {
|
|
638
487
|
const totalBytes = file instanceof Blob ? file.size : file instanceof Uint8Array ? file.byteLength : file.byteLength;
|
|
639
488
|
const rawBody = await xhrUpload(url, form, headers, (loaded, total) => {
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
});
|
|
652
|
-
}
|
|
489
|
+
onProgress == null ? void 0 : onProgress({
|
|
490
|
+
index: 0,
|
|
491
|
+
total: 1,
|
|
492
|
+
path: path != null ? path : "",
|
|
493
|
+
stage: "uploading",
|
|
494
|
+
bytesUploaded: loaded,
|
|
495
|
+
totalBytes: total || totalBytes,
|
|
496
|
+
percent: Math.min(99, Math.round(loaded / (total || totalBytes) * 100)),
|
|
497
|
+
bytesPerSecond: null,
|
|
498
|
+
eta: null
|
|
499
|
+
});
|
|
653
500
|
});
|
|
654
|
-
const { results, errors } =
|
|
501
|
+
const { results, errors } = drainSSE(rawBody, onProgress);
|
|
655
502
|
if (errors.length > 0 && results.length === 0) {
|
|
656
503
|
return { data: null, error: { message: errors[0].error, code: errors[0].code } };
|
|
657
504
|
}
|
|
@@ -674,33 +521,32 @@ var StorageClient = class {
|
|
|
674
521
|
}
|
|
675
522
|
const res = await fetch(url, { method: "POST", headers, body: form });
|
|
676
523
|
if (!res.ok) {
|
|
677
|
-
const
|
|
678
|
-
throw new
|
|
524
|
+
const e = await res.json().catch(() => ({}));
|
|
525
|
+
throw new HydrousDBError((_b = e.error) != null ? _b : `HTTP ${res.status}`, "HTTP_ERROR", res.status);
|
|
679
526
|
}
|
|
680
527
|
let finalResult = null;
|
|
681
528
|
await readSSEStream(res, (eventType, data) => {
|
|
682
|
-
var _a2, _b2, _c, _d, _e, _f, _g, _h
|
|
529
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h;
|
|
683
530
|
const d = data;
|
|
684
531
|
if (eventType === "progress" && onProgress) {
|
|
685
532
|
onProgress({
|
|
686
|
-
index:
|
|
687
|
-
total:
|
|
688
|
-
path:
|
|
689
|
-
stage: (
|
|
690
|
-
bytesUploaded: (
|
|
691
|
-
totalBytes: (
|
|
692
|
-
percent: (
|
|
693
|
-
bytesPerSecond: (
|
|
694
|
-
eta: (
|
|
695
|
-
result: d["result"]
|
|
696
|
-
error: d["error"]
|
|
533
|
+
index: 0,
|
|
534
|
+
total: 1,
|
|
535
|
+
path: path != null ? path : "",
|
|
536
|
+
stage: (_a2 = d["stage"]) != null ? _a2 : "uploading",
|
|
537
|
+
bytesUploaded: (_b2 = d["bytesUploaded"]) != null ? _b2 : 0,
|
|
538
|
+
totalBytes: (_c = d["totalBytes"]) != null ? _c : 0,
|
|
539
|
+
percent: (_d = d["percent"]) != null ? _d : 0,
|
|
540
|
+
bytesPerSecond: (_e = d["bytesPerSecond"]) != null ? _e : null,
|
|
541
|
+
eta: (_f = d["eta"]) != null ? _f : null,
|
|
542
|
+
result: d["result"]
|
|
697
543
|
});
|
|
698
544
|
}
|
|
699
545
|
if (eventType === "done") finalResult = data;
|
|
700
546
|
if (eventType === "error") {
|
|
701
|
-
throw new
|
|
702
|
-
(
|
|
703
|
-
(
|
|
547
|
+
throw new HydrousDBError(
|
|
548
|
+
(_g = d["error"]) != null ? _g : "Upload failed",
|
|
549
|
+
(_h = d["code"]) != null ? _h : "UPLOAD_ERROR"
|
|
704
550
|
);
|
|
705
551
|
}
|
|
706
552
|
});
|
|
@@ -710,39 +556,31 @@ var StorageClient = class {
|
|
|
710
556
|
}
|
|
711
557
|
}
|
|
712
558
|
// ══════════════════════════════════════════════════════════════════════════
|
|
713
|
-
// UPLOAD
|
|
559
|
+
// UPLOAD TEXT / JSON
|
|
714
560
|
// ══════════════════════════════════════════════════════════════════════════
|
|
715
561
|
/**
|
|
716
|
-
* Upload raw text or JSON content directly — no
|
|
717
|
-
* Great for saving generated content, config files, or JSON records.
|
|
718
|
-
*
|
|
719
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
720
|
-
* @param path Destination path (e.g. `"configs/settings.json"`)
|
|
721
|
-
* @param content String content to store
|
|
722
|
-
* @param options `mimeType`, `overwrite`, `onProgress`
|
|
562
|
+
* Upload raw text or JSON content directly — no File object needed.
|
|
723
563
|
*
|
|
724
564
|
* @example
|
|
725
|
-
*
|
|
726
|
-
*
|
|
727
|
-
* '
|
|
728
|
-
*
|
|
729
|
-
* { mimeType: '
|
|
565
|
+
* // Save a JSON config
|
|
566
|
+
* await db.storage('configs').uploadText(
|
|
567
|
+
* 'settings/app.json',
|
|
568
|
+
* JSON.stringify({ theme: 'dark' }),
|
|
569
|
+
* { mimeType: 'application/json' }
|
|
730
570
|
* );
|
|
731
571
|
*/
|
|
732
|
-
async uploadText(
|
|
572
|
+
async uploadText(path, content, options = {}) {
|
|
733
573
|
var _a;
|
|
734
574
|
const { mimeType = "text/plain", overwrite = false, onProgress } = options;
|
|
735
575
|
try {
|
|
736
|
-
const
|
|
737
|
-
const headers = { ...storageHeaders(bucketKey), "Content-Type": "application/json" };
|
|
738
|
-
const res = await fetch(url, {
|
|
576
|
+
const res = await fetch(`${this.base}/upload-raw`, {
|
|
739
577
|
method: "POST",
|
|
740
|
-
headers,
|
|
578
|
+
headers: jsonHeaders(this.key),
|
|
741
579
|
body: JSON.stringify({ path, content, mimeType, overwrite })
|
|
742
580
|
});
|
|
743
581
|
if (!res.ok) {
|
|
744
582
|
const e = await res.json().catch(() => ({}));
|
|
745
|
-
throw new
|
|
583
|
+
throw new HydrousDBError((_a = e.error) != null ? _a : `HTTP ${res.status}`, "HTTP_ERROR", res.status);
|
|
746
584
|
}
|
|
747
585
|
let finalResult = null;
|
|
748
586
|
await readSSEStream(res, (eventType, data) => {
|
|
@@ -774,84 +612,62 @@ var StorageClient = class {
|
|
|
774
612
|
/**
|
|
775
613
|
* Upload multiple files in one request.
|
|
776
614
|
*
|
|
777
|
-
* `onProgress` fires
|
|
778
|
-
*
|
|
779
|
-
*
|
|
780
|
-
* so you can render all progress bars immediately.
|
|
781
|
-
*
|
|
782
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
783
|
-
* @param files Array of `File` objects (browser) or `{ name, data }` objects (Node)
|
|
784
|
-
* @param options Prefix, per-file paths, overwrite, concurrency, onProgress
|
|
615
|
+
* `onProgress` fires per file — use `p.index` to identify which file.
|
|
616
|
+
* All files receive a `pending` event upfront so you can render progress
|
|
617
|
+
* bars immediately before any data is sent.
|
|
785
618
|
*
|
|
786
619
|
* @example
|
|
787
|
-
* await
|
|
788
|
-
* '
|
|
789
|
-
*
|
|
790
|
-
*
|
|
791
|
-
* prefix: 'uploads/2024/',
|
|
792
|
-
* onProgress: (p) => {
|
|
793
|
-
* console.log(`File ${p.index}: ${p.stage} ${p.percent}%`);
|
|
794
|
-
* },
|
|
795
|
-
* }
|
|
796
|
-
* );
|
|
620
|
+
* await db.storage('documents').batchUpload(files, {
|
|
621
|
+
* prefix: 'reports/2024/',
|
|
622
|
+
* onProgress: (p) => updateBar(p.index, p.percent),
|
|
623
|
+
* });
|
|
797
624
|
*/
|
|
798
|
-
async batchUpload(
|
|
625
|
+
async batchUpload(files, options = {}) {
|
|
799
626
|
var _a;
|
|
800
627
|
const { prefix = "", paths, overwrite = false, onProgress } = options;
|
|
801
628
|
try {
|
|
802
|
-
const url =
|
|
629
|
+
const url = `${this.base}/batch-upload`;
|
|
630
|
+
const resolvedPaths = files.map((f, i) => {
|
|
631
|
+
var _a2;
|
|
632
|
+
return (_a2 = paths == null ? void 0 : paths[i]) != null ? _a2 : `${prefix}${f.name}`;
|
|
633
|
+
});
|
|
803
634
|
const form = new FormData();
|
|
804
|
-
const resolvedPaths = files.map(
|
|
805
|
-
(f, i) => {
|
|
806
|
-
var _a2;
|
|
807
|
-
return (_a2 = paths == null ? void 0 : paths[i]) != null ? _a2 : `${prefix}${f.name}`;
|
|
808
|
-
}
|
|
809
|
-
);
|
|
810
635
|
files.forEach((f) => form.append("files", f, f.name));
|
|
811
636
|
form.append("paths", JSON.stringify(resolvedPaths));
|
|
812
637
|
if (overwrite) form.append("overwrite", "true");
|
|
813
|
-
const headers = storageHeaders(
|
|
638
|
+
const headers = storageHeaders(this.key);
|
|
814
639
|
if (isBrowser) {
|
|
815
640
|
const totalBytes = files.reduce((s, f) => s + f.size, 0);
|
|
816
641
|
const rawBody = await xhrUpload(url, form, headers, (loaded, total) => {
|
|
817
|
-
if (onProgress)
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
});
|
|
838
|
-
cursor = myEnd;
|
|
839
|
-
}
|
|
642
|
+
if (!onProgress) return;
|
|
643
|
+
let cursor = 0;
|
|
644
|
+
for (let i = 0; i < files.length; i++) {
|
|
645
|
+
const share = files[i].size / (totalBytes || 1);
|
|
646
|
+
const fileLoaded = Math.max(0, Math.min(
|
|
647
|
+
files[i].size,
|
|
648
|
+
(loaded / (total || totalBytes) - cursor) / share * files[i].size
|
|
649
|
+
));
|
|
650
|
+
onProgress({
|
|
651
|
+
index: i,
|
|
652
|
+
total: files.length,
|
|
653
|
+
path: resolvedPaths[i],
|
|
654
|
+
stage: "uploading",
|
|
655
|
+
bytesUploaded: Math.round(fileLoaded),
|
|
656
|
+
totalBytes: files[i].size,
|
|
657
|
+
percent: Math.min(99, Math.round(fileLoaded / files[i].size * 100)),
|
|
658
|
+
bytesPerSecond: null,
|
|
659
|
+
eta: null
|
|
660
|
+
});
|
|
661
|
+
cursor += share;
|
|
840
662
|
}
|
|
841
663
|
});
|
|
842
|
-
const { results, errors } =
|
|
843
|
-
return {
|
|
844
|
-
data: {
|
|
845
|
-
succeeded: results,
|
|
846
|
-
failed: errors
|
|
847
|
-
},
|
|
848
|
-
error: null
|
|
849
|
-
};
|
|
664
|
+
const { results, errors } = drainSSE(rawBody, onProgress);
|
|
665
|
+
return { data: { succeeded: results, failed: errors }, error: null };
|
|
850
666
|
}
|
|
851
667
|
const res = await fetch(url, { method: "POST", headers, body: form });
|
|
852
668
|
if (!res.ok) {
|
|
853
669
|
const e = await res.json().catch(() => ({}));
|
|
854
|
-
throw new
|
|
670
|
+
throw new HydrousDBError((_a = e.error) != null ? _a : `HTTP ${res.status}`, "HTTP_ERROR", res.status);
|
|
855
671
|
}
|
|
856
672
|
const succeeded = [];
|
|
857
673
|
const failed = [];
|
|
@@ -868,10 +684,7 @@ var StorageClient = class {
|
|
|
868
684
|
totalBytes: (_f = d["totalBytes"]) != null ? _f : 0,
|
|
869
685
|
percent: (_g = d["percent"]) != null ? _g : 0,
|
|
870
686
|
bytesPerSecond: (_h = d["bytesPerSecond"]) != null ? _h : null,
|
|
871
|
-
eta: (_i = d["eta"]) != null ? _i : null
|
|
872
|
-
result: d["result"],
|
|
873
|
-
error: d["error"],
|
|
874
|
-
code: d["code"]
|
|
687
|
+
eta: (_i = d["eta"]) != null ? _i : null
|
|
875
688
|
});
|
|
876
689
|
}
|
|
877
690
|
if (eventType === "done" && d["succeeded"]) {
|
|
@@ -890,30 +703,22 @@ var StorageClient = class {
|
|
|
890
703
|
/**
|
|
891
704
|
* Download a single file and return its content as an `ArrayBuffer`.
|
|
892
705
|
*
|
|
893
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
894
|
-
* @param filePath Path of the file within your bucket
|
|
895
|
-
*
|
|
896
706
|
* @example
|
|
897
|
-
* const { data
|
|
898
|
-
*
|
|
899
|
-
*
|
|
900
|
-
* );
|
|
901
|
-
* if (data) {
|
|
902
|
-
* const blob = new Blob([data]);
|
|
903
|
-
* const url = URL.createObjectURL(blob);
|
|
904
|
-
* }
|
|
707
|
+
* const { data } = await db.storage('avatars').download('users/alice.jpg');
|
|
708
|
+
* const blob = new Blob([data!]);
|
|
709
|
+
* img.src = URL.createObjectURL(blob);
|
|
905
710
|
*/
|
|
906
|
-
async download(
|
|
711
|
+
async download(filePath) {
|
|
907
712
|
var _a;
|
|
908
713
|
try {
|
|
909
|
-
const
|
|
910
|
-
|
|
714
|
+
const res = await fetch(`${this.base}/download/${filePath}`, {
|
|
715
|
+
headers: storageHeaders(this.key)
|
|
716
|
+
});
|
|
911
717
|
if (!res.ok) {
|
|
912
718
|
const e = await res.json().catch(() => ({}));
|
|
913
|
-
throw new
|
|
719
|
+
throw new HydrousDBError((_a = e.error) != null ? _a : `HTTP ${res.status}`, "HTTP_ERROR", res.status);
|
|
914
720
|
}
|
|
915
|
-
|
|
916
|
-
return { data: buffer, error: null };
|
|
721
|
+
return { data: await res.arrayBuffer(), error: null };
|
|
917
722
|
} catch (err) {
|
|
918
723
|
return { data: null, error: toHydrousError(err) };
|
|
919
724
|
}
|
|
@@ -924,36 +729,26 @@ var StorageClient = class {
|
|
|
924
729
|
/**
|
|
925
730
|
* Download multiple files in one request.
|
|
926
731
|
*
|
|
927
|
-
*
|
|
928
|
-
* to the user's Downloads folder as it arrives.
|
|
929
|
-
*
|
|
930
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
931
|
-
* @param filePaths Array of file paths within your bucket
|
|
932
|
-
* @param options Concurrency, onProgress, autoSave
|
|
732
|
+
* Set `autoSave: true` (browser only) to trigger a Save dialog per file.
|
|
933
733
|
*
|
|
934
734
|
* @example
|
|
935
|
-
* const { data } = await
|
|
936
|
-
* '
|
|
937
|
-
*
|
|
938
|
-
* {
|
|
939
|
-
* onProgress: (p) => console.log(p.path, p.status),
|
|
940
|
-
* autoSave: true, // triggers browser file-save dialog per file
|
|
941
|
-
* }
|
|
735
|
+
* const { data } = await db.storage('reports').batchDownload(
|
|
736
|
+
* ['jan.pdf', 'feb.pdf'],
|
|
737
|
+
* { autoSave: true, onProgress: (p) => console.log(p.path, p.status) }
|
|
942
738
|
* );
|
|
943
739
|
*/
|
|
944
|
-
async batchDownload(
|
|
740
|
+
async batchDownload(filePaths, options = {}) {
|
|
945
741
|
var _a;
|
|
946
742
|
const { concurrency = 5, onProgress, autoSave = false } = options;
|
|
947
743
|
try {
|
|
948
|
-
const
|
|
949
|
-
const res = await fetch(url, {
|
|
744
|
+
const res = await fetch(`${this.base}/batch-download`, {
|
|
950
745
|
method: "POST",
|
|
951
|
-
headers:
|
|
746
|
+
headers: jsonHeaders(this.key),
|
|
952
747
|
body: JSON.stringify({ paths: filePaths, concurrency })
|
|
953
748
|
});
|
|
954
749
|
if (!res.ok) {
|
|
955
750
|
const e = await res.json().catch(() => ({}));
|
|
956
|
-
throw new
|
|
751
|
+
throw new HydrousDBError((_a = e.error) != null ? _a : `HTTP ${res.status}`, "HTTP_ERROR", res.status);
|
|
957
752
|
}
|
|
958
753
|
const downloadedFiles = [];
|
|
959
754
|
await readSSEStream(res, (eventType, data) => {
|
|
@@ -968,20 +763,10 @@ var StorageClient = class {
|
|
|
968
763
|
const binary = atob(base64);
|
|
969
764
|
const bytes = new Uint8Array(binary.length);
|
|
970
765
|
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
if (onProgress) {
|
|
974
|
-
onProgress({
|
|
975
|
-
index,
|
|
976
|
-
total: filePaths.length,
|
|
977
|
-
path,
|
|
978
|
-
status: "success",
|
|
979
|
-
size,
|
|
980
|
-
mimeType
|
|
981
|
-
});
|
|
982
|
-
}
|
|
766
|
+
downloadedFiles.push({ path, content: bytes.buffer, mimeType, size });
|
|
767
|
+
onProgress == null ? void 0 : onProgress({ index, total: filePaths.length, path, status: "success", size, mimeType });
|
|
983
768
|
if (autoSave && isBrowser) {
|
|
984
|
-
const blob = new Blob([
|
|
769
|
+
const blob = new Blob([bytes.buffer], { type: mimeType });
|
|
985
770
|
const blobUrl = URL.createObjectURL(blob);
|
|
986
771
|
const a = document.createElement("a");
|
|
987
772
|
a.href = blobUrl;
|
|
@@ -1010,37 +795,30 @@ var StorageClient = class {
|
|
|
1010
795
|
// LIST
|
|
1011
796
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1012
797
|
/**
|
|
1013
|
-
* List files and folders
|
|
1014
|
-
*
|
|
1015
|
-
* Results are paginated — use `pagination.nextCursor` to fetch the next page.
|
|
1016
|
-
*
|
|
1017
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1018
|
-
* @param options `prefix`, `limit`, `cursor`
|
|
798
|
+
* List files and folders (paginated).
|
|
1019
799
|
*
|
|
1020
800
|
* @example
|
|
1021
|
-
* const { data } = await
|
|
1022
|
-
*
|
|
1023
|
-
*
|
|
1024
|
-
* });
|
|
1025
|
-
* for (const item of data.items) {
|
|
1026
|
-
* console.log(item.type, item.path);
|
|
801
|
+
* const { data } = await db.storage('avatars').list({ prefix: 'users/' });
|
|
802
|
+
* for (const item of data!.items) {
|
|
803
|
+
* console.log(item.type, item.path, item.size);
|
|
1027
804
|
* }
|
|
1028
805
|
*/
|
|
1029
|
-
async list(
|
|
806
|
+
async list(options = {}) {
|
|
1030
807
|
const { prefix = "", limit = 50, cursor } = options;
|
|
1031
808
|
try {
|
|
1032
|
-
const
|
|
809
|
+
const url = buildUrl(this.base, "list", {
|
|
1033
810
|
prefix: prefix || void 0,
|
|
1034
811
|
limit,
|
|
1035
812
|
cursor: cursor || void 0
|
|
1036
|
-
};
|
|
1037
|
-
const
|
|
1038
|
-
this.
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
const
|
|
813
|
+
});
|
|
814
|
+
const res = await fetch(url.replace(this.base + "/list", `${this.base}/list`), {
|
|
815
|
+
headers: storageHeaders(this.key)
|
|
816
|
+
});
|
|
817
|
+
const u = `${this.base}/list?${new URLSearchParams(
|
|
818
|
+
Object.entries({ prefix: prefix || "", limit: String(limit), ...cursor ? { cursor } : {} }).filter(([, v]) => v !== "")
|
|
819
|
+
).toString()}`;
|
|
820
|
+
const r = await fetch(u, { headers: storageHeaders(this.key) });
|
|
821
|
+
const json = await parseResponse(r);
|
|
1044
822
|
return { data: json, error: null };
|
|
1045
823
|
} catch (err) {
|
|
1046
824
|
return { data: null, error: toHydrousError(err) };
|
|
@@ -1050,22 +828,17 @@ var StorageClient = class {
|
|
|
1050
828
|
// METADATA
|
|
1051
829
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1052
830
|
/**
|
|
1053
|
-
* Get metadata for a
|
|
1054
|
-
*
|
|
1055
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1056
|
-
* @param filePath Path of the file within your bucket
|
|
831
|
+
* Get metadata for a file (size, MIME type, compression, etc.)
|
|
1057
832
|
*
|
|
1058
833
|
* @example
|
|
1059
|
-
* const { data } = await
|
|
1060
|
-
*
|
|
1061
|
-
* 'avatars/alice.jpg'
|
|
1062
|
-
* );
|
|
1063
|
-
* console.log(data.size, data.mimeType);
|
|
834
|
+
* const { data: meta } = await db.storage('docs').metadata('report.pdf');
|
|
835
|
+
* console.log(meta!.size, meta!.mimeType, meta!.isCompressed);
|
|
1064
836
|
*/
|
|
1065
|
-
async metadata(
|
|
837
|
+
async metadata(filePath) {
|
|
1066
838
|
try {
|
|
1067
|
-
const
|
|
1068
|
-
|
|
839
|
+
const res = await fetch(`${this.base}/metadata/${filePath}`, {
|
|
840
|
+
headers: storageHeaders(this.key)
|
|
841
|
+
});
|
|
1069
842
|
const json = await parseResponse(res);
|
|
1070
843
|
return { data: json.data, error: null };
|
|
1071
844
|
} catch (err) {
|
|
@@ -1073,23 +846,14 @@ var StorageClient = class {
|
|
|
1073
846
|
}
|
|
1074
847
|
}
|
|
1075
848
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1076
|
-
// DELETE
|
|
849
|
+
// DELETE
|
|
1077
850
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1078
|
-
/**
|
|
1079
|
-
|
|
1080
|
-
*
|
|
1081
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1082
|
-
* @param filePath Path of the file to delete
|
|
1083
|
-
*
|
|
1084
|
-
* @example
|
|
1085
|
-
* await hydrous.storage.deleteFile('ssk_my_bucket_key', 'avatars/old.jpg');
|
|
1086
|
-
*/
|
|
1087
|
-
async deleteFile(bucketKey, filePath) {
|
|
851
|
+
/** Delete a single file */
|
|
852
|
+
async deleteFile(filePath) {
|
|
1088
853
|
try {
|
|
1089
|
-
const
|
|
1090
|
-
const res = await fetch(url, {
|
|
854
|
+
const res = await fetch(`${this.base}/file`, {
|
|
1091
855
|
method: "DELETE",
|
|
1092
|
-
headers:
|
|
856
|
+
headers: jsonHeaders(this.key),
|
|
1093
857
|
body: JSON.stringify({ path: filePath })
|
|
1094
858
|
});
|
|
1095
859
|
await parseResponse(res);
|
|
@@ -1098,24 +862,12 @@ var StorageClient = class {
|
|
|
1098
862
|
return { data: null, error: toHydrousError(err) };
|
|
1099
863
|
}
|
|
1100
864
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
1104
|
-
/**
|
|
1105
|
-
* Recursively delete a folder and all of its contents.
|
|
1106
|
-
*
|
|
1107
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1108
|
-
* @param folderPath Folder path to delete (e.g. `"old-uploads/"`)
|
|
1109
|
-
*
|
|
1110
|
-
* @example
|
|
1111
|
-
* await hydrous.storage.deleteFolder('ssk_my_bucket_key', 'temp/');
|
|
1112
|
-
*/
|
|
1113
|
-
async deleteFolder(bucketKey, folderPath) {
|
|
865
|
+
/** Recursively delete a folder and all its contents */
|
|
866
|
+
async deleteFolder(folderPath) {
|
|
1114
867
|
try {
|
|
1115
|
-
const
|
|
1116
|
-
const res = await fetch(url, {
|
|
868
|
+
const res = await fetch(`${this.base}/folder`, {
|
|
1117
869
|
method: "DELETE",
|
|
1118
|
-
headers:
|
|
870
|
+
headers: jsonHeaders(this.key),
|
|
1119
871
|
body: JSON.stringify({ path: folderPath })
|
|
1120
872
|
});
|
|
1121
873
|
await parseResponse(res);
|
|
@@ -1124,24 +876,12 @@ var StorageClient = class {
|
|
|
1124
876
|
return { data: null, error: toHydrousError(err) };
|
|
1125
877
|
}
|
|
1126
878
|
}
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
1130
|
-
/**
|
|
1131
|
-
* Create an empty folder.
|
|
1132
|
-
*
|
|
1133
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1134
|
-
* @param folderPath Path for the new folder (e.g. `"avatars/2024/"`)
|
|
1135
|
-
*
|
|
1136
|
-
* @example
|
|
1137
|
-
* await hydrous.storage.createFolder('ssk_my_bucket_key', 'avatars/2024/');
|
|
1138
|
-
*/
|
|
1139
|
-
async createFolder(bucketKey, folderPath) {
|
|
879
|
+
/** Create an empty folder */
|
|
880
|
+
async createFolder(folderPath) {
|
|
1140
881
|
try {
|
|
1141
|
-
const
|
|
1142
|
-
const res = await fetch(url, {
|
|
882
|
+
const res = await fetch(`${this.base}/folder`, {
|
|
1143
883
|
method: "POST",
|
|
1144
|
-
headers:
|
|
884
|
+
headers: jsonHeaders(this.key),
|
|
1145
885
|
body: JSON.stringify({ path: folderPath })
|
|
1146
886
|
});
|
|
1147
887
|
await parseResponse(res);
|
|
@@ -1151,28 +891,14 @@ var StorageClient = class {
|
|
|
1151
891
|
}
|
|
1152
892
|
}
|
|
1153
893
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1154
|
-
// MOVE
|
|
894
|
+
// MOVE & COPY
|
|
1155
895
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1156
|
-
/**
|
|
1157
|
-
|
|
1158
|
-
*
|
|
1159
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1160
|
-
* @param fromPath Current path of the file
|
|
1161
|
-
* @param toPath New path for the file
|
|
1162
|
-
*
|
|
1163
|
-
* @example
|
|
1164
|
-
* await hydrous.storage.move(
|
|
1165
|
-
* 'ssk_my_bucket_key',
|
|
1166
|
-
* 'drafts/report.pdf',
|
|
1167
|
-
* 'published/report.pdf'
|
|
1168
|
-
* );
|
|
1169
|
-
*/
|
|
1170
|
-
async move(bucketKey, fromPath, toPath) {
|
|
896
|
+
/** Move (rename) a file */
|
|
897
|
+
async move(fromPath, toPath) {
|
|
1171
898
|
try {
|
|
1172
|
-
const
|
|
1173
|
-
const res = await fetch(url, {
|
|
899
|
+
const res = await fetch(`${this.base}/move`, {
|
|
1174
900
|
method: "POST",
|
|
1175
|
-
headers:
|
|
901
|
+
headers: jsonHeaders(this.key),
|
|
1176
902
|
body: JSON.stringify({ from: fromPath, to: toPath })
|
|
1177
903
|
});
|
|
1178
904
|
await parseResponse(res);
|
|
@@ -1181,29 +907,12 @@ var StorageClient = class {
|
|
|
1181
907
|
return { data: null, error: toHydrousError(err) };
|
|
1182
908
|
}
|
|
1183
909
|
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
// ══════════════════════════════════════════════════════════════════════════
|
|
1187
|
-
/**
|
|
1188
|
-
* Copy a file to a new path (original is kept).
|
|
1189
|
-
*
|
|
1190
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1191
|
-
* @param fromPath Source path
|
|
1192
|
-
* @param toPath Destination path
|
|
1193
|
-
*
|
|
1194
|
-
* @example
|
|
1195
|
-
* await hydrous.storage.copy(
|
|
1196
|
-
* 'ssk_my_bucket_key',
|
|
1197
|
-
* 'templates/invoice.pdf',
|
|
1198
|
-
* 'invoices/invoice-001.pdf'
|
|
1199
|
-
* );
|
|
1200
|
-
*/
|
|
1201
|
-
async copy(bucketKey, fromPath, toPath) {
|
|
910
|
+
/** Copy a file (original is kept) */
|
|
911
|
+
async copy(fromPath, toPath) {
|
|
1202
912
|
try {
|
|
1203
|
-
const
|
|
1204
|
-
const res = await fetch(url, {
|
|
913
|
+
const res = await fetch(`${this.base}/copy`, {
|
|
1205
914
|
method: "POST",
|
|
1206
|
-
headers:
|
|
915
|
+
headers: jsonHeaders(this.key),
|
|
1207
916
|
body: JSON.stringify({ from: fromPath, to: toPath })
|
|
1208
917
|
});
|
|
1209
918
|
await parseResponse(res);
|
|
@@ -1218,25 +927,16 @@ var StorageClient = class {
|
|
|
1218
927
|
/**
|
|
1219
928
|
* Generate a time-limited public URL for a private file.
|
|
1220
929
|
*
|
|
1221
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
1222
|
-
* @param filePath Path of the file
|
|
1223
|
-
* @param options `expiresIn` seconds (default: 3600)
|
|
1224
|
-
*
|
|
1225
930
|
* @example
|
|
1226
|
-
* const { data } = await
|
|
1227
|
-
*
|
|
1228
|
-
* 'private/contract.pdf',
|
|
1229
|
-
* { expiresIn: 300 } // 5 minutes
|
|
1230
|
-
* );
|
|
1231
|
-
* console.log(data.signedUrl); // share this URL
|
|
931
|
+
* const { data } = await db.storage('contracts').signedUrl('nda.pdf', { expiresIn: 300 });
|
|
932
|
+
* console.log(data!.signedUrl); // share this
|
|
1232
933
|
*/
|
|
1233
|
-
async signedUrl(
|
|
934
|
+
async signedUrl(filePath, options = {}) {
|
|
1234
935
|
const { expiresIn = 3600 } = options;
|
|
1235
936
|
try {
|
|
1236
|
-
const
|
|
1237
|
-
const res = await fetch(url, {
|
|
937
|
+
const res = await fetch(`${this.base}/signed-url`, {
|
|
1238
938
|
method: "POST",
|
|
1239
|
-
headers:
|
|
939
|
+
headers: jsonHeaders(this.key),
|
|
1240
940
|
body: JSON.stringify({ path: filePath, expiresInSeconds: expiresIn })
|
|
1241
941
|
});
|
|
1242
942
|
const json = await parseResponse(res);
|
|
@@ -1249,18 +949,17 @@ var StorageClient = class {
|
|
|
1249
949
|
// STATS
|
|
1250
950
|
// ══════════════════════════════════════════════════════════════════════════
|
|
1251
951
|
/**
|
|
1252
|
-
* Get usage and billing
|
|
1253
|
-
*
|
|
1254
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
952
|
+
* Get usage and billing stats for this storage key.
|
|
1255
953
|
*
|
|
1256
954
|
* @example
|
|
1257
|
-
* const { data } = await
|
|
1258
|
-
* console.log(
|
|
955
|
+
* const { data } = await db.storage('main').stats();
|
|
956
|
+
* console.log(data!.totalFiles, data!.totalSizeBytes);
|
|
1259
957
|
*/
|
|
1260
|
-
async stats(
|
|
958
|
+
async stats() {
|
|
1261
959
|
try {
|
|
1262
|
-
const
|
|
1263
|
-
|
|
960
|
+
const res = await fetch(`${this.base}/stats`, {
|
|
961
|
+
headers: storageHeaders(this.key)
|
|
962
|
+
});
|
|
1264
963
|
const json = await parseResponse(res);
|
|
1265
964
|
return { data: json.data, error: null };
|
|
1266
965
|
} catch (err) {
|
|
@@ -1269,15 +968,63 @@ var StorageClient = class {
|
|
|
1269
968
|
}
|
|
1270
969
|
};
|
|
1271
970
|
|
|
971
|
+
// src/storage/manager.ts
|
|
972
|
+
var StorageManager = class {
|
|
973
|
+
constructor(config) {
|
|
974
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
975
|
+
this.baseUrl = config.url;
|
|
976
|
+
this._keys = config.storageKeys;
|
|
977
|
+
}
|
|
978
|
+
/**
|
|
979
|
+
* Get a storage client scoped to a named key.
|
|
980
|
+
*
|
|
981
|
+
* @param keyName - Must match a property you declared in `storageKeys`
|
|
982
|
+
*
|
|
983
|
+
* @example
|
|
984
|
+
* const avatarStore = db.storage('avatars');
|
|
985
|
+
* const documentStore = db.storage('documents');
|
|
986
|
+
*
|
|
987
|
+
* await avatarStore.upload(file, { path: 'users/alice.jpg' });
|
|
988
|
+
* const list = await documentStore.list({ prefix: 'invoices/' });
|
|
989
|
+
*/
|
|
990
|
+
use(keyName) {
|
|
991
|
+
const bucketKey = this._keys[keyName];
|
|
992
|
+
if (!bucketKey) {
|
|
993
|
+
const available = Object.keys(this._keys).join(", ");
|
|
994
|
+
throw new HydrousDBError(
|
|
995
|
+
`Storage key "${keyName}" is not defined.
|
|
996
|
+
Available: ${available || "(none)"}`,
|
|
997
|
+
"UNKNOWN_STORAGE_KEY"
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
if (!this.cache.has(keyName)) {
|
|
1001
|
+
this.cache.set(keyName, new ScopedStorageClient(this.baseUrl, keyName, bucketKey));
|
|
1002
|
+
}
|
|
1003
|
+
return this.cache.get(keyName);
|
|
1004
|
+
}
|
|
1005
|
+
/** Return the names of all configured storage keys */
|
|
1006
|
+
keyNames() {
|
|
1007
|
+
return Object.keys(this._keys);
|
|
1008
|
+
}
|
|
1009
|
+
};
|
|
1010
|
+
|
|
1272
1011
|
// src/client.ts
|
|
1273
1012
|
var HydrousClient = class {
|
|
1274
1013
|
constructor(config) {
|
|
1275
|
-
if (!config.url) throw new Error("[
|
|
1276
|
-
if (!config.
|
|
1014
|
+
if (!config.url) throw new Error("[HydrousDB] config.url is required");
|
|
1015
|
+
if (!config.authKey) throw new Error("[HydrousDB] config.authKey is required");
|
|
1016
|
+
if (!config.bucketSecurityKey) throw new Error("[HydrousDB] config.bucketSecurityKey is required");
|
|
1017
|
+
if (!config.storageKeys || typeof config.storageKeys !== "object") {
|
|
1018
|
+
throw new Error("[HydrousDB] config.storageKeys must be an object of named keys");
|
|
1019
|
+
}
|
|
1277
1020
|
this.auth = new AuthClient(config);
|
|
1278
1021
|
this.records = new RecordsClient(config);
|
|
1279
1022
|
this.analytics = new AnalyticsClient(config);
|
|
1280
|
-
|
|
1023
|
+
const manager = new StorageManager(config);
|
|
1024
|
+
const fn = (keyName) => manager.use(keyName);
|
|
1025
|
+
fn.use = (keyName) => manager.use(keyName);
|
|
1026
|
+
fn.keyNames = () => manager.keyNames();
|
|
1027
|
+
this.storage = fn;
|
|
1281
1028
|
}
|
|
1282
1029
|
};
|
|
1283
1030
|
|
|
@@ -1286,6 +1033,6 @@ function createClient(config) {
|
|
|
1286
1033
|
return new HydrousClient(config);
|
|
1287
1034
|
}
|
|
1288
1035
|
|
|
1289
|
-
export { AnalyticsClient, AuthClient, HydrousClient,
|
|
1036
|
+
export { AnalyticsClient, AuthClient, HydrousClient, HydrousDBError, RecordsClient, ScopedStorageClient, StorageManager, createClient, eq, gt, gte, inArray, isHydrousError, lt, lte, neq };
|
|
1290
1037
|
//# sourceMappingURL=index.mjs.map
|
|
1291
1038
|
//# sourceMappingURL=index.mjs.map
|