hydrousdb 3.0.0 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +246 -172
- package/dist/index.cjs +157 -610
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -602
- package/dist/index.d.ts +142 -602
- package/dist/index.js +157 -610
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.cts
CHANGED
|
@@ -7,24 +7,58 @@ interface RequestOptions {
|
|
|
7
7
|
}
|
|
8
8
|
declare class HttpClient {
|
|
9
9
|
private readonly baseUrl;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
delete<T = unknown>(path: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
10
|
+
constructor(baseUrl: string);
|
|
11
|
+
request<T = unknown>(path: string, apiKeyOrOpts?: string | RequestOptions, opts?: RequestOptions): Promise<T>;
|
|
12
|
+
get<T = unknown>(path: string, apiKey?: string, headers?: Record<string, string>): Promise<T>;
|
|
13
|
+
post<T = unknown>(path: string, apiKey?: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
14
|
+
put<T = unknown>(path: string, apiKey?: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
15
|
+
patch<T = unknown>(path: string, apiKey?: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
16
|
+
delete<T = unknown>(path: string, apiKey?: string, body?: unknown, headers?: Record<string, string>): Promise<T>;
|
|
18
17
|
putToSignedUrl(signedUrl: string, data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
19
18
|
}
|
|
20
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Storage keys map — one named key per storage bucket/permission scope.
|
|
22
|
+
* Keys start with `ssk_`. You can define as many as you need.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* storageKeys: {
|
|
27
|
+
* main: 'ssk_main_…',
|
|
28
|
+
* avatars: 'ssk_avatars_…',
|
|
29
|
+
* documents: 'ssk_docs_…',
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
type StorageKeys = Record<string, string>;
|
|
21
34
|
interface HydrousConfig {
|
|
22
35
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
36
|
+
* Auth service key (starts with `hk_auth_`).
|
|
37
|
+
* Used exclusively for all `/auth/*` routes — signup, login, sessions, etc.
|
|
38
|
+
* Obtain from your dashboard at https://hydrousdb.com/dashboard.
|
|
26
39
|
*/
|
|
27
|
-
|
|
40
|
+
authKey: string;
|
|
41
|
+
/**
|
|
42
|
+
* Bucket security key (starts with `hk_bucket_`).
|
|
43
|
+
* Used for all `/records/*` and `/analytics/*` routes.
|
|
44
|
+
* Obtain from your dashboard at https://hydrousdb.com/dashboard.
|
|
45
|
+
*/
|
|
46
|
+
bucketSecurityKey: string;
|
|
47
|
+
/**
|
|
48
|
+
* Named storage keys (each starts with `ssk_`).
|
|
49
|
+
* Define one key per storage bucket/permission scope.
|
|
50
|
+
* Pass the name of the key you want when calling `db.storage('keyName')`.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* storageKeys: {
|
|
55
|
+
* main: 'ssk_main_…', // default general-purpose bucket
|
|
56
|
+
* avatars: 'ssk_avatars_…', // user avatar uploads
|
|
57
|
+
* documents: 'ssk_docs_…', // private documents
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
storageKeys: StorageKeys;
|
|
28
62
|
/**
|
|
29
63
|
* Override the API base URL. Defaults to the official HydrousDB endpoint.
|
|
30
64
|
* You almost never need to set this.
|
|
@@ -304,175 +338,53 @@ interface CrossBucketRow {
|
|
|
304
338
|
|
|
305
339
|
/**
|
|
306
340
|
* 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").
|
|
341
|
+
* Uses the `authKey` (`hk_auth_…`) sent via `X-Api-Key` header.
|
|
310
342
|
*
|
|
311
343
|
* @example
|
|
312
344
|
* ```ts
|
|
313
|
-
* const db = createClient({
|
|
345
|
+
* const db = createClient({ authKey: 'hk_auth_…', bucketSecurityKey: '…', storageKeys: { main: '…' } });
|
|
314
346
|
* 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
|
-
* });
|
|
347
|
+
* const { user, session } = await auth.signup({ email: 'alice@example.com', password: 'hunter2' });
|
|
321
348
|
* ```
|
|
322
349
|
*/
|
|
323
350
|
declare class AuthClient {
|
|
324
351
|
private readonly http;
|
|
325
|
-
private readonly
|
|
352
|
+
private readonly authKey;
|
|
326
353
|
private readonly basePath;
|
|
327
|
-
constructor(http: HttpClient, bucketKey: string);
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
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
|
-
*/
|
|
354
|
+
constructor(http: HttpClient, authKey: string, bucketKey: string);
|
|
355
|
+
private post;
|
|
356
|
+
private get;
|
|
357
|
+
private patch;
|
|
358
|
+
private delete;
|
|
342
359
|
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
360
|
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
361
|
logout({ sessionId }: {
|
|
366
362
|
sessionId: string;
|
|
367
363
|
}): 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
364
|
refreshSession({ refreshToken }: {
|
|
378
365
|
refreshToken: string;
|
|
379
366
|
}): 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
367
|
getUser({ userId }: {
|
|
389
368
|
userId: string;
|
|
390
369
|
}): 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
370
|
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
371
|
deleteUser({ sessionId, userId }: {
|
|
414
372
|
sessionId: string;
|
|
415
373
|
userId: string;
|
|
416
374
|
}): 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
375
|
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
376
|
hardDeleteUser({ sessionId, userId }: {
|
|
440
377
|
sessionId: string;
|
|
441
378
|
userId: string;
|
|
442
379
|
}): 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, }: {
|
|
380
|
+
bulkDeleteUsers({ sessionId, userIds }: {
|
|
455
381
|
sessionId: string;
|
|
456
382
|
userIds: string[];
|
|
457
383
|
}): Promise<{
|
|
458
384
|
deleted: number;
|
|
459
385
|
failed: string[];
|
|
460
386
|
}>;
|
|
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, }: {
|
|
387
|
+
lockAccount({ sessionId, userId, duration }: {
|
|
476
388
|
sessionId: string;
|
|
477
389
|
userId: string;
|
|
478
390
|
duration?: number;
|
|
@@ -480,392 +392,103 @@ declare class AuthClient {
|
|
|
480
392
|
lockedUntil: number;
|
|
481
393
|
unlockTime: string;
|
|
482
394
|
}>;
|
|
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, }: {
|
|
395
|
+
unlockAccount({ sessionId, userId }: {
|
|
492
396
|
sessionId: string;
|
|
493
397
|
userId: string;
|
|
494
398
|
}): 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
399
|
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
400
|
requestPasswordReset({ email }: {
|
|
519
401
|
email: string;
|
|
520
402
|
}): 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, }: {
|
|
403
|
+
confirmPasswordReset({ resetToken, newPassword }: {
|
|
533
404
|
resetToken: string;
|
|
534
405
|
newPassword: string;
|
|
535
406
|
}): 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
407
|
requestEmailVerification({ userId }: {
|
|
545
408
|
userId: string;
|
|
546
409
|
}): 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
410
|
confirmEmailVerification({ verifyToken }: {
|
|
556
411
|
verifyToken: string;
|
|
557
412
|
}): Promise<void>;
|
|
558
413
|
}
|
|
559
414
|
|
|
560
415
|
/**
|
|
561
|
-
* RecordsClient —
|
|
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`.
|
|
416
|
+
* RecordsClient — CRUD + query for a single bucket.
|
|
417
|
+
* Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
|
|
566
418
|
*
|
|
567
419
|
* @example
|
|
568
420
|
* ```ts
|
|
569
|
-
* const db = createClient({
|
|
421
|
+
* const db = createClient({ authKey: '…', bucketSecurityKey: 'hk_bucket_…', storageKeys: { main: '…' } });
|
|
570
422
|
* const posts = db.records('blog-posts');
|
|
571
|
-
*
|
|
572
|
-
* // Create a record
|
|
573
423
|
* 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
424
|
* ```
|
|
581
425
|
*/
|
|
582
426
|
declare class RecordsClient<T extends RecordData = RecordData> {
|
|
583
427
|
private readonly http;
|
|
584
428
|
private readonly bucketKey;
|
|
585
429
|
private readonly basePath;
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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
|
-
*/
|
|
430
|
+
private readonly bucketKey_;
|
|
431
|
+
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
432
|
+
private get key();
|
|
600
433
|
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
434
|
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
435
|
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
436
|
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
437
|
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
438
|
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
439
|
batchDelete(ids: string[]): Promise<{
|
|
665
440
|
deleted: number;
|
|
666
441
|
failed: string[];
|
|
667
442
|
}>;
|
|
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
443
|
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
444
|
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
445
|
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
446
|
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
447
|
restoreVersion(id: string, version: number): Promise<T & RecordResult>;
|
|
734
448
|
}
|
|
735
449
|
|
|
736
450
|
/**
|
|
737
|
-
* AnalyticsClient —
|
|
738
|
-
*
|
|
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.
|
|
451
|
+
* AnalyticsClient — BigQuery-powered aggregations for a bucket.
|
|
452
|
+
* Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
|
|
742
453
|
*
|
|
743
454
|
* @example
|
|
744
455
|
* ```ts
|
|
745
|
-
* const db = createClient({
|
|
456
|
+
* const db = createClient({ authKey: '…', bucketSecurityKey: 'hk_bucket_…', storageKeys: { main: '…' } });
|
|
746
457
|
* 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
|
-
* });
|
|
458
|
+
* const { count } = await analytics.count();
|
|
752
459
|
* ```
|
|
753
460
|
*/
|
|
754
461
|
declare class AnalyticsClient {
|
|
755
462
|
private readonly http;
|
|
756
|
-
private readonly
|
|
463
|
+
private readonly bucketSecurityKey;
|
|
757
464
|
private readonly basePath;
|
|
758
|
-
constructor(http: HttpClient, bucketKey: string);
|
|
759
|
-
/** Internal dispatcher — all queries POST to the same endpoint. */
|
|
465
|
+
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
760
466
|
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
467
|
count(opts?: {
|
|
776
468
|
dateRange?: DateRange;
|
|
777
469
|
}): 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
470
|
distribution(opts: {
|
|
793
471
|
field: string;
|
|
794
472
|
limit?: number;
|
|
795
473
|
order?: SortOrder;
|
|
796
474
|
dateRange?: DateRange;
|
|
797
475
|
}): 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
476
|
sum(opts: {
|
|
813
477
|
field: string;
|
|
814
478
|
groupBy?: string;
|
|
815
479
|
limit?: number;
|
|
816
480
|
dateRange?: DateRange;
|
|
817
481
|
}): 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
482
|
timeSeries(opts?: {
|
|
832
483
|
granularity?: Granularity;
|
|
833
484
|
dateRange?: DateRange;
|
|
834
485
|
}): 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
486
|
fieldTimeSeries(opts: {
|
|
849
487
|
field: string;
|
|
850
488
|
aggregation?: Aggregation;
|
|
851
489
|
granularity?: Granularity;
|
|
852
490
|
dateRange?: DateRange;
|
|
853
491
|
}): 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
492
|
topN(opts: {
|
|
870
493
|
field: string;
|
|
871
494
|
n?: number;
|
|
@@ -873,34 +496,10 @@ declare class AnalyticsClient {
|
|
|
873
496
|
order?: SortOrder;
|
|
874
497
|
dateRange?: DateRange;
|
|
875
498
|
}): 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
499
|
stats(opts: {
|
|
886
500
|
field: string;
|
|
887
501
|
dateRange?: DateRange;
|
|
888
502
|
}): 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
503
|
records<T extends RecordData = RecordData>(opts?: {
|
|
905
504
|
filters?: AnalyticsFilter[];
|
|
906
505
|
selectFields?: string[];
|
|
@@ -910,100 +509,35 @@ declare class AnalyticsClient {
|
|
|
910
509
|
order?: SortOrder;
|
|
911
510
|
dateRange?: DateRange;
|
|
912
511
|
}): 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
512
|
multiMetric(opts: {
|
|
930
513
|
metrics: MetricDefinition[];
|
|
931
514
|
dateRange?: DateRange;
|
|
932
515
|
}): 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
516
|
storageStats(opts?: {
|
|
943
517
|
dateRange?: DateRange;
|
|
944
518
|
}): 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
519
|
crossBucket(opts: {
|
|
964
520
|
bucketKeys: string[];
|
|
965
521
|
field: string;
|
|
966
522
|
aggregation?: Aggregation;
|
|
967
523
|
dateRange?: DateRange;
|
|
968
524
|
}): 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
525
|
query<T = unknown>(query: AnalyticsQuery): Promise<AnalyticsResult<T>>;
|
|
984
526
|
}
|
|
985
527
|
|
|
986
528
|
/**
|
|
987
529
|
* StorageManager — upload, download, list, move, copy, and delete files.
|
|
530
|
+
* Uses an `X-Storage-Key` (`ssk_…`) header — separate from auth and bucket keys.
|
|
531
|
+
* Each key is scoped to a specific storage bucket and permission set.
|
|
988
532
|
*
|
|
989
|
-
*
|
|
990
|
-
*
|
|
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.
|
|
533
|
+
* Get a StorageManager via `db.storage('keyName')` where the key name
|
|
534
|
+
* matches one of the keys you defined in `storageKeys` when calling `createClient`.
|
|
999
535
|
*
|
|
1000
536
|
* @example
|
|
1001
537
|
* ```ts
|
|
1002
|
-
* const db = createClient({
|
|
1003
|
-
*
|
|
1004
|
-
*
|
|
1005
|
-
* const file = await db.storage.upload(fileBlob, 'avatars/alice.jpg', { isPublic: true });
|
|
1006
|
-
* console.log(file.publicUrl); // CDN URL, usable anywhere
|
|
538
|
+
* const db = createClient({ authKey: '…', bucketSecurityKey: '…', storageKeys: { avatars: 'ssk_avatars_…' } });
|
|
539
|
+
* const avatars = db.storage('avatars');
|
|
540
|
+
* const result = await avatars.upload(file, 'alice.jpg', { isPublic: true });
|
|
1007
541
|
* ```
|
|
1008
542
|
*/
|
|
1009
543
|
declare class StorageManager {
|
|
@@ -1300,8 +834,6 @@ declare class StorageManager {
|
|
|
1300
834
|
}>;
|
|
1301
835
|
}
|
|
1302
836
|
|
|
1303
|
-
/** Accepted data types for file uploads. */
|
|
1304
|
-
type UploadData = Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer;
|
|
1305
837
|
/**
|
|
1306
838
|
* ScopedStorage — a StorageManager pre-scoped to a specific folder prefix.
|
|
1307
839
|
*
|
|
@@ -1326,7 +858,7 @@ declare class ScopedStorage {
|
|
|
1326
858
|
constructor(manager: StorageManager, prefix: string);
|
|
1327
859
|
private scopedPath;
|
|
1328
860
|
/** Upload a file within the scoped folder. */
|
|
1329
|
-
upload(data:
|
|
861
|
+
upload(data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
1330
862
|
/** Upload raw JSON or text within the scoped folder. */
|
|
1331
863
|
uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
1332
864
|
/** Get a signed upload URL for a file within the scoped folder. */
|
|
@@ -1337,8 +869,6 @@ declare class ScopedStorage {
|
|
|
1337
869
|
isPublic?: boolean;
|
|
1338
870
|
overwrite?: boolean;
|
|
1339
871
|
}): 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
872
|
/** Confirm a direct upload within the scoped folder. */
|
|
1343
873
|
confirmUpload(opts: {
|
|
1344
874
|
path: string;
|
|
@@ -1347,7 +877,10 @@ declare class ScopedStorage {
|
|
|
1347
877
|
}): Promise<UploadResult>;
|
|
1348
878
|
/** Download a file within the scoped folder. */
|
|
1349
879
|
download(path: string): Promise<ArrayBuffer>;
|
|
1350
|
-
/**
|
|
880
|
+
/**
|
|
881
|
+
* List files within the scoped folder.
|
|
882
|
+
* `prefix` in options is relative to the scope.
|
|
883
|
+
*/
|
|
1351
884
|
list(opts?: ListOptions): Promise<ListResult>;
|
|
1352
885
|
/** Get metadata for a file within the scoped folder. */
|
|
1353
886
|
getMetadata(path: string): Promise<FileMetadata>;
|
|
@@ -1384,7 +917,7 @@ declare class ScopedStorage {
|
|
|
1384
917
|
* @example
|
|
1385
918
|
* ```ts
|
|
1386
919
|
* const uploads = db.storage.scope('user-uploads');
|
|
1387
|
-
* const images
|
|
920
|
+
* const images = uploads.scope('images'); // → "user-uploads/images/"
|
|
1388
921
|
* ```
|
|
1389
922
|
*/
|
|
1390
923
|
scope(subPrefix: string): ScopedStorage;
|
|
@@ -1393,75 +926,73 @@ declare class ScopedStorage {
|
|
|
1393
926
|
/**
|
|
1394
927
|
* HydrousClient — the main entry point for the HydrousDB SDK.
|
|
1395
928
|
*
|
|
1396
|
-
*
|
|
1397
|
-
*
|
|
1398
|
-
*
|
|
929
|
+
* Each service uses its own dedicated key:
|
|
930
|
+
* - `authKey` (`hk_auth_…`) → `db.auth('bucket')`
|
|
931
|
+
* - `bucketSecurityKey` (`hk_bucket_…`) → `db.records('bucket')` + `db.analytics('bucket')`
|
|
932
|
+
* - `storageKeys` (`ssk_…`) → `db.storage('keyName')`
|
|
1399
933
|
*
|
|
1400
934
|
* @example
|
|
1401
935
|
* ```ts
|
|
1402
936
|
* import { createClient } from 'hydrousdb';
|
|
1403
937
|
*
|
|
1404
|
-
* const db = createClient({
|
|
1405
|
-
*
|
|
1406
|
-
*
|
|
1407
|
-
*
|
|
1408
|
-
*
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
938
|
+
* const db = createClient({
|
|
939
|
+
* authKey: 'hk_auth_…',
|
|
940
|
+
* bucketSecurityKey: 'hk_bucket_…',
|
|
941
|
+
* storageKeys: {
|
|
942
|
+
* main: 'ssk_main_…',
|
|
943
|
+
* avatars: 'ssk_avatars_…',
|
|
944
|
+
* documents: 'ssk_docs_…',
|
|
945
|
+
* },
|
|
946
|
+
* });
|
|
1412
947
|
*
|
|
1413
|
-
* // Analytics
|
|
1414
|
-
* const
|
|
948
|
+
* // Records & Analytics — use bucketSecurityKey automatically
|
|
949
|
+
* const posts = db.records('blog-posts');
|
|
950
|
+
* const analytics = db.analytics('orders');
|
|
1415
951
|
*
|
|
1416
|
-
* //
|
|
1417
|
-
* const
|
|
952
|
+
* // Auth — uses authKey automatically
|
|
953
|
+
* const auth = db.auth('app-users');
|
|
1418
954
|
*
|
|
1419
|
-
* // Storage
|
|
1420
|
-
* const
|
|
955
|
+
* // Storage — pick which key to use by name
|
|
956
|
+
* const avatarStorage = db.storage('avatars');
|
|
957
|
+
* const documentStorage = db.storage('documents');
|
|
1421
958
|
* ```
|
|
1422
959
|
*/
|
|
1423
960
|
declare class HydrousClient {
|
|
1424
961
|
private readonly http;
|
|
1425
|
-
private readonly
|
|
1426
|
-
private
|
|
962
|
+
private readonly authKey_;
|
|
963
|
+
private readonly bucketSecurityKey_;
|
|
964
|
+
private readonly storageKeys_;
|
|
1427
965
|
private readonly _recordsCache;
|
|
1428
966
|
private readonly _authCache;
|
|
1429
967
|
private readonly _analyticsCache;
|
|
968
|
+
private readonly _storageCache;
|
|
1430
969
|
constructor(config: HydrousConfig);
|
|
1431
970
|
/**
|
|
1432
|
-
* Get a typed records client for the
|
|
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).
|
|
971
|
+
* Get a typed records client for the named bucket.
|
|
972
|
+
* Uses your `bucketSecurityKey` automatically.
|
|
1438
973
|
*
|
|
1439
974
|
* @example
|
|
1440
975
|
* ```ts
|
|
1441
|
-
* interface Post { title: string;
|
|
976
|
+
* interface Post { title: string; published: boolean }
|
|
1442
977
|
* 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
|
|
978
|
+
* const post = await posts.create({ title: 'Hello', published: false });
|
|
1446
979
|
* ```
|
|
1447
980
|
*/
|
|
1448
981
|
records<T extends RecordData = RecordData>(bucketKey: string): RecordsClient<T>;
|
|
1449
982
|
/**
|
|
1450
|
-
* Get an auth client for the
|
|
1451
|
-
*
|
|
1452
|
-
* @param bucketKey The name of your user bucket (e.g. `"app-users"`).
|
|
983
|
+
* Get an auth client for the named user bucket.
|
|
984
|
+
* Uses your `authKey` automatically.
|
|
1453
985
|
*
|
|
1454
986
|
* @example
|
|
1455
987
|
* ```ts
|
|
1456
988
|
* const auth = db.auth('app-users');
|
|
1457
|
-
* const { user, session } = await auth.login({ email: '
|
|
989
|
+
* const { user, session } = await auth.login({ email: '…', password: '…' });
|
|
1458
990
|
* ```
|
|
1459
991
|
*/
|
|
1460
992
|
auth(bucketKey: string): AuthClient;
|
|
1461
993
|
/**
|
|
1462
|
-
* Get an analytics client for the
|
|
1463
|
-
*
|
|
1464
|
-
* @param bucketKey The name of the bucket to analyse.
|
|
994
|
+
* Get an analytics client for the named bucket.
|
|
995
|
+
* Uses your `bucketSecurityKey` automatically.
|
|
1465
996
|
*
|
|
1466
997
|
* @example
|
|
1467
998
|
* ```ts
|
|
@@ -1471,48 +1002,57 @@ declare class HydrousClient {
|
|
|
1471
1002
|
*/
|
|
1472
1003
|
analytics(bucketKey: string): AnalyticsClient;
|
|
1473
1004
|
/**
|
|
1474
|
-
*
|
|
1005
|
+
* Get a storage manager for the named storage key.
|
|
1006
|
+
* The name must match a key you defined in `storageKeys` when calling `createClient`.
|
|
1007
|
+
* Uses the corresponding `ssk_…` key automatically via `X-Storage-Key` header.
|
|
1475
1008
|
*
|
|
1476
|
-
*
|
|
1009
|
+
* @param keyName The name of the storage key (e.g. `"avatars"`, `"documents"`, `"main"`).
|
|
1477
1010
|
*
|
|
1478
1011
|
* @example
|
|
1479
1012
|
* ```ts
|
|
1480
|
-
*
|
|
1481
|
-
* const
|
|
1013
|
+
* const avatars = db.storage('avatars');
|
|
1014
|
+
* const documents = db.storage('documents');
|
|
1015
|
+
*
|
|
1016
|
+
* // Upload to avatars bucket
|
|
1017
|
+
* await avatars.upload(file, `${userId}.jpg`, { isPublic: true });
|
|
1482
1018
|
*
|
|
1483
|
-
* // Scope to a folder
|
|
1484
|
-
* const
|
|
1485
|
-
* await
|
|
1019
|
+
* // Scope to a sub-folder
|
|
1020
|
+
* const userDocs = db.storage('documents').scope(`users/${userId}`);
|
|
1021
|
+
* await userDocs.upload(pdfBuffer, 'contract.pdf');
|
|
1486
1022
|
* ```
|
|
1487
1023
|
*/
|
|
1488
|
-
|
|
1024
|
+
storage(keyName: string): StorageManager & {
|
|
1489
1025
|
scope: (prefix: string) => ScopedStorage;
|
|
1490
1026
|
};
|
|
1491
1027
|
}
|
|
1492
1028
|
/**
|
|
1493
1029
|
* Create a new HydrousDB client.
|
|
1494
1030
|
*
|
|
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
1031
|
* @example
|
|
1502
1032
|
* ```ts
|
|
1503
1033
|
* import { createClient } from 'hydrousdb';
|
|
1504
1034
|
*
|
|
1505
1035
|
* const db = createClient({
|
|
1506
|
-
*
|
|
1036
|
+
* authKey: process.env.HYDROUS_AUTH_KEY!,
|
|
1037
|
+
* bucketSecurityKey: process.env.HYDROUS_BUCKET_KEY!,
|
|
1038
|
+
* storageKeys: {
|
|
1039
|
+
* main: process.env.HYDROUS_STORAGE_MAIN!,
|
|
1040
|
+
* avatars: process.env.HYDROUS_STORAGE_AVATARS!,
|
|
1041
|
+
* documents: process.env.HYDROUS_STORAGE_DOCS!,
|
|
1042
|
+
* },
|
|
1507
1043
|
* });
|
|
1508
1044
|
* ```
|
|
1509
1045
|
*/
|
|
1510
1046
|
declare function createClient(config: HydrousConfig): HydrousClient;
|
|
1511
1047
|
|
|
1512
1048
|
declare class HydrousError extends Error {
|
|
1049
|
+
/** Machine-readable error code returned by the API. */
|
|
1513
1050
|
readonly code: string;
|
|
1051
|
+
/** HTTP status code (if applicable). */
|
|
1514
1052
|
readonly status?: number;
|
|
1053
|
+
/** The original request ID for support tracing. */
|
|
1515
1054
|
readonly requestId?: string;
|
|
1055
|
+
/** Additional validation details. */
|
|
1516
1056
|
readonly details?: string[];
|
|
1517
1057
|
constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
|
|
1518
1058
|
toString(): string;
|