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/dist/index.d.cts CHANGED
@@ -1,3 +1,8 @@
1
+ /**
2
+ * The server base URL — no trailing slash, no /api suffix.
3
+ * Routes in routes.ts already include /api, /api/analytics, /api/auth, /storage.
4
+ */
5
+ declare const DEFAULT_BASE_URL = "https://db-api-82687684612.us-central1.run.app";
1
6
  interface RequestOptions {
2
7
  method: string;
3
8
  body?: unknown;
@@ -14,21 +19,32 @@ declare class HttpClient {
14
19
  patch<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
15
20
  delete<T>(path: string, apiKey: string, body?: unknown): Promise<T>;
16
21
  /**
17
- * 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,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
- id: string;
128
- version: number;
129
- createdAt: number;
130
- data: RecordData;
147
+ generation: number | null;
148
+ savedAt: number | null;
149
+ savedBy: string | null;
150
+ sizeBytes: number | null;
131
151
  }
132
- /** Options for creating a record — includes queryable fields for filtering. */
152
+ /** Options for `records.create()`. */
133
153
  interface CreateRecordOptions {
134
154
  /**
135
- * Fields that should be indexed for server-side filtering.
136
- * Only fields listed here will be queryable via `query({ filters: [...] })`.
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
- /** Email of the user performing the action (for audit trails). */
159
+ /** User email for audit trails. */
140
160
  userEmail?: string;
141
161
  /**
142
- * Assign a custom record ID instead of an auto-generated one.
143
- * If the ID already exists, the record will be upserted.
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 batch-creating records. */
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 — full user authentication for a single bucket.
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/:bucketKey/` the bucketKey is the user bucket
344
- * name you passed when calling `db.auth('bucketKey')`.
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 db = createClient({ authKey: 'hk_auth_…', … });
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
- private readonly basePath;
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
- private delete;
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
- refreshSession({ refreshToken }: {
369
- refreshToken: string;
370
- }): Promise<Session>;
371
- validateSession({ sessionId }: {
372
- sessionId: string;
373
- }): Promise<{
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
- getUser({ userId }: {
381
- userId: string;
382
- }): Promise<UserRecord>;
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
- deleteUser({ sessionId, userId }: {
385
- sessionId: string;
386
- userId: string;
387
- }): Promise<void>;
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
- hardDeleteUser({ sessionId, userId }: {
390
- sessionId: string;
391
- userId: string;
392
- }): Promise<void>;
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
- unlockAccount({ sessionId, userId }: {
410
- sessionId: string;
411
- userId: string;
412
- }): Promise<void>;
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
- 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>;
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 + query + batch for a single bucket.
431
- * Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
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
- * @param data The record fields to store.
450
- * @param options Optional: queryableFields (for server-side filtering),
451
- * userEmail (audit trail), customRecordId (upsert by ID).
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
- * 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.
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): Promise<T & RecordResult>;
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
- * Create multiple records in one request (max 500).
482
- * Each record can include a `_customRecordId` field for upsert behaviour.
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 created = await posts.batchCreate(
617
+ * const results = await posts.batchCreate(
487
618
  * [{ title: 'A' }, { title: 'B' }],
488
- * { queryableFields: ['title'], userEmail: 'alice@example.com' },
619
+ * { queryableFields: ['title'] },
489
620
  * );
490
621
  * ```
491
622
  */
492
- batchCreate(items: T[], options?: BatchCreateOptions): Promise<(T & RecordResult)[]>;
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 multiple records in one request (max 500).
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
- deleted: number;
648
+ batchDelete(ids: string[], userEmail?: string): Promise<{
649
+ successful: number;
498
650
  failed: string[];
499
651
  }>;
500
652
  /**
501
- * Query records with optional filters, sorting, and pagination.
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
- * Get all records matching the given options (no filter support — use `query()` for filters).
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 basePath;
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
- /** Get value distribution for a field (e.g. how many records per status). */
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
- /** Fetch filtered records via the analytics engine (bypasses Firestore pagination). */
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
- /** Compute multiple aggregations in a single request. */
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 every bucket in `bucketKeys`.
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 — use this when none of the typed helpers cover your use case.
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
- * Uses an `X-Storage-Key` (`ssk_…`) header — separate from auth and bucket keys.
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 avatars = db.storage('avatars');
641
- * const result = await avatars.upload(file, 'alice.jpg', { isPublic: true });
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 to storage in one step (server-buffered, up to 500 MB).
653
- * For files >10 MB or when upload progress is needed, use `getUploadUrl()`.
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 JSON or plain-text data as a file.
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 directly from the client.
673
- * Supports upload progress via `uploadToSignedUrl()`.
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: confirmedPath } = await storage.getUploadUrl({
678
- * path: 'videos/intro.mp4',
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 => console.log(pct + '%'));
684
- * const result = await storage.confirmUpload({ path: confirmedPath, mimeType: 'video/mp4', isPublic: true });
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 a signed GCS URL.
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 on the server.
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 multiple files at once (max 50).
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
- * @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
- * ```
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
- * Returns both succeeded and failed results.
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 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.
902
+ * Download up to 20 files at once. Returns base64-encoded content.
749
903
  *
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
- * ```
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
- * Returns separate `files` and `folders` arrays for easy consumption.
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 for a file: size, MIME type, visibility, URLs.
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 without requiring an `X-Storage-Key`.
928
+ * Can be shared externally no X-Storage-Key required to access.
777
929
  *
778
- * > Note: Downloads via signed URLs bypass the server — download stats are NOT tracked.
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 after upload.
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: users/{userId}/
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. The `prefix` option is relative to the scope root.
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 = storage.scope('users/alice/');
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 records client for the named bucket.
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 an auth client for the named user bucket.
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 auth = db.auth('app-users');
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(bucketKey: string): AuthClient;
1141
+ auth(): AuthClient;
974
1142
  /**
975
- * Get an analytics client for the named bucket.
1143
+ * Get an AnalyticsClient for a bucket.
976
1144
  *
977
1145
  * @example
978
1146
  * ```ts
979
- * const analytics = db.analytics('orders');
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 storage manager for the named storage key.
986
- * The name must match a key defined in `storageKeys` when calling `createClient`.
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 namespace all operations under a path prefix.
1155
+ * Attach `.scope('prefix/')` to get a path-prefixed ScopedStorage.
989
1156
  *
990
1157
  * @example
991
1158
  * ```ts
992
- * const avatars = db.storage('avatars');
993
- * const userDocs = db.storage('documents').scope(`users/${userId}/`);
1159
+ * const avatars = db.storage('avatars');
1160
+ * const result = await avatars.upload(file, 'alice.jpg', { isPublic: true });
994
1161
  *
995
- * await avatars.upload(file, `${userId}.jpg`, { isPublic: true });
996
- * await userDocs.upload(pdfBuffer, 'contract.pdf');
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 new HydrousDB client.
1172
+ * Create a HydrousDB client.
1005
1173
  *
1006
1174
  * @example
1007
1175
  * ```ts
1008
- * import { createClient } from 'hydrousdb';
1176
+ * import { createClient } from 'hydrous-sdk';
1009
1177
  *
1010
1178
  * 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! },
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 };