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/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
- * Upload directly to a signed GCS URL (no auth headers — signed URL is self-authenticating).
18
- * Supports optional progress tracking via XHR in browser environments.
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
- /** Bucket security key (starts with `hk_bucket_`). Used for records + analytics. */
32
+ /**
33
+ * Bucket security key (starts with `hk_bucket_`).
34
+ * Used for records and analytics routes.
35
+ */
28
36
  bucketSecurityKey: string;
29
- /** Named storage keys (each starts with `ssk_`). */
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
- /** Override the API base URL. Defaults to the official HydrousDB endpoint. */
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 nested under `updates` when sent to the server. */
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
- /** Maps to `oldPassword` on the server. */
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
- /** Cursor for the next page (URL-encoded value returned by the previous call). */
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: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'CONTAINS';
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
- id: string;
128
- version: number;
129
- createdAt: number;
130
- data: RecordData;
166
+ generation: number | null;
167
+ savedAt: number | null;
168
+ savedBy: string | null;
169
+ sizeBytes: number | null;
131
170
  }
132
- /** Options for creating a record — includes queryable fields for filtering. */
171
+ /** Options for `records.create()`. */
133
172
  interface CreateRecordOptions {
134
173
  /**
135
- * Fields that should be indexed for server-side filtering.
136
- * Only fields listed here will be queryable via `query({ filters: [...] })`.
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
- /** Email of the user performing the action (for audit trails). */
178
+ /** User email for audit trails. */
140
179
  userEmail?: string;
141
180
  /**
142
- * Assign a custom record ID instead of an auto-generated one.
143
- * If the ID already exists, the record will be upserted.
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 batch-creating records. */
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 — full user authentication for a single bucket.
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/:bucketKey/` the bucketKey is the user bucket
344
- * name you passed when calling `db.auth('bucketKey')`.
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 db = createClient({ authKey: 'hk_auth_…', … });
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
- private readonly basePath;
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
- private delete;
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
- refreshSession({ refreshToken }: {
369
- refreshToken: string;
370
- }): Promise<Session>;
371
- validateSession({ sessionId }: {
372
- sessionId: string;
373
- }): Promise<{
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
- getUser({ userId }: {
381
- userId: string;
382
- }): Promise<UserRecord>;
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
- deleteUser({ sessionId, userId }: {
385
- sessionId: string;
386
- userId: string;
387
- }): Promise<void>;
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
- hardDeleteUser({ sessionId, userId }: {
390
- sessionId: string;
391
- userId: string;
392
- }): Promise<void>;
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
- unlockAccount({ sessionId, userId }: {
410
- sessionId: string;
411
- userId: string;
412
- }): Promise<void>;
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
- requestPasswordReset({ email }: {
415
- email: string;
416
- }): Promise<void>;
417
- confirmPasswordReset({ resetToken, newPassword }: {
418
- resetToken: string;
419
- newPassword: string;
420
- }): Promise<void>;
421
- requestEmailVerification({ userId }: {
422
- userId: string;
423
- }): Promise<void>;
424
- confirmEmailVerification({ verifyToken }: {
425
- verifyToken: string;
426
- }): Promise<void>;
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 + query + batch for a single bucket.
431
- * Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
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
- * @param data The record fields to store.
450
- * @param options Optional: queryableFields (for server-side filtering),
451
- * userEmail (audit trail), customRecordId (upsert by ID).
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
- * Fully replace a record (PUT semantics).
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): Promise<T & RecordResult>;
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
- * Create multiple records in one request (max 500).
482
- * Each record can include a `_customRecordId` field for upsert behaviour.
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 created = await posts.batchCreate(
636
+ * const results = await posts.batchCreate(
487
637
  * [{ title: 'A' }, { title: 'B' }],
488
- * { queryableFields: ['title'], userEmail: 'alice@example.com' },
638
+ * { queryableFields: ['title'] },
489
639
  * );
490
640
  * ```
491
641
  */
492
- batchCreate(items: T[], options?: BatchCreateOptions): Promise<(T & RecordResult)[]>;
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 multiple records in one request (max 500).
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
- deleted: number;
667
+ batchDelete(ids: string[], userEmail?: string): Promise<{
668
+ successful: number;
498
669
  failed: string[];
499
670
  }>;
500
671
  /**
501
- * Query records with optional filters, sorting, and pagination.
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
- * Get all records matching the given options (no filter support — use `query()` for filters).
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 basePath;
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
- /** Get value distribution for a field (e.g. how many records per status). */
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
- /** Fetch filtered records via the analytics engine (bypasses Firestore pagination). */
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
- /** Compute multiple aggregations in a single request. */
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 every bucket in `bucketKeys`.
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 — use this when none of the typed helpers cover your use case.
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
- * Uses an `X-Storage-Key` (`ssk_…`) header — separate from auth and bucket keys.
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 avatars = db.storage('avatars');
641
- * const result = await avatars.upload(file, 'alice.jpg', { isPublic: true });
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 to storage in one step (server-buffered, up to 500 MB).
653
- * For files >10 MB or when upload progress is needed, use `getUploadUrl()`.
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 JSON or plain-text data as a file.
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 directly from the client.
673
- * Supports upload progress via `uploadToSignedUrl()`.
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: confirmedPath } = await storage.getUploadUrl({
678
- * path: 'videos/intro.mp4',
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 => console.log(pct + '%'));
684
- * const result = await storage.confirmUpload({ path: confirmedPath, mimeType: 'video/mp4', isPublic: true });
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 a signed GCS URL.
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 on the server.
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 multiple files at once (max 50).
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
- * @example
713
- * ```ts
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
- * Returns both succeeded and failed results.
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 multiple files at once (max 20).
747
- * Returns a structured result with succeeded and failed items.
748
- * Each succeeded item includes the file content as a base64 string.
921
+ * Download up to 20 files at once. Returns base64-encoded content.
749
922
  *
750
- * @example
751
- * ```ts
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
- * Returns separate `files` and `folders` arrays for easy consumption.
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 for a file: size, MIME type, visibility, URLs.
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 without requiring an `X-Storage-Key`.
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
- * > Note: Downloads via signed URLs bypass the server — download stats are NOT tracked.
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 after upload.
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: users/{userId}/
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. The `prefix` option is relative to the scope root.
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 = storage.scope('users/alice/');
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 records client for the named bucket.
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 an auth client for the named user bucket.
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 auth = db.auth('app-users');
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(bucketKey: string): AuthClient;
1160
+ auth(): AuthClient;
974
1161
  /**
975
- * Get an analytics client for the named bucket.
1162
+ * Get an AnalyticsClient for a bucket.
976
1163
  *
977
1164
  * @example
978
1165
  * ```ts
979
- * const analytics = db.analytics('orders');
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 storage manager for the named storage key.
986
- * The name must match a key defined in `storageKeys` when calling `createClient`.
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 namespace all operations under a path prefix.
1174
+ * Attach `.scope('prefix/')` to get a path-prefixed ScopedStorage.
989
1175
  *
990
1176
  * @example
991
1177
  * ```ts
992
- * const avatars = db.storage('avatars');
993
- * const userDocs = db.storage('documents').scope(`users/${userId}/`);
1178
+ * const avatars = db.storage('avatars');
1179
+ * const result = await avatars.upload(file, 'alice.jpg', { isPublic: true });
994
1180
  *
995
- * await avatars.upload(file, `${userId}.jpg`, { isPublic: true });
996
- * await userDocs.upload(pdfBuffer, 'contract.pdf');
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 new HydrousDB client.
1191
+ * Create a HydrousDB client.
1005
1192
  *
1006
1193
  * @example
1007
1194
  * ```ts
1008
- * import { createClient } from 'hydrousdb';
1195
+ * import { createClient } from 'hydrous-sdk';
1009
1196
  *
1010
1197
  * const db = createClient({
1011
- * authKey: process.env.HYDROUS_AUTH_KEY!,
1012
- * bucketSecurityKey: process.env.HYDROUS_BUCKET_KEY!,
1013
- * storageKeys: { main: process.env.HYDROUS_STORAGE_MAIN! },
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 };