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