hydrousdb 3.2.0 → 3.5.1
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 +832 -1124
- package/dist/index.cjs +618 -321
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +519 -222
- package/dist/index.d.ts +519 -222
- package/dist/index.mjs +613 -322
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server base URL — no trailing slash, no /api suffix.
|
|
3
|
+
* Routes in routes.ts already include /api, /api/analytics, /api/auth, /storage.
|
|
4
|
+
*/
|
|
5
|
+
declare const DEFAULT_BASE_URL = "https://db-api-82687684612.us-central1.run.app";
|
|
1
6
|
interface RequestOptions {
|
|
2
7
|
method: string;
|
|
3
8
|
body?: unknown;
|
|
@@ -14,21 +19,32 @@ declare class HttpClient {
|
|
|
14
19
|
patch<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
|
|
15
20
|
delete<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
|
|
16
21
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
22
|
+
* PUT directly to a signed GCS URL.
|
|
23
|
+
* Uses XHR in browsers for onprogress support; fetch in Node.
|
|
19
24
|
*/
|
|
20
25
|
putToSignedUrl(signedUrl: string, data: Blob | Uint8Array | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
type StorageKeys = Record<string, string>;
|
|
24
29
|
interface HydrousConfig {
|
|
25
|
-
/** Auth service key (starts with `hk_auth_`). */
|
|
30
|
+
/** Auth service key (starts with `hk_auth_`). Required for auth routes. */
|
|
26
31
|
authKey: string;
|
|
27
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Bucket security key (starts with `hk_bucket_`).
|
|
34
|
+
* Used for records and analytics routes.
|
|
35
|
+
*/
|
|
28
36
|
bucketSecurityKey: string;
|
|
29
|
-
/**
|
|
37
|
+
/**
|
|
38
|
+
* Named storage keys — each value starts with `ssk_`.
|
|
39
|
+
* Key names are arbitrary labels you choose; pass the same label to `db.storage('label')`.
|
|
40
|
+
* Example: { avatars: 'ssk_…', documents: 'ssk_…' }
|
|
41
|
+
*/
|
|
30
42
|
storageKeys: StorageKeys;
|
|
31
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* Override the API base URL.
|
|
45
|
+
* Defaults to the official HydrousDB endpoint.
|
|
46
|
+
* Should NOT include /api — route paths are fully qualified in routes.ts.
|
|
47
|
+
*/
|
|
32
48
|
baseUrl?: string;
|
|
33
49
|
}
|
|
34
50
|
interface SignupOptions {
|
|
@@ -69,20 +85,20 @@ interface AuthResult {
|
|
|
69
85
|
interface UpdateUserOptions {
|
|
70
86
|
sessionId: string;
|
|
71
87
|
userId: string;
|
|
72
|
-
/** Fields to update
|
|
88
|
+
/** Fields to update. Sent as `updates: {...}` to the server. */
|
|
73
89
|
updates: Partial<Omit<UserRecord, 'id' | 'email' | 'createdAt'>>;
|
|
74
90
|
}
|
|
75
91
|
interface ChangePasswordOptions {
|
|
76
92
|
sessionId: string;
|
|
77
93
|
userId: string;
|
|
78
|
-
/**
|
|
94
|
+
/** Sent to server as `oldPassword`. */
|
|
79
95
|
currentPassword: string;
|
|
80
96
|
newPassword: string;
|
|
81
97
|
}
|
|
82
98
|
interface ListUsersOptions {
|
|
83
99
|
sessionId: string;
|
|
84
100
|
limit?: number;
|
|
85
|
-
/**
|
|
101
|
+
/** URL-encoded cursor returned by the previous page. */
|
|
86
102
|
cursor?: string;
|
|
87
103
|
}
|
|
88
104
|
interface ListUsersResult {
|
|
@@ -99,7 +115,7 @@ interface RecordResult {
|
|
|
99
115
|
}
|
|
100
116
|
interface QueryFilter {
|
|
101
117
|
field: string;
|
|
102
|
-
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | '
|
|
118
|
+
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'contains';
|
|
103
119
|
value: string | number | boolean;
|
|
104
120
|
}
|
|
105
121
|
interface QueryOptions {
|
|
@@ -109,10 +125,33 @@ interface QueryOptions {
|
|
|
109
125
|
offset?: number;
|
|
110
126
|
orderBy?: string;
|
|
111
127
|
order?: 'asc' | 'desc';
|
|
128
|
+
/**
|
|
129
|
+
* Pagination cursor — pass the `nextCursor` from the previous page.
|
|
130
|
+
* Maps to `?cursor=` on the server.
|
|
131
|
+
*/
|
|
112
132
|
startAfter?: string;
|
|
113
133
|
startAt?: string;
|
|
114
134
|
endAt?: string;
|
|
115
135
|
dateRange?: DateRange;
|
|
136
|
+
/**
|
|
137
|
+
* Time-scope shorthand filter — narrows the query to a specific day, month, or year
|
|
138
|
+
* using the record ID prefix convention.
|
|
139
|
+
*
|
|
140
|
+
* Format: `_<type>_<code>`
|
|
141
|
+
* - Day: `_day_YYMMDD` e.g. `_day_260305` → March 5, 2026
|
|
142
|
+
* - Month: `_month_YYMM` e.g. `_month_2603` → March 2026
|
|
143
|
+
* - Year: `_year_YY` e.g. `_year_26` → 2026
|
|
144
|
+
*
|
|
145
|
+
* Maps to `?timeScope=` on the server.
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* // All records from March 2026
|
|
149
|
+
* await posts.query({ timeScope: '_month_2603' });
|
|
150
|
+
*
|
|
151
|
+
* // All records from a specific day
|
|
152
|
+
* await posts.query({ timeScope: '_day_260305' });
|
|
153
|
+
*/
|
|
154
|
+
timeScope?: string;
|
|
116
155
|
}
|
|
117
156
|
interface QueryResult<T = RecordData> {
|
|
118
157
|
records: (T & RecordResult)[];
|
|
@@ -124,41 +163,36 @@ interface PatchRecordOptions {
|
|
|
124
163
|
merge?: boolean;
|
|
125
164
|
}
|
|
126
165
|
interface RecordHistoryEntry {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
166
|
+
generation: number | null;
|
|
167
|
+
savedAt: number | null;
|
|
168
|
+
savedBy: string | null;
|
|
169
|
+
sizeBytes: number | null;
|
|
131
170
|
}
|
|
132
|
-
/** Options for
|
|
171
|
+
/** Options for `records.create()`. */
|
|
133
172
|
interface CreateRecordOptions {
|
|
134
173
|
/**
|
|
135
|
-
* Fields
|
|
136
|
-
* Only
|
|
174
|
+
* Fields to index for server-side filtering.
|
|
175
|
+
* Only listed fields will be queryable via `query({ filters: [...] })`.
|
|
137
176
|
*/
|
|
138
177
|
queryableFields?: string[];
|
|
139
|
-
/**
|
|
178
|
+
/** User email for audit trails. */
|
|
140
179
|
userEmail?: string;
|
|
141
180
|
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
181
|
+
* Custom record ID for upsert behaviour.
|
|
182
|
+
* Format: `YYMMDD-segment1__segment2` (e.g. `260307-user_alice__post_1`).
|
|
183
|
+
* If the ID already exists the record is updated in-place.
|
|
144
184
|
*/
|
|
145
185
|
customRecordId?: string;
|
|
146
186
|
}
|
|
147
|
-
/** Options for
|
|
187
|
+
/** Options for `records.batchCreate()`. */
|
|
148
188
|
interface BatchCreateOptions {
|
|
149
|
-
/** Fields to index for filtering — applied to all records in the batch. */
|
|
150
189
|
queryableFields?: string[];
|
|
151
|
-
/** Email of the user performing the action. */
|
|
152
190
|
userEmail?: string;
|
|
153
191
|
}
|
|
154
192
|
interface UploadOptions {
|
|
155
|
-
/** Make the file publicly accessible without authentication. */
|
|
156
193
|
isPublic?: boolean;
|
|
157
|
-
/** Overwrite an existing file at the same path. */
|
|
158
194
|
overwrite?: boolean;
|
|
159
|
-
/** MIME type of the file. Auto-detected from extension if omitted. */
|
|
160
195
|
mimeType?: string;
|
|
161
|
-
/** TTL in seconds for the signed upload URL (default 900 = 15 min). */
|
|
162
196
|
expiresInSeconds?: number;
|
|
163
197
|
}
|
|
164
198
|
interface UploadResult {
|
|
@@ -337,59 +371,112 @@ interface CrossBucketRow {
|
|
|
337
371
|
}
|
|
338
372
|
|
|
339
373
|
/**
|
|
340
|
-
* AuthClient —
|
|
341
|
-
* Uses the `authKey` (`hk_auth_…`) sent via `X-Api-Key` header.
|
|
374
|
+
* AuthClient — user authentication for a project.
|
|
342
375
|
*
|
|
343
|
-
* All routes are under `/auth
|
|
344
|
-
*
|
|
376
|
+
* All routes are under `/api/auth` (NOT `/api/auth/:bucketKey`).
|
|
377
|
+
* The server resolves which user bucket to use from the API key itself.
|
|
378
|
+
* Uses `X-Api-Key: <authKey>`.
|
|
345
379
|
*
|
|
346
380
|
* @example
|
|
347
381
|
* ```ts
|
|
348
|
-
* const
|
|
349
|
-
* const auth = db.auth('app-users');
|
|
382
|
+
* const auth = db.auth();
|
|
350
383
|
* const { user, session } = await auth.signup({ email: 'alice@example.com', password: 'hunter2' });
|
|
351
384
|
* ```
|
|
352
385
|
*/
|
|
353
386
|
declare class AuthClient {
|
|
354
387
|
private readonly http;
|
|
355
388
|
private readonly authKey;
|
|
356
|
-
|
|
357
|
-
constructor(http: HttpClient, authKey: string, bucketKey: string);
|
|
389
|
+
constructor(http: HttpClient, authKey: string);
|
|
358
390
|
private post;
|
|
359
391
|
private get;
|
|
360
392
|
private patch;
|
|
361
|
-
|
|
393
|
+
/**
|
|
394
|
+
* Register a new user account.
|
|
395
|
+
*
|
|
396
|
+
* Server: POST /api/auth/signup
|
|
397
|
+
* Body: { email, password, fullName?, ...extraData }
|
|
398
|
+
*/
|
|
362
399
|
signup(options: SignupOptions): Promise<AuthResult>;
|
|
400
|
+
/**
|
|
401
|
+
* Sign in with email + password.
|
|
402
|
+
*
|
|
403
|
+
* Server: POST /api/auth/signin (NOT /login)
|
|
404
|
+
* Body: { email, password }
|
|
405
|
+
*/
|
|
363
406
|
login(options: LoginOptions): Promise<AuthResult>;
|
|
407
|
+
/**
|
|
408
|
+
* Sign out — revoke a session (or all sessions with `allDevices: true`).
|
|
409
|
+
*
|
|
410
|
+
* Server: POST /api/auth/signout
|
|
411
|
+
* Body: { sessionId, allDevices? }
|
|
412
|
+
*/
|
|
364
413
|
logout(options: {
|
|
365
414
|
sessionId: string;
|
|
366
415
|
allDevices?: boolean;
|
|
367
416
|
}): Promise<void>;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
417
|
+
/**
|
|
418
|
+
* Validate an existing session and retrieve the current user.
|
|
419
|
+
*
|
|
420
|
+
* Server: POST /api/auth/session/validate
|
|
421
|
+
* Body: { sessionId }
|
|
422
|
+
*/
|
|
423
|
+
validateSession(sessionId: string): Promise<{
|
|
374
424
|
user: UserRecord;
|
|
375
425
|
session: {
|
|
376
426
|
sessionId: string;
|
|
377
427
|
expiresAt: number;
|
|
378
428
|
};
|
|
379
429
|
}>;
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
430
|
+
/**
|
|
431
|
+
* Rotate a refresh token to get a new session.
|
|
432
|
+
*
|
|
433
|
+
* Server: POST /api/auth/session/refresh
|
|
434
|
+
* Body: { refreshToken }
|
|
435
|
+
*/
|
|
436
|
+
refreshSession(refreshToken: string): Promise<Session>;
|
|
437
|
+
/**
|
|
438
|
+
* Fetch a user by ID.
|
|
439
|
+
*
|
|
440
|
+
* Server: GET /api/auth/user?userId=:userId
|
|
441
|
+
*/
|
|
442
|
+
getUser(userId: string): Promise<UserRecord>;
|
|
443
|
+
/**
|
|
444
|
+
* Update a user's profile fields.
|
|
445
|
+
* Regular users can only update themselves; admins can update any user.
|
|
446
|
+
*
|
|
447
|
+
* Server: PATCH /api/auth/user
|
|
448
|
+
* Body: { sessionId, userId, updates: { ...fields } }
|
|
449
|
+
*/
|
|
383
450
|
updateUser(options: UpdateUserOptions): Promise<UserRecord>;
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
451
|
+
/**
|
|
452
|
+
* Soft-delete a user account.
|
|
453
|
+
* Regular users can only delete themselves; admins can delete any user.
|
|
454
|
+
*
|
|
455
|
+
* Server: DELETE /api/auth/user?userId=:userId
|
|
456
|
+
* Body: { sessionId }
|
|
457
|
+
*/
|
|
458
|
+
deleteUser(sessionId: string, userId: string): Promise<void>;
|
|
459
|
+
/**
|
|
460
|
+
* List all users (paginated). Admin only.
|
|
461
|
+
*
|
|
462
|
+
* Server: GET /api/auth/users?limit=&cursor=
|
|
463
|
+
* The sessionId is passed via the X-Session-Id header (GET body is unreliable).
|
|
464
|
+
*/
|
|
388
465
|
listUsers(options: ListUsersOptions): Promise<ListUsersResult>;
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
466
|
+
/**
|
|
467
|
+
* Permanently delete a user (hard delete — cannot be undone).
|
|
468
|
+
* Admin only. Charged at 1 HC per deletion.
|
|
469
|
+
*
|
|
470
|
+
* Server: DELETE /api/auth/user/hard?userId=:userId
|
|
471
|
+
* Body: { sessionId }
|
|
472
|
+
*/
|
|
473
|
+
hardDeleteUser(sessionId: string, userId: string): Promise<void>;
|
|
474
|
+
/**
|
|
475
|
+
* Delete multiple users at once (soft or hard). Admin only.
|
|
476
|
+
*
|
|
477
|
+
* Server: DELETE /api/auth/users/bulk
|
|
478
|
+
* Body: { userIds, hard?, sessionId }
|
|
479
|
+
*/
|
|
393
480
|
bulkDeleteUsers(options: {
|
|
394
481
|
sessionId: string;
|
|
395
482
|
userIds: string[];
|
|
@@ -398,6 +485,12 @@ declare class AuthClient {
|
|
|
398
485
|
succeeded: number;
|
|
399
486
|
failed: number;
|
|
400
487
|
}>;
|
|
488
|
+
/**
|
|
489
|
+
* Lock a user account for a specified duration. Admin only.
|
|
490
|
+
*
|
|
491
|
+
* Server: POST /api/auth/account/lock
|
|
492
|
+
* Body: { sessionId, userId, duration? } — duration in ms, default 15 min
|
|
493
|
+
*/
|
|
401
494
|
lockAccount(options: {
|
|
402
495
|
sessionId: string;
|
|
403
496
|
userId: string;
|
|
@@ -406,29 +499,57 @@ declare class AuthClient {
|
|
|
406
499
|
lockedUntil: number;
|
|
407
500
|
unlockTime: string;
|
|
408
501
|
}>;
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
502
|
+
/**
|
|
503
|
+
* Unlock a locked user account. Admin only.
|
|
504
|
+
*
|
|
505
|
+
* Server: POST /api/auth/account/unlock
|
|
506
|
+
* Body: { sessionId, userId }
|
|
507
|
+
*/
|
|
508
|
+
unlockAccount(sessionId: string, userId: string): Promise<void>;
|
|
509
|
+
/**
|
|
510
|
+
* Change a user's password. Requires both a valid session AND the old password.
|
|
511
|
+
*
|
|
512
|
+
* Server: POST /api/auth/password/change
|
|
513
|
+
* Body: { sessionId, userId, oldPassword, newPassword }
|
|
514
|
+
*/
|
|
413
515
|
changePassword(options: ChangePasswordOptions): Promise<void>;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
516
|
+
/**
|
|
517
|
+
* Request a password reset email.
|
|
518
|
+
* Always returns success regardless of whether the email exists (prevents enumeration).
|
|
519
|
+
*
|
|
520
|
+
* Server: POST /api/auth/password/reset/request
|
|
521
|
+
* Body: { email }
|
|
522
|
+
*/
|
|
523
|
+
requestPasswordReset(email: string): Promise<void>;
|
|
524
|
+
/**
|
|
525
|
+
* Confirm a password reset using the token from the reset email.
|
|
526
|
+
*
|
|
527
|
+
* Server: POST /api/auth/password/reset/confirm
|
|
528
|
+
* Body: { resetToken, newPassword }
|
|
529
|
+
*/
|
|
530
|
+
confirmPasswordReset(resetToken: string, newPassword: string): Promise<void>;
|
|
531
|
+
/**
|
|
532
|
+
* Request a verification email be sent to a user.
|
|
533
|
+
*
|
|
534
|
+
* Server: POST /api/auth/email/verify/request
|
|
535
|
+
* Body: { userId }
|
|
536
|
+
*/
|
|
537
|
+
requestEmailVerification(userId: string): Promise<void>;
|
|
538
|
+
/**
|
|
539
|
+
* Confirm email ownership using the token from the verification email.
|
|
540
|
+
*
|
|
541
|
+
* Server: POST /api/auth/email/verify/confirm
|
|
542
|
+
* Body: { verifyToken }
|
|
543
|
+
*/
|
|
544
|
+
confirmEmailVerification(verifyToken: string): Promise<void>;
|
|
545
|
+
private _buildAuthResult;
|
|
427
546
|
}
|
|
428
547
|
|
|
429
548
|
/**
|
|
430
|
-
* RecordsClient — typed CRUD +
|
|
431
|
-
*
|
|
549
|
+
* RecordsClient — typed CRUD + batch + query for a single bucket.
|
|
550
|
+
*
|
|
551
|
+
* All requests use `X-Api-Key: <bucketSecurityKey>`.
|
|
552
|
+
* Routes: GET|POST|PATCH|DELETE /api/:bucketKey
|
|
432
553
|
*
|
|
433
554
|
* @example
|
|
434
555
|
* ```ts
|
|
@@ -441,14 +562,13 @@ declare class RecordsClient<T extends RecordData = RecordData> {
|
|
|
441
562
|
private readonly http;
|
|
442
563
|
private readonly bucketKey;
|
|
443
564
|
private readonly apiKey;
|
|
444
|
-
private readonly basePath;
|
|
445
565
|
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
446
566
|
/**
|
|
447
|
-
* Create a new record
|
|
567
|
+
* Create a new record (auto-generated ID) or upsert by `customRecordId`.
|
|
448
568
|
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
451
|
-
*
|
|
569
|
+
* Server: POST /api/:bucketKey
|
|
570
|
+
* Body: { values, queryableFields?, userEmail?, customRecordId? }
|
|
571
|
+
* Returns 201 for new records, 200 for upserts.
|
|
452
572
|
*
|
|
453
573
|
* @example
|
|
454
574
|
* ```ts
|
|
@@ -461,44 +581,97 @@ declare class RecordsClient<T extends RecordData = RecordData> {
|
|
|
461
581
|
create(data: T, options?: CreateRecordOptions): Promise<T & RecordResult>;
|
|
462
582
|
/**
|
|
463
583
|
* Get a single record by ID.
|
|
584
|
+
*
|
|
585
|
+
* Server: GET /api/:bucketKey?recordId=:id
|
|
464
586
|
*/
|
|
465
587
|
get(id: string): Promise<T & RecordResult>;
|
|
466
588
|
/**
|
|
467
|
-
*
|
|
468
|
-
*/
|
|
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.
|
|
589
|
+
* Partially update an existing record (PATCH semantics).
|
|
473
590
|
* Supports write-filter sentinels: `{ __op: 'increment', delta: 1 }` etc.
|
|
591
|
+
*
|
|
592
|
+
* Server: PATCH /api/:bucketKey
|
|
593
|
+
* Body: { recordId, values, userEmail?, track_record_history? }
|
|
474
594
|
*/
|
|
475
|
-
patch(id: string, data: Partial<T>, options?: PatchRecordOptions
|
|
595
|
+
patch(id: string, data: Partial<T>, options?: PatchRecordOptions & {
|
|
596
|
+
userEmail?: string;
|
|
597
|
+
trackHistory?: boolean;
|
|
598
|
+
}): Promise<{
|
|
599
|
+
id: string;
|
|
600
|
+
updatedAt?: number;
|
|
601
|
+
}>;
|
|
476
602
|
/**
|
|
477
603
|
* Delete a record permanently.
|
|
604
|
+
*
|
|
605
|
+
* Server: DELETE /api/:bucketKey?recordId=:id
|
|
478
606
|
*/
|
|
479
607
|
delete(id: string): Promise<void>;
|
|
480
608
|
/**
|
|
481
|
-
*
|
|
482
|
-
*
|
|
609
|
+
* Check whether a record exists (HEAD request — very lightweight).
|
|
610
|
+
*
|
|
611
|
+
* Server: HEAD /api/:bucketKey?recordId=:id
|
|
612
|
+
* Returns true if the record exists, false if 404.
|
|
613
|
+
*/
|
|
614
|
+
exists(id: string): Promise<boolean>;
|
|
615
|
+
/**
|
|
616
|
+
* Get a historical snapshot of a record at a specific generation.
|
|
617
|
+
*
|
|
618
|
+
* Server: GET /api/:bucketKey?recordId=:id&generation=:gen
|
|
619
|
+
*/
|
|
620
|
+
getVersion(id: string, generation: string | number): Promise<T & RecordResult>;
|
|
621
|
+
/**
|
|
622
|
+
* Get the version history of a record.
|
|
623
|
+
*
|
|
624
|
+
* Server: GET /api/:bucketKey?recordId=:id&showHistory=true
|
|
625
|
+
*/
|
|
626
|
+
getHistory(id: string): Promise<RecordHistoryEntry[]>;
|
|
627
|
+
/**
|
|
628
|
+
* Create up to 500 records in one request.
|
|
629
|
+
* Each record may include `_customRecordId` for upsert behaviour.
|
|
630
|
+
*
|
|
631
|
+
* Server: POST /api/:bucketKey/batch/insert
|
|
632
|
+
* Body: { records, queryableFields?, userEmail? }
|
|
483
633
|
*
|
|
484
634
|
* @example
|
|
485
635
|
* ```ts
|
|
486
|
-
* const
|
|
636
|
+
* const results = await posts.batchCreate(
|
|
487
637
|
* [{ title: 'A' }, { title: 'B' }],
|
|
488
|
-
* { queryableFields: ['title']
|
|
638
|
+
* { queryableFields: ['title'] },
|
|
489
639
|
* );
|
|
490
640
|
* ```
|
|
491
641
|
*/
|
|
492
|
-
batchCreate(items: T[], options?: BatchCreateOptions): Promise<
|
|
642
|
+
batchCreate(items: T[], options?: BatchCreateOptions): Promise<{
|
|
643
|
+
results: (T & RecordResult)[];
|
|
644
|
+
errors: unknown[];
|
|
645
|
+
successful: number;
|
|
646
|
+
failed: number;
|
|
647
|
+
}>;
|
|
648
|
+
/**
|
|
649
|
+
* Update up to 500 records in one request.
|
|
650
|
+
*
|
|
651
|
+
* Server: POST /api/:bucketKey/batch/update
|
|
652
|
+
* Body: { updates: [{ recordId, values }], userEmail? }
|
|
653
|
+
*/
|
|
654
|
+
batchUpdate(updates: Array<{
|
|
655
|
+
recordId: string;
|
|
656
|
+
values: Partial<T>;
|
|
657
|
+
}>, userEmail?: string): Promise<{
|
|
658
|
+
successful: number;
|
|
659
|
+
failed: string[];
|
|
660
|
+
}>;
|
|
493
661
|
/**
|
|
494
|
-
* Delete
|
|
662
|
+
* Delete up to 500 records in one request.
|
|
663
|
+
*
|
|
664
|
+
* Server: POST /api/:bucketKey/batch/delete
|
|
665
|
+
* Body: { recordIds, userEmail? }
|
|
495
666
|
*/
|
|
496
|
-
batchDelete(ids: string[]): Promise<{
|
|
497
|
-
|
|
667
|
+
batchDelete(ids: string[], userEmail?: string): Promise<{
|
|
668
|
+
successful: number;
|
|
498
669
|
failed: string[];
|
|
499
670
|
}>;
|
|
500
671
|
/**
|
|
501
|
-
* Query records with
|
|
672
|
+
* Query records with filters, sorting, and cursor-based pagination.
|
|
673
|
+
*
|
|
674
|
+
* Server: GET /api/:bucketKey?field=value&field[op]=value&limit=&sortBy=&sortOrder=&cursor=
|
|
502
675
|
*
|
|
503
676
|
* @example
|
|
504
677
|
* ```ts
|
|
@@ -512,30 +685,18 @@ declare class RecordsClient<T extends RecordData = RecordData> {
|
|
|
512
685
|
*/
|
|
513
686
|
query(options?: QueryOptions): Promise<QueryResult<T>>;
|
|
514
687
|
/**
|
|
515
|
-
*
|
|
688
|
+
* Retrieve all records matching options (no filter support — use `query()` for filters).
|
|
516
689
|
*/
|
|
517
690
|
getAll(options?: Omit<QueryOptions, 'filters'>): Promise<(T & RecordResult)[]>;
|
|
518
|
-
/**
|
|
519
|
-
* Count records matching the given filters.
|
|
520
|
-
*/
|
|
521
|
-
count(filters?: QueryOptions['filters']): Promise<number>;
|
|
522
|
-
/**
|
|
523
|
-
* Get the version history of a record.
|
|
524
|
-
*/
|
|
525
|
-
getHistory(id: string): Promise<RecordHistoryEntry[]>;
|
|
526
|
-
/**
|
|
527
|
-
* Restore a record to a previous version.
|
|
528
|
-
*/
|
|
529
|
-
restoreVersion(id: string, version: number): Promise<T & RecordResult>;
|
|
530
691
|
}
|
|
531
692
|
|
|
532
693
|
/**
|
|
533
694
|
* AnalyticsClient — BigQuery-powered aggregations for a single bucket.
|
|
534
|
-
* Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
|
|
535
695
|
*
|
|
536
|
-
* All methods POST a `queryType` body to `POST /analytics/:bucketKey`.
|
|
696
|
+
* All methods POST a `queryType` body to `POST /api/analytics/:bucketKey`.
|
|
537
697
|
* The `dateRange` is passed as `{ start, end }` ms timestamps — the server
|
|
538
698
|
* converts them to ISO date strings internally.
|
|
699
|
+
* Uses `X-Api-Key: <bucketSecurityKey>`.
|
|
539
700
|
*
|
|
540
701
|
* @example
|
|
541
702
|
* ```ts
|
|
@@ -547,14 +708,17 @@ declare class RecordsClient<T extends RecordData = RecordData> {
|
|
|
547
708
|
declare class AnalyticsClient {
|
|
548
709
|
private readonly http;
|
|
549
710
|
private readonly bucketSecurityKey;
|
|
550
|
-
private readonly
|
|
711
|
+
private readonly bucketKey;
|
|
551
712
|
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
552
713
|
private run;
|
|
553
714
|
/** Count all records, optionally within a date range. */
|
|
554
715
|
count(opts?: {
|
|
555
716
|
dateRange?: DateRange;
|
|
556
717
|
}): Promise<CountResult>;
|
|
557
|
-
/**
|
|
718
|
+
/**
|
|
719
|
+
* Get value distribution for a field (e.g. records per status).
|
|
720
|
+
* `order` maps to `sortBy` on the wire (the server param name).
|
|
721
|
+
*/
|
|
558
722
|
distribution(opts: {
|
|
559
723
|
field: string;
|
|
560
724
|
limit?: number;
|
|
@@ -593,7 +757,10 @@ declare class AnalyticsClient {
|
|
|
593
757
|
field: string;
|
|
594
758
|
dateRange?: DateRange;
|
|
595
759
|
}): Promise<FieldStats>;
|
|
596
|
-
/**
|
|
760
|
+
/**
|
|
761
|
+
* Fetch filtered records via the analytics engine (BigQuery).
|
|
762
|
+
* Bypasses Firestore pagination — useful for large result sets.
|
|
763
|
+
*/
|
|
597
764
|
records<T extends RecordData = RecordData>(opts?: {
|
|
598
765
|
filters?: AnalyticsFilter[];
|
|
599
766
|
selectFields?: string[];
|
|
@@ -603,7 +770,10 @@ declare class AnalyticsClient {
|
|
|
603
770
|
order?: SortOrder;
|
|
604
771
|
dateRange?: DateRange;
|
|
605
772
|
}): Promise<(T & RecordResult)[]>;
|
|
606
|
-
/**
|
|
773
|
+
/**
|
|
774
|
+
* Compute multiple aggregations in a single request.
|
|
775
|
+
* `metrics` must have valid `field` and `name` (used as BigQuery column aliases).
|
|
776
|
+
*/
|
|
607
777
|
multiMetric(opts: {
|
|
608
778
|
metrics: MetricDefinition[];
|
|
609
779
|
dateRange?: DateRange;
|
|
@@ -614,7 +784,8 @@ declare class AnalyticsClient {
|
|
|
614
784
|
}): Promise<StorageStatsResult>;
|
|
615
785
|
/**
|
|
616
786
|
* Compare a metric across multiple buckets in one query.
|
|
617
|
-
* The caller's key must have read access to
|
|
787
|
+
* The caller's key must have read access to EVERY bucket in `bucketKeys`.
|
|
788
|
+
* System buckets (`users`, `_sys_*`) are blocked server-side.
|
|
618
789
|
*/
|
|
619
790
|
crossBucket(opts: {
|
|
620
791
|
bucketKeys: string[];
|
|
@@ -623,34 +794,39 @@ declare class AnalyticsClient {
|
|
|
623
794
|
dateRange?: DateRange;
|
|
624
795
|
}): Promise<CrossBucketRow[]>;
|
|
625
796
|
/**
|
|
626
|
-
* Raw query —
|
|
797
|
+
* Raw query — escape hatch when the typed helpers don't cover your case.
|
|
627
798
|
*/
|
|
628
799
|
query<T = unknown>(query: AnalyticsQuery): Promise<AnalyticsResult<T>>;
|
|
629
800
|
}
|
|
630
801
|
|
|
631
802
|
/**
|
|
632
803
|
* StorageManager — upload, download, list, move, copy, and delete files.
|
|
633
|
-
*
|
|
804
|
+
*
|
|
805
|
+
* Uses `X-Storage-Key: <ssk_…>` header — separate from auth and bucket keys.
|
|
806
|
+
* Files are scoped server-side to `hydrous-storage/{ownerId}/{userPath}`.
|
|
807
|
+
* You only ever deal with your own `userPath` — the server handles scoping.
|
|
634
808
|
*
|
|
635
809
|
* Get a StorageManager via `db.storage('keyName')` where the name matches
|
|
636
810
|
* one of the keys defined in `storageKeys` when calling `createClient`.
|
|
637
811
|
*
|
|
638
812
|
* @example
|
|
639
813
|
* ```ts
|
|
640
|
-
* const
|
|
641
|
-
* const result = await
|
|
814
|
+
* const storage = db.storage('avatars');
|
|
815
|
+
* const result = await storage.upload(file, 'alice.jpg', { isPublic: true });
|
|
642
816
|
* console.log(result.publicUrl);
|
|
643
817
|
* ```
|
|
644
818
|
*/
|
|
645
819
|
declare class StorageManager {
|
|
646
820
|
private readonly http;
|
|
647
821
|
private readonly storageKey;
|
|
648
|
-
readonly basePath = "/storage";
|
|
649
822
|
constructor(http: HttpClient, storageKey: string);
|
|
650
823
|
private get authHeaders();
|
|
651
824
|
/**
|
|
652
|
-
* Upload a file
|
|
653
|
-
* For files >10 MB or when upload progress is needed, use
|
|
825
|
+
* Upload a file in one step (server-buffered, up to 500 MB).
|
|
826
|
+
* For files >10 MB or when upload progress tracking is needed, use the
|
|
827
|
+
* signed URL flow: `getUploadUrl()` → `uploadToSignedUrl()` → `confirmUpload()`.
|
|
828
|
+
*
|
|
829
|
+
* Server: POST /storage/upload (multipart/form-data)
|
|
654
830
|
*
|
|
655
831
|
* @example
|
|
656
832
|
* ```ts
|
|
@@ -660,7 +836,10 @@ declare class StorageManager {
|
|
|
660
836
|
*/
|
|
661
837
|
upload(data: Blob | Uint8Array | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
662
838
|
/**
|
|
663
|
-
* Upload raw
|
|
839
|
+
* Upload raw string or JSON data directly as a file.
|
|
840
|
+
*
|
|
841
|
+
* Server: POST /storage/upload-raw
|
|
842
|
+
* Body: { path, content, mimeType?, isPublic?, overwrite? }
|
|
664
843
|
*
|
|
665
844
|
* @example
|
|
666
845
|
* ```ts
|
|
@@ -669,19 +848,18 @@ declare class StorageManager {
|
|
|
669
848
|
*/
|
|
670
849
|
uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
671
850
|
/**
|
|
672
|
-
* Step 1 — get a signed GCS URL to upload
|
|
673
|
-
*
|
|
851
|
+
* Step 1 — get a signed GCS PUT URL for direct client-to-GCS upload.
|
|
852
|
+
*
|
|
853
|
+
* Server: POST /storage/upload-url
|
|
854
|
+
* Body: { path, mimeType, size, isPublic?, overwrite?, expiresIn? }
|
|
674
855
|
*
|
|
675
856
|
* @example
|
|
676
857
|
* ```ts
|
|
677
|
-
* const { uploadUrl, path:
|
|
678
|
-
* path:
|
|
679
|
-
* mimeType: 'video/mp4',
|
|
680
|
-
* size: file.size,
|
|
681
|
-
* isPublic: true,
|
|
858
|
+
* const { uploadUrl, path: p } = await storage.getUploadUrl({
|
|
859
|
+
* path: 'videos/intro.mp4', mimeType: 'video/mp4', size: file.size,
|
|
682
860
|
* });
|
|
683
|
-
* await storage.uploadToSignedUrl(uploadUrl, file, 'video/mp4', pct =>
|
|
684
|
-
* const result = await storage.confirmUpload({ path:
|
|
861
|
+
* await storage.uploadToSignedUrl(uploadUrl, file, 'video/mp4', pct => setProgress(pct));
|
|
862
|
+
* const result = await storage.confirmUpload({ path: p, mimeType: 'video/mp4' });
|
|
685
863
|
* ```
|
|
686
864
|
*/
|
|
687
865
|
getUploadUrl(opts: {
|
|
@@ -693,12 +871,15 @@ declare class StorageManager {
|
|
|
693
871
|
expiresInSeconds?: number;
|
|
694
872
|
}): Promise<UploadUrlResult>;
|
|
695
873
|
/**
|
|
696
|
-
* Step 2 — upload data directly to
|
|
697
|
-
* Supports progress tracking in browser environments.
|
|
874
|
+
* Step 2 — upload data directly to the signed GCS URL.
|
|
875
|
+
* Supports progress tracking in browser environments via XHR.
|
|
698
876
|
*/
|
|
699
877
|
uploadToSignedUrl(signedUrl: string, data: Blob | Uint8Array | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
700
878
|
/**
|
|
701
|
-
* Step 3 — confirm a direct upload and register metadata
|
|
879
|
+
* Step 3 — confirm a direct upload and register metadata server-side.
|
|
880
|
+
*
|
|
881
|
+
* Server: POST /storage/confirm
|
|
882
|
+
* Body: { path, mimeType, isPublic? }
|
|
702
883
|
*/
|
|
703
884
|
confirmUpload(opts: {
|
|
704
885
|
path: string;
|
|
@@ -706,25 +887,17 @@ declare class StorageManager {
|
|
|
706
887
|
isPublic?: boolean;
|
|
707
888
|
}): Promise<UploadResult>;
|
|
708
889
|
/**
|
|
709
|
-
* Get signed upload URLs for
|
|
710
|
-
* Server returns `{ succeeded, failed }` — only succeeded items have URLs.
|
|
890
|
+
* Get signed upload URLs for up to 50 files at once.
|
|
711
891
|
*
|
|
712
|
-
*
|
|
713
|
-
*
|
|
714
|
-
* const { files } = await storage.getBatchUploadUrls([
|
|
715
|
-
* { path: 'images/a.jpg', mimeType: 'image/jpeg', size: 204800 },
|
|
716
|
-
* { path: 'images/b.jpg', mimeType: 'image/jpeg', size: 153600 },
|
|
717
|
-
* ]);
|
|
718
|
-
* for (const f of files) {
|
|
719
|
-
* await storage.uploadToSignedUrl(f.uploadUrl, blobs[f.index], f.mimeType);
|
|
720
|
-
* await storage.confirmUpload({ path: f.path, mimeType: f.mimeType });
|
|
721
|
-
* }
|
|
722
|
-
* ```
|
|
892
|
+
* Server: POST /storage/batch-upload-urls
|
|
893
|
+
* Body: { files: [...], expiresIn? }
|
|
723
894
|
*/
|
|
724
895
|
getBatchUploadUrls(files: BatchUploadItem[]): Promise<BatchUploadUrlResult>;
|
|
725
896
|
/**
|
|
726
897
|
* Confirm multiple direct uploads at once.
|
|
727
|
-
*
|
|
898
|
+
*
|
|
899
|
+
* Server: POST /storage/batch-confirm
|
|
900
|
+
* Body: { files: [{ path, mimeType, isPublic? }] }
|
|
728
901
|
*/
|
|
729
902
|
batchConfirmUploads(items: Array<{
|
|
730
903
|
path: string;
|
|
@@ -740,25 +913,21 @@ declare class StorageManager {
|
|
|
740
913
|
/**
|
|
741
914
|
* Download a private file as an ArrayBuffer.
|
|
742
915
|
* For public files, use the `publicUrl` directly — no SDK needed.
|
|
916
|
+
*
|
|
917
|
+
* Server: GET /storage/download/:path (requires X-Storage-Key)
|
|
743
918
|
*/
|
|
744
919
|
download(path: string): Promise<ArrayBuffer>;
|
|
745
920
|
/**
|
|
746
|
-
* Download
|
|
747
|
-
* Returns a structured result with succeeded and failed items.
|
|
748
|
-
* Each succeeded item includes the file content as a base64 string.
|
|
921
|
+
* Download up to 20 files at once. Returns base64-encoded content.
|
|
749
922
|
*
|
|
750
|
-
*
|
|
751
|
-
*
|
|
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
|
-
* }
|
|
756
|
-
* ```
|
|
923
|
+
* Server: POST /storage/batch-download
|
|
924
|
+
* Body: { paths, concurrency? }
|
|
757
925
|
*/
|
|
758
|
-
batchDownload(paths: string[]): Promise<BatchDownloadResult>;
|
|
926
|
+
batchDownload(paths: string[], concurrency?: number): Promise<BatchDownloadResult>;
|
|
759
927
|
/**
|
|
760
928
|
* List files and folders at a given path prefix.
|
|
761
|
-
*
|
|
929
|
+
*
|
|
930
|
+
* Server: GET /storage/list?prefix=&limit=&cursor=
|
|
762
931
|
*
|
|
763
932
|
* @example
|
|
764
933
|
* ```ts
|
|
@@ -768,21 +937,29 @@ declare class StorageManager {
|
|
|
768
937
|
*/
|
|
769
938
|
list(opts?: ListOptions): Promise<ListResult>;
|
|
770
939
|
/**
|
|
771
|
-
* Get metadata
|
|
940
|
+
* Get file metadata: size, MIME type, visibility, URLs.
|
|
941
|
+
*
|
|
942
|
+
* Server: GET /storage/metadata/:path
|
|
772
943
|
*/
|
|
773
944
|
getMetadata(path: string): Promise<FileMetadata>;
|
|
774
945
|
/**
|
|
775
946
|
* Generate a time-limited download URL for a private file.
|
|
776
|
-
* Can be shared externally
|
|
947
|
+
* Can be shared externally — no X-Storage-Key required to access.
|
|
948
|
+
*
|
|
949
|
+
* Note: Downloads via signed URLs bypass the server — stats are NOT tracked.
|
|
777
950
|
*
|
|
778
|
-
*
|
|
951
|
+
* Server: POST /storage/signed-url
|
|
952
|
+
* Body: { path, expiresIn? }
|
|
779
953
|
*
|
|
780
954
|
* @param path File path.
|
|
781
955
|
* @param expiresIn URL lifetime in seconds (default 3600 = 1 hour).
|
|
782
956
|
*/
|
|
783
957
|
getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
|
|
784
958
|
/**
|
|
785
|
-
* Change a file's visibility between public and private
|
|
959
|
+
* Change a file's visibility between public and private.
|
|
960
|
+
*
|
|
961
|
+
* Server: PATCH /storage/visibility
|
|
962
|
+
* Body: { path, isPublic }
|
|
786
963
|
*/
|
|
787
964
|
setVisibility(path: string, isPublic: boolean): Promise<{
|
|
788
965
|
path: string;
|
|
@@ -790,20 +967,60 @@ declare class StorageManager {
|
|
|
790
967
|
publicUrl: string | null;
|
|
791
968
|
downloadUrl: string | null;
|
|
792
969
|
}>;
|
|
970
|
+
/**
|
|
971
|
+
* Create a folder (empty GCS object used as a prefix marker).
|
|
972
|
+
*
|
|
973
|
+
* Server: POST /storage/folder
|
|
974
|
+
* Body: { path }
|
|
975
|
+
*/
|
|
793
976
|
createFolder(path: string): Promise<{
|
|
794
977
|
path: string;
|
|
795
978
|
}>;
|
|
979
|
+
/**
|
|
980
|
+
* Permanently delete a file.
|
|
981
|
+
*
|
|
982
|
+
* Server: DELETE /storage/file
|
|
983
|
+
* Body: { path }
|
|
984
|
+
*/
|
|
796
985
|
deleteFile(path: string): Promise<void>;
|
|
986
|
+
/**
|
|
987
|
+
* Recursively delete a folder and all its contents.
|
|
988
|
+
*
|
|
989
|
+
* Server: DELETE /storage/folder
|
|
990
|
+
* Body: { path }
|
|
991
|
+
*/
|
|
797
992
|
deleteFolder(path: string): Promise<void>;
|
|
993
|
+
/**
|
|
994
|
+
* Move (rename) a file.
|
|
995
|
+
*
|
|
996
|
+
* Server: POST /storage/move
|
|
997
|
+
* Body: { from, to }
|
|
998
|
+
*/
|
|
798
999
|
move(from: string, to: string): Promise<{
|
|
799
1000
|
from: string;
|
|
800
1001
|
to: string;
|
|
801
1002
|
}>;
|
|
1003
|
+
/**
|
|
1004
|
+
* Copy a file to a new path.
|
|
1005
|
+
*
|
|
1006
|
+
* Server: POST /storage/copy
|
|
1007
|
+
* Body: { from, to }
|
|
1008
|
+
*/
|
|
802
1009
|
copy(from: string, to: string): Promise<{
|
|
803
1010
|
from: string;
|
|
804
1011
|
to: string;
|
|
805
1012
|
}>;
|
|
1013
|
+
/**
|
|
1014
|
+
* Get usage statistics for this storage key.
|
|
1015
|
+
*
|
|
1016
|
+
* Server: GET /storage/stats
|
|
1017
|
+
*/
|
|
806
1018
|
getStats(): Promise<StorageStats>;
|
|
1019
|
+
/**
|
|
1020
|
+
* Get server info (no auth required).
|
|
1021
|
+
*
|
|
1022
|
+
* Server: GET /storage/info
|
|
1023
|
+
*/
|
|
807
1024
|
info(): Promise<{
|
|
808
1025
|
ok: boolean;
|
|
809
1026
|
storageRoot: string;
|
|
@@ -812,8 +1029,8 @@ declare class StorageManager {
|
|
|
812
1029
|
|
|
813
1030
|
/**
|
|
814
1031
|
* ScopedStorage — a path-prefixed view over a StorageManager.
|
|
815
|
-
* All paths you pass are automatically prefixed with the scope.
|
|
816
1032
|
*
|
|
1033
|
+
* Every path you pass is automatically prefixed with the scope.
|
|
817
1034
|
* Obtain via `db.storage('keyName').scope('prefix/')`.
|
|
818
1035
|
*
|
|
819
1036
|
* @example
|
|
@@ -823,7 +1040,7 @@ declare class StorageManager {
|
|
|
823
1040
|
* // Uploads to: users/{userId}/contract.pdf
|
|
824
1041
|
* await userDocs.upload(pdfBuffer, 'contract.pdf');
|
|
825
1042
|
*
|
|
826
|
-
* // Lists:
|
|
1043
|
+
* // Lists: users/{userId}/
|
|
827
1044
|
* const { files } = await userDocs.list();
|
|
828
1045
|
* ```
|
|
829
1046
|
*/
|
|
@@ -863,7 +1080,8 @@ declare class ScopedStorage {
|
|
|
863
1080
|
download(path: string): Promise<ArrayBuffer>;
|
|
864
1081
|
batchDownload(paths: string[]): Promise<BatchDownloadResult>;
|
|
865
1082
|
/**
|
|
866
|
-
* List files within this scope.
|
|
1083
|
+
* List files within this scope.
|
|
1084
|
+
* The `prefix` option is relative to the scope root.
|
|
867
1085
|
*
|
|
868
1086
|
* @example
|
|
869
1087
|
* ```ts
|
|
@@ -900,7 +1118,7 @@ declare class ScopedStorage {
|
|
|
900
1118
|
*
|
|
901
1119
|
* @example
|
|
902
1120
|
* ```ts
|
|
903
|
-
* const user
|
|
1121
|
+
* const user = storage.scope('users/alice/');
|
|
904
1122
|
* const userDocs = user.scope('docs/');
|
|
905
1123
|
* // Effective prefix: users/alice/docs/
|
|
906
1124
|
* ```
|
|
@@ -908,92 +1126,61 @@ declare class ScopedStorage {
|
|
|
908
1126
|
scope(subPrefix: string): ScopedStorage;
|
|
909
1127
|
}
|
|
910
1128
|
|
|
911
|
-
/**
|
|
912
|
-
* HydrousClient — the main entry point for the HydrousDB SDK.
|
|
913
|
-
*
|
|
914
|
-
* Each service uses its own dedicated API key:
|
|
915
|
-
* - `authKey` (`hk_auth_…`) → `db.auth('bucket')`
|
|
916
|
-
* - `bucketSecurityKey` (`hk_bucket_…`) → `db.records('bucket')` + `db.analytics('bucket')`
|
|
917
|
-
* - `storageKeys` (`ssk_…`) → `db.storage('keyName')`
|
|
918
|
-
*
|
|
919
|
-
* Sub-clients are cached — calling `db.records('posts')` twice returns the same instance.
|
|
920
|
-
*
|
|
921
|
-
* @example
|
|
922
|
-
* ```ts
|
|
923
|
-
* import { createClient } from 'hydrousdb';
|
|
924
|
-
*
|
|
925
|
-
* const db = createClient({
|
|
926
|
-
* authKey: process.env.HYDROUS_AUTH_KEY!,
|
|
927
|
-
* bucketSecurityKey: process.env.HYDROUS_BUCKET_KEY!,
|
|
928
|
-
* storageKeys: {
|
|
929
|
-
* avatars: process.env.HYDROUS_STORAGE_AVATARS!,
|
|
930
|
-
* documents: process.env.HYDROUS_STORAGE_DOCS!,
|
|
931
|
-
* },
|
|
932
|
-
* });
|
|
933
|
-
*
|
|
934
|
-
* const posts = db.records('blog-posts');
|
|
935
|
-
* const auth = db.auth('app-users');
|
|
936
|
-
* const analytics = db.analytics('orders');
|
|
937
|
-
* const avatars = db.storage('avatars');
|
|
938
|
-
* ```
|
|
939
|
-
*/
|
|
940
1129
|
declare class HydrousClient {
|
|
941
1130
|
private readonly http;
|
|
942
1131
|
private readonly authKey_;
|
|
943
1132
|
private readonly bucketSecurityKey_;
|
|
944
1133
|
private readonly storageKeys_;
|
|
945
1134
|
private readonly _recordsCache;
|
|
946
|
-
private readonly _authCache;
|
|
947
1135
|
private readonly _analyticsCache;
|
|
948
1136
|
private readonly _storageCache;
|
|
1137
|
+
private _authClient?;
|
|
949
1138
|
constructor(config: HydrousConfig);
|
|
950
1139
|
/**
|
|
951
|
-
* Get a typed
|
|
1140
|
+
* Get a typed RecordsClient for a bucket.
|
|
952
1141
|
*
|
|
953
1142
|
* @example
|
|
954
1143
|
* ```ts
|
|
955
1144
|
* interface Post { title: string; published: boolean }
|
|
956
1145
|
* const posts = db.records<Post>('blog-posts');
|
|
957
|
-
* const post = await posts.create(
|
|
958
|
-
* { title: 'Hello', published: false },
|
|
959
|
-
* { queryableFields: ['published'] },
|
|
960
|
-
* );
|
|
1146
|
+
* const post = await posts.create({ title: 'Hello', published: false });
|
|
961
1147
|
* ```
|
|
962
1148
|
*/
|
|
963
1149
|
records<T extends RecordData = RecordData>(bucketKey: string): RecordsClient<T>;
|
|
964
1150
|
/**
|
|
965
|
-
* Get
|
|
1151
|
+
* Get the AuthClient.
|
|
1152
|
+
* Auth routes are NOT bucket-scoped in the URL — the bucket is determined
|
|
1153
|
+
* server-side from the API key itself.
|
|
966
1154
|
*
|
|
967
1155
|
* @example
|
|
968
1156
|
* ```ts
|
|
969
|
-
* const
|
|
970
|
-
* const { user, session } = await auth.login({ email: '…', password: '…' });
|
|
1157
|
+
* const { user, session } = await db.auth().signup({ email: 'alice@example.com', password: 'pw' });
|
|
971
1158
|
* ```
|
|
972
1159
|
*/
|
|
973
|
-
auth(
|
|
1160
|
+
auth(): AuthClient;
|
|
974
1161
|
/**
|
|
975
|
-
* Get an
|
|
1162
|
+
* Get an AnalyticsClient for a bucket.
|
|
976
1163
|
*
|
|
977
1164
|
* @example
|
|
978
1165
|
* ```ts
|
|
979
|
-
* const
|
|
980
|
-
* const { count } = await analytics.count();
|
|
1166
|
+
* const { count } = await db.analytics('orders').count();
|
|
981
1167
|
* ```
|
|
982
1168
|
*/
|
|
983
1169
|
analytics(bucketKey: string): AnalyticsClient;
|
|
984
1170
|
/**
|
|
985
|
-
* Get a
|
|
986
|
-
* The name must match a key
|
|
1171
|
+
* Get a StorageManager for a named storage key.
|
|
1172
|
+
* The name must match a key in the `storageKeys` config object.
|
|
987
1173
|
*
|
|
988
|
-
* Attach `.scope(prefix)` to
|
|
1174
|
+
* Attach `.scope('prefix/')` to get a path-prefixed ScopedStorage.
|
|
989
1175
|
*
|
|
990
1176
|
* @example
|
|
991
1177
|
* ```ts
|
|
992
|
-
* const avatars
|
|
993
|
-
* const
|
|
1178
|
+
* const avatars = db.storage('avatars');
|
|
1179
|
+
* const result = await avatars.upload(file, 'alice.jpg', { isPublic: true });
|
|
994
1180
|
*
|
|
995
|
-
*
|
|
996
|
-
*
|
|
1181
|
+
* // Scoped:
|
|
1182
|
+
* const userFiles = db.storage('documents').scope(`users/${userId}/`);
|
|
1183
|
+
* await userFiles.upload(pdf, 'contract.pdf');
|
|
997
1184
|
* ```
|
|
998
1185
|
*/
|
|
999
1186
|
storage(keyName: string): StorageManager & {
|
|
@@ -1001,21 +1188,131 @@ declare class HydrousClient {
|
|
|
1001
1188
|
};
|
|
1002
1189
|
}
|
|
1003
1190
|
/**
|
|
1004
|
-
* Create a
|
|
1191
|
+
* Create a HydrousDB client.
|
|
1005
1192
|
*
|
|
1006
1193
|
* @example
|
|
1007
1194
|
* ```ts
|
|
1008
|
-
* import { createClient } from '
|
|
1195
|
+
* import { createClient } from 'hydrous-sdk';
|
|
1009
1196
|
*
|
|
1010
1197
|
* const db = createClient({
|
|
1011
|
-
* authKey:
|
|
1012
|
-
* bucketSecurityKey:
|
|
1013
|
-
* storageKeys:
|
|
1198
|
+
* authKey: 'hk_auth_…',
|
|
1199
|
+
* bucketSecurityKey: 'hk_bucket_…',
|
|
1200
|
+
* storageKeys: { avatars: 'ssk_…' },
|
|
1014
1201
|
* });
|
|
1015
1202
|
* ```
|
|
1016
1203
|
*/
|
|
1017
1204
|
declare function createClient(config: HydrousConfig): HydrousClient;
|
|
1018
1205
|
|
|
1206
|
+
/**
|
|
1207
|
+
* routes.ts — Single source of truth for every API path in the HydrousDB SDK.
|
|
1208
|
+
*
|
|
1209
|
+
* Base URL: https://db-api-82687684612.us-central1.run.app
|
|
1210
|
+
*
|
|
1211
|
+
* Mount points (from server.js):
|
|
1212
|
+
* /api → records router (X-Api-Key: bucketSecurityKey)
|
|
1213
|
+
* /api/analytics → analytics router (X-Api-Key: bucketSecurityKey)
|
|
1214
|
+
* /api/auth → auth router (X-Api-Key: authKey)
|
|
1215
|
+
* /storage → storage router (X-Storage-Key: ssk_…)
|
|
1216
|
+
*
|
|
1217
|
+
* ⚠️ Keys MUST be sent in headers — NEVER in URLs or query strings.
|
|
1218
|
+
* Records + Analytics: X-Api-Key (or Authorization: Bearer …)
|
|
1219
|
+
* Storage: X-Storage-Key (or Authorization: Bearer …)
|
|
1220
|
+
*/
|
|
1221
|
+
declare const RECORDS: {
|
|
1222
|
+
/** GET|POST|PATCH|DELETE|HEAD /api/:bucketKey */
|
|
1223
|
+
readonly bucket: (bucketKey: string) => string;
|
|
1224
|
+
/** POST /api/:bucketKey/batch/insert */
|
|
1225
|
+
readonly batchInsert: (bucketKey: string) => string;
|
|
1226
|
+
/** POST /api/:bucketKey/batch/update */
|
|
1227
|
+
readonly batchUpdate: (bucketKey: string) => string;
|
|
1228
|
+
/** POST /api/:bucketKey/batch/delete */
|
|
1229
|
+
readonly batchDelete: (bucketKey: string) => string;
|
|
1230
|
+
};
|
|
1231
|
+
declare const ANALYTICS: {
|
|
1232
|
+
/** POST /api/analytics/:bucketKey */
|
|
1233
|
+
readonly query: (bucketKey: string) => string;
|
|
1234
|
+
};
|
|
1235
|
+
declare const AUTH: {
|
|
1236
|
+
/** POST /api/auth/signup body: { email, password, fullName?, ...extra } */
|
|
1237
|
+
readonly signup: "/api/auth/signup";
|
|
1238
|
+
/** POST /api/auth/signin body: { email, password } */
|
|
1239
|
+
readonly signin: "/api/auth/signin";
|
|
1240
|
+
/** POST /api/auth/signout body: { sessionId, allDevices? } */
|
|
1241
|
+
readonly signout: "/api/auth/signout";
|
|
1242
|
+
/** POST /api/auth/session/validate body: { sessionId } */
|
|
1243
|
+
readonly sessionValidate: "/api/auth/session/validate";
|
|
1244
|
+
/** POST /api/auth/session/refresh body: { refreshToken } */
|
|
1245
|
+
readonly sessionRefresh: "/api/auth/session/refresh";
|
|
1246
|
+
/** GET /api/auth/user?userId=... */
|
|
1247
|
+
readonly getUser: "/api/auth/user";
|
|
1248
|
+
/** GET /api/auth/users?limit=&cursor= */
|
|
1249
|
+
readonly listUsers: "/api/auth/users";
|
|
1250
|
+
/** PATCH /api/auth/user body: { sessionId, userId, updates: {...} } */
|
|
1251
|
+
readonly updateUser: "/api/auth/user";
|
|
1252
|
+
/** DELETE /api/auth/user?userId=... body: { sessionId } */
|
|
1253
|
+
readonly deleteUser: "/api/auth/user";
|
|
1254
|
+
/** DELETE /api/auth/user/hard?userId=... body: { sessionId } */
|
|
1255
|
+
readonly hardDeleteUser: "/api/auth/user/hard";
|
|
1256
|
+
/** DELETE /api/auth/users/bulk body: { userIds, hard?, sessionId } */
|
|
1257
|
+
readonly bulkDeleteUsers: "/api/auth/users/bulk";
|
|
1258
|
+
/** POST /api/auth/password/change body: { sessionId, userId, oldPassword, newPassword } */
|
|
1259
|
+
readonly passwordChange: "/api/auth/password/change";
|
|
1260
|
+
/** POST /api/auth/password/reset/request body: { email } */
|
|
1261
|
+
readonly passwordResetRequest: "/api/auth/password/reset/request";
|
|
1262
|
+
/** POST /api/auth/password/reset/confirm body: { resetToken, newPassword } */
|
|
1263
|
+
readonly passwordResetConfirm: "/api/auth/password/reset/confirm";
|
|
1264
|
+
/** POST /api/auth/email/verify/request body: { userId } */
|
|
1265
|
+
readonly emailVerifyRequest: "/api/auth/email/verify/request";
|
|
1266
|
+
/** POST /api/auth/email/verify/confirm body: { verifyToken } */
|
|
1267
|
+
readonly emailVerifyConfirm: "/api/auth/email/verify/confirm";
|
|
1268
|
+
/** POST /api/auth/account/lock body: { sessionId, userId, duration? } */
|
|
1269
|
+
readonly accountLock: "/api/auth/account/lock";
|
|
1270
|
+
/** POST /api/auth/account/unlock body: { sessionId, userId } */
|
|
1271
|
+
readonly accountUnlock: "/api/auth/account/unlock";
|
|
1272
|
+
};
|
|
1273
|
+
declare const STORAGE: {
|
|
1274
|
+
/** GET /storage/info — no auth required */
|
|
1275
|
+
readonly info: "/storage/info";
|
|
1276
|
+
/** GET /storage/public/:fullScopedPath — no auth required */
|
|
1277
|
+
readonly publicFile: (fullScopedPath: string) => string;
|
|
1278
|
+
/** POST /storage/upload-url body: { path, mimeType, size, isPublic?, overwrite?, expiresIn? } */
|
|
1279
|
+
readonly uploadUrl: "/storage/upload-url";
|
|
1280
|
+
/** POST /storage/batch-upload-urls body: { files: [...], expiresIn? } */
|
|
1281
|
+
readonly batchUploadUrls: "/storage/batch-upload-urls";
|
|
1282
|
+
/** POST /storage/confirm body: { path, mimeType, isPublic? } */
|
|
1283
|
+
readonly confirm: "/storage/confirm";
|
|
1284
|
+
/** POST /storage/batch-confirm body: { files: [...] } */
|
|
1285
|
+
readonly batchConfirm: "/storage/batch-confirm";
|
|
1286
|
+
/** POST /storage/upload multipart/form-data: file, path, mimeType, isPublic, overwrite */
|
|
1287
|
+
readonly upload: "/storage/upload";
|
|
1288
|
+
/** POST /storage/upload-raw body: { path, content, mimeType?, isPublic?, overwrite? } */
|
|
1289
|
+
readonly uploadRaw: "/storage/upload-raw";
|
|
1290
|
+
/** GET /storage/list?prefix=&limit=&cursor= */
|
|
1291
|
+
readonly list: "/storage/list";
|
|
1292
|
+
/** GET /storage/download/:path — requires X-Storage-Key */
|
|
1293
|
+
readonly download: (filePath: string) => string;
|
|
1294
|
+
/** POST /storage/batch-download body: { paths: [...], concurrency? } */
|
|
1295
|
+
readonly batchDownload: "/storage/batch-download";
|
|
1296
|
+
/** GET /storage/metadata/:path */
|
|
1297
|
+
readonly metadata: (filePath: string) => string;
|
|
1298
|
+
/** POST /storage/signed-url body: { path, expiresIn? } */
|
|
1299
|
+
readonly signedUrl: "/storage/signed-url";
|
|
1300
|
+
/** PATCH /storage/visibility body: { path, isPublic } */
|
|
1301
|
+
readonly visibility: "/storage/visibility";
|
|
1302
|
+
/** POST /storage/folder body: { path } */
|
|
1303
|
+
readonly folder: "/storage/folder";
|
|
1304
|
+
/** DELETE /storage/file body: { path } */
|
|
1305
|
+
readonly file: "/storage/file";
|
|
1306
|
+
/** DELETE /storage/folder body: { path } */
|
|
1307
|
+
readonly folderDelete: "/storage/folder";
|
|
1308
|
+
/** POST /storage/move body: { from, to } */
|
|
1309
|
+
readonly move: "/storage/move";
|
|
1310
|
+
/** POST /storage/copy body: { from, to } */
|
|
1311
|
+
readonly copy: "/storage/copy";
|
|
1312
|
+
/** GET /storage/stats */
|
|
1313
|
+
readonly stats: "/storage/stats";
|
|
1314
|
+
};
|
|
1315
|
+
|
|
1019
1316
|
declare class HydrousError extends Error {
|
|
1020
1317
|
readonly code: string;
|
|
1021
1318
|
readonly status?: number;
|
|
@@ -1044,4 +1341,4 @@ declare class NetworkError extends HydrousError {
|
|
|
1044
1341
|
constructor(message: string, cause?: unknown);
|
|
1045
1342
|
}
|
|
1046
1343
|
|
|
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 };
|
|
1344
|
+
export { ANALYTICS, AUTH, 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, DEFAULT_BASE_URL, type DateRange, type DistributionRow, type FieldStats, type FieldTimeSeriesRow, type FileEntry, type FileMetadata, type Granularity, HttpClient, 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, RECORDS, type RecordData, RecordError, type RecordHistoryEntry, type RecordResult, RecordsClient, STORAGE, 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 };
|