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