hydrousdb 3.0.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +877 -499
- package/dist/index.cjs +539 -427
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +292 -325
- package/dist/index.d.ts +292 -325
- package/dist/{index.js → index.mjs} +541 -429
- package/dist/index.mjs.map +1 -0
- package/package.json +7 -6
- package/dist/index.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,68 +1,34 @@
|
|
|
1
1
|
interface RequestOptions {
|
|
2
|
-
method
|
|
2
|
+
method: string;
|
|
3
3
|
body?: unknown;
|
|
4
|
+
rawBody?: FormData | Uint8Array | ArrayBuffer;
|
|
4
5
|
headers?: Record<string, string>;
|
|
5
|
-
rawBody?: string | FormData | Uint8Array<ArrayBuffer>;
|
|
6
|
-
contentType?: string;
|
|
7
6
|
}
|
|
8
7
|
declare class HttpClient {
|
|
9
8
|
private readonly baseUrl;
|
|
10
9
|
constructor(baseUrl: string);
|
|
11
|
-
request<T
|
|
12
|
-
get<T
|
|
13
|
-
post<T
|
|
14
|
-
put<T
|
|
15
|
-
patch<T
|
|
16
|
-
delete<T
|
|
17
|
-
|
|
10
|
+
request<T>(path: string, options: RequestOptions): Promise<T>;
|
|
11
|
+
get<T>(path: string, apiKey?: string, extraHeaders?: Record<string, string>): Promise<T>;
|
|
12
|
+
post<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
|
|
13
|
+
put<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
|
|
14
|
+
patch<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
|
|
15
|
+
delete<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Upload directly to a signed GCS URL (no auth headers — signed URL is self-authenticating).
|
|
18
|
+
* Supports optional progress tracking via XHR in browser environments.
|
|
19
|
+
*/
|
|
20
|
+
putToSignedUrl(signedUrl: string, data: Blob | Uint8Array | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
/**
|
|
21
|
-
* Storage keys map — one named key per storage bucket/permission scope.
|
|
22
|
-
* Keys start with `ssk_`. You can define as many as you need.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```ts
|
|
26
|
-
* storageKeys: {
|
|
27
|
-
* main: 'ssk_main_…',
|
|
28
|
-
* avatars: 'ssk_avatars_…',
|
|
29
|
-
* documents: 'ssk_docs_…',
|
|
30
|
-
* }
|
|
31
|
-
* ```
|
|
32
|
-
*/
|
|
33
23
|
type StorageKeys = Record<string, string>;
|
|
34
24
|
interface HydrousConfig {
|
|
35
|
-
/**
|
|
36
|
-
* Auth service key (starts with `hk_auth_`).
|
|
37
|
-
* Used exclusively for all `/auth/*` routes — signup, login, sessions, etc.
|
|
38
|
-
* Obtain from your dashboard at https://hydrousdb.com/dashboard.
|
|
39
|
-
*/
|
|
25
|
+
/** Auth service key (starts with `hk_auth_`). */
|
|
40
26
|
authKey: string;
|
|
41
|
-
/**
|
|
42
|
-
* Bucket security key (starts with `hk_bucket_`).
|
|
43
|
-
* Used for all `/records/*` and `/analytics/*` routes.
|
|
44
|
-
* Obtain from your dashboard at https://hydrousdb.com/dashboard.
|
|
45
|
-
*/
|
|
27
|
+
/** Bucket security key (starts with `hk_bucket_`). Used for records + analytics. */
|
|
46
28
|
bucketSecurityKey: string;
|
|
47
|
-
/**
|
|
48
|
-
* Named storage keys (each starts with `ssk_`).
|
|
49
|
-
* Define one key per storage bucket/permission scope.
|
|
50
|
-
* Pass the name of the key you want when calling `db.storage('keyName')`.
|
|
51
|
-
*
|
|
52
|
-
* @example
|
|
53
|
-
* ```ts
|
|
54
|
-
* storageKeys: {
|
|
55
|
-
* main: 'ssk_main_…', // default general-purpose bucket
|
|
56
|
-
* avatars: 'ssk_avatars_…', // user avatar uploads
|
|
57
|
-
* documents: 'ssk_docs_…', // private documents
|
|
58
|
-
* }
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
29
|
+
/** Named storage keys (each starts with `ssk_`). */
|
|
61
30
|
storageKeys: StorageKeys;
|
|
62
|
-
/**
|
|
63
|
-
* Override the API base URL. Defaults to the official HydrousDB endpoint.
|
|
64
|
-
* You almost never need to set this.
|
|
65
|
-
*/
|
|
31
|
+
/** Override the API base URL. Defaults to the official HydrousDB endpoint. */
|
|
66
32
|
baseUrl?: string;
|
|
67
33
|
}
|
|
68
34
|
interface SignupOptions {
|
|
@@ -103,24 +69,26 @@ interface AuthResult {
|
|
|
103
69
|
interface UpdateUserOptions {
|
|
104
70
|
sessionId: string;
|
|
105
71
|
userId: string;
|
|
106
|
-
|
|
72
|
+
/** Fields to update — nested under `updates` when sent to the server. */
|
|
73
|
+
updates: Partial<Omit<UserRecord, 'id' | 'email' | 'createdAt'>>;
|
|
107
74
|
}
|
|
108
75
|
interface ChangePasswordOptions {
|
|
109
76
|
sessionId: string;
|
|
110
77
|
userId: string;
|
|
78
|
+
/** Maps to `oldPassword` on the server. */
|
|
111
79
|
currentPassword: string;
|
|
112
80
|
newPassword: string;
|
|
113
81
|
}
|
|
114
82
|
interface ListUsersOptions {
|
|
115
83
|
sessionId: string;
|
|
116
84
|
limit?: number;
|
|
117
|
-
|
|
85
|
+
/** Cursor for the next page (URL-encoded value returned by the previous call). */
|
|
86
|
+
cursor?: string;
|
|
118
87
|
}
|
|
119
88
|
interface ListUsersResult {
|
|
120
89
|
users: UserRecord[];
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
offset: number;
|
|
90
|
+
hasMore: boolean;
|
|
91
|
+
nextCursor: string | null;
|
|
124
92
|
}
|
|
125
93
|
type RecordData = Record<string, unknown>;
|
|
126
94
|
interface RecordResult {
|
|
@@ -161,12 +129,34 @@ interface RecordHistoryEntry {
|
|
|
161
129
|
createdAt: number;
|
|
162
130
|
data: RecordData;
|
|
163
131
|
}
|
|
132
|
+
/** Options for creating a record — includes queryable fields for filtering. */
|
|
133
|
+
interface CreateRecordOptions {
|
|
134
|
+
/**
|
|
135
|
+
* Fields that should be indexed for server-side filtering.
|
|
136
|
+
* Only fields listed here will be queryable via `query({ filters: [...] })`.
|
|
137
|
+
*/
|
|
138
|
+
queryableFields?: string[];
|
|
139
|
+
/** Email of the user performing the action (for audit trails). */
|
|
140
|
+
userEmail?: string;
|
|
141
|
+
/**
|
|
142
|
+
* Assign a custom record ID instead of an auto-generated one.
|
|
143
|
+
* If the ID already exists, the record will be upserted.
|
|
144
|
+
*/
|
|
145
|
+
customRecordId?: string;
|
|
146
|
+
}
|
|
147
|
+
/** Options for batch-creating records. */
|
|
148
|
+
interface BatchCreateOptions {
|
|
149
|
+
/** Fields to index for filtering — applied to all records in the batch. */
|
|
150
|
+
queryableFields?: string[];
|
|
151
|
+
/** Email of the user performing the action. */
|
|
152
|
+
userEmail?: string;
|
|
153
|
+
}
|
|
164
154
|
interface UploadOptions {
|
|
165
|
-
/**
|
|
155
|
+
/** Make the file publicly accessible without authentication. */
|
|
166
156
|
isPublic?: boolean;
|
|
167
|
-
/**
|
|
157
|
+
/** Overwrite an existing file at the same path. */
|
|
168
158
|
overwrite?: boolean;
|
|
169
|
-
/** MIME type of the file. Auto-detected if omitted. */
|
|
159
|
+
/** MIME type of the file. Auto-detected from extension if omitted. */
|
|
170
160
|
mimeType?: string;
|
|
171
161
|
/** TTL in seconds for the signed upload URL (default 900 = 15 min). */
|
|
172
162
|
expiresInSeconds?: number;
|
|
@@ -195,6 +185,7 @@ interface ListOptions {
|
|
|
195
185
|
interface FileEntry {
|
|
196
186
|
name: string;
|
|
197
187
|
path: string;
|
|
188
|
+
type?: 'file' | 'folder';
|
|
198
189
|
size?: number;
|
|
199
190
|
mimeType?: string;
|
|
200
191
|
isPublic?: boolean;
|
|
@@ -243,14 +234,27 @@ interface BatchUploadUrlResult {
|
|
|
243
234
|
index: number;
|
|
244
235
|
}>;
|
|
245
236
|
}
|
|
237
|
+
interface BatchDownloadResult {
|
|
238
|
+
succeeded: Array<{
|
|
239
|
+
index: number;
|
|
240
|
+
path: string;
|
|
241
|
+
mimeType: string;
|
|
242
|
+
size: number;
|
|
243
|
+
content: string;
|
|
244
|
+
}>;
|
|
245
|
+
failed: Array<{
|
|
246
|
+
index: number;
|
|
247
|
+
path: string;
|
|
248
|
+
error: string;
|
|
249
|
+
code?: string;
|
|
250
|
+
}>;
|
|
251
|
+
}
|
|
246
252
|
type QueryType = 'count' | 'distribution' | 'sum' | 'timeSeries' | 'fieldTimeSeries' | 'topN' | 'stats' | 'records' | 'multiMetric' | 'storageStats' | 'crossBucket';
|
|
247
253
|
type Aggregation = 'sum' | 'avg' | 'min' | 'max' | 'count';
|
|
248
254
|
type Granularity = 'hour' | 'day' | 'week' | 'month' | 'year';
|
|
249
255
|
type SortOrder = 'asc' | 'desc';
|
|
250
256
|
interface DateRange {
|
|
251
|
-
/** Start timestamp in milliseconds (Unix epoch). */
|
|
252
257
|
start?: number;
|
|
253
|
-
/** End timestamp in milliseconds (Unix epoch). */
|
|
254
258
|
end?: number;
|
|
255
259
|
}
|
|
256
260
|
interface AnalyticsFilter {
|
|
@@ -259,11 +263,8 @@ interface AnalyticsFilter {
|
|
|
259
263
|
value: string | number | boolean;
|
|
260
264
|
}
|
|
261
265
|
interface MetricDefinition {
|
|
262
|
-
/** Field name in your records to aggregate. */
|
|
263
266
|
field: string;
|
|
264
|
-
/** Alias used in the result object. Must be a safe identifier. */
|
|
265
267
|
name: string;
|
|
266
|
-
/** Aggregation function. Defaults to 'count'. */
|
|
267
268
|
aggregation?: Aggregation;
|
|
268
269
|
}
|
|
269
270
|
interface AnalyticsQuery {
|
|
@@ -282,7 +283,6 @@ interface AnalyticsQuery {
|
|
|
282
283
|
order?: SortOrder;
|
|
283
284
|
n?: number;
|
|
284
285
|
metrics?: MetricDefinition[];
|
|
285
|
-
/** For crossBucket queries: list of bucket names to compare. */
|
|
286
286
|
bucketKeys?: string[];
|
|
287
287
|
}
|
|
288
288
|
interface AnalyticsResult<T = unknown> {
|
|
@@ -340,10 +340,13 @@ interface CrossBucketRow {
|
|
|
340
340
|
* AuthClient — full user authentication for a single bucket.
|
|
341
341
|
* Uses the `authKey` (`hk_auth_…`) sent via `X-Api-Key` header.
|
|
342
342
|
*
|
|
343
|
+
* All routes are under `/auth/:bucketKey/` — the bucketKey is the user bucket
|
|
344
|
+
* name you passed when calling `db.auth('bucketKey')`.
|
|
345
|
+
*
|
|
343
346
|
* @example
|
|
344
347
|
* ```ts
|
|
345
|
-
* const db
|
|
346
|
-
* const auth = db.auth('
|
|
348
|
+
* const db = createClient({ authKey: 'hk_auth_…', … });
|
|
349
|
+
* const auth = db.auth('app-users');
|
|
347
350
|
* const { user, session } = await auth.signup({ email: 'alice@example.com', password: 'hunter2' });
|
|
348
351
|
* ```
|
|
349
352
|
*/
|
|
@@ -358,12 +361,22 @@ declare class AuthClient {
|
|
|
358
361
|
private delete;
|
|
359
362
|
signup(options: SignupOptions): Promise<AuthResult>;
|
|
360
363
|
login(options: LoginOptions): Promise<AuthResult>;
|
|
361
|
-
logout(
|
|
364
|
+
logout(options: {
|
|
362
365
|
sessionId: string;
|
|
366
|
+
allDevices?: boolean;
|
|
363
367
|
}): Promise<void>;
|
|
364
368
|
refreshSession({ refreshToken }: {
|
|
365
369
|
refreshToken: string;
|
|
366
370
|
}): Promise<Session>;
|
|
371
|
+
validateSession({ sessionId }: {
|
|
372
|
+
sessionId: string;
|
|
373
|
+
}): Promise<{
|
|
374
|
+
user: UserRecord;
|
|
375
|
+
session: {
|
|
376
|
+
sessionId: string;
|
|
377
|
+
expiresAt: number;
|
|
378
|
+
};
|
|
379
|
+
}>;
|
|
367
380
|
getUser({ userId }: {
|
|
368
381
|
userId: string;
|
|
369
382
|
}): Promise<UserRecord>;
|
|
@@ -377,14 +390,15 @@ declare class AuthClient {
|
|
|
377
390
|
sessionId: string;
|
|
378
391
|
userId: string;
|
|
379
392
|
}): Promise<void>;
|
|
380
|
-
bulkDeleteUsers(
|
|
393
|
+
bulkDeleteUsers(options: {
|
|
381
394
|
sessionId: string;
|
|
382
395
|
userIds: string[];
|
|
396
|
+
hard?: boolean;
|
|
383
397
|
}): Promise<{
|
|
384
|
-
|
|
385
|
-
failed:
|
|
398
|
+
succeeded: number;
|
|
399
|
+
failed: number;
|
|
386
400
|
}>;
|
|
387
|
-
lockAccount(
|
|
401
|
+
lockAccount(options: {
|
|
388
402
|
sessionId: string;
|
|
389
403
|
userId: string;
|
|
390
404
|
duration?: number;
|
|
@@ -413,49 +427,121 @@ declare class AuthClient {
|
|
|
413
427
|
}
|
|
414
428
|
|
|
415
429
|
/**
|
|
416
|
-
* RecordsClient — CRUD + query for a single bucket.
|
|
430
|
+
* RecordsClient — typed CRUD + query + batch for a single bucket.
|
|
417
431
|
* Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
|
|
418
432
|
*
|
|
419
433
|
* @example
|
|
420
434
|
* ```ts
|
|
421
|
-
*
|
|
422
|
-
* const posts = db.records('blog-posts');
|
|
423
|
-
* const post
|
|
435
|
+
* interface Post { title: string; published: boolean }
|
|
436
|
+
* const posts = db.records<Post>('blog-posts');
|
|
437
|
+
* const post = await posts.create({ title: 'Hello', published: false });
|
|
424
438
|
* ```
|
|
425
439
|
*/
|
|
426
440
|
declare class RecordsClient<T extends RecordData = RecordData> {
|
|
427
441
|
private readonly http;
|
|
428
442
|
private readonly bucketKey;
|
|
443
|
+
private readonly apiKey;
|
|
429
444
|
private readonly basePath;
|
|
430
|
-
private readonly bucketKey_;
|
|
431
445
|
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
432
|
-
|
|
433
|
-
|
|
446
|
+
/**
|
|
447
|
+
* Create a new record.
|
|
448
|
+
*
|
|
449
|
+
* @param data The record fields to store.
|
|
450
|
+
* @param options Optional: queryableFields (for server-side filtering),
|
|
451
|
+
* userEmail (audit trail), customRecordId (upsert by ID).
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* ```ts
|
|
455
|
+
* const post = await posts.create(
|
|
456
|
+
* { title: 'Hello', status: 'draft', authorId: 'u1' },
|
|
457
|
+
* { queryableFields: ['status', 'authorId'], userEmail: 'alice@example.com' },
|
|
458
|
+
* );
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
create(data: T, options?: CreateRecordOptions): Promise<T & RecordResult>;
|
|
462
|
+
/**
|
|
463
|
+
* Get a single record by ID.
|
|
464
|
+
*/
|
|
434
465
|
get(id: string): Promise<T & RecordResult>;
|
|
466
|
+
/**
|
|
467
|
+
* Fully replace a record (PUT semantics).
|
|
468
|
+
*/
|
|
435
469
|
set(id: string, data: T): Promise<T & RecordResult>;
|
|
470
|
+
/**
|
|
471
|
+
* Partially update a record (PATCH semantics).
|
|
472
|
+
* By default merges with existing fields; set `merge: false` to replace.
|
|
473
|
+
* Supports write-filter sentinels: `{ __op: 'increment', delta: 1 }` etc.
|
|
474
|
+
*/
|
|
436
475
|
patch(id: string, data: Partial<T>, options?: PatchRecordOptions): Promise<T & RecordResult>;
|
|
476
|
+
/**
|
|
477
|
+
* Delete a record permanently.
|
|
478
|
+
*/
|
|
437
479
|
delete(id: string): Promise<void>;
|
|
438
|
-
|
|
480
|
+
/**
|
|
481
|
+
* Create multiple records in one request (max 500).
|
|
482
|
+
* Each record can include a `_customRecordId` field for upsert behaviour.
|
|
483
|
+
*
|
|
484
|
+
* @example
|
|
485
|
+
* ```ts
|
|
486
|
+
* const created = await posts.batchCreate(
|
|
487
|
+
* [{ title: 'A' }, { title: 'B' }],
|
|
488
|
+
* { queryableFields: ['title'], userEmail: 'alice@example.com' },
|
|
489
|
+
* );
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
batchCreate(items: T[], options?: BatchCreateOptions): Promise<(T & RecordResult)[]>;
|
|
493
|
+
/**
|
|
494
|
+
* Delete multiple records in one request (max 500).
|
|
495
|
+
*/
|
|
439
496
|
batchDelete(ids: string[]): Promise<{
|
|
440
497
|
deleted: number;
|
|
441
498
|
failed: string[];
|
|
442
499
|
}>;
|
|
500
|
+
/**
|
|
501
|
+
* Query records with optional filters, sorting, and pagination.
|
|
502
|
+
*
|
|
503
|
+
* @example
|
|
504
|
+
* ```ts
|
|
505
|
+
* const { records, hasMore, nextCursor } = await posts.query({
|
|
506
|
+
* filters: [{ field: 'status', op: '==', value: 'published' }],
|
|
507
|
+
* orderBy: 'createdAt',
|
|
508
|
+
* order: 'desc',
|
|
509
|
+
* limit: 20,
|
|
510
|
+
* });
|
|
511
|
+
* ```
|
|
512
|
+
*/
|
|
443
513
|
query(options?: QueryOptions): Promise<QueryResult<T>>;
|
|
514
|
+
/**
|
|
515
|
+
* Get all records matching the given options (no filter support — use `query()` for filters).
|
|
516
|
+
*/
|
|
444
517
|
getAll(options?: Omit<QueryOptions, 'filters'>): Promise<(T & RecordResult)[]>;
|
|
518
|
+
/**
|
|
519
|
+
* Count records matching the given filters.
|
|
520
|
+
*/
|
|
445
521
|
count(filters?: QueryOptions['filters']): Promise<number>;
|
|
522
|
+
/**
|
|
523
|
+
* Get the version history of a record.
|
|
524
|
+
*/
|
|
446
525
|
getHistory(id: string): Promise<RecordHistoryEntry[]>;
|
|
526
|
+
/**
|
|
527
|
+
* Restore a record to a previous version.
|
|
528
|
+
*/
|
|
447
529
|
restoreVersion(id: string, version: number): Promise<T & RecordResult>;
|
|
448
530
|
}
|
|
449
531
|
|
|
450
532
|
/**
|
|
451
|
-
* AnalyticsClient — BigQuery-powered aggregations for a bucket.
|
|
533
|
+
* AnalyticsClient — BigQuery-powered aggregations for a single bucket.
|
|
452
534
|
* Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
|
|
453
535
|
*
|
|
536
|
+
* All methods POST a `queryType` body to `POST /analytics/:bucketKey`.
|
|
537
|
+
* The `dateRange` is passed as `{ start, end }` ms timestamps — the server
|
|
538
|
+
* converts them to ISO date strings internally.
|
|
539
|
+
*
|
|
454
540
|
* @example
|
|
455
541
|
* ```ts
|
|
456
|
-
* const db = createClient({ authKey: '…', bucketSecurityKey: 'hk_bucket_…', storageKeys: { main: '…' } });
|
|
457
542
|
* const analytics = db.analytics('orders');
|
|
458
543
|
* const { count } = await analytics.count();
|
|
544
|
+
* const top5 = await analytics.topN({ field: 'country', n: 5 });
|
|
459
545
|
* ```
|
|
460
546
|
*/
|
|
461
547
|
declare class AnalyticsClient {
|
|
@@ -464,31 +550,37 @@ declare class AnalyticsClient {
|
|
|
464
550
|
private readonly basePath;
|
|
465
551
|
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
466
552
|
private run;
|
|
553
|
+
/** Count all records, optionally within a date range. */
|
|
467
554
|
count(opts?: {
|
|
468
555
|
dateRange?: DateRange;
|
|
469
556
|
}): Promise<CountResult>;
|
|
557
|
+
/** Get value distribution for a field (e.g. how many records per status). */
|
|
470
558
|
distribution(opts: {
|
|
471
559
|
field: string;
|
|
472
560
|
limit?: number;
|
|
473
561
|
order?: SortOrder;
|
|
474
562
|
dateRange?: DateRange;
|
|
475
563
|
}): Promise<DistributionRow[]>;
|
|
564
|
+
/** Sum a numeric field, optionally grouped by another field. */
|
|
476
565
|
sum(opts: {
|
|
477
566
|
field: string;
|
|
478
567
|
groupBy?: string;
|
|
479
568
|
limit?: number;
|
|
480
569
|
dateRange?: DateRange;
|
|
481
570
|
}): Promise<SumRow[]>;
|
|
571
|
+
/** Count of records over time, bucketed by granularity. */
|
|
482
572
|
timeSeries(opts?: {
|
|
483
573
|
granularity?: Granularity;
|
|
484
574
|
dateRange?: DateRange;
|
|
485
575
|
}): Promise<TimeSeriesRow[]>;
|
|
576
|
+
/** Aggregate a numeric field over time. */
|
|
486
577
|
fieldTimeSeries(opts: {
|
|
487
578
|
field: string;
|
|
488
579
|
aggregation?: Aggregation;
|
|
489
580
|
granularity?: Granularity;
|
|
490
581
|
dateRange?: DateRange;
|
|
491
582
|
}): Promise<FieldTimeSeriesRow[]>;
|
|
583
|
+
/** Top N values for a field by count. */
|
|
492
584
|
topN(opts: {
|
|
493
585
|
field: string;
|
|
494
586
|
n?: number;
|
|
@@ -496,10 +588,12 @@ declare class AnalyticsClient {
|
|
|
496
588
|
order?: SortOrder;
|
|
497
589
|
dateRange?: DateRange;
|
|
498
590
|
}): Promise<TopNRow[]>;
|
|
591
|
+
/** Statistical summary (min, max, avg, sum, count, stddev) for a numeric field. */
|
|
499
592
|
stats(opts: {
|
|
500
593
|
field: string;
|
|
501
594
|
dateRange?: DateRange;
|
|
502
595
|
}): Promise<FieldStats>;
|
|
596
|
+
/** Fetch filtered records via the analytics engine (bypasses Firestore pagination). */
|
|
503
597
|
records<T extends RecordData = RecordData>(opts?: {
|
|
504
598
|
filters?: AnalyticsFilter[];
|
|
505
599
|
selectFields?: string[];
|
|
@@ -509,96 +603,84 @@ declare class AnalyticsClient {
|
|
|
509
603
|
order?: SortOrder;
|
|
510
604
|
dateRange?: DateRange;
|
|
511
605
|
}): Promise<(T & RecordResult)[]>;
|
|
606
|
+
/** Compute multiple aggregations in a single request. */
|
|
512
607
|
multiMetric(opts: {
|
|
513
608
|
metrics: MetricDefinition[];
|
|
514
609
|
dateRange?: DateRange;
|
|
515
610
|
}): Promise<MultiMetricResult>;
|
|
611
|
+
/** Storage usage stats for the bucket (record count, bytes, avg/min/max size). */
|
|
516
612
|
storageStats(opts?: {
|
|
517
613
|
dateRange?: DateRange;
|
|
518
614
|
}): Promise<StorageStatsResult>;
|
|
615
|
+
/**
|
|
616
|
+
* Compare a metric across multiple buckets in one query.
|
|
617
|
+
* The caller's key must have read access to every bucket in `bucketKeys`.
|
|
618
|
+
*/
|
|
519
619
|
crossBucket(opts: {
|
|
520
620
|
bucketKeys: string[];
|
|
521
621
|
field: string;
|
|
522
622
|
aggregation?: Aggregation;
|
|
523
623
|
dateRange?: DateRange;
|
|
524
624
|
}): Promise<CrossBucketRow[]>;
|
|
625
|
+
/**
|
|
626
|
+
* Raw query — use this when none of the typed helpers cover your use case.
|
|
627
|
+
*/
|
|
525
628
|
query<T = unknown>(query: AnalyticsQuery): Promise<AnalyticsResult<T>>;
|
|
526
629
|
}
|
|
527
630
|
|
|
528
631
|
/**
|
|
529
632
|
* StorageManager — upload, download, list, move, copy, and delete files.
|
|
530
633
|
* Uses an `X-Storage-Key` (`ssk_…`) header — separate from auth and bucket keys.
|
|
531
|
-
* Each key is scoped to a specific storage bucket and permission set.
|
|
532
634
|
*
|
|
533
|
-
* Get a StorageManager via `db.storage('keyName')` where the
|
|
534
|
-
*
|
|
635
|
+
* Get a StorageManager via `db.storage('keyName')` where the name matches
|
|
636
|
+
* one of the keys defined in `storageKeys` when calling `createClient`.
|
|
535
637
|
*
|
|
536
638
|
* @example
|
|
537
639
|
* ```ts
|
|
538
|
-
* const db = createClient({ authKey: '…', bucketSecurityKey: '…', storageKeys: { avatars: 'ssk_avatars_…' } });
|
|
539
640
|
* const avatars = db.storage('avatars');
|
|
540
|
-
* const result
|
|
641
|
+
* const result = await avatars.upload(file, 'alice.jpg', { isPublic: true });
|
|
642
|
+
* console.log(result.publicUrl);
|
|
541
643
|
* ```
|
|
542
644
|
*/
|
|
543
645
|
declare class StorageManager {
|
|
544
646
|
private readonly http;
|
|
545
647
|
private readonly storageKey;
|
|
546
|
-
|
|
648
|
+
readonly basePath = "/storage";
|
|
547
649
|
constructor(http: HttpClient, storageKey: string);
|
|
548
|
-
/** Headers for all storage requests — uses X-Storage-Key, not X-Api-Key. */
|
|
549
650
|
private get authHeaders();
|
|
550
651
|
/**
|
|
551
652
|
* Upload a file to storage in one step (server-buffered, up to 500 MB).
|
|
552
|
-
* For files >10 MB or when
|
|
553
|
-
*
|
|
554
|
-
* @param data File data as a Blob, Buffer, Uint8Array, or ArrayBuffer.
|
|
555
|
-
* @param path Destination path in your storage (e.g. `"avatars/alice.jpg"`).
|
|
556
|
-
* @param options Upload options: isPublic, overwrite, mimeType.
|
|
653
|
+
* For files >10 MB or when upload progress is needed, use `getUploadUrl()`.
|
|
557
654
|
*
|
|
558
655
|
* @example
|
|
559
656
|
* ```ts
|
|
560
|
-
* // Upload a public avatar
|
|
561
657
|
* const result = await storage.upload(file, 'avatars/alice.jpg', { isPublic: true });
|
|
562
|
-
* console.log(result.publicUrl);
|
|
563
|
-
*
|
|
564
|
-
* // Upload a private document
|
|
565
|
-
* const result = await storage.upload(pdfBuffer, 'docs/contract.pdf');
|
|
566
|
-
* console.log(result.downloadUrl); // → /storage/download/docs/contract.pdf
|
|
658
|
+
* console.log(result.publicUrl);
|
|
567
659
|
* ```
|
|
568
660
|
*/
|
|
569
|
-
upload(data: Blob | Uint8Array
|
|
661
|
+
upload(data: Blob | Uint8Array | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
570
662
|
/**
|
|
571
|
-
* Upload raw JSON or plain
|
|
663
|
+
* Upload raw JSON or plain-text data as a file.
|
|
572
664
|
*
|
|
573
665
|
* @example
|
|
574
666
|
* ```ts
|
|
575
|
-
*
|
|
576
|
-
* { config: { theme: 'dark' } },
|
|
577
|
-
* 'settings/user-config.json',
|
|
578
|
-
* { isPublic: false },
|
|
579
|
-
* );
|
|
667
|
+
* await storage.uploadRaw({ theme: 'dark' }, 'settings/config.json');
|
|
580
668
|
* ```
|
|
581
669
|
*/
|
|
582
670
|
uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
583
671
|
/**
|
|
584
|
-
* Step 1
|
|
585
|
-
*
|
|
672
|
+
* Step 1 — get a signed GCS URL to upload directly from the client.
|
|
673
|
+
* Supports upload progress via `uploadToSignedUrl()`.
|
|
586
674
|
*
|
|
587
675
|
* @example
|
|
588
676
|
* ```ts
|
|
589
677
|
* const { uploadUrl, path: confirmedPath } = await storage.getUploadUrl({
|
|
590
|
-
* path:
|
|
678
|
+
* path: 'videos/intro.mp4',
|
|
591
679
|
* mimeType: 'video/mp4',
|
|
592
|
-
* size:
|
|
680
|
+
* size: file.size,
|
|
593
681
|
* isPublic: true,
|
|
594
682
|
* });
|
|
595
|
-
*
|
|
596
|
-
* // Upload using XHR for progress tracking
|
|
597
|
-
* await storage.uploadToSignedUrl(uploadUrl, file, 'video/mp4', (pct) => {
|
|
598
|
-
* console.log(`${pct}% uploaded`);
|
|
599
|
-
* });
|
|
600
|
-
*
|
|
601
|
-
* // Step 3: confirm
|
|
683
|
+
* await storage.uploadToSignedUrl(uploadUrl, file, 'video/mp4', pct => console.log(pct + '%'));
|
|
602
684
|
* const result = await storage.confirmUpload({ path: confirmedPath, mimeType: 'video/mp4', isPublic: true });
|
|
603
685
|
* ```
|
|
604
686
|
*/
|
|
@@ -611,28 +693,12 @@ declare class StorageManager {
|
|
|
611
693
|
expiresInSeconds?: number;
|
|
612
694
|
}): Promise<UploadUrlResult>;
|
|
613
695
|
/**
|
|
614
|
-
*
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
* @param signedUrl The URL returned by `getUploadUrl()`.
|
|
618
|
-
* @param data File data.
|
|
619
|
-
* @param mimeType Must match what was used in `getUploadUrl()`.
|
|
620
|
-
* @param onProgress Optional callback called with 0–100 progress percentage.
|
|
696
|
+
* Step 2 — upload data directly to a signed GCS URL.
|
|
697
|
+
* Supports progress tracking in browser environments.
|
|
621
698
|
*/
|
|
622
|
-
uploadToSignedUrl(signedUrl: string, data: Blob | Uint8Array
|
|
699
|
+
uploadToSignedUrl(signedUrl: string, data: Blob | Uint8Array | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
623
700
|
/**
|
|
624
|
-
* Step 3
|
|
625
|
-
* Confirm a direct upload and register metadata on the server.
|
|
626
|
-
*
|
|
627
|
-
* @example
|
|
628
|
-
* ```ts
|
|
629
|
-
* const result = await storage.confirmUpload({
|
|
630
|
-
* path: 'videos/intro.mp4',
|
|
631
|
-
* mimeType: 'video/mp4',
|
|
632
|
-
* isPublic: true,
|
|
633
|
-
* });
|
|
634
|
-
* console.log(result.publicUrl);
|
|
635
|
-
* ```
|
|
701
|
+
* Step 3 — confirm a direct upload and register metadata on the server.
|
|
636
702
|
*/
|
|
637
703
|
confirmUpload(opts: {
|
|
638
704
|
path: string;
|
|
@@ -640,16 +706,15 @@ declare class StorageManager {
|
|
|
640
706
|
isPublic?: boolean;
|
|
641
707
|
}): Promise<UploadResult>;
|
|
642
708
|
/**
|
|
643
|
-
* Get signed upload URLs for multiple files at once.
|
|
709
|
+
* Get signed upload URLs for multiple files at once (max 50).
|
|
710
|
+
* Server returns `{ succeeded, failed }` — only succeeded items have URLs.
|
|
644
711
|
*
|
|
645
712
|
* @example
|
|
646
713
|
* ```ts
|
|
647
714
|
* const { files } = await storage.getBatchUploadUrls([
|
|
648
|
-
* { path: 'images/
|
|
649
|
-
* { path: 'images/
|
|
715
|
+
* { path: 'images/a.jpg', mimeType: 'image/jpeg', size: 204800 },
|
|
716
|
+
* { path: 'images/b.jpg', mimeType: 'image/jpeg', size: 153600 },
|
|
650
717
|
* ]);
|
|
651
|
-
*
|
|
652
|
-
* // Upload each file and confirm
|
|
653
718
|
* for (const f of files) {
|
|
654
719
|
* await storage.uploadToSignedUrl(f.uploadUrl, blobs[f.index], f.mimeType);
|
|
655
720
|
* await storage.confirmUpload({ path: f.path, mimeType: f.mimeType });
|
|
@@ -659,93 +724,65 @@ declare class StorageManager {
|
|
|
659
724
|
getBatchUploadUrls(files: BatchUploadItem[]): Promise<BatchUploadUrlResult>;
|
|
660
725
|
/**
|
|
661
726
|
* Confirm multiple direct uploads at once.
|
|
727
|
+
* Returns both succeeded and failed results.
|
|
662
728
|
*/
|
|
663
729
|
batchConfirmUploads(items: Array<{
|
|
664
730
|
path: string;
|
|
665
731
|
mimeType: string;
|
|
666
732
|
isPublic?: boolean;
|
|
667
|
-
}>): Promise<
|
|
733
|
+
}>): Promise<{
|
|
734
|
+
succeeded: UploadResult[];
|
|
735
|
+
failed: Array<{
|
|
736
|
+
path: string;
|
|
737
|
+
error: string;
|
|
738
|
+
}>;
|
|
739
|
+
}>;
|
|
668
740
|
/**
|
|
669
741
|
* Download a private file as an ArrayBuffer.
|
|
670
742
|
* For public files, use the `publicUrl` directly — no SDK needed.
|
|
671
|
-
*
|
|
672
|
-
* @example
|
|
673
|
-
* ```ts
|
|
674
|
-
* const buffer = await storage.download('docs/contract.pdf');
|
|
675
|
-
* const blob = new Blob([buffer], { type: 'application/pdf' });
|
|
676
|
-
* // Open in browser:
|
|
677
|
-
* window.open(URL.createObjectURL(blob));
|
|
678
|
-
* ```
|
|
679
743
|
*/
|
|
680
744
|
download(path: string): Promise<ArrayBuffer>;
|
|
681
745
|
/**
|
|
682
|
-
* Download multiple files at once
|
|
746
|
+
* Download multiple files at once (max 20).
|
|
747
|
+
* Returns a structured result with succeeded and failed items.
|
|
748
|
+
* Each succeeded item includes the file content as a base64 string.
|
|
683
749
|
*
|
|
684
750
|
* @example
|
|
685
751
|
* ```ts
|
|
686
|
-
* const
|
|
752
|
+
* const { succeeded, failed } = await storage.batchDownload(['docs/a.pdf', 'docs/b.pdf']);
|
|
753
|
+
* for (const f of succeeded) {
|
|
754
|
+
* const bytes = Buffer.from(f.content, 'base64');
|
|
755
|
+
* }
|
|
687
756
|
* ```
|
|
688
757
|
*/
|
|
689
|
-
batchDownload(paths: string[]): Promise<
|
|
758
|
+
batchDownload(paths: string[]): Promise<BatchDownloadResult>;
|
|
690
759
|
/**
|
|
691
760
|
* List files and folders at a given path prefix.
|
|
761
|
+
* Returns separate `files` and `folders` arrays for easy consumption.
|
|
692
762
|
*
|
|
693
763
|
* @example
|
|
694
764
|
* ```ts
|
|
695
|
-
*
|
|
696
|
-
* const { files, folders } = await storage.list();
|
|
697
|
-
*
|
|
698
|
-
* // List a specific folder
|
|
699
|
-
* const { files, folders, hasMore, nextCursor } = await storage.list({
|
|
700
|
-
* prefix: 'avatars/',
|
|
701
|
-
* limit: 20,
|
|
702
|
-
* });
|
|
703
|
-
*
|
|
704
|
-
* // Next page
|
|
765
|
+
* const { files, folders, hasMore, nextCursor } = await storage.list({ prefix: 'avatars/', limit: 20 });
|
|
705
766
|
* const page2 = await storage.list({ prefix: 'avatars/', cursor: nextCursor });
|
|
706
767
|
* ```
|
|
707
768
|
*/
|
|
708
769
|
list(opts?: ListOptions): Promise<ListResult>;
|
|
709
770
|
/**
|
|
710
|
-
* Get metadata for a file
|
|
711
|
-
*
|
|
712
|
-
* @example
|
|
713
|
-
* ```ts
|
|
714
|
-
* const meta = await storage.getMetadata('avatars/alice.jpg');
|
|
715
|
-
* console.log(meta.size, meta.isPublic, meta.publicUrl);
|
|
716
|
-
* ```
|
|
771
|
+
* Get metadata for a file: size, MIME type, visibility, URLs.
|
|
717
772
|
*/
|
|
718
773
|
getMetadata(path: string): Promise<FileMetadata>;
|
|
719
774
|
/**
|
|
720
775
|
* Generate a time-limited download URL for a private file.
|
|
721
|
-
*
|
|
722
|
-
*
|
|
723
|
-
* > **Note:** Downloads via signed URLs bypass the server, so download stats
|
|
724
|
-
* > are NOT tracked. Use `downloadUrl` for tracked downloads.
|
|
776
|
+
* Can be shared externally without requiring an `X-Storage-Key`.
|
|
725
777
|
*
|
|
726
|
-
*
|
|
727
|
-
* @param expiresIn URL lifetime in seconds (default 3600 = 1 hour).
|
|
778
|
+
* > Note: Downloads via signed URLs bypass the server — download stats are NOT tracked.
|
|
728
779
|
*
|
|
729
|
-
* @
|
|
730
|
-
*
|
|
731
|
-
* const { signedUrl, expiresAt } = await storage.getSignedUrl('docs/invoice.pdf', 1800);
|
|
732
|
-
* // Share signedUrl with the recipient — it expires in 30 minutes.
|
|
733
|
-
* ```
|
|
780
|
+
* @param path File path.
|
|
781
|
+
* @param expiresIn URL lifetime in seconds (default 3600 = 1 hour).
|
|
734
782
|
*/
|
|
735
783
|
getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
|
|
736
784
|
/**
|
|
737
785
|
* Change a file's visibility between public and private after upload.
|
|
738
|
-
*
|
|
739
|
-
* @example
|
|
740
|
-
* ```ts
|
|
741
|
-
* // Make a file public
|
|
742
|
-
* const result = await storage.setVisibility('avatars/alice.jpg', true);
|
|
743
|
-
* console.log(result.publicUrl); // CDN URL
|
|
744
|
-
*
|
|
745
|
-
* // Make a file private
|
|
746
|
-
* const result = await storage.setVisibility('avatars/alice.jpg', false);
|
|
747
|
-
* console.log(result.downloadUrl); // Auth-required URL
|
|
748
|
-
* ```
|
|
749
786
|
*/
|
|
750
787
|
setVisibility(path: string, isPublic: boolean): Promise<{
|
|
751
788
|
path: string;
|
|
@@ -753,81 +790,20 @@ declare class StorageManager {
|
|
|
753
790
|
publicUrl: string | null;
|
|
754
791
|
downloadUrl: string | null;
|
|
755
792
|
}>;
|
|
756
|
-
/**
|
|
757
|
-
* Create a folder (a GCS prefix placeholder).
|
|
758
|
-
*
|
|
759
|
-
* @example
|
|
760
|
-
* ```ts
|
|
761
|
-
* await storage.createFolder('uploads/2025/');
|
|
762
|
-
* ```
|
|
763
|
-
*/
|
|
764
793
|
createFolder(path: string): Promise<{
|
|
765
794
|
path: string;
|
|
766
795
|
}>;
|
|
767
|
-
/**
|
|
768
|
-
* Delete a single file.
|
|
769
|
-
*
|
|
770
|
-
* @example
|
|
771
|
-
* ```ts
|
|
772
|
-
* await storage.deleteFile('avatars/old-avatar.jpg');
|
|
773
|
-
* ```
|
|
774
|
-
*/
|
|
775
796
|
deleteFile(path: string): Promise<void>;
|
|
776
|
-
/**
|
|
777
|
-
* Delete a folder and all its contents recursively.
|
|
778
|
-
*
|
|
779
|
-
* @example
|
|
780
|
-
* ```ts
|
|
781
|
-
* await storage.deleteFolder('temp/');
|
|
782
|
-
* ```
|
|
783
|
-
*/
|
|
784
797
|
deleteFolder(path: string): Promise<void>;
|
|
785
|
-
/**
|
|
786
|
-
* Move or rename a file.
|
|
787
|
-
*
|
|
788
|
-
* @example
|
|
789
|
-
* ```ts
|
|
790
|
-
* // Rename
|
|
791
|
-
* await storage.move('docs/draft.pdf', 'docs/final.pdf');
|
|
792
|
-
* // Move to a different folder
|
|
793
|
-
* await storage.move('inbox/report.xlsx', 'archive/2025/report.xlsx');
|
|
794
|
-
* ```
|
|
795
|
-
*/
|
|
796
798
|
move(from: string, to: string): Promise<{
|
|
797
799
|
from: string;
|
|
798
800
|
to: string;
|
|
799
801
|
}>;
|
|
800
|
-
/**
|
|
801
|
-
* Copy a file to a new path.
|
|
802
|
-
*
|
|
803
|
-
* @example
|
|
804
|
-
* ```ts
|
|
805
|
-
* await storage.copy('templates/base.html', 'sites/my-site/index.html');
|
|
806
|
-
* ```
|
|
807
|
-
*/
|
|
808
802
|
copy(from: string, to: string): Promise<{
|
|
809
803
|
from: string;
|
|
810
804
|
to: string;
|
|
811
805
|
}>;
|
|
812
|
-
/**
|
|
813
|
-
* Get storage statistics for your key: total files, bytes, operation counts.
|
|
814
|
-
*
|
|
815
|
-
* @example
|
|
816
|
-
* ```ts
|
|
817
|
-
* const stats = await storage.getStats();
|
|
818
|
-
* console.log(`${stats.totalFiles} files, ${(stats.totalBytes / 1e6).toFixed(1)} MB`);
|
|
819
|
-
* ```
|
|
820
|
-
*/
|
|
821
806
|
getStats(): Promise<StorageStats>;
|
|
822
|
-
/**
|
|
823
|
-
* Ping the storage service. No authentication required.
|
|
824
|
-
*
|
|
825
|
-
* @example
|
|
826
|
-
* ```ts
|
|
827
|
-
* const info = await storage.info();
|
|
828
|
-
* // → { ok: true, storageRoot: 'hydrous-storage' }
|
|
829
|
-
* ```
|
|
830
|
-
*/
|
|
831
807
|
info(): Promise<{
|
|
832
808
|
ok: boolean;
|
|
833
809
|
storageRoot: string;
|
|
@@ -835,89 +811,98 @@ declare class StorageManager {
|
|
|
835
811
|
}
|
|
836
812
|
|
|
837
813
|
/**
|
|
838
|
-
* ScopedStorage — a
|
|
814
|
+
* ScopedStorage — a path-prefixed view over a StorageManager.
|
|
815
|
+
* All paths you pass are automatically prefixed with the scope.
|
|
839
816
|
*
|
|
840
|
-
*
|
|
841
|
-
* have to repeat the folder name.
|
|
817
|
+
* Obtain via `db.storage('keyName').scope('prefix/')`.
|
|
842
818
|
*
|
|
843
819
|
* @example
|
|
844
820
|
* ```ts
|
|
845
|
-
* const
|
|
821
|
+
* const userDocs = db.storage('documents').scope(`users/${userId}/`);
|
|
846
822
|
*
|
|
847
|
-
* //
|
|
848
|
-
*
|
|
823
|
+
* // Uploads to: users/{userId}/contract.pdf
|
|
824
|
+
* await userDocs.upload(pdfBuffer, 'contract.pdf');
|
|
849
825
|
*
|
|
850
|
-
*
|
|
851
|
-
* const
|
|
852
|
-
* await avatars.deleteFile('alice.jpg'); // → deletes "avatars/alice.jpg"
|
|
826
|
+
* // Lists: users/{userId}/
|
|
827
|
+
* const { files } = await userDocs.list();
|
|
853
828
|
* ```
|
|
854
829
|
*/
|
|
855
830
|
declare class ScopedStorage {
|
|
856
831
|
private readonly manager;
|
|
857
832
|
private readonly prefix;
|
|
858
833
|
constructor(manager: StorageManager, prefix: string);
|
|
859
|
-
private
|
|
860
|
-
|
|
861
|
-
upload(data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
862
|
-
/** Upload raw JSON or text within the scoped folder. */
|
|
834
|
+
private p;
|
|
835
|
+
upload(data: Blob | Uint8Array | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
863
836
|
uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
864
|
-
/** Get a signed upload URL for a file within the scoped folder. */
|
|
865
837
|
getUploadUrl(opts: {
|
|
866
838
|
path: string;
|
|
867
839
|
mimeType: string;
|
|
868
840
|
size: number;
|
|
869
841
|
isPublic?: boolean;
|
|
870
842
|
overwrite?: boolean;
|
|
843
|
+
expiresInSeconds?: number;
|
|
871
844
|
}): Promise<UploadUrlResult>;
|
|
872
|
-
|
|
845
|
+
uploadToSignedUrl(signedUrl: string, data: Blob | Uint8Array | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
873
846
|
confirmUpload(opts: {
|
|
874
847
|
path: string;
|
|
875
848
|
mimeType: string;
|
|
876
849
|
isPublic?: boolean;
|
|
877
850
|
}): Promise<UploadResult>;
|
|
878
|
-
|
|
851
|
+
getBatchUploadUrls(files: BatchUploadItem[]): Promise<BatchUploadUrlResult>;
|
|
852
|
+
batchConfirmUploads(items: Array<{
|
|
853
|
+
path: string;
|
|
854
|
+
mimeType: string;
|
|
855
|
+
isPublic?: boolean;
|
|
856
|
+
}>): Promise<{
|
|
857
|
+
succeeded: UploadResult[];
|
|
858
|
+
failed: Array<{
|
|
859
|
+
path: string;
|
|
860
|
+
error: string;
|
|
861
|
+
}>;
|
|
862
|
+
}>;
|
|
879
863
|
download(path: string): Promise<ArrayBuffer>;
|
|
864
|
+
batchDownload(paths: string[]): Promise<BatchDownloadResult>;
|
|
880
865
|
/**
|
|
881
|
-
* List files within the
|
|
882
|
-
*
|
|
866
|
+
* List files within this scope. The `prefix` option is relative to the scope root.
|
|
867
|
+
*
|
|
868
|
+
* @example
|
|
869
|
+
* ```ts
|
|
870
|
+
* const userDocs = storage.scope('users/alice/');
|
|
871
|
+
* // Lists users/alice/docs/
|
|
872
|
+
* const { files } = await userDocs.list({ prefix: 'docs/' });
|
|
873
|
+
* ```
|
|
883
874
|
*/
|
|
884
875
|
list(opts?: ListOptions): Promise<ListResult>;
|
|
885
|
-
/** Get metadata for a file within the scoped folder. */
|
|
886
876
|
getMetadata(path: string): Promise<FileMetadata>;
|
|
887
|
-
/** Get a time-limited signed URL for a file within the scoped folder. */
|
|
888
877
|
getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
|
|
889
|
-
/** Change visibility of a file within the scoped folder. */
|
|
890
878
|
setVisibility(path: string, isPublic: boolean): Promise<{
|
|
891
879
|
path: string;
|
|
892
880
|
isPublic: boolean;
|
|
893
881
|
publicUrl: string | null;
|
|
894
882
|
downloadUrl: string | null;
|
|
895
883
|
}>;
|
|
896
|
-
|
|
884
|
+
createFolder(path: string): Promise<{
|
|
885
|
+
path: string;
|
|
886
|
+
}>;
|
|
897
887
|
deleteFile(path: string): Promise<void>;
|
|
898
|
-
/** Delete a sub-folder within the scoped folder. */
|
|
899
888
|
deleteFolder(path: string): Promise<void>;
|
|
900
|
-
/** Move a file within the scoped folder. */
|
|
901
889
|
move(from: string, to: string): Promise<{
|
|
902
890
|
from: string;
|
|
903
891
|
to: string;
|
|
904
892
|
}>;
|
|
905
|
-
/** Copy a file within the scoped folder. */
|
|
906
893
|
copy(from: string, to: string): Promise<{
|
|
907
894
|
from: string;
|
|
908
895
|
to: string;
|
|
909
896
|
}>;
|
|
910
|
-
|
|
911
|
-
createFolder(path: string): Promise<{
|
|
912
|
-
path: string;
|
|
913
|
-
}>;
|
|
897
|
+
getStats(): Promise<StorageStats>;
|
|
914
898
|
/**
|
|
915
|
-
* Create a
|
|
899
|
+
* Create a deeper scope within this one.
|
|
916
900
|
*
|
|
917
901
|
* @example
|
|
918
902
|
* ```ts
|
|
919
|
-
* const
|
|
920
|
-
* const
|
|
903
|
+
* const user = storage.scope('users/alice/');
|
|
904
|
+
* const userDocs = user.scope('docs/');
|
|
905
|
+
* // Effective prefix: users/alice/docs/
|
|
921
906
|
* ```
|
|
922
907
|
*/
|
|
923
908
|
scope(subPrefix: string): ScopedStorage;
|
|
@@ -926,35 +911,30 @@ declare class ScopedStorage {
|
|
|
926
911
|
/**
|
|
927
912
|
* HydrousClient — the main entry point for the HydrousDB SDK.
|
|
928
913
|
*
|
|
929
|
-
* Each service uses its own dedicated key:
|
|
914
|
+
* Each service uses its own dedicated API key:
|
|
930
915
|
* - `authKey` (`hk_auth_…`) → `db.auth('bucket')`
|
|
931
916
|
* - `bucketSecurityKey` (`hk_bucket_…`) → `db.records('bucket')` + `db.analytics('bucket')`
|
|
932
917
|
* - `storageKeys` (`ssk_…`) → `db.storage('keyName')`
|
|
933
918
|
*
|
|
919
|
+
* Sub-clients are cached — calling `db.records('posts')` twice returns the same instance.
|
|
920
|
+
*
|
|
934
921
|
* @example
|
|
935
922
|
* ```ts
|
|
936
923
|
* import { createClient } from 'hydrousdb';
|
|
937
924
|
*
|
|
938
925
|
* const db = createClient({
|
|
939
|
-
* authKey:
|
|
940
|
-
* bucketSecurityKey:
|
|
926
|
+
* authKey: process.env.HYDROUS_AUTH_KEY!,
|
|
927
|
+
* bucketSecurityKey: process.env.HYDROUS_BUCKET_KEY!,
|
|
941
928
|
* storageKeys: {
|
|
942
|
-
*
|
|
943
|
-
*
|
|
944
|
-
* documents: 'ssk_docs_…',
|
|
929
|
+
* avatars: process.env.HYDROUS_STORAGE_AVATARS!,
|
|
930
|
+
* documents: process.env.HYDROUS_STORAGE_DOCS!,
|
|
945
931
|
* },
|
|
946
932
|
* });
|
|
947
933
|
*
|
|
948
|
-
*
|
|
949
|
-
* const
|
|
934
|
+
* const posts = db.records('blog-posts');
|
|
935
|
+
* const auth = db.auth('app-users');
|
|
950
936
|
* const analytics = db.analytics('orders');
|
|
951
|
-
*
|
|
952
|
-
* // Auth — uses authKey automatically
|
|
953
|
-
* const auth = db.auth('app-users');
|
|
954
|
-
*
|
|
955
|
-
* // Storage — pick which key to use by name
|
|
956
|
-
* const avatarStorage = db.storage('avatars');
|
|
957
|
-
* const documentStorage = db.storage('documents');
|
|
937
|
+
* const avatars = db.storage('avatars');
|
|
958
938
|
* ```
|
|
959
939
|
*/
|
|
960
940
|
declare class HydrousClient {
|
|
@@ -969,19 +949,20 @@ declare class HydrousClient {
|
|
|
969
949
|
constructor(config: HydrousConfig);
|
|
970
950
|
/**
|
|
971
951
|
* Get a typed records client for the named bucket.
|
|
972
|
-
* Uses your `bucketSecurityKey` automatically.
|
|
973
952
|
*
|
|
974
953
|
* @example
|
|
975
954
|
* ```ts
|
|
976
955
|
* interface Post { title: string; published: boolean }
|
|
977
956
|
* const posts = db.records<Post>('blog-posts');
|
|
978
|
-
* const post
|
|
957
|
+
* const post = await posts.create(
|
|
958
|
+
* { title: 'Hello', published: false },
|
|
959
|
+
* { queryableFields: ['published'] },
|
|
960
|
+
* );
|
|
979
961
|
* ```
|
|
980
962
|
*/
|
|
981
963
|
records<T extends RecordData = RecordData>(bucketKey: string): RecordsClient<T>;
|
|
982
964
|
/**
|
|
983
965
|
* Get an auth client for the named user bucket.
|
|
984
|
-
* Uses your `authKey` automatically.
|
|
985
966
|
*
|
|
986
967
|
* @example
|
|
987
968
|
* ```ts
|
|
@@ -992,7 +973,6 @@ declare class HydrousClient {
|
|
|
992
973
|
auth(bucketKey: string): AuthClient;
|
|
993
974
|
/**
|
|
994
975
|
* Get an analytics client for the named bucket.
|
|
995
|
-
* Uses your `bucketSecurityKey` automatically.
|
|
996
976
|
*
|
|
997
977
|
* @example
|
|
998
978
|
* ```ts
|
|
@@ -1003,21 +983,16 @@ declare class HydrousClient {
|
|
|
1003
983
|
analytics(bucketKey: string): AnalyticsClient;
|
|
1004
984
|
/**
|
|
1005
985
|
* Get a storage manager for the named storage key.
|
|
1006
|
-
* The name must match a key
|
|
1007
|
-
* Uses the corresponding `ssk_…` key automatically via `X-Storage-Key` header.
|
|
986
|
+
* The name must match a key defined in `storageKeys` when calling `createClient`.
|
|
1008
987
|
*
|
|
1009
|
-
*
|
|
988
|
+
* Attach `.scope(prefix)` to namespace all operations under a path prefix.
|
|
1010
989
|
*
|
|
1011
990
|
* @example
|
|
1012
991
|
* ```ts
|
|
1013
|
-
* const avatars
|
|
1014
|
-
* const
|
|
992
|
+
* const avatars = db.storage('avatars');
|
|
993
|
+
* const userDocs = db.storage('documents').scope(`users/${userId}/`);
|
|
1015
994
|
*
|
|
1016
|
-
* // Upload to avatars bucket
|
|
1017
995
|
* await avatars.upload(file, `${userId}.jpg`, { isPublic: true });
|
|
1018
|
-
*
|
|
1019
|
-
* // Scope to a sub-folder
|
|
1020
|
-
* const userDocs = db.storage('documents').scope(`users/${userId}`);
|
|
1021
996
|
* await userDocs.upload(pdfBuffer, 'contract.pdf');
|
|
1022
997
|
* ```
|
|
1023
998
|
*/
|
|
@@ -1035,24 +1010,16 @@ declare class HydrousClient {
|
|
|
1035
1010
|
* const db = createClient({
|
|
1036
1011
|
* authKey: process.env.HYDROUS_AUTH_KEY!,
|
|
1037
1012
|
* bucketSecurityKey: process.env.HYDROUS_BUCKET_KEY!,
|
|
1038
|
-
* storageKeys: {
|
|
1039
|
-
* main: process.env.HYDROUS_STORAGE_MAIN!,
|
|
1040
|
-
* avatars: process.env.HYDROUS_STORAGE_AVATARS!,
|
|
1041
|
-
* documents: process.env.HYDROUS_STORAGE_DOCS!,
|
|
1042
|
-
* },
|
|
1013
|
+
* storageKeys: { main: process.env.HYDROUS_STORAGE_MAIN! },
|
|
1043
1014
|
* });
|
|
1044
1015
|
* ```
|
|
1045
1016
|
*/
|
|
1046
1017
|
declare function createClient(config: HydrousConfig): HydrousClient;
|
|
1047
1018
|
|
|
1048
1019
|
declare class HydrousError extends Error {
|
|
1049
|
-
/** Machine-readable error code returned by the API. */
|
|
1050
1020
|
readonly code: string;
|
|
1051
|
-
/** HTTP status code (if applicable). */
|
|
1052
1021
|
readonly status?: number;
|
|
1053
|
-
/** The original request ID for support tracing. */
|
|
1054
1022
|
readonly requestId?: string;
|
|
1055
|
-
/** Additional validation details. */
|
|
1056
1023
|
readonly details?: string[];
|
|
1057
1024
|
constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
|
|
1058
1025
|
toString(): string;
|
|
@@ -1077,4 +1044,4 @@ declare class NetworkError extends HydrousError {
|
|
|
1077
1044
|
constructor(message: string, cause?: unknown);
|
|
1078
1045
|
}
|
|
1079
1046
|
|
|
1080
|
-
export { type Aggregation, AnalyticsClient, AnalyticsError, type AnalyticsFilter, type AnalyticsQuery, type AnalyticsResult, AuthClient, AuthError, type AuthResult, type BatchUploadItem, type BatchUploadUrlResult, type ChangePasswordOptions, type CountResult, type CrossBucketRow, type DateRange, type DistributionRow, type FieldStats, type FieldTimeSeriesRow, type FileEntry, type FileMetadata, type Granularity, HydrousClient, type HydrousConfig, HydrousError, type ListOptions, type ListResult, type ListUsersOptions, type ListUsersResult, type LoginOptions, type MetricDefinition, type MultiMetricResult, NetworkError, type PatchRecordOptions, type QueryFilter, type QueryOptions, type QueryResult, type QueryType, type RecordData, RecordError, type RecordHistoryEntry, type RecordResult, RecordsClient, ScopedStorage, type Session, type SignedUrlResult, type SignupOptions, type SortOrder, StorageError, StorageManager, type StorageStats, type StorageStatsResult, type SumRow, type TimeSeriesRow, type TopNRow, type UpdateUserOptions, type UploadOptions, type UploadResult, type UploadUrlResult, type UserRecord, ValidationError, createClient };
|
|
1047
|
+
export { type Aggregation, AnalyticsClient, AnalyticsError, type AnalyticsFilter, type AnalyticsQuery, type AnalyticsResult, AuthClient, AuthError, type AuthResult, type BatchCreateOptions, type BatchDownloadResult, type BatchUploadItem, type BatchUploadUrlResult, type ChangePasswordOptions, type CountResult, type CreateRecordOptions, type CrossBucketRow, type DateRange, type DistributionRow, type FieldStats, type FieldTimeSeriesRow, type FileEntry, type FileMetadata, type Granularity, HydrousClient, type HydrousConfig, HydrousError, type ListOptions, type ListResult, type ListUsersOptions, type ListUsersResult, type LoginOptions, type MetricDefinition, type MultiMetricResult, NetworkError, type PatchRecordOptions, type QueryFilter, type QueryOptions, type QueryResult, type QueryType, type RecordData, RecordError, type RecordHistoryEntry, type RecordResult, RecordsClient, ScopedStorage, type Session, type SignedUrlResult, type SignupOptions, type SortOrder, StorageError, type StorageKeys, StorageManager, type StorageStats, type StorageStatsResult, type SumRow, type TimeSeriesRow, type TopNRow, type UpdateUserOptions, type UploadOptions, type UploadResult, type UploadUrlResult, type UserRecord, ValidationError, createClient };
|