hydrousdb 2.0.1 → 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.
- package/LICENSE +1 -1
- package/README.md +911 -515
- package/dist/index.cjs +1647 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1540 -0
- package/dist/index.d.ts +1339 -510
- package/dist/index.js +1427 -1100
- package/dist/index.js.map +1 -1
- package/package.json +31 -14
- package/dist/index.d.mts +0 -711
- package/dist/index.mjs +0 -1291
- package/dist/index.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,168 +1,188 @@
|
|
|
1
|
-
interface
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
timeout?: number;
|
|
8
|
-
}
|
|
9
|
-
interface HydrousResponse<T = unknown> {
|
|
10
|
-
data: T | null;
|
|
11
|
-
error: HydrousError | null;
|
|
12
|
-
}
|
|
13
|
-
interface HydrousError {
|
|
14
|
-
message: string;
|
|
15
|
-
code: string;
|
|
16
|
-
status?: number;
|
|
17
|
-
}
|
|
18
|
-
type FilterOperator = 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'ilike' | 'in' | 'nin' | 'is' | 'not';
|
|
19
|
-
interface Filter {
|
|
20
|
-
field: string;
|
|
21
|
-
operator: FilterOperator;
|
|
22
|
-
value: unknown;
|
|
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;
|
|
23
7
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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>;
|
|
33
19
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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;
|
|
38
33
|
}
|
|
39
|
-
interface
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
interface SignupOptions {
|
|
35
|
+
email: string;
|
|
36
|
+
password: string;
|
|
37
|
+
fullName?: string;
|
|
38
|
+
[key: string]: unknown;
|
|
42
39
|
}
|
|
43
|
-
interface
|
|
40
|
+
interface LoginOptions {
|
|
41
|
+
email: string;
|
|
42
|
+
password: string;
|
|
43
|
+
}
|
|
44
|
+
interface UserRecord {
|
|
44
45
|
id: string;
|
|
45
46
|
email: string;
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
fullName?: string | null;
|
|
48
|
+
emailVerified: boolean;
|
|
49
|
+
accountStatus: 'active' | 'locked' | 'suspended';
|
|
50
|
+
role: 'user' | 'admin';
|
|
51
|
+
createdAt: number;
|
|
52
|
+
updatedAt: number;
|
|
48
53
|
metadata?: Record<string, unknown>;
|
|
54
|
+
[key: string]: unknown;
|
|
49
55
|
}
|
|
50
|
-
interface
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
interface Session {
|
|
57
|
+
sessionId: string;
|
|
58
|
+
userId: string;
|
|
59
|
+
bucketId: string;
|
|
60
|
+
createdAt: number;
|
|
53
61
|
expiresAt: number;
|
|
54
|
-
|
|
62
|
+
refreshToken: string;
|
|
63
|
+
refreshExpiresAt: number;
|
|
55
64
|
}
|
|
56
|
-
interface
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
metadata?: Record<string, unknown>;
|
|
65
|
+
interface AuthResult {
|
|
66
|
+
user: UserRecord;
|
|
67
|
+
session: Session;
|
|
60
68
|
}
|
|
61
|
-
interface
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
interface UpdateUserOptions {
|
|
70
|
+
sessionId: string;
|
|
71
|
+
userId: string;
|
|
72
|
+
data: Partial<Omit<UserRecord, 'id' | 'email' | 'createdAt'>>;
|
|
64
73
|
}
|
|
65
|
-
interface
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
event?: string;
|
|
74
|
-
from?: string;
|
|
75
|
-
to?: string;
|
|
74
|
+
interface ChangePasswordOptions {
|
|
75
|
+
sessionId: string;
|
|
76
|
+
userId: string;
|
|
77
|
+
currentPassword: string;
|
|
78
|
+
newPassword: string;
|
|
79
|
+
}
|
|
80
|
+
interface ListUsersOptions {
|
|
81
|
+
sessionId: string;
|
|
76
82
|
limit?: number;
|
|
77
|
-
|
|
83
|
+
offset?: number;
|
|
78
84
|
}
|
|
79
|
-
interface
|
|
80
|
-
|
|
81
|
-
event: string;
|
|
82
|
-
properties: Record<string, unknown>;
|
|
83
|
-
userId?: string;
|
|
84
|
-
sessionId?: string;
|
|
85
|
-
timestamp: number;
|
|
86
|
-
}
|
|
87
|
-
/** The bucket key (ssk_…) that authorizes access to a specific storage bucket */
|
|
88
|
-
type BucketKey = string;
|
|
89
|
-
type UploadStage = 'pending' | 'compressing' | 'uploading' | 'done' | 'error';
|
|
90
|
-
/** Fired for every progress tick during an upload */
|
|
91
|
-
interface UploadProgress {
|
|
92
|
-
/** 0-based index (always 0 for single uploads) */
|
|
93
|
-
index: number;
|
|
94
|
-
/** Total files in this operation */
|
|
95
|
-
total: number;
|
|
96
|
-
/** Destination path (relative to your bucket root) */
|
|
97
|
-
path: string;
|
|
98
|
-
/** Current lifecycle stage */
|
|
99
|
-
stage: UploadStage;
|
|
100
|
-
/** Bytes sent to the server so far */
|
|
101
|
-
bytesUploaded: number;
|
|
102
|
-
/** Total bytes to send */
|
|
103
|
-
totalBytes: number;
|
|
104
|
-
/** 0–100 integer */
|
|
105
|
-
percent: number;
|
|
106
|
-
/** Upload speed in bytes/second – null before the first tick */
|
|
107
|
-
bytesPerSecond: number | null;
|
|
108
|
-
/** Estimated seconds remaining – null until speed is known */
|
|
109
|
-
eta: number | null;
|
|
110
|
-
/** Set when stage === 'done' */
|
|
111
|
-
result?: UploadResult;
|
|
112
|
-
/** Set when stage === 'error' */
|
|
113
|
-
error?: string;
|
|
114
|
-
/** Set when stage === 'error' */
|
|
115
|
-
code?: string;
|
|
116
|
-
}
|
|
117
|
-
/** Per-file progress during a batch download */
|
|
118
|
-
interface DownloadProgress {
|
|
119
|
-
index: number;
|
|
85
|
+
interface ListUsersResult {
|
|
86
|
+
users: UserRecord[];
|
|
120
87
|
total: number;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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. */
|
|
124
136
|
mimeType?: string;
|
|
125
|
-
|
|
137
|
+
/** TTL in seconds for the signed upload URL (default 900 = 15 min). */
|
|
138
|
+
expiresInSeconds?: number;
|
|
126
139
|
}
|
|
127
140
|
interface UploadResult {
|
|
128
141
|
path: string;
|
|
129
|
-
compressed: boolean;
|
|
130
|
-
originalSize: number;
|
|
131
|
-
storedSize: number;
|
|
132
|
-
spaceSaved: number;
|
|
133
142
|
mimeType: string;
|
|
143
|
+
size: number;
|
|
144
|
+
isPublic: boolean;
|
|
145
|
+
publicUrl: string | null;
|
|
146
|
+
downloadUrl: string | null;
|
|
134
147
|
}
|
|
135
|
-
interface
|
|
148
|
+
interface UploadUrlResult {
|
|
149
|
+
uploadUrl: string;
|
|
136
150
|
path: string;
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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 {
|
|
147
162
|
name: string;
|
|
148
163
|
path: string;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
updatedAt?: string
|
|
155
|
-
createdAt?: string | null;
|
|
156
|
-
md5Hash?: string | null;
|
|
164
|
+
size?: number;
|
|
165
|
+
mimeType?: string;
|
|
166
|
+
isPublic?: boolean;
|
|
167
|
+
publicUrl?: string | null;
|
|
168
|
+
downloadUrl?: string | null;
|
|
169
|
+
updatedAt?: string;
|
|
157
170
|
}
|
|
158
171
|
interface ListResult {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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;
|
|
166
186
|
}
|
|
167
187
|
interface SignedUrlResult {
|
|
168
188
|
signedUrl: string;
|
|
@@ -170,542 +190,1351 @@ interface SignedUrlResult {
|
|
|
170
190
|
expiresIn: number;
|
|
171
191
|
path: string;
|
|
172
192
|
}
|
|
173
|
-
interface
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}>;
|
|
193
|
+
interface StorageStats {
|
|
194
|
+
totalFiles: number;
|
|
195
|
+
totalBytes: number;
|
|
196
|
+
uploadCount: number;
|
|
197
|
+
downloadCount: number;
|
|
198
|
+
deleteCount: number;
|
|
180
199
|
}
|
|
181
|
-
interface
|
|
200
|
+
interface BatchUploadItem {
|
|
182
201
|
path: string;
|
|
183
|
-
content: ArrayBuffer;
|
|
184
202
|
mimeType: string;
|
|
185
203
|
size: number;
|
|
204
|
+
isPublic?: boolean;
|
|
205
|
+
overwrite?: boolean;
|
|
186
206
|
}
|
|
187
|
-
interface
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
spaceSavedBytes: number;
|
|
192
|
-
uploadsCount: number;
|
|
193
|
-
downloadsCount: number;
|
|
194
|
-
deletesCount: number;
|
|
195
|
-
creditsUsedUpload: number;
|
|
196
|
-
creditsUsedDownload: number;
|
|
197
|
-
creditsTotalUsed: number;
|
|
198
|
-
bytesDelivered: number;
|
|
199
|
-
compressionRatio: string;
|
|
207
|
+
interface BatchUploadUrlResult {
|
|
208
|
+
files: Array<UploadUrlResult & {
|
|
209
|
+
index: number;
|
|
210
|
+
}>;
|
|
200
211
|
}
|
|
201
|
-
|
|
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);
|
|
202
328
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
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
|
+
* ```
|
|
205
341
|
*/
|
|
206
|
-
|
|
342
|
+
signup(options: SignupOptions): Promise<AuthResult>;
|
|
207
343
|
/**
|
|
208
|
-
*
|
|
209
|
-
*
|
|
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
|
+
* ```
|
|
210
355
|
*/
|
|
211
|
-
|
|
356
|
+
login(options: LoginOptions): Promise<AuthResult>;
|
|
212
357
|
/**
|
|
213
|
-
*
|
|
214
|
-
*
|
|
358
|
+
* Invalidate a session (sign out).
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* ```ts
|
|
362
|
+
* await auth.logout({ sessionId: session.sessionId });
|
|
363
|
+
* ```
|
|
215
364
|
*/
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
365
|
+
logout({ sessionId }: {
|
|
366
|
+
sessionId: string;
|
|
367
|
+
}): Promise<void>;
|
|
219
368
|
/**
|
|
220
|
-
*
|
|
221
|
-
*
|
|
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
|
+
* ```
|
|
222
376
|
*/
|
|
223
|
-
|
|
377
|
+
refreshSession({ refreshToken }: {
|
|
378
|
+
refreshToken: string;
|
|
379
|
+
}): Promise<Session>;
|
|
224
380
|
/**
|
|
225
|
-
*
|
|
226
|
-
*
|
|
381
|
+
* Fetch a user by their ID.
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* ```ts
|
|
385
|
+
* const user = await auth.getUser({ userId: 'usr_abc123' });
|
|
386
|
+
* ```
|
|
227
387
|
*/
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
/** Max simultaneous uploads (1–10). @default 5 */
|
|
232
|
-
concurrency?: number;
|
|
388
|
+
getUser({ userId }: {
|
|
389
|
+
userId: string;
|
|
390
|
+
}): Promise<UserRecord>;
|
|
233
391
|
/**
|
|
234
|
-
*
|
|
235
|
-
*
|
|
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
|
+
* ```
|
|
236
402
|
*/
|
|
237
|
-
|
|
238
|
-
}
|
|
239
|
-
interface BatchDownloadOptions {
|
|
240
|
-
/** Max simultaneous downloads (1–10). @default 5 */
|
|
241
|
-
concurrency?: number;
|
|
403
|
+
updateUser(options: UpdateUserOptions): Promise<UserRecord>;
|
|
242
404
|
/**
|
|
243
|
-
*
|
|
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
|
+
* ```
|
|
244
412
|
*/
|
|
245
|
-
|
|
413
|
+
deleteUser({ sessionId, userId }: {
|
|
414
|
+
sessionId: string;
|
|
415
|
+
userId: string;
|
|
416
|
+
}): Promise<void>;
|
|
246
417
|
/**
|
|
247
|
-
*
|
|
248
|
-
*
|
|
249
|
-
* @
|
|
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
|
+
* ```
|
|
250
428
|
*/
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
interface ListOptions {
|
|
254
|
-
/** Folder prefix to list (e.g. "avatars/"). Empty string = root. */
|
|
255
|
-
prefix?: string;
|
|
256
|
-
/** Max items per page (1–100). @default 50 */
|
|
257
|
-
limit?: number;
|
|
258
|
-
/** Pagination cursor returned from the previous call. */
|
|
259
|
-
cursor?: string;
|
|
260
|
-
}
|
|
261
|
-
interface SignedUrlOptions {
|
|
262
|
-
/** How long the URL stays valid, in seconds. @default 3600 (1 hour) */
|
|
263
|
-
expiresIn?: number;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
declare class AuthClient {
|
|
267
|
-
private readonly baseUrl;
|
|
268
|
-
private readonly headers;
|
|
269
|
-
private session;
|
|
270
|
-
constructor(config: HydrousConfig);
|
|
429
|
+
listUsers(options: ListUsersOptions): Promise<ListUsersResult>;
|
|
271
430
|
/**
|
|
272
|
-
*
|
|
431
|
+
* Permanently hard-delete a user and all their data. **Admin session required.**
|
|
432
|
+
* This action is irreversible.
|
|
273
433
|
*
|
|
274
434
|
* @example
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
*
|
|
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'],
|
|
278
451
|
* });
|
|
452
|
+
* ```
|
|
279
453
|
*/
|
|
280
|
-
|
|
454
|
+
bulkDeleteUsers({ sessionId, userIds, }: {
|
|
455
|
+
sessionId: string;
|
|
456
|
+
userIds: string[];
|
|
457
|
+
}): Promise<{
|
|
458
|
+
deleted: number;
|
|
459
|
+
failed: string[];
|
|
460
|
+
}>;
|
|
281
461
|
/**
|
|
282
|
-
*
|
|
462
|
+
* Lock a user account, preventing login. **Admin session required.**
|
|
463
|
+
*
|
|
464
|
+
* @param options.duration Lock duration in milliseconds. Defaults to 15 minutes.
|
|
283
465
|
*
|
|
284
466
|
* @example
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
467
|
+
* ```ts
|
|
468
|
+
* await auth.lockAccount({
|
|
469
|
+
* sessionId: adminSession.sessionId,
|
|
470
|
+
* userId: user.id,
|
|
471
|
+
* duration: 60 * 60 * 1000, // 1 hour
|
|
288
472
|
* });
|
|
289
|
-
*
|
|
473
|
+
* ```
|
|
290
474
|
*/
|
|
291
|
-
|
|
475
|
+
lockAccount({ sessionId, userId, duration, }: {
|
|
476
|
+
sessionId: string;
|
|
477
|
+
userId: string;
|
|
478
|
+
duration?: number;
|
|
479
|
+
}): Promise<{
|
|
480
|
+
lockedUntil: number;
|
|
481
|
+
unlockTime: string;
|
|
482
|
+
}>;
|
|
292
483
|
/**
|
|
293
|
-
*
|
|
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
|
+
* ```
|
|
294
490
|
*/
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
491
|
+
unlockAccount({ sessionId, userId, }: {
|
|
492
|
+
sessionId: string;
|
|
493
|
+
userId: string;
|
|
494
|
+
}): Promise<void>;
|
|
298
495
|
/**
|
|
299
|
-
*
|
|
300
|
-
*
|
|
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
|
+
* ```
|
|
301
507
|
*/
|
|
302
|
-
|
|
303
|
-
/** Return the current in-memory session (may be null). */
|
|
304
|
-
getSession(): AuthSession | null;
|
|
305
|
-
private _sessionHeader;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
declare class RecordsClient {
|
|
309
|
-
private readonly baseUrl;
|
|
310
|
-
private readonly headers;
|
|
311
|
-
constructor(config: HydrousConfig);
|
|
508
|
+
changePassword(options: ChangePasswordOptions): Promise<void>;
|
|
312
509
|
/**
|
|
313
|
-
*
|
|
510
|
+
* Request a password reset email for a user.
|
|
511
|
+
* Always returns success to prevent user enumeration.
|
|
314
512
|
*
|
|
315
|
-
* @
|
|
316
|
-
*
|
|
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.
|
|
317
523
|
*
|
|
318
524
|
* @example
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
525
|
+
* ```ts
|
|
526
|
+
* await auth.confirmPasswordReset({
|
|
527
|
+
* resetToken: 'tok_from_email',
|
|
528
|
+
* newPassword: 'correcthorsebatterystaple',
|
|
323
529
|
* });
|
|
530
|
+
* ```
|
|
324
531
|
*/
|
|
325
|
-
|
|
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);
|
|
326
587
|
/**
|
|
327
|
-
*
|
|
588
|
+
* Create a new record.
|
|
328
589
|
*
|
|
329
590
|
* @example
|
|
330
|
-
*
|
|
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
|
+
* ```
|
|
331
599
|
*/
|
|
332
|
-
|
|
600
|
+
create(data: T): Promise<T & RecordResult>;
|
|
333
601
|
/**
|
|
334
|
-
*
|
|
602
|
+
* Fetch a single record by ID.
|
|
335
603
|
*
|
|
336
|
-
* @
|
|
337
|
-
*
|
|
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).
|
|
338
612
|
*
|
|
339
613
|
* @example
|
|
340
|
-
*
|
|
341
|
-
* const
|
|
342
|
-
* name: 'Alice',
|
|
614
|
+
* ```ts
|
|
615
|
+
* const updated = await records.set('rec_abc123', {
|
|
616
|
+
* name: 'Alice Updated',
|
|
617
|
+
* email: 'alice2@example.com',
|
|
343
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 });
|
|
344
629
|
*
|
|
345
|
-
* //
|
|
346
|
-
* const
|
|
347
|
-
*
|
|
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 },
|
|
348
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
|
+
* ```
|
|
349
663
|
*/
|
|
350
|
-
|
|
664
|
+
batchDelete(ids: string[]): Promise<{
|
|
665
|
+
deleted: number;
|
|
666
|
+
failed: string[];
|
|
667
|
+
}>;
|
|
351
668
|
/**
|
|
352
|
-
*
|
|
669
|
+
* Query records with optional filters, sorting, and pagination.
|
|
353
670
|
*
|
|
354
671
|
* @example
|
|
355
|
-
*
|
|
356
|
-
*
|
|
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,
|
|
357
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
|
+
* ```
|
|
358
702
|
*/
|
|
359
|
-
|
|
703
|
+
getAll(options?: Omit<QueryOptions, 'filters'>): Promise<(T & RecordResult)[]>;
|
|
360
704
|
/**
|
|
361
|
-
*
|
|
705
|
+
* Count records matching optional filters.
|
|
362
706
|
*
|
|
363
707
|
* @example
|
|
364
|
-
*
|
|
708
|
+
* ```ts
|
|
709
|
+
* const total = await posts.count([{ field: 'status', op: '==', value: 'published' }]);
|
|
710
|
+
* ```
|
|
365
711
|
*/
|
|
366
|
-
|
|
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>;
|
|
367
734
|
}
|
|
368
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
|
+
*/
|
|
369
754
|
declare class AnalyticsClient {
|
|
370
|
-
private readonly
|
|
371
|
-
private readonly
|
|
372
|
-
|
|
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;
|
|
373
761
|
/**
|
|
374
|
-
*
|
|
762
|
+
* Count the total number of records in the bucket, with optional date filter.
|
|
375
763
|
*
|
|
376
764
|
* @example
|
|
377
|
-
*
|
|
378
|
-
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
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() },
|
|
381
772
|
* });
|
|
773
|
+
* ```
|
|
382
774
|
*/
|
|
383
|
-
|
|
775
|
+
count(opts?: {
|
|
776
|
+
dateRange?: DateRange;
|
|
777
|
+
}): Promise<CountResult>;
|
|
384
778
|
/**
|
|
385
|
-
*
|
|
779
|
+
* Count how many records have each unique value for a given field.
|
|
780
|
+
* Great for pie charts and bar charts.
|
|
386
781
|
*
|
|
387
782
|
* @example
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
*
|
|
392
|
-
*
|
|
783
|
+
* ```ts
|
|
784
|
+
* const rows = await analytics.distribution({
|
|
785
|
+
* field: 'status',
|
|
786
|
+
* limit: 10,
|
|
787
|
+
* order: 'desc',
|
|
393
788
|
* });
|
|
789
|
+
* // → [{ value: 'completed', count: 312 }, { value: 'pending', count: 88 }, ...]
|
|
790
|
+
* ```
|
|
394
791
|
*/
|
|
395
|
-
|
|
792
|
+
distribution(opts: {
|
|
793
|
+
field: string;
|
|
794
|
+
limit?: number;
|
|
795
|
+
order?: SortOrder;
|
|
796
|
+
dateRange?: DateRange;
|
|
797
|
+
}): Promise<DistributionRow[]>;
|
|
396
798
|
/**
|
|
397
|
-
*
|
|
398
|
-
* calling `track` in a loop).
|
|
799
|
+
* Sum a numeric field, optionally grouped by another field.
|
|
399
800
|
*
|
|
400
801
|
* @example
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
*
|
|
404
|
-
* ]
|
|
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
|
+
* ```
|
|
405
811
|
*/
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
812
|
+
sum(opts: {
|
|
813
|
+
field: string;
|
|
814
|
+
groupBy?: string;
|
|
815
|
+
limit?: number;
|
|
816
|
+
dateRange?: DateRange;
|
|
817
|
+
}): Promise<SumRow[]>;
|
|
412
818
|
/**
|
|
413
|
-
*
|
|
414
|
-
*
|
|
415
|
-
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
*
|
|
419
|
-
*
|
|
420
|
-
*
|
|
421
|
-
*
|
|
422
|
-
*
|
|
423
|
-
*
|
|
424
|
-
* | `uploading` | Bytes flowing to cloud storage |
|
|
425
|
-
* | `done` | Confirmed written to cloud storage |
|
|
426
|
-
* | `error` | Something went wrong |
|
|
427
|
-
*
|
|
428
|
-
* @param bucketKey Your storage bucket key (`ssk_…`)
|
|
429
|
-
* @param file A `File`, `Blob`, or `Buffer` (Node)
|
|
430
|
-
* @param options Path, overwrite flag, progress callback
|
|
431
|
-
*
|
|
432
|
-
* @example
|
|
433
|
-
* const { data, error } = await hydrous.storage.upload(
|
|
434
|
-
* 'ssk_my_bucket_key',
|
|
435
|
-
* file,
|
|
436
|
-
* {
|
|
437
|
-
* path: 'avatars/alice.jpg',
|
|
438
|
-
* overwrite: true,
|
|
439
|
-
* onProgress: (p) => {
|
|
440
|
-
* console.log(`${p.stage} — ${p.percent}% ${p.bytesPerSecond} B/s ETA ${p.eta}s`);
|
|
441
|
-
* },
|
|
442
|
-
* }
|
|
443
|
-
* );
|
|
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
|
+
* ```
|
|
444
830
|
*/
|
|
445
|
-
|
|
831
|
+
timeSeries(opts?: {
|
|
832
|
+
granularity?: Granularity;
|
|
833
|
+
dateRange?: DateRange;
|
|
834
|
+
}): Promise<TimeSeriesRow[]>;
|
|
446
835
|
/**
|
|
447
|
-
*
|
|
448
|
-
* Great for saving generated content, config files, or JSON records.
|
|
836
|
+
* Aggregate a numeric field over time (e.g. daily revenue, hourly signups).
|
|
449
837
|
*
|
|
450
|
-
* @
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
*
|
|
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.
|
|
454
857
|
*
|
|
455
858
|
* @example
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
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
|
+
* ```
|
|
462
868
|
*/
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
* @param options Prefix, per-file paths, overwrite, concurrency, onProgress
|
|
479
|
-
*
|
|
480
|
-
* @example
|
|
481
|
-
* await hydrous.storage.batchUpload(
|
|
482
|
-
* 'ssk_my_bucket_key',
|
|
483
|
-
* fileArray,
|
|
484
|
-
* {
|
|
485
|
-
* prefix: 'uploads/2024/',
|
|
486
|
-
* onProgress: (p) => {
|
|
487
|
-
* console.log(`File ${p.index}: ${p.stage} ${p.percent}%`);
|
|
488
|
-
* },
|
|
489
|
-
* }
|
|
490
|
-
* );
|
|
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
|
+
* ```
|
|
491
884
|
*/
|
|
492
|
-
|
|
885
|
+
stats(opts: {
|
|
886
|
+
field: string;
|
|
887
|
+
dateRange?: DateRange;
|
|
888
|
+
}): Promise<FieldStats>;
|
|
493
889
|
/**
|
|
494
|
-
*
|
|
890
|
+
* Query raw records with filters, field selection, and pagination.
|
|
891
|
+
* This is the analytics version of `records.query()` but powered by BigQuery.
|
|
495
892
|
*
|
|
496
|
-
* @
|
|
497
|
-
*
|
|
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.
|
|
498
916
|
*
|
|
499
917
|
* @example
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
503
|
-
*
|
|
504
|
-
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
* }
|
|
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
|
+
* ```
|
|
508
928
|
*/
|
|
509
|
-
|
|
929
|
+
multiMetric(opts: {
|
|
930
|
+
metrics: MetricDefinition[];
|
|
931
|
+
dateRange?: DateRange;
|
|
932
|
+
}): Promise<MultiMetricResult>;
|
|
510
933
|
/**
|
|
511
|
-
*
|
|
934
|
+
* Get storage statistics for this bucket: record counts, byte sizes.
|
|
512
935
|
*
|
|
513
|
-
*
|
|
514
|
-
*
|
|
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.
|
|
515
948
|
*
|
|
516
|
-
* @
|
|
517
|
-
*
|
|
518
|
-
*
|
|
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.
|
|
519
972
|
*
|
|
520
973
|
* @example
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
974
|
+
* ```ts
|
|
975
|
+
* const result = await analytics.query({
|
|
976
|
+
* queryType: 'topN',
|
|
977
|
+
* field: 'category',
|
|
978
|
+
* n: 3,
|
|
979
|
+
* order: 'asc',
|
|
980
|
+
* });
|
|
981
|
+
* ```
|
|
529
982
|
*/
|
|
530
|
-
|
|
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();
|
|
531
1016
|
/**
|
|
532
|
-
*
|
|
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.
|
|
533
1023
|
*
|
|
534
|
-
*
|
|
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://...
|
|
535
1029
|
*
|
|
536
|
-
*
|
|
537
|
-
*
|
|
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.
|
|
538
1038
|
*
|
|
539
1039
|
* @example
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
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,
|
|
543
1060
|
* });
|
|
544
|
-
*
|
|
545
|
-
*
|
|
546
|
-
*
|
|
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
|
+
* ```
|
|
547
1070
|
*/
|
|
548
|
-
|
|
1071
|
+
getUploadUrl(opts: {
|
|
1072
|
+
path: string;
|
|
1073
|
+
mimeType: string;
|
|
1074
|
+
size: number;
|
|
1075
|
+
isPublic?: boolean;
|
|
1076
|
+
overwrite?: boolean;
|
|
1077
|
+
expiresInSeconds?: number;
|
|
1078
|
+
}): Promise<UploadUrlResult>;
|
|
549
1079
|
/**
|
|
550
|
-
*
|
|
1080
|
+
* Upload data directly to a signed GCS URL (no auth headers needed).
|
|
1081
|
+
* Optionally tracks progress via a callback.
|
|
551
1082
|
*
|
|
552
|
-
* @param
|
|
553
|
-
* @param
|
|
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.
|
|
554
1092
|
*
|
|
555
1093
|
* @example
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
* '
|
|
559
|
-
*
|
|
560
|
-
*
|
|
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
|
+
* ```
|
|
561
1102
|
*/
|
|
562
|
-
|
|
1103
|
+
confirmUpload(opts: {
|
|
1104
|
+
path: string;
|
|
1105
|
+
mimeType: string;
|
|
1106
|
+
isPublic?: boolean;
|
|
1107
|
+
}): Promise<UploadResult>;
|
|
563
1108
|
/**
|
|
564
|
-
*
|
|
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.
|
|
565
1137
|
*
|
|
566
|
-
* @
|
|
567
|
-
*
|
|
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 }`.
|
|
568
1149
|
*
|
|
569
1150
|
* @example
|
|
570
|
-
*
|
|
1151
|
+
* ```ts
|
|
1152
|
+
* const files = await storage.batchDownload(['docs/a.pdf', 'docs/b.pdf']);
|
|
1153
|
+
* ```
|
|
571
1154
|
*/
|
|
572
|
-
|
|
1155
|
+
batchDownload(paths: string[]): Promise<Record<string, string>>;
|
|
573
1156
|
/**
|
|
574
|
-
*
|
|
1157
|
+
* List files and folders at a given path prefix.
|
|
575
1158
|
*
|
|
576
|
-
* @
|
|
577
|
-
*
|
|
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).
|
|
578
1177
|
*
|
|
579
1178
|
* @example
|
|
580
|
-
*
|
|
1179
|
+
* ```ts
|
|
1180
|
+
* const meta = await storage.getMetadata('avatars/alice.jpg');
|
|
1181
|
+
* console.log(meta.size, meta.isPublic, meta.publicUrl);
|
|
1182
|
+
* ```
|
|
581
1183
|
*/
|
|
582
|
-
|
|
1184
|
+
getMetadata(path: string): Promise<FileMetadata>;
|
|
583
1185
|
/**
|
|
584
|
-
*
|
|
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.
|
|
585
1191
|
*
|
|
586
|
-
* @param
|
|
587
|
-
* @param
|
|
1192
|
+
* @param path Path to the file.
|
|
1193
|
+
* @param expiresIn URL lifetime in seconds (default 3600 = 1 hour).
|
|
588
1194
|
*
|
|
589
1195
|
* @example
|
|
590
|
-
*
|
|
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
|
+
* ```
|
|
591
1200
|
*/
|
|
592
|
-
|
|
1201
|
+
getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
|
|
593
1202
|
/**
|
|
594
|
-
*
|
|
1203
|
+
* Change a file's visibility between public and private after upload.
|
|
595
1204
|
*
|
|
596
|
-
* @
|
|
597
|
-
*
|
|
598
|
-
*
|
|
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).
|
|
599
1224
|
*
|
|
600
1225
|
* @example
|
|
601
|
-
*
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
* 'published/report.pdf'
|
|
605
|
-
* );
|
|
1226
|
+
* ```ts
|
|
1227
|
+
* await storage.createFolder('uploads/2025/');
|
|
1228
|
+
* ```
|
|
606
1229
|
*/
|
|
607
|
-
|
|
1230
|
+
createFolder(path: string): Promise<{
|
|
1231
|
+
path: string;
|
|
1232
|
+
}>;
|
|
608
1233
|
/**
|
|
609
|
-
*
|
|
1234
|
+
* Delete a single file.
|
|
610
1235
|
*
|
|
611
|
-
* @
|
|
612
|
-
*
|
|
613
|
-
*
|
|
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.
|
|
614
1244
|
*
|
|
615
1245
|
* @example
|
|
616
|
-
*
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
* 'invoices/invoice-001.pdf'
|
|
620
|
-
* );
|
|
1246
|
+
* ```ts
|
|
1247
|
+
* await storage.deleteFolder('temp/');
|
|
1248
|
+
* ```
|
|
621
1249
|
*/
|
|
622
|
-
|
|
1250
|
+
deleteFolder(path: string): Promise<void>;
|
|
623
1251
|
/**
|
|
624
|
-
*
|
|
1252
|
+
* Move or rename a file.
|
|
625
1253
|
*
|
|
626
|
-
* @
|
|
627
|
-
*
|
|
628
|
-
*
|
|
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.
|
|
629
1268
|
*
|
|
630
1269
|
* @example
|
|
631
|
-
*
|
|
632
|
-
*
|
|
633
|
-
*
|
|
634
|
-
* { expiresIn: 300 } // 5 minutes
|
|
635
|
-
* );
|
|
636
|
-
* console.log(data.signedUrl); // share this URL
|
|
1270
|
+
* ```ts
|
|
1271
|
+
* await storage.copy('templates/base.html', 'sites/my-site/index.html');
|
|
1272
|
+
* ```
|
|
637
1273
|
*/
|
|
638
|
-
|
|
1274
|
+
copy(from: string, to: string): Promise<{
|
|
1275
|
+
from: string;
|
|
1276
|
+
to: string;
|
|
1277
|
+
}>;
|
|
639
1278
|
/**
|
|
640
|
-
* Get
|
|
1279
|
+
* Get storage statistics for your key: total files, bytes, operation counts.
|
|
641
1280
|
*
|
|
642
|
-
* @
|
|
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.
|
|
643
1290
|
*
|
|
644
1291
|
* @example
|
|
645
|
-
*
|
|
646
|
-
*
|
|
1292
|
+
* ```ts
|
|
1293
|
+
* const info = await storage.info();
|
|
1294
|
+
* // → { ok: true, storageRoot: 'hydrous-storage' }
|
|
1295
|
+
* ```
|
|
647
1296
|
*/
|
|
648
|
-
|
|
1297
|
+
info(): Promise<{
|
|
1298
|
+
ok: boolean;
|
|
1299
|
+
storageRoot: string;
|
|
1300
|
+
}>;
|
|
649
1301
|
}
|
|
650
1302
|
|
|
1303
|
+
/** Accepted data types for file uploads. */
|
|
1304
|
+
type UploadData = Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer;
|
|
651
1305
|
/**
|
|
652
|
-
*
|
|
1306
|
+
* ScopedStorage — a StorageManager pre-scoped to a specific folder prefix.
|
|
653
1307
|
*
|
|
654
|
-
*
|
|
1308
|
+
* All paths are automatically prepended with the scope, so you never
|
|
1309
|
+
* have to repeat the folder name.
|
|
655
1310
|
*
|
|
656
1311
|
* @example
|
|
657
|
-
*
|
|
1312
|
+
* ```ts
|
|
1313
|
+
* const db = createClient({ securityKey: 'sk_...' });
|
|
658
1314
|
*
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
*
|
|
662
|
-
*
|
|
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
|
+
* ```
|
|
663
1322
|
*/
|
|
664
|
-
declare class
|
|
665
|
-
|
|
666
|
-
readonly
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
/**
|
|
670
|
-
|
|
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
|
+
}>;
|
|
671
1381
|
/**
|
|
672
|
-
*
|
|
1382
|
+
* Create a further-scoped instance nested within this scope.
|
|
673
1383
|
*
|
|
674
|
-
*
|
|
1384
|
+
* @example
|
|
1385
|
+
* ```ts
|
|
1386
|
+
* const uploads = db.storage.scope('user-uploads');
|
|
1387
|
+
* const images = uploads.scope('images'); // → "user-uploads/images/"
|
|
1388
|
+
* ```
|
|
675
1389
|
*/
|
|
676
|
-
|
|
677
|
-
constructor(config: HydrousConfig);
|
|
1390
|
+
scope(subPrefix: string): ScopedStorage;
|
|
678
1391
|
}
|
|
679
1392
|
|
|
680
|
-
/**
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
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
|
+
};
|
|
695
1491
|
}
|
|
696
|
-
declare function isHydrousError(err: unknown): err is HydrousSDKError;
|
|
697
|
-
|
|
698
1492
|
/**
|
|
699
|
-
* Create
|
|
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.
|
|
700
1500
|
*
|
|
701
1501
|
* @example
|
|
702
|
-
*
|
|
1502
|
+
* ```ts
|
|
1503
|
+
* import { createClient } from 'hydrousdb';
|
|
703
1504
|
*
|
|
704
|
-
* const
|
|
705
|
-
*
|
|
706
|
-
* apiKey: 'hk_live_…',
|
|
1505
|
+
* const db = createClient({
|
|
1506
|
+
* securityKey: process.env.HYDROUS_SECURITY_KEY!,
|
|
707
1507
|
* });
|
|
1508
|
+
* ```
|
|
708
1509
|
*/
|
|
709
1510
|
declare function createClient(config: HydrousConfig): HydrousClient;
|
|
710
1511
|
|
|
711
|
-
|
|
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 };
|