hydrousdb 2.0.3 → 3.0.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.
@@ -0,0 +1,1540 @@
1
+ interface RequestOptions {
2
+ method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
3
+ body?: unknown;
4
+ headers?: Record<string, string>;
5
+ rawBody?: string | FormData | Uint8Array<ArrayBuffer>;
6
+ contentType?: string;
7
+ }
8
+ declare class HttpClient {
9
+ private readonly baseUrl;
10
+ private readonly securityKey;
11
+ constructor(baseUrl: string, securityKey: string);
12
+ request<T = unknown>(path: string, opts?: RequestOptions): Promise<T>;
13
+ get<T = unknown>(path: string, headers?: Record<string, string>): Promise<T>;
14
+ post<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
15
+ put<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
16
+ patch<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
17
+ delete<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
18
+ putToSignedUrl(signedUrl: string, data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
19
+ }
20
+
21
+ interface HydrousConfig {
22
+ /**
23
+ * Your project's Security Key (starts with `sk_`).
24
+ * Obtain this from your dashboard at https://hydrousdb.com/dashboard.
25
+ * This is your most important credential — keep it secret.
26
+ */
27
+ securityKey: string;
28
+ /**
29
+ * Override the API base URL. Defaults to the official HydrousDB endpoint.
30
+ * You almost never need to set this.
31
+ */
32
+ baseUrl?: string;
33
+ }
34
+ interface SignupOptions {
35
+ email: string;
36
+ password: string;
37
+ fullName?: string;
38
+ [key: string]: unknown;
39
+ }
40
+ interface LoginOptions {
41
+ email: string;
42
+ password: string;
43
+ }
44
+ interface UserRecord {
45
+ id: string;
46
+ email: string;
47
+ fullName?: string | null;
48
+ emailVerified: boolean;
49
+ accountStatus: 'active' | 'locked' | 'suspended';
50
+ role: 'user' | 'admin';
51
+ createdAt: number;
52
+ updatedAt: number;
53
+ metadata?: Record<string, unknown>;
54
+ [key: string]: unknown;
55
+ }
56
+ interface Session {
57
+ sessionId: string;
58
+ userId: string;
59
+ bucketId: string;
60
+ createdAt: number;
61
+ expiresAt: number;
62
+ refreshToken: string;
63
+ refreshExpiresAt: number;
64
+ }
65
+ interface AuthResult {
66
+ user: UserRecord;
67
+ session: Session;
68
+ }
69
+ interface UpdateUserOptions {
70
+ sessionId: string;
71
+ userId: string;
72
+ data: Partial<Omit<UserRecord, 'id' | 'email' | 'createdAt'>>;
73
+ }
74
+ interface ChangePasswordOptions {
75
+ sessionId: string;
76
+ userId: string;
77
+ currentPassword: string;
78
+ newPassword: string;
79
+ }
80
+ interface ListUsersOptions {
81
+ sessionId: string;
82
+ limit?: number;
83
+ offset?: number;
84
+ }
85
+ interface ListUsersResult {
86
+ users: UserRecord[];
87
+ total: number;
88
+ limit: number;
89
+ offset: number;
90
+ }
91
+ type RecordData = Record<string, unknown>;
92
+ interface RecordResult {
93
+ id: string;
94
+ createdAt?: number;
95
+ updatedAt?: number;
96
+ [key: string]: unknown;
97
+ }
98
+ interface QueryFilter {
99
+ field: string;
100
+ op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'CONTAINS';
101
+ value: string | number | boolean;
102
+ }
103
+ interface QueryOptions {
104
+ filters?: QueryFilter[];
105
+ fields?: string;
106
+ limit?: number;
107
+ offset?: number;
108
+ orderBy?: string;
109
+ order?: 'asc' | 'desc';
110
+ startAfter?: string;
111
+ startAt?: string;
112
+ endAt?: string;
113
+ dateRange?: DateRange;
114
+ }
115
+ interface QueryResult<T = RecordData> {
116
+ records: (T & RecordResult)[];
117
+ total?: number;
118
+ hasMore?: boolean;
119
+ nextCursor?: string;
120
+ }
121
+ interface PatchRecordOptions {
122
+ merge?: boolean;
123
+ }
124
+ interface RecordHistoryEntry {
125
+ id: string;
126
+ version: number;
127
+ createdAt: number;
128
+ data: RecordData;
129
+ }
130
+ interface UploadOptions {
131
+ /** Set to true to make the file publicly accessible without authentication. */
132
+ isPublic?: boolean;
133
+ /** Set to true to overwrite an existing file at the same path. */
134
+ overwrite?: boolean;
135
+ /** MIME type of the file. Auto-detected if omitted. */
136
+ mimeType?: string;
137
+ /** TTL in seconds for the signed upload URL (default 900 = 15 min). */
138
+ expiresInSeconds?: number;
139
+ }
140
+ interface UploadResult {
141
+ path: string;
142
+ mimeType: string;
143
+ size: number;
144
+ isPublic: boolean;
145
+ publicUrl: string | null;
146
+ downloadUrl: string | null;
147
+ }
148
+ interface UploadUrlResult {
149
+ uploadUrl: string;
150
+ path: string;
151
+ mimeType: string;
152
+ expiresAt: string;
153
+ expiresIn: number;
154
+ }
155
+ interface ListOptions {
156
+ prefix?: string;
157
+ limit?: number;
158
+ cursor?: string;
159
+ recursive?: boolean;
160
+ }
161
+ interface FileEntry {
162
+ name: string;
163
+ path: string;
164
+ size?: number;
165
+ mimeType?: string;
166
+ isPublic?: boolean;
167
+ publicUrl?: string | null;
168
+ downloadUrl?: string | null;
169
+ updatedAt?: string;
170
+ }
171
+ interface ListResult {
172
+ files: FileEntry[];
173
+ folders: string[];
174
+ hasMore: boolean;
175
+ nextCursor?: string;
176
+ }
177
+ interface FileMetadata {
178
+ path: string;
179
+ size: number;
180
+ mimeType: string;
181
+ isPublic: boolean;
182
+ publicUrl: string | null;
183
+ downloadUrl: string | null;
184
+ createdAt?: string;
185
+ updatedAt?: string;
186
+ }
187
+ interface SignedUrlResult {
188
+ signedUrl: string;
189
+ expiresAt: string;
190
+ expiresIn: number;
191
+ path: string;
192
+ }
193
+ interface StorageStats {
194
+ totalFiles: number;
195
+ totalBytes: number;
196
+ uploadCount: number;
197
+ downloadCount: number;
198
+ deleteCount: number;
199
+ }
200
+ interface BatchUploadItem {
201
+ path: string;
202
+ mimeType: string;
203
+ size: number;
204
+ isPublic?: boolean;
205
+ overwrite?: boolean;
206
+ }
207
+ interface BatchUploadUrlResult {
208
+ files: Array<UploadUrlResult & {
209
+ index: number;
210
+ }>;
211
+ }
212
+ type QueryType = 'count' | 'distribution' | 'sum' | 'timeSeries' | 'fieldTimeSeries' | 'topN' | 'stats' | 'records' | 'multiMetric' | 'storageStats' | 'crossBucket';
213
+ type Aggregation = 'sum' | 'avg' | 'min' | 'max' | 'count';
214
+ type Granularity = 'hour' | 'day' | 'week' | 'month' | 'year';
215
+ type SortOrder = 'asc' | 'desc';
216
+ interface DateRange {
217
+ /** Start timestamp in milliseconds (Unix epoch). */
218
+ start?: number;
219
+ /** End timestamp in milliseconds (Unix epoch). */
220
+ end?: number;
221
+ }
222
+ interface AnalyticsFilter {
223
+ field: string;
224
+ op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'CONTAINS';
225
+ value: string | number | boolean;
226
+ }
227
+ interface MetricDefinition {
228
+ /** Field name in your records to aggregate. */
229
+ field: string;
230
+ /** Alias used in the result object. Must be a safe identifier. */
231
+ name: string;
232
+ /** Aggregation function. Defaults to 'count'. */
233
+ aggregation?: Aggregation;
234
+ }
235
+ interface AnalyticsQuery {
236
+ queryType: QueryType;
237
+ dateRange?: DateRange;
238
+ field?: string;
239
+ groupBy?: string;
240
+ labelField?: string;
241
+ aggregation?: Aggregation;
242
+ granularity?: Granularity;
243
+ filters?: AnalyticsFilter[];
244
+ selectFields?: string[];
245
+ limit?: number;
246
+ offset?: number;
247
+ orderBy?: string;
248
+ order?: SortOrder;
249
+ n?: number;
250
+ metrics?: MetricDefinition[];
251
+ /** For crossBucket queries: list of bucket names to compare. */
252
+ bucketKeys?: string[];
253
+ }
254
+ interface AnalyticsResult<T = unknown> {
255
+ queryType: QueryType;
256
+ data: T;
257
+ }
258
+ interface CountResult {
259
+ count: number;
260
+ }
261
+ interface DistributionRow {
262
+ value: string | number;
263
+ count: number;
264
+ }
265
+ interface SumRow {
266
+ group?: string | number;
267
+ sum: number;
268
+ }
269
+ interface TimeSeriesRow {
270
+ date: string;
271
+ count: number;
272
+ }
273
+ interface FieldTimeSeriesRow {
274
+ date: string;
275
+ value: number;
276
+ }
277
+ interface TopNRow {
278
+ value: string | number;
279
+ label?: string;
280
+ count: number;
281
+ }
282
+ interface FieldStats {
283
+ min: number;
284
+ max: number;
285
+ avg: number;
286
+ sum: number;
287
+ count: number;
288
+ stddev?: number;
289
+ }
290
+ interface MultiMetricResult {
291
+ [metricName: string]: number;
292
+ }
293
+ interface StorageStatsResult {
294
+ totalRecords: number;
295
+ totalBytes: number;
296
+ avgBytes: number;
297
+ minBytes: number;
298
+ maxBytes: number;
299
+ }
300
+ interface CrossBucketRow {
301
+ bucket: string;
302
+ value: number;
303
+ }
304
+
305
+ /**
306
+ * AuthClient — full user authentication for a single bucket.
307
+ *
308
+ * Every method maps directly to a route in the server's `auth.js` router.
309
+ * The bucket key is the name of your user bucket (e.g. "users" or "customers").
310
+ *
311
+ * @example
312
+ * ```ts
313
+ * const db = createClient({ securityKey: 'sk_...' });
314
+ * const auth = db.auth('my-app-users');
315
+ *
316
+ * const { user, session } = await auth.signup({
317
+ * email: 'alice@example.com',
318
+ * password: 'hunter2',
319
+ * fullName: 'Alice',
320
+ * });
321
+ * ```
322
+ */
323
+ declare class AuthClient {
324
+ private readonly http;
325
+ private readonly bucketKey;
326
+ private readonly basePath;
327
+ constructor(http: HttpClient, bucketKey: string);
328
+ /**
329
+ * Register a new user in this bucket.
330
+ *
331
+ * @example
332
+ * ```ts
333
+ * const { user, session } = await auth.signup({
334
+ * email: 'alice@example.com',
335
+ * password: 'hunter2',
336
+ * fullName: 'Alice Wonderland',
337
+ * // Any extra fields are stored on the user record:
338
+ * plan: 'pro',
339
+ * });
340
+ * ```
341
+ */
342
+ signup(options: SignupOptions): Promise<AuthResult>;
343
+ /**
344
+ * Authenticate an existing user and create a session.
345
+ * Sessions are valid for 24 hours; use `refreshSession` to extend.
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * const { user, session } = await auth.login({
350
+ * email: 'alice@example.com',
351
+ * password: 'hunter2',
352
+ * });
353
+ * // Store session.sessionId safely — you'll need it for other calls.
354
+ * ```
355
+ */
356
+ login(options: LoginOptions): Promise<AuthResult>;
357
+ /**
358
+ * Invalidate a session (sign out).
359
+ *
360
+ * @example
361
+ * ```ts
362
+ * await auth.logout({ sessionId: session.sessionId });
363
+ * ```
364
+ */
365
+ logout({ sessionId }: {
366
+ sessionId: string;
367
+ }): Promise<void>;
368
+ /**
369
+ * Extend a session using its refresh token.
370
+ * Returns a new session object.
371
+ *
372
+ * @example
373
+ * ```ts
374
+ * const newSession = await auth.refreshSession({ refreshToken: session.refreshToken });
375
+ * ```
376
+ */
377
+ refreshSession({ refreshToken }: {
378
+ refreshToken: string;
379
+ }): Promise<Session>;
380
+ /**
381
+ * Fetch a user by their ID.
382
+ *
383
+ * @example
384
+ * ```ts
385
+ * const user = await auth.getUser({ userId: 'usr_abc123' });
386
+ * ```
387
+ */
388
+ getUser({ userId }: {
389
+ userId: string;
390
+ }): Promise<UserRecord>;
391
+ /**
392
+ * Update fields on a user record. Requires a valid session.
393
+ *
394
+ * @example
395
+ * ```ts
396
+ * const updated = await auth.updateUser({
397
+ * sessionId: session.sessionId,
398
+ * userId: user.id,
399
+ * data: { fullName: 'Alice Smith', plan: 'enterprise' },
400
+ * });
401
+ * ```
402
+ */
403
+ updateUser(options: UpdateUserOptions): Promise<UserRecord>;
404
+ /**
405
+ * Soft-delete a user. The record is marked deleted but not removed from storage.
406
+ * Requires a valid session (the user can delete themselves, or an admin can delete any user).
407
+ *
408
+ * @example
409
+ * ```ts
410
+ * await auth.deleteUser({ sessionId: session.sessionId, userId: user.id });
411
+ * ```
412
+ */
413
+ deleteUser({ sessionId, userId }: {
414
+ sessionId: string;
415
+ userId: string;
416
+ }): Promise<void>;
417
+ /**
418
+ * List all users in the bucket. **Admin session required.**
419
+ *
420
+ * @example
421
+ * ```ts
422
+ * const { users, total } = await auth.listUsers({
423
+ * sessionId: adminSession.sessionId,
424
+ * limit: 50,
425
+ * offset: 0,
426
+ * });
427
+ * ```
428
+ */
429
+ listUsers(options: ListUsersOptions): Promise<ListUsersResult>;
430
+ /**
431
+ * Permanently hard-delete a user and all their data. **Admin session required.**
432
+ * This action is irreversible.
433
+ *
434
+ * @example
435
+ * ```ts
436
+ * await auth.hardDeleteUser({ sessionId: adminSession.sessionId, userId: user.id });
437
+ * ```
438
+ */
439
+ hardDeleteUser({ sessionId, userId }: {
440
+ sessionId: string;
441
+ userId: string;
442
+ }): Promise<void>;
443
+ /**
444
+ * Bulk delete multiple users. **Admin session required.**
445
+ *
446
+ * @example
447
+ * ```ts
448
+ * const result = await auth.bulkDeleteUsers({
449
+ * sessionId: adminSession.sessionId,
450
+ * userIds: ['usr_a', 'usr_b'],
451
+ * });
452
+ * ```
453
+ */
454
+ bulkDeleteUsers({ sessionId, userIds, }: {
455
+ sessionId: string;
456
+ userIds: string[];
457
+ }): Promise<{
458
+ deleted: number;
459
+ failed: string[];
460
+ }>;
461
+ /**
462
+ * Lock a user account, preventing login. **Admin session required.**
463
+ *
464
+ * @param options.duration Lock duration in milliseconds. Defaults to 15 minutes.
465
+ *
466
+ * @example
467
+ * ```ts
468
+ * await auth.lockAccount({
469
+ * sessionId: adminSession.sessionId,
470
+ * userId: user.id,
471
+ * duration: 60 * 60 * 1000, // 1 hour
472
+ * });
473
+ * ```
474
+ */
475
+ lockAccount({ sessionId, userId, duration, }: {
476
+ sessionId: string;
477
+ userId: string;
478
+ duration?: number;
479
+ }): Promise<{
480
+ lockedUntil: number;
481
+ unlockTime: string;
482
+ }>;
483
+ /**
484
+ * Unlock a previously locked user account. **Admin session required.**
485
+ *
486
+ * @example
487
+ * ```ts
488
+ * await auth.unlockAccount({ sessionId: adminSession.sessionId, userId: user.id });
489
+ * ```
490
+ */
491
+ unlockAccount({ sessionId, userId, }: {
492
+ sessionId: string;
493
+ userId: string;
494
+ }): Promise<void>;
495
+ /**
496
+ * Change a user's password. The user must supply their current password.
497
+ *
498
+ * @example
499
+ * ```ts
500
+ * await auth.changePassword({
501
+ * sessionId: session.sessionId,
502
+ * userId: user.id,
503
+ * currentPassword: 'hunter2',
504
+ * newPassword: 'correcthorsebatterystaple',
505
+ * });
506
+ * ```
507
+ */
508
+ changePassword(options: ChangePasswordOptions): Promise<void>;
509
+ /**
510
+ * Request a password reset email for a user.
511
+ * Always returns success to prevent user enumeration.
512
+ *
513
+ * @example
514
+ * ```ts
515
+ * await auth.requestPasswordReset({ email: 'alice@example.com' });
516
+ * ```
517
+ */
518
+ requestPasswordReset({ email }: {
519
+ email: string;
520
+ }): Promise<void>;
521
+ /**
522
+ * Complete a password reset using the token from the reset email.
523
+ *
524
+ * @example
525
+ * ```ts
526
+ * await auth.confirmPasswordReset({
527
+ * resetToken: 'tok_from_email',
528
+ * newPassword: 'correcthorsebatterystaple',
529
+ * });
530
+ * ```
531
+ */
532
+ confirmPasswordReset({ resetToken, newPassword, }: {
533
+ resetToken: string;
534
+ newPassword: string;
535
+ }): Promise<void>;
536
+ /**
537
+ * Send (or resend) an email verification message to a user.
538
+ *
539
+ * @example
540
+ * ```ts
541
+ * await auth.requestEmailVerification({ userId: user.id });
542
+ * ```
543
+ */
544
+ requestEmailVerification({ userId }: {
545
+ userId: string;
546
+ }): Promise<void>;
547
+ /**
548
+ * Confirm an email address using the token from the verification email.
549
+ *
550
+ * @example
551
+ * ```ts
552
+ * await auth.confirmEmailVerification({ verifyToken: 'tok_from_email' });
553
+ * ```
554
+ */
555
+ confirmEmailVerification({ verifyToken }: {
556
+ verifyToken: string;
557
+ }): Promise<void>;
558
+ }
559
+
560
+ /**
561
+ * RecordsClient — create, read, update, delete, and query records in a bucket.
562
+ *
563
+ * A bucket is simply a named collection of JSON records. You create buckets
564
+ * from your HydrousDB dashboard. Each record is a JSON object with any fields
565
+ * you want; HydrousDB automatically adds `id`, `createdAt`, and `updatedAt`.
566
+ *
567
+ * @example
568
+ * ```ts
569
+ * const db = createClient({ securityKey: 'sk_...' });
570
+ * const posts = db.records('blog-posts');
571
+ *
572
+ * // Create a record
573
+ * const post = await posts.create({ title: 'Hello World', status: 'draft' });
574
+ *
575
+ * // Query records
576
+ * const { records } = await posts.query({
577
+ * filters: [{ field: 'status', op: '==', value: 'published' }],
578
+ * limit: 20,
579
+ * });
580
+ * ```
581
+ */
582
+ declare class RecordsClient<T extends RecordData = RecordData> {
583
+ private readonly http;
584
+ private readonly bucketKey;
585
+ private readonly basePath;
586
+ constructor(http: HttpClient, bucketKey: string);
587
+ /**
588
+ * Create a new record.
589
+ *
590
+ * @example
591
+ * ```ts
592
+ * const user = await records.create({
593
+ * name: 'Alice',
594
+ * email: 'alice@example.com',
595
+ * score: 100,
596
+ * });
597
+ * console.log(user.id); // "rec_xxxxxxxx"
598
+ * ```
599
+ */
600
+ create(data: T): Promise<T & RecordResult>;
601
+ /**
602
+ * Fetch a single record by ID.
603
+ *
604
+ * @example
605
+ * ```ts
606
+ * const post = await records.get('rec_abc123');
607
+ * ```
608
+ */
609
+ get(id: string): Promise<T & RecordResult>;
610
+ /**
611
+ * Overwrite a record entirely (full replace).
612
+ *
613
+ * @example
614
+ * ```ts
615
+ * const updated = await records.set('rec_abc123', {
616
+ * name: 'Alice Updated',
617
+ * email: 'alice2@example.com',
618
+ * });
619
+ * ```
620
+ */
621
+ set(id: string, data: T): Promise<T & RecordResult>;
622
+ /**
623
+ * Partially update a record (merge by default).
624
+ *
625
+ * @example
626
+ * ```ts
627
+ * // Merge: only the provided fields are updated
628
+ * const updated = await records.patch('rec_abc123', { score: 200 });
629
+ *
630
+ * // Replace: equivalent to set()
631
+ * const replaced = await records.patch('rec_abc123', { score: 200 }, { merge: false });
632
+ * ```
633
+ */
634
+ patch(id: string, data: Partial<T>, options?: PatchRecordOptions): Promise<T & RecordResult>;
635
+ /**
636
+ * Delete a record permanently.
637
+ *
638
+ * @example
639
+ * ```ts
640
+ * await records.delete('rec_abc123');
641
+ * ```
642
+ */
643
+ delete(id: string): Promise<void>;
644
+ /**
645
+ * Create multiple records in one request.
646
+ *
647
+ * @example
648
+ * ```ts
649
+ * const created = await records.batchCreate([
650
+ * { name: 'Alice', score: 100 },
651
+ * { name: 'Bob', score: 200 },
652
+ * ]);
653
+ * ```
654
+ */
655
+ batchCreate(items: T[]): Promise<(T & RecordResult)[]>;
656
+ /**
657
+ * Delete multiple records by ID in one request.
658
+ *
659
+ * @example
660
+ * ```ts
661
+ * await records.batchDelete(['rec_a', 'rec_b', 'rec_c']);
662
+ * ```
663
+ */
664
+ batchDelete(ids: string[]): Promise<{
665
+ deleted: number;
666
+ failed: string[];
667
+ }>;
668
+ /**
669
+ * Query records with optional filters, sorting, and pagination.
670
+ *
671
+ * @example
672
+ * ```ts
673
+ * // Simple query
674
+ * const { records } = await posts.query({ limit: 10 });
675
+ *
676
+ * // Filtered query with cursor pagination
677
+ * const page1 = await posts.query({
678
+ * filters: [
679
+ * { field: 'status', op: '==', value: 'published' },
680
+ * { field: 'views', op: '>', value: 1000 },
681
+ * ],
682
+ * orderBy: 'createdAt',
683
+ * order: 'desc',
684
+ * limit: 20,
685
+ * });
686
+ *
687
+ * const page2 = await posts.query({
688
+ * filters: [{ field: 'status', op: '==', value: 'published' }],
689
+ * limit: 20,
690
+ * startAfter: page1.nextCursor,
691
+ * });
692
+ * ```
693
+ */
694
+ query(options?: QueryOptions): Promise<QueryResult<T>>;
695
+ /**
696
+ * Convenience alias: get all records up to `limit` (default 100).
697
+ *
698
+ * @example
699
+ * ```ts
700
+ * const allPosts = await posts.getAll({ limit: 500 });
701
+ * ```
702
+ */
703
+ getAll(options?: Omit<QueryOptions, 'filters'>): Promise<(T & RecordResult)[]>;
704
+ /**
705
+ * Count records matching optional filters.
706
+ *
707
+ * @example
708
+ * ```ts
709
+ * const total = await posts.count([{ field: 'status', op: '==', value: 'published' }]);
710
+ * ```
711
+ */
712
+ count(filters?: QueryOptions['filters']): Promise<number>;
713
+ /**
714
+ * Retrieve the full version history of a record.
715
+ * Each write creates a new version stored in GCS.
716
+ *
717
+ * @example
718
+ * ```ts
719
+ * const history = await records.getHistory('rec_abc123');
720
+ * console.log(history[0].data); // latest version
721
+ * ```
722
+ */
723
+ getHistory(id: string): Promise<RecordHistoryEntry[]>;
724
+ /**
725
+ * Restore a record to a specific historical version.
726
+ *
727
+ * @example
728
+ * ```ts
729
+ * const history = await records.getHistory('rec_abc123');
730
+ * const restored = await records.restoreVersion('rec_abc123', history[2].version);
731
+ * ```
732
+ */
733
+ restoreVersion(id: string, version: number): Promise<T & RecordResult>;
734
+ }
735
+
736
+ /**
737
+ * AnalyticsClient — run powerful aggregation and time-series queries against
738
+ * your bucket data using BigQuery under the hood.
739
+ *
740
+ * All query types accept an optional `dateRange` to filter by time.
741
+ * The security key is sent automatically — you never pass it manually.
742
+ *
743
+ * @example
744
+ * ```ts
745
+ * const db = createClient({ securityKey: 'sk_...' });
746
+ * const analytics = db.analytics('orders');
747
+ *
748
+ * // How many orders in the last 30 days?
749
+ * const { count } = await analytics.count({
750
+ * dateRange: { start: Date.now() - 30 * 24 * 60 * 60 * 1000, end: Date.now() },
751
+ * });
752
+ * ```
753
+ */
754
+ declare class AnalyticsClient {
755
+ private readonly http;
756
+ private readonly bucketKey;
757
+ private readonly basePath;
758
+ constructor(http: HttpClient, bucketKey: string);
759
+ /** Internal dispatcher — all queries POST to the same endpoint. */
760
+ private run;
761
+ /**
762
+ * Count the total number of records in the bucket, with optional date filter.
763
+ *
764
+ * @example
765
+ * ```ts
766
+ * const { count } = await analytics.count();
767
+ * // → { count: 4821 }
768
+ *
769
+ * // Count only this month's records
770
+ * const { count } = await analytics.count({
771
+ * dateRange: { start: new Date('2025-01-01').getTime(), end: Date.now() },
772
+ * });
773
+ * ```
774
+ */
775
+ count(opts?: {
776
+ dateRange?: DateRange;
777
+ }): Promise<CountResult>;
778
+ /**
779
+ * Count how many records have each unique value for a given field.
780
+ * Great for pie charts and bar charts.
781
+ *
782
+ * @example
783
+ * ```ts
784
+ * const rows = await analytics.distribution({
785
+ * field: 'status',
786
+ * limit: 10,
787
+ * order: 'desc',
788
+ * });
789
+ * // → [{ value: 'completed', count: 312 }, { value: 'pending', count: 88 }, ...]
790
+ * ```
791
+ */
792
+ distribution(opts: {
793
+ field: string;
794
+ limit?: number;
795
+ order?: SortOrder;
796
+ dateRange?: DateRange;
797
+ }): Promise<DistributionRow[]>;
798
+ /**
799
+ * Sum a numeric field, optionally grouped by another field.
800
+ *
801
+ * @example
802
+ * ```ts
803
+ * // Total revenue
804
+ * const rows = await analytics.sum({ field: 'amount' });
805
+ * // → [{ sum: 198432.50 }]
806
+ *
807
+ * // Revenue by country
808
+ * const rows = await analytics.sum({ field: 'amount', groupBy: 'country', limit: 10 });
809
+ * // → [{ group: 'US', sum: 120000 }, { group: 'UK', sum: 45000 }, ...]
810
+ * ```
811
+ */
812
+ sum(opts: {
813
+ field: string;
814
+ groupBy?: string;
815
+ limit?: number;
816
+ dateRange?: DateRange;
817
+ }): Promise<SumRow[]>;
818
+ /**
819
+ * Count records created over time, grouped by a time granularity.
820
+ * Perfect for line charts and activity graphs.
821
+ *
822
+ * @example
823
+ * ```ts
824
+ * const rows = await analytics.timeSeries({
825
+ * granularity: 'day',
826
+ * dateRange: { start: Date.now() - 7 * 86400000, end: Date.now() },
827
+ * });
828
+ * // → [{ date: '2025-06-01', count: 42 }, { date: '2025-06-02', count: 67 }, ...]
829
+ * ```
830
+ */
831
+ timeSeries(opts?: {
832
+ granularity?: Granularity;
833
+ dateRange?: DateRange;
834
+ }): Promise<TimeSeriesRow[]>;
835
+ /**
836
+ * Aggregate a numeric field over time (e.g. daily revenue, hourly signups).
837
+ *
838
+ * @example
839
+ * ```ts
840
+ * const rows = await analytics.fieldTimeSeries({
841
+ * field: 'amount',
842
+ * aggregation: 'sum',
843
+ * granularity: 'week',
844
+ * });
845
+ * // → [{ date: '2025-W22', value: 14230.50 }, ...]
846
+ * ```
847
+ */
848
+ fieldTimeSeries(opts: {
849
+ field: string;
850
+ aggregation?: Aggregation;
851
+ granularity?: Granularity;
852
+ dateRange?: DateRange;
853
+ }): Promise<FieldTimeSeriesRow[]>;
854
+ /**
855
+ * Get the top N values by frequency for a field.
856
+ * Optionally pair with a `labelField` for human-readable labels.
857
+ *
858
+ * @example
859
+ * ```ts
860
+ * // Top 5 most purchased products
861
+ * const rows = await analytics.topN({
862
+ * field: 'productId',
863
+ * labelField: 'productName',
864
+ * n: 5,
865
+ * });
866
+ * // → [{ value: 'prod_123', label: 'Widget Pro', count: 892 }, ...]
867
+ * ```
868
+ */
869
+ topN(opts: {
870
+ field: string;
871
+ n?: number;
872
+ labelField?: string;
873
+ order?: SortOrder;
874
+ dateRange?: DateRange;
875
+ }): Promise<TopNRow[]>;
876
+ /**
877
+ * Get statistical summary (min, max, avg, sum, count, stddev) for a numeric field.
878
+ *
879
+ * @example
880
+ * ```ts
881
+ * const stats = await analytics.stats({ field: 'orderValue' });
882
+ * // → { min: 4.99, max: 9999.99, avg: 87.23, sum: 420948.27, count: 4823, stddev: 143.2 }
883
+ * ```
884
+ */
885
+ stats(opts: {
886
+ field: string;
887
+ dateRange?: DateRange;
888
+ }): Promise<FieldStats>;
889
+ /**
890
+ * Query raw records with filters, field selection, and pagination.
891
+ * This is the analytics version of `records.query()` but powered by BigQuery.
892
+ *
893
+ * @example
894
+ * ```ts
895
+ * const { records } = await analytics.records({
896
+ * filters: [{ field: 'status', op: '==', value: 'refunded' }],
897
+ * selectFields: ['orderId', 'amount', 'createdAt'],
898
+ * limit: 50,
899
+ * orderBy: 'amount',
900
+ * order: 'desc',
901
+ * });
902
+ * ```
903
+ */
904
+ records<T extends RecordData = RecordData>(opts?: {
905
+ filters?: AnalyticsFilter[];
906
+ selectFields?: string[];
907
+ limit?: number;
908
+ offset?: number;
909
+ orderBy?: string;
910
+ order?: SortOrder;
911
+ dateRange?: DateRange;
912
+ }): Promise<(T & RecordResult)[]>;
913
+ /**
914
+ * Calculate multiple aggregations in a single query.
915
+ * Ideal for dashboards that need several numbers at once.
916
+ *
917
+ * @example
918
+ * ```ts
919
+ * const result = await analytics.multiMetric({
920
+ * metrics: [
921
+ * { field: 'amount', name: 'totalRevenue', aggregation: 'sum' },
922
+ * { field: 'amount', name: 'avgOrderValue', aggregation: 'avg' },
923
+ * { field: 'userId', name: 'uniqueCustomers', aggregation: 'count' },
924
+ * ],
925
+ * });
926
+ * // → { totalRevenue: 198432.50, avgOrderValue: 87.23, uniqueCustomers: 2275 }
927
+ * ```
928
+ */
929
+ multiMetric(opts: {
930
+ metrics: MetricDefinition[];
931
+ dateRange?: DateRange;
932
+ }): Promise<MultiMetricResult>;
933
+ /**
934
+ * Get storage statistics for this bucket: record counts, byte sizes.
935
+ *
936
+ * @example
937
+ * ```ts
938
+ * const stats = await analytics.storageStats();
939
+ * // → { totalRecords: 4821, totalBytes: 48293820, avgBytes: 10015, ... }
940
+ * ```
941
+ */
942
+ storageStats(opts?: {
943
+ dateRange?: DateRange;
944
+ }): Promise<StorageStatsResult>;
945
+ /**
946
+ * Compare the same field aggregation across multiple buckets in one query.
947
+ * Your security key must have read access to ALL listed buckets.
948
+ *
949
+ * @example
950
+ * ```ts
951
+ * const rows = await analytics.crossBucket({
952
+ * bucketKeys: ['orders-us', 'orders-eu', 'orders-apac'],
953
+ * field: 'amount',
954
+ * aggregation: 'sum',
955
+ * });
956
+ * // → [
957
+ * // { bucket: 'orders-us', value: 120000 },
958
+ * // { bucket: 'orders-eu', value: 45000 },
959
+ * // { bucket: 'orders-apac', value: 33000 },
960
+ * // ]
961
+ * ```
962
+ */
963
+ crossBucket(opts: {
964
+ bucketKeys: string[];
965
+ field: string;
966
+ aggregation?: Aggregation;
967
+ dateRange?: DateRange;
968
+ }): Promise<CrossBucketRow[]>;
969
+ /**
970
+ * Send a raw analytics query object. Use this when you need full control
971
+ * over the query shape or want to use a queryType not covered by the helpers.
972
+ *
973
+ * @example
974
+ * ```ts
975
+ * const result = await analytics.query({
976
+ * queryType: 'topN',
977
+ * field: 'category',
978
+ * n: 3,
979
+ * order: 'asc',
980
+ * });
981
+ * ```
982
+ */
983
+ query<T = unknown>(query: AnalyticsQuery): Promise<AnalyticsResult<T>>;
984
+ }
985
+
986
+ /**
987
+ * StorageManager — upload, download, list, move, copy, and delete files.
988
+ *
989
+ * Authentication is handled automatically via the X-Storage-Key header.
990
+ * Files are scoped to your owner ID — you can never access another owner's files.
991
+ *
992
+ * **Recommended upload flow** (for progress tracking and large files):
993
+ * 1. Call `getUploadUrl()` to get a signed PUT URL.
994
+ * 2. Upload directly to GCS using XHR (supports progress events).
995
+ * 3. Call `confirmUpload()` to finalize metadata.
996
+ *
997
+ * **Simple upload** (small files, no progress needed):
998
+ * - Call `upload()` — it handles everything in one call.
999
+ *
1000
+ * @example
1001
+ * ```ts
1002
+ * const db = createClient({ securityKey: 'sk_...' });
1003
+ *
1004
+ * // Simple upload
1005
+ * const file = await db.storage.upload(fileBlob, 'avatars/alice.jpg', { isPublic: true });
1006
+ * console.log(file.publicUrl); // CDN URL, usable anywhere
1007
+ * ```
1008
+ */
1009
+ declare class StorageManager {
1010
+ private readonly http;
1011
+ private readonly storageKey;
1012
+ private readonly basePath;
1013
+ constructor(http: HttpClient, storageKey: string);
1014
+ /** Headers for all storage requests — uses X-Storage-Key, not X-Api-Key. */
1015
+ private get authHeaders();
1016
+ /**
1017
+ * Upload a file to storage in one step (server-buffered, up to 500 MB).
1018
+ * For files >10 MB or when you need upload progress, use `getUploadUrl()` instead.
1019
+ *
1020
+ * @param data File data as a Blob, Buffer, Uint8Array, or ArrayBuffer.
1021
+ * @param path Destination path in your storage (e.g. `"avatars/alice.jpg"`).
1022
+ * @param options Upload options: isPublic, overwrite, mimeType.
1023
+ *
1024
+ * @example
1025
+ * ```ts
1026
+ * // Upload a public avatar
1027
+ * const result = await storage.upload(file, 'avatars/alice.jpg', { isPublic: true });
1028
+ * console.log(result.publicUrl); // → https://...
1029
+ *
1030
+ * // Upload a private document
1031
+ * const result = await storage.upload(pdfBuffer, 'docs/contract.pdf');
1032
+ * console.log(result.downloadUrl); // → /storage/download/docs/contract.pdf
1033
+ * ```
1034
+ */
1035
+ upload(data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
1036
+ /**
1037
+ * Upload raw JSON or plain text data as a file.
1038
+ *
1039
+ * @example
1040
+ * ```ts
1041
+ * const result = await storage.uploadRaw(
1042
+ * { config: { theme: 'dark' } },
1043
+ * 'settings/user-config.json',
1044
+ * { isPublic: false },
1045
+ * );
1046
+ * ```
1047
+ */
1048
+ uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
1049
+ /**
1050
+ * Step 1 of the recommended upload flow.
1051
+ * Get a signed URL to upload directly to GCS from the client (supports progress).
1052
+ *
1053
+ * @example
1054
+ * ```ts
1055
+ * const { uploadUrl, path: confirmedPath } = await storage.getUploadUrl({
1056
+ * path: 'videos/intro.mp4',
1057
+ * mimeType: 'video/mp4',
1058
+ * size: file.size,
1059
+ * isPublic: true,
1060
+ * });
1061
+ *
1062
+ * // Upload using XHR for progress tracking
1063
+ * await storage.uploadToSignedUrl(uploadUrl, file, 'video/mp4', (pct) => {
1064
+ * console.log(`${pct}% uploaded`);
1065
+ * });
1066
+ *
1067
+ * // Step 3: confirm
1068
+ * const result = await storage.confirmUpload({ path: confirmedPath, mimeType: 'video/mp4', isPublic: true });
1069
+ * ```
1070
+ */
1071
+ getUploadUrl(opts: {
1072
+ path: string;
1073
+ mimeType: string;
1074
+ size: number;
1075
+ isPublic?: boolean;
1076
+ overwrite?: boolean;
1077
+ expiresInSeconds?: number;
1078
+ }): Promise<UploadUrlResult>;
1079
+ /**
1080
+ * Upload data directly to a signed GCS URL (no auth headers needed).
1081
+ * Optionally tracks progress via a callback.
1082
+ *
1083
+ * @param signedUrl The URL returned by `getUploadUrl()`.
1084
+ * @param data File data.
1085
+ * @param mimeType Must match what was used in `getUploadUrl()`.
1086
+ * @param onProgress Optional callback called with 0–100 progress percentage.
1087
+ */
1088
+ uploadToSignedUrl(signedUrl: string, data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
1089
+ /**
1090
+ * Step 3 of the recommended upload flow.
1091
+ * Confirm a direct upload and register metadata on the server.
1092
+ *
1093
+ * @example
1094
+ * ```ts
1095
+ * const result = await storage.confirmUpload({
1096
+ * path: 'videos/intro.mp4',
1097
+ * mimeType: 'video/mp4',
1098
+ * isPublic: true,
1099
+ * });
1100
+ * console.log(result.publicUrl);
1101
+ * ```
1102
+ */
1103
+ confirmUpload(opts: {
1104
+ path: string;
1105
+ mimeType: string;
1106
+ isPublic?: boolean;
1107
+ }): Promise<UploadResult>;
1108
+ /**
1109
+ * Get signed upload URLs for multiple files at once.
1110
+ *
1111
+ * @example
1112
+ * ```ts
1113
+ * const { files } = await storage.getBatchUploadUrls([
1114
+ * { path: 'images/photo1.jpg', mimeType: 'image/jpeg', size: 204800 },
1115
+ * { path: 'images/photo2.jpg', mimeType: 'image/jpeg', size: 153600 },
1116
+ * ]);
1117
+ *
1118
+ * // Upload each file and confirm
1119
+ * for (const f of files) {
1120
+ * await storage.uploadToSignedUrl(f.uploadUrl, blobs[f.index], f.mimeType);
1121
+ * await storage.confirmUpload({ path: f.path, mimeType: f.mimeType });
1122
+ * }
1123
+ * ```
1124
+ */
1125
+ getBatchUploadUrls(files: BatchUploadItem[]): Promise<BatchUploadUrlResult>;
1126
+ /**
1127
+ * Confirm multiple direct uploads at once.
1128
+ */
1129
+ batchConfirmUploads(items: Array<{
1130
+ path: string;
1131
+ mimeType: string;
1132
+ isPublic?: boolean;
1133
+ }>): Promise<UploadResult[]>;
1134
+ /**
1135
+ * Download a private file as an ArrayBuffer.
1136
+ * For public files, use the `publicUrl` directly — no SDK needed.
1137
+ *
1138
+ * @example
1139
+ * ```ts
1140
+ * const buffer = await storage.download('docs/contract.pdf');
1141
+ * const blob = new Blob([buffer], { type: 'application/pdf' });
1142
+ * // Open in browser:
1143
+ * window.open(URL.createObjectURL(blob));
1144
+ * ```
1145
+ */
1146
+ download(path: string): Promise<ArrayBuffer>;
1147
+ /**
1148
+ * Download multiple files at once, returned as a JSON map of `{ path: base64 }`.
1149
+ *
1150
+ * @example
1151
+ * ```ts
1152
+ * const files = await storage.batchDownload(['docs/a.pdf', 'docs/b.pdf']);
1153
+ * ```
1154
+ */
1155
+ batchDownload(paths: string[]): Promise<Record<string, string>>;
1156
+ /**
1157
+ * List files and folders at a given path prefix.
1158
+ *
1159
+ * @example
1160
+ * ```ts
1161
+ * // List everything in the root
1162
+ * const { files, folders } = await storage.list();
1163
+ *
1164
+ * // List a specific folder
1165
+ * const { files, folders, hasMore, nextCursor } = await storage.list({
1166
+ * prefix: 'avatars/',
1167
+ * limit: 20,
1168
+ * });
1169
+ *
1170
+ * // Next page
1171
+ * const page2 = await storage.list({ prefix: 'avatars/', cursor: nextCursor });
1172
+ * ```
1173
+ */
1174
+ list(opts?: ListOptions): Promise<ListResult>;
1175
+ /**
1176
+ * Get metadata for a file (size, MIME type, visibility, URLs).
1177
+ *
1178
+ * @example
1179
+ * ```ts
1180
+ * const meta = await storage.getMetadata('avatars/alice.jpg');
1181
+ * console.log(meta.size, meta.isPublic, meta.publicUrl);
1182
+ * ```
1183
+ */
1184
+ getMetadata(path: string): Promise<FileMetadata>;
1185
+ /**
1186
+ * Generate a time-limited download URL for a private file.
1187
+ * The URL can be shared externally without requiring an `X-Storage-Key`.
1188
+ *
1189
+ * > **Note:** Downloads via signed URLs bypass the server, so download stats
1190
+ * > are NOT tracked. Use `downloadUrl` for tracked downloads.
1191
+ *
1192
+ * @param path Path to the file.
1193
+ * @param expiresIn URL lifetime in seconds (default 3600 = 1 hour).
1194
+ *
1195
+ * @example
1196
+ * ```ts
1197
+ * const { signedUrl, expiresAt } = await storage.getSignedUrl('docs/invoice.pdf', 1800);
1198
+ * // Share signedUrl with the recipient — it expires in 30 minutes.
1199
+ * ```
1200
+ */
1201
+ getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
1202
+ /**
1203
+ * Change a file's visibility between public and private after upload.
1204
+ *
1205
+ * @example
1206
+ * ```ts
1207
+ * // Make a file public
1208
+ * const result = await storage.setVisibility('avatars/alice.jpg', true);
1209
+ * console.log(result.publicUrl); // CDN URL
1210
+ *
1211
+ * // Make a file private
1212
+ * const result = await storage.setVisibility('avatars/alice.jpg', false);
1213
+ * console.log(result.downloadUrl); // Auth-required URL
1214
+ * ```
1215
+ */
1216
+ setVisibility(path: string, isPublic: boolean): Promise<{
1217
+ path: string;
1218
+ isPublic: boolean;
1219
+ publicUrl: string | null;
1220
+ downloadUrl: string | null;
1221
+ }>;
1222
+ /**
1223
+ * Create a folder (a GCS prefix placeholder).
1224
+ *
1225
+ * @example
1226
+ * ```ts
1227
+ * await storage.createFolder('uploads/2025/');
1228
+ * ```
1229
+ */
1230
+ createFolder(path: string): Promise<{
1231
+ path: string;
1232
+ }>;
1233
+ /**
1234
+ * Delete a single file.
1235
+ *
1236
+ * @example
1237
+ * ```ts
1238
+ * await storage.deleteFile('avatars/old-avatar.jpg');
1239
+ * ```
1240
+ */
1241
+ deleteFile(path: string): Promise<void>;
1242
+ /**
1243
+ * Delete a folder and all its contents recursively.
1244
+ *
1245
+ * @example
1246
+ * ```ts
1247
+ * await storage.deleteFolder('temp/');
1248
+ * ```
1249
+ */
1250
+ deleteFolder(path: string): Promise<void>;
1251
+ /**
1252
+ * Move or rename a file.
1253
+ *
1254
+ * @example
1255
+ * ```ts
1256
+ * // Rename
1257
+ * await storage.move('docs/draft.pdf', 'docs/final.pdf');
1258
+ * // Move to a different folder
1259
+ * await storage.move('inbox/report.xlsx', 'archive/2025/report.xlsx');
1260
+ * ```
1261
+ */
1262
+ move(from: string, to: string): Promise<{
1263
+ from: string;
1264
+ to: string;
1265
+ }>;
1266
+ /**
1267
+ * Copy a file to a new path.
1268
+ *
1269
+ * @example
1270
+ * ```ts
1271
+ * await storage.copy('templates/base.html', 'sites/my-site/index.html');
1272
+ * ```
1273
+ */
1274
+ copy(from: string, to: string): Promise<{
1275
+ from: string;
1276
+ to: string;
1277
+ }>;
1278
+ /**
1279
+ * Get storage statistics for your key: total files, bytes, operation counts.
1280
+ *
1281
+ * @example
1282
+ * ```ts
1283
+ * const stats = await storage.getStats();
1284
+ * console.log(`${stats.totalFiles} files, ${(stats.totalBytes / 1e6).toFixed(1)} MB`);
1285
+ * ```
1286
+ */
1287
+ getStats(): Promise<StorageStats>;
1288
+ /**
1289
+ * Ping the storage service. No authentication required.
1290
+ *
1291
+ * @example
1292
+ * ```ts
1293
+ * const info = await storage.info();
1294
+ * // → { ok: true, storageRoot: 'hydrous-storage' }
1295
+ * ```
1296
+ */
1297
+ info(): Promise<{
1298
+ ok: boolean;
1299
+ storageRoot: string;
1300
+ }>;
1301
+ }
1302
+
1303
+ /** Accepted data types for file uploads. */
1304
+ type UploadData = Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer;
1305
+ /**
1306
+ * ScopedStorage — a StorageManager pre-scoped to a specific folder prefix.
1307
+ *
1308
+ * All paths are automatically prepended with the scope, so you never
1309
+ * have to repeat the folder name.
1310
+ *
1311
+ * @example
1312
+ * ```ts
1313
+ * const db = createClient({ securityKey: 'sk_...' });
1314
+ *
1315
+ * // All operations in the "avatars/" folder
1316
+ * const avatars = db.storage.scope('avatars');
1317
+ *
1318
+ * await avatars.upload(file, 'alice.jpg'); // → "avatars/alice.jpg"
1319
+ * const list = await avatars.list(); // → files under "avatars/"
1320
+ * await avatars.deleteFile('alice.jpg'); // → deletes "avatars/alice.jpg"
1321
+ * ```
1322
+ */
1323
+ declare class ScopedStorage {
1324
+ private readonly manager;
1325
+ private readonly prefix;
1326
+ constructor(manager: StorageManager, prefix: string);
1327
+ private scopedPath;
1328
+ /** Upload a file within the scoped folder. */
1329
+ upload(data: UploadData, path: string, options?: UploadOptions): Promise<UploadResult>;
1330
+ /** Upload raw JSON or text within the scoped folder. */
1331
+ uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
1332
+ /** Get a signed upload URL for a file within the scoped folder. */
1333
+ getUploadUrl(opts: {
1334
+ path: string;
1335
+ mimeType: string;
1336
+ size: number;
1337
+ isPublic?: boolean;
1338
+ overwrite?: boolean;
1339
+ }): Promise<UploadUrlResult>;
1340
+ /** Upload data directly to a signed GCS URL with optional progress tracking. */
1341
+ uploadToSignedUrl(signedUrl: string, data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
1342
+ /** Confirm a direct upload within the scoped folder. */
1343
+ confirmUpload(opts: {
1344
+ path: string;
1345
+ mimeType: string;
1346
+ isPublic?: boolean;
1347
+ }): Promise<UploadResult>;
1348
+ /** Download a file within the scoped folder. */
1349
+ download(path: string): Promise<ArrayBuffer>;
1350
+ /** List files within the scoped folder. */
1351
+ list(opts?: ListOptions): Promise<ListResult>;
1352
+ /** Get metadata for a file within the scoped folder. */
1353
+ getMetadata(path: string): Promise<FileMetadata>;
1354
+ /** Get a time-limited signed URL for a file within the scoped folder. */
1355
+ getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
1356
+ /** Change visibility of a file within the scoped folder. */
1357
+ setVisibility(path: string, isPublic: boolean): Promise<{
1358
+ path: string;
1359
+ isPublic: boolean;
1360
+ publicUrl: string | null;
1361
+ downloadUrl: string | null;
1362
+ }>;
1363
+ /** Delete a file within the scoped folder. */
1364
+ deleteFile(path: string): Promise<void>;
1365
+ /** Delete a sub-folder within the scoped folder. */
1366
+ deleteFolder(path: string): Promise<void>;
1367
+ /** Move a file within the scoped folder. */
1368
+ move(from: string, to: string): Promise<{
1369
+ from: string;
1370
+ to: string;
1371
+ }>;
1372
+ /** Copy a file within the scoped folder. */
1373
+ copy(from: string, to: string): Promise<{
1374
+ from: string;
1375
+ to: string;
1376
+ }>;
1377
+ /** Create a sub-folder within the scoped folder. */
1378
+ createFolder(path: string): Promise<{
1379
+ path: string;
1380
+ }>;
1381
+ /**
1382
+ * Create a further-scoped instance nested within this scope.
1383
+ *
1384
+ * @example
1385
+ * ```ts
1386
+ * const uploads = db.storage.scope('user-uploads');
1387
+ * const images = uploads.scope('images'); // → "user-uploads/images/"
1388
+ * ```
1389
+ */
1390
+ scope(subPrefix: string): ScopedStorage;
1391
+ }
1392
+
1393
+ /**
1394
+ * HydrousClient — the main entry point for the HydrousDB SDK.
1395
+ *
1396
+ * Create one instance per application (it is safe to share globally).
1397
+ * Every sub-client (`auth`, `records`, `analytics`, `storage`) is lazily
1398
+ * instantiated and cached on first access.
1399
+ *
1400
+ * @example
1401
+ * ```ts
1402
+ * import { createClient } from 'hydrousdb';
1403
+ *
1404
+ * const db = createClient({ securityKey: 'sk_live_...' });
1405
+ *
1406
+ * // Records
1407
+ * const posts = db.records('blog-posts');
1408
+ * const users = db.records('app-users');
1409
+ *
1410
+ * // Auth
1411
+ * const auth = db.auth('app-users');
1412
+ *
1413
+ * // Analytics
1414
+ * const stats = db.analytics('orders');
1415
+ *
1416
+ * // Storage (flat)
1417
+ * const storage = db.storage; // StorageManager
1418
+ *
1419
+ * // Storage (scoped to a folder)
1420
+ * const avatars = db.storage.scope('avatars');
1421
+ * ```
1422
+ */
1423
+ declare class HydrousClient {
1424
+ private readonly http;
1425
+ private readonly _storageKey;
1426
+ private _storage;
1427
+ private readonly _recordsCache;
1428
+ private readonly _authCache;
1429
+ private readonly _analyticsCache;
1430
+ constructor(config: HydrousConfig);
1431
+ /**
1432
+ * Get a typed records client for the given bucket.
1433
+ *
1434
+ * The generic type parameter `T` describes the shape of records in this
1435
+ * bucket. Leave it unset for a generic `Record<string, unknown>` shape.
1436
+ *
1437
+ * @param bucketKey The name of your bucket (must match what you created in the dashboard).
1438
+ *
1439
+ * @example
1440
+ * ```ts
1441
+ * interface Post { title: string; body: string; published: boolean }
1442
+ * const posts = db.records<Post>('blog-posts');
1443
+ *
1444
+ * const post = await posts.create({ title: 'Hello', body: '...', published: false });
1445
+ * // post.id, post.createdAt, post.updatedAt are added automatically
1446
+ * ```
1447
+ */
1448
+ records<T extends RecordData = RecordData>(bucketKey: string): RecordsClient<T>;
1449
+ /**
1450
+ * Get an auth client for the given user bucket.
1451
+ *
1452
+ * @param bucketKey The name of your user bucket (e.g. `"app-users"`).
1453
+ *
1454
+ * @example
1455
+ * ```ts
1456
+ * const auth = db.auth('app-users');
1457
+ * const { user, session } = await auth.login({ email: '...', password: '...' });
1458
+ * ```
1459
+ */
1460
+ auth(bucketKey: string): AuthClient;
1461
+ /**
1462
+ * Get an analytics client for the given bucket.
1463
+ *
1464
+ * @param bucketKey The name of the bucket to analyse.
1465
+ *
1466
+ * @example
1467
+ * ```ts
1468
+ * const analytics = db.analytics('orders');
1469
+ * const { count } = await analytics.count();
1470
+ * ```
1471
+ */
1472
+ analytics(bucketKey: string): AnalyticsClient;
1473
+ /**
1474
+ * The storage manager for uploading, downloading, listing, and managing files.
1475
+ *
1476
+ * Scoped to your project — you can never access another project's files.
1477
+ *
1478
+ * @example
1479
+ * ```ts
1480
+ * // Upload a file
1481
+ * const result = await db.storage.upload(file, 'images/photo.jpg', { isPublic: true });
1482
+ *
1483
+ * // Scope to a folder
1484
+ * const avatars = db.storage.scope('user-avatars');
1485
+ * await avatars.upload(blob, `${userId}.jpg`, { isPublic: true });
1486
+ * ```
1487
+ */
1488
+ get storage(): StorageManager & {
1489
+ scope: (prefix: string) => ScopedStorage;
1490
+ };
1491
+ }
1492
+ /**
1493
+ * Create a new HydrousDB client.
1494
+ *
1495
+ * This is the **only** export you need to get started.
1496
+ * The API URL is pre-configured — you only need your Security Key.
1497
+ *
1498
+ * @param config.securityKey Your project's Security Key from https://hydrousdb.com/dashboard
1499
+ * @param config.baseUrl (Optional) Override the API base URL.
1500
+ *
1501
+ * @example
1502
+ * ```ts
1503
+ * import { createClient } from 'hydrousdb';
1504
+ *
1505
+ * const db = createClient({
1506
+ * securityKey: process.env.HYDROUS_SECURITY_KEY!,
1507
+ * });
1508
+ * ```
1509
+ */
1510
+ declare function createClient(config: HydrousConfig): HydrousClient;
1511
+
1512
+ declare class HydrousError extends Error {
1513
+ readonly code: string;
1514
+ readonly status?: number;
1515
+ readonly requestId?: string;
1516
+ readonly details?: string[];
1517
+ constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
1518
+ toString(): string;
1519
+ }
1520
+ declare class AuthError extends HydrousError {
1521
+ constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
1522
+ }
1523
+ declare class RecordError extends HydrousError {
1524
+ constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
1525
+ }
1526
+ declare class StorageError extends HydrousError {
1527
+ constructor(message: string, code: string, status?: number, requestId?: string);
1528
+ }
1529
+ declare class AnalyticsError extends HydrousError {
1530
+ constructor(message: string, code: string, status?: number, requestId?: string);
1531
+ }
1532
+ declare class ValidationError extends HydrousError {
1533
+ constructor(message: string, details?: string[]);
1534
+ }
1535
+ declare class NetworkError extends HydrousError {
1536
+ readonly cause?: unknown;
1537
+ constructor(message: string, cause?: unknown);
1538
+ }
1539
+
1540
+ export { type Aggregation, AnalyticsClient, AnalyticsError, type AnalyticsFilter, type AnalyticsQuery, type AnalyticsResult, AuthClient, AuthError, type AuthResult, type BatchUploadItem, type BatchUploadUrlResult, type ChangePasswordOptions, type CountResult, type CrossBucketRow, type DateRange, type DistributionRow, type FieldStats, type FieldTimeSeriesRow, type FileEntry, type FileMetadata, type Granularity, HydrousClient, type HydrousConfig, HydrousError, type ListOptions, type ListResult, type ListUsersOptions, type ListUsersResult, type LoginOptions, type MetricDefinition, type MultiMetricResult, NetworkError, type PatchRecordOptions, type QueryFilter, type QueryOptions, type QueryResult, type QueryType, type RecordData, RecordError, type RecordHistoryEntry, type RecordResult, RecordsClient, ScopedStorage, type Session, type SignedUrlResult, type SignupOptions, type SortOrder, StorageError, StorageManager, type StorageStats, type StorageStatsResult, type SumRow, type TimeSeriesRow, type TopNRow, type UpdateUserOptions, type UploadOptions, type UploadResult, type UploadUrlResult, type UserRecord, ValidationError, createClient };