hydrousdb 2.0.3 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +857 -1016
- package/dist/index.cjs +1194 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1080 -0
- package/dist/index.d.ts +921 -395
- package/dist/index.js +1048 -924
- package/dist/index.js.map +1 -1
- package/package.json +47 -18
- package/dist/index.d.mts +0 -554
- package/dist/index.mjs +0 -1038
- package/dist/index.mjs.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,180 +1,222 @@
|
|
|
1
|
+
interface RequestOptions {
|
|
2
|
+
method?: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
3
|
+
body?: unknown;
|
|
4
|
+
headers?: Record<string, string>;
|
|
5
|
+
rawBody?: string | FormData | Uint8Array<ArrayBuffer>;
|
|
6
|
+
contentType?: string;
|
|
7
|
+
}
|
|
8
|
+
declare class HttpClient {
|
|
9
|
+
private readonly baseUrl;
|
|
10
|
+
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>;
|
|
17
|
+
putToSignedUrl(signedUrl: string, data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
1
20
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* meaningful name — you'll reference it by name when calling storage methods.
|
|
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.
|
|
5
23
|
*
|
|
6
24
|
* @example
|
|
7
|
-
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* storageKeys: {
|
|
8
27
|
* main: 'ssk_main_…',
|
|
9
28
|
* avatars: 'ssk_avatars_…',
|
|
10
29
|
* documents: 'ssk_docs_…',
|
|
11
30
|
* }
|
|
31
|
+
* ```
|
|
12
32
|
*/
|
|
13
33
|
type StorageKeys = Record<string, string>;
|
|
14
34
|
interface HydrousConfig {
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
35
|
+
/**
|
|
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.
|
|
39
|
+
*/
|
|
18
40
|
authKey: string;
|
|
19
|
-
/**
|
|
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
|
+
*/
|
|
20
46
|
bucketSecurityKey: string;
|
|
21
47
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
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
|
+
* ```
|
|
25
60
|
*/
|
|
26
61
|
storageKeys: StorageKeys;
|
|
27
|
-
/**
|
|
28
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Override the API base URL. Defaults to the official HydrousDB endpoint.
|
|
64
|
+
* You almost never need to set this.
|
|
65
|
+
*/
|
|
66
|
+
baseUrl?: string;
|
|
29
67
|
}
|
|
30
|
-
interface
|
|
31
|
-
|
|
32
|
-
|
|
68
|
+
interface SignupOptions {
|
|
69
|
+
email: string;
|
|
70
|
+
password: string;
|
|
71
|
+
fullName?: string;
|
|
72
|
+
[key: string]: unknown;
|
|
33
73
|
}
|
|
34
|
-
interface
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
status?: number;
|
|
74
|
+
interface LoginOptions {
|
|
75
|
+
email: string;
|
|
76
|
+
password: string;
|
|
38
77
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
78
|
+
interface UserRecord {
|
|
79
|
+
id: string;
|
|
80
|
+
email: string;
|
|
81
|
+
fullName?: string | null;
|
|
82
|
+
emailVerified: boolean;
|
|
83
|
+
accountStatus: 'active' | 'locked' | 'suspended';
|
|
84
|
+
role: 'user' | 'admin';
|
|
85
|
+
createdAt: number;
|
|
86
|
+
updatedAt: number;
|
|
87
|
+
metadata?: Record<string, unknown>;
|
|
88
|
+
[key: string]: unknown;
|
|
44
89
|
}
|
|
45
|
-
interface
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
90
|
+
interface Session {
|
|
91
|
+
sessionId: string;
|
|
92
|
+
userId: string;
|
|
93
|
+
bucketId: string;
|
|
94
|
+
createdAt: number;
|
|
95
|
+
expiresAt: number;
|
|
96
|
+
refreshToken: string;
|
|
97
|
+
refreshExpiresAt: number;
|
|
98
|
+
}
|
|
99
|
+
interface AuthResult {
|
|
100
|
+
user: UserRecord;
|
|
101
|
+
session: Session;
|
|
102
|
+
}
|
|
103
|
+
interface UpdateUserOptions {
|
|
104
|
+
sessionId: string;
|
|
105
|
+
userId: string;
|
|
106
|
+
data: Partial<Omit<UserRecord, 'id' | 'email' | 'createdAt'>>;
|
|
107
|
+
}
|
|
108
|
+
interface ChangePasswordOptions {
|
|
109
|
+
sessionId: string;
|
|
110
|
+
userId: string;
|
|
111
|
+
currentPassword: string;
|
|
112
|
+
newPassword: string;
|
|
113
|
+
}
|
|
114
|
+
interface ListUsersOptions {
|
|
115
|
+
sessionId: string;
|
|
51
116
|
limit?: number;
|
|
52
117
|
offset?: number;
|
|
53
|
-
select?: string[];
|
|
54
|
-
}
|
|
55
|
-
interface RecordResponse<T = Record<string, unknown>> {
|
|
56
|
-
data: T[];
|
|
57
|
-
count: number;
|
|
58
|
-
error: HydrousError | null;
|
|
59
118
|
}
|
|
60
|
-
interface
|
|
61
|
-
|
|
62
|
-
|
|
119
|
+
interface ListUsersResult {
|
|
120
|
+
users: UserRecord[];
|
|
121
|
+
total: number;
|
|
122
|
+
limit: number;
|
|
123
|
+
offset: number;
|
|
63
124
|
}
|
|
64
|
-
|
|
125
|
+
type RecordData = Record<string, unknown>;
|
|
126
|
+
interface RecordResult {
|
|
65
127
|
id: string;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
metadata?: Record<string, unknown>;
|
|
128
|
+
createdAt?: number;
|
|
129
|
+
updatedAt?: number;
|
|
130
|
+
[key: string]: unknown;
|
|
70
131
|
}
|
|
71
|
-
interface
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
user: AuthUser;
|
|
132
|
+
interface QueryFilter {
|
|
133
|
+
field: string;
|
|
134
|
+
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'CONTAINS';
|
|
135
|
+
value: string | number | boolean;
|
|
76
136
|
}
|
|
77
|
-
interface
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
137
|
+
interface QueryOptions {
|
|
138
|
+
filters?: QueryFilter[];
|
|
139
|
+
fields?: string;
|
|
140
|
+
limit?: number;
|
|
141
|
+
offset?: number;
|
|
142
|
+
orderBy?: string;
|
|
143
|
+
order?: 'asc' | 'desc';
|
|
144
|
+
startAfter?: string;
|
|
145
|
+
startAt?: string;
|
|
146
|
+
endAt?: string;
|
|
147
|
+
dateRange?: DateRange;
|
|
81
148
|
}
|
|
82
|
-
interface
|
|
83
|
-
|
|
84
|
-
|
|
149
|
+
interface QueryResult<T = RecordData> {
|
|
150
|
+
records: (T & RecordResult)[];
|
|
151
|
+
total?: number;
|
|
152
|
+
hasMore?: boolean;
|
|
153
|
+
nextCursor?: string;
|
|
85
154
|
}
|
|
86
|
-
interface
|
|
87
|
-
|
|
88
|
-
properties?: Record<string, unknown>;
|
|
89
|
-
userId?: string;
|
|
90
|
-
sessionId?: string;
|
|
91
|
-
timestamp?: number;
|
|
92
|
-
}
|
|
93
|
-
interface AnalyticsQueryOptions {
|
|
94
|
-
event?: string;
|
|
95
|
-
from?: string;
|
|
96
|
-
to?: string;
|
|
97
|
-
limit?: number;
|
|
98
|
-
groupBy?: string;
|
|
155
|
+
interface PatchRecordOptions {
|
|
156
|
+
merge?: boolean;
|
|
99
157
|
}
|
|
100
|
-
interface
|
|
158
|
+
interface RecordHistoryEntry {
|
|
101
159
|
id: string;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
/** Total files in the operation */
|
|
113
|
-
total: number;
|
|
114
|
-
/** Destination path in the bucket */
|
|
115
|
-
path: string;
|
|
116
|
-
/** Current lifecycle stage */
|
|
117
|
-
stage: UploadStage;
|
|
118
|
-
bytesUploaded: number;
|
|
119
|
-
totalBytes: number;
|
|
120
|
-
/** 0 – 100 */
|
|
121
|
-
percent: number;
|
|
122
|
-
/** Upload speed in bytes/sec; null until the first tick */
|
|
123
|
-
bytesPerSecond: number | null;
|
|
124
|
-
/** Estimated seconds remaining; null until speed is known */
|
|
125
|
-
eta: number | null;
|
|
126
|
-
result?: UploadResult;
|
|
127
|
-
error?: string;
|
|
128
|
-
code?: string;
|
|
129
|
-
}
|
|
130
|
-
interface DownloadProgress {
|
|
131
|
-
index: number;
|
|
132
|
-
total: number;
|
|
133
|
-
path: string;
|
|
134
|
-
status: 'pending' | 'success' | 'error';
|
|
135
|
-
size?: number;
|
|
160
|
+
version: number;
|
|
161
|
+
createdAt: number;
|
|
162
|
+
data: RecordData;
|
|
163
|
+
}
|
|
164
|
+
interface UploadOptions {
|
|
165
|
+
/** Set to true to make the file publicly accessible without authentication. */
|
|
166
|
+
isPublic?: boolean;
|
|
167
|
+
/** Set to true to overwrite an existing file at the same path. */
|
|
168
|
+
overwrite?: boolean;
|
|
169
|
+
/** MIME type of the file. Auto-detected if omitted. */
|
|
136
170
|
mimeType?: string;
|
|
137
|
-
|
|
171
|
+
/** TTL in seconds for the signed upload URL (default 900 = 15 min). */
|
|
172
|
+
expiresInSeconds?: number;
|
|
138
173
|
}
|
|
139
174
|
interface UploadResult {
|
|
140
175
|
path: string;
|
|
141
|
-
compressed: boolean;
|
|
142
|
-
originalSize: number;
|
|
143
|
-
storedSize: number;
|
|
144
|
-
spaceSaved: number;
|
|
145
176
|
mimeType: string;
|
|
177
|
+
size: number;
|
|
178
|
+
isPublic: boolean;
|
|
179
|
+
publicUrl: string | null;
|
|
180
|
+
downloadUrl: string | null;
|
|
146
181
|
}
|
|
147
|
-
interface
|
|
182
|
+
interface UploadUrlResult {
|
|
183
|
+
uploadUrl: string;
|
|
148
184
|
path: string;
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
185
|
+
mimeType: string;
|
|
186
|
+
expiresAt: string;
|
|
187
|
+
expiresIn: number;
|
|
188
|
+
}
|
|
189
|
+
interface ListOptions {
|
|
190
|
+
prefix?: string;
|
|
191
|
+
limit?: number;
|
|
192
|
+
cursor?: string;
|
|
193
|
+
recursive?: boolean;
|
|
194
|
+
}
|
|
195
|
+
interface FileEntry {
|
|
159
196
|
name: string;
|
|
160
197
|
path: string;
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
updatedAt?: string
|
|
167
|
-
createdAt?: string | null;
|
|
168
|
-
md5Hash?: string | null;
|
|
198
|
+
size?: number;
|
|
199
|
+
mimeType?: string;
|
|
200
|
+
isPublic?: boolean;
|
|
201
|
+
publicUrl?: string | null;
|
|
202
|
+
downloadUrl?: string | null;
|
|
203
|
+
updatedAt?: string;
|
|
169
204
|
}
|
|
170
205
|
interface ListResult {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
206
|
+
files: FileEntry[];
|
|
207
|
+
folders: string[];
|
|
208
|
+
hasMore: boolean;
|
|
209
|
+
nextCursor?: string;
|
|
210
|
+
}
|
|
211
|
+
interface FileMetadata {
|
|
212
|
+
path: string;
|
|
213
|
+
size: number;
|
|
214
|
+
mimeType: string;
|
|
215
|
+
isPublic: boolean;
|
|
216
|
+
publicUrl: string | null;
|
|
217
|
+
downloadUrl: string | null;
|
|
218
|
+
createdAt?: string;
|
|
219
|
+
updatedAt?: string;
|
|
178
220
|
}
|
|
179
221
|
interface SignedUrlResult {
|
|
180
222
|
signedUrl: string;
|
|
@@ -182,276 +224,718 @@ interface SignedUrlResult {
|
|
|
182
224
|
expiresIn: number;
|
|
183
225
|
path: string;
|
|
184
226
|
}
|
|
185
|
-
interface
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}>;
|
|
227
|
+
interface StorageStats {
|
|
228
|
+
totalFiles: number;
|
|
229
|
+
totalBytes: number;
|
|
230
|
+
uploadCount: number;
|
|
231
|
+
downloadCount: number;
|
|
232
|
+
deleteCount: number;
|
|
192
233
|
}
|
|
193
|
-
interface
|
|
234
|
+
interface BatchUploadItem {
|
|
194
235
|
path: string;
|
|
195
|
-
content: ArrayBuffer;
|
|
196
236
|
mimeType: string;
|
|
197
237
|
size: number;
|
|
238
|
+
isPublic?: boolean;
|
|
239
|
+
overwrite?: boolean;
|
|
198
240
|
}
|
|
199
|
-
interface
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
spaceSavedBytes: number;
|
|
204
|
-
uploadsCount: number;
|
|
205
|
-
downloadsCount: number;
|
|
206
|
-
deletesCount: number;
|
|
207
|
-
creditsUsedUpload: number;
|
|
208
|
-
creditsUsedDownload: number;
|
|
209
|
-
creditsTotalUsed: number;
|
|
210
|
-
bytesDelivered: number;
|
|
211
|
-
compressionRatio: string;
|
|
241
|
+
interface BatchUploadUrlResult {
|
|
242
|
+
files: Array<UploadUrlResult & {
|
|
243
|
+
index: number;
|
|
244
|
+
}>;
|
|
212
245
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
onProgress?: (progress: UploadProgress) => void;
|
|
246
|
+
type QueryType = 'count' | 'distribution' | 'sum' | 'timeSeries' | 'fieldTimeSeries' | 'topN' | 'stats' | 'records' | 'multiMetric' | 'storageStats' | 'crossBucket';
|
|
247
|
+
type Aggregation = 'sum' | 'avg' | 'min' | 'max' | 'count';
|
|
248
|
+
type Granularity = 'hour' | 'day' | 'week' | 'month' | 'year';
|
|
249
|
+
type SortOrder = 'asc' | 'desc';
|
|
250
|
+
interface DateRange {
|
|
251
|
+
/** Start timestamp in milliseconds (Unix epoch). */
|
|
252
|
+
start?: number;
|
|
253
|
+
/** End timestamp in milliseconds (Unix epoch). */
|
|
254
|
+
end?: number;
|
|
223
255
|
}
|
|
224
|
-
interface
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
paths?: string[];
|
|
229
|
-
overwrite?: boolean;
|
|
230
|
-
/** Max simultaneous server-side uploads (1–10, default 5) */
|
|
231
|
-
concurrency?: number;
|
|
232
|
-
/** Called for every progress tick on every file */
|
|
233
|
-
onProgress?: (progress: UploadProgress) => void;
|
|
234
|
-
}
|
|
235
|
-
interface BatchDownloadOptions {
|
|
236
|
-
concurrency?: number;
|
|
237
|
-
onProgress?: (progress: DownloadProgress) => void;
|
|
238
|
-
/**
|
|
239
|
-
* Browser only — automatically triggers a Save dialog for each file as it
|
|
240
|
-
* arrives (default: false)
|
|
241
|
-
*/
|
|
242
|
-
autoSave?: boolean;
|
|
256
|
+
interface AnalyticsFilter {
|
|
257
|
+
field: string;
|
|
258
|
+
op: '==' | '!=' | '>' | '<' | '>=' | '<=' | 'CONTAINS';
|
|
259
|
+
value: string | number | boolean;
|
|
243
260
|
}
|
|
244
|
-
interface
|
|
245
|
-
/**
|
|
246
|
-
|
|
261
|
+
interface MetricDefinition {
|
|
262
|
+
/** Field name in your records to aggregate. */
|
|
263
|
+
field: string;
|
|
264
|
+
/** Alias used in the result object. Must be a safe identifier. */
|
|
265
|
+
name: string;
|
|
266
|
+
/** Aggregation function. Defaults to 'count'. */
|
|
267
|
+
aggregation?: Aggregation;
|
|
268
|
+
}
|
|
269
|
+
interface AnalyticsQuery {
|
|
270
|
+
queryType: QueryType;
|
|
271
|
+
dateRange?: DateRange;
|
|
272
|
+
field?: string;
|
|
273
|
+
groupBy?: string;
|
|
274
|
+
labelField?: string;
|
|
275
|
+
aggregation?: Aggregation;
|
|
276
|
+
granularity?: Granularity;
|
|
277
|
+
filters?: AnalyticsFilter[];
|
|
278
|
+
selectFields?: string[];
|
|
247
279
|
limit?: number;
|
|
248
|
-
|
|
280
|
+
offset?: number;
|
|
281
|
+
orderBy?: string;
|
|
282
|
+
order?: SortOrder;
|
|
283
|
+
n?: number;
|
|
284
|
+
metrics?: MetricDefinition[];
|
|
285
|
+
/** For crossBucket queries: list of bucket names to compare. */
|
|
286
|
+
bucketKeys?: string[];
|
|
249
287
|
}
|
|
250
|
-
interface
|
|
251
|
-
|
|
252
|
-
|
|
288
|
+
interface AnalyticsResult<T = unknown> {
|
|
289
|
+
queryType: QueryType;
|
|
290
|
+
data: T;
|
|
291
|
+
}
|
|
292
|
+
interface CountResult {
|
|
293
|
+
count: number;
|
|
294
|
+
}
|
|
295
|
+
interface DistributionRow {
|
|
296
|
+
value: string | number;
|
|
297
|
+
count: number;
|
|
298
|
+
}
|
|
299
|
+
interface SumRow {
|
|
300
|
+
group?: string | number;
|
|
301
|
+
sum: number;
|
|
302
|
+
}
|
|
303
|
+
interface TimeSeriesRow {
|
|
304
|
+
date: string;
|
|
305
|
+
count: number;
|
|
306
|
+
}
|
|
307
|
+
interface FieldTimeSeriesRow {
|
|
308
|
+
date: string;
|
|
309
|
+
value: number;
|
|
310
|
+
}
|
|
311
|
+
interface TopNRow {
|
|
312
|
+
value: string | number;
|
|
313
|
+
label?: string;
|
|
314
|
+
count: number;
|
|
315
|
+
}
|
|
316
|
+
interface FieldStats {
|
|
317
|
+
min: number;
|
|
318
|
+
max: number;
|
|
319
|
+
avg: number;
|
|
320
|
+
sum: number;
|
|
321
|
+
count: number;
|
|
322
|
+
stddev?: number;
|
|
323
|
+
}
|
|
324
|
+
interface MultiMetricResult {
|
|
325
|
+
[metricName: string]: number;
|
|
326
|
+
}
|
|
327
|
+
interface StorageStatsResult {
|
|
328
|
+
totalRecords: number;
|
|
329
|
+
totalBytes: number;
|
|
330
|
+
avgBytes: number;
|
|
331
|
+
minBytes: number;
|
|
332
|
+
maxBytes: number;
|
|
333
|
+
}
|
|
334
|
+
interface CrossBucketRow {
|
|
335
|
+
bucket: string;
|
|
336
|
+
value: number;
|
|
253
337
|
}
|
|
254
338
|
|
|
339
|
+
/**
|
|
340
|
+
* AuthClient — full user authentication for a single bucket.
|
|
341
|
+
* Uses the `authKey` (`hk_auth_…`) sent via `X-Api-Key` header.
|
|
342
|
+
*
|
|
343
|
+
* @example
|
|
344
|
+
* ```ts
|
|
345
|
+
* const db = createClient({ authKey: 'hk_auth_…', bucketSecurityKey: '…', storageKeys: { main: '…' } });
|
|
346
|
+
* const auth = db.auth('my-app-users');
|
|
347
|
+
* const { user, session } = await auth.signup({ email: 'alice@example.com', password: 'hunter2' });
|
|
348
|
+
* ```
|
|
349
|
+
*/
|
|
255
350
|
declare class AuthClient {
|
|
256
|
-
private readonly
|
|
257
|
-
private readonly
|
|
258
|
-
private
|
|
259
|
-
constructor(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
refreshSession(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
351
|
+
private readonly http;
|
|
352
|
+
private readonly authKey;
|
|
353
|
+
private readonly basePath;
|
|
354
|
+
constructor(http: HttpClient, authKey: string, bucketKey: string);
|
|
355
|
+
private post;
|
|
356
|
+
private get;
|
|
357
|
+
private patch;
|
|
358
|
+
private delete;
|
|
359
|
+
signup(options: SignupOptions): Promise<AuthResult>;
|
|
360
|
+
login(options: LoginOptions): Promise<AuthResult>;
|
|
361
|
+
logout({ sessionId }: {
|
|
362
|
+
sessionId: string;
|
|
363
|
+
}): Promise<void>;
|
|
364
|
+
refreshSession({ refreshToken }: {
|
|
365
|
+
refreshToken: string;
|
|
366
|
+
}): Promise<Session>;
|
|
367
|
+
getUser({ userId }: {
|
|
368
|
+
userId: string;
|
|
369
|
+
}): Promise<UserRecord>;
|
|
370
|
+
updateUser(options: UpdateUserOptions): Promise<UserRecord>;
|
|
371
|
+
deleteUser({ sessionId, userId }: {
|
|
372
|
+
sessionId: string;
|
|
373
|
+
userId: string;
|
|
374
|
+
}): Promise<void>;
|
|
375
|
+
listUsers(options: ListUsersOptions): Promise<ListUsersResult>;
|
|
376
|
+
hardDeleteUser({ sessionId, userId }: {
|
|
377
|
+
sessionId: string;
|
|
378
|
+
userId: string;
|
|
379
|
+
}): Promise<void>;
|
|
380
|
+
bulkDeleteUsers({ sessionId, userIds }: {
|
|
381
|
+
sessionId: string;
|
|
382
|
+
userIds: string[];
|
|
383
|
+
}): Promise<{
|
|
384
|
+
deleted: number;
|
|
385
|
+
failed: string[];
|
|
386
|
+
}>;
|
|
387
|
+
lockAccount({ sessionId, userId, duration }: {
|
|
388
|
+
sessionId: string;
|
|
389
|
+
userId: string;
|
|
390
|
+
duration?: number;
|
|
391
|
+
}): Promise<{
|
|
392
|
+
lockedUntil: number;
|
|
393
|
+
unlockTime: string;
|
|
394
|
+
}>;
|
|
395
|
+
unlockAccount({ sessionId, userId }: {
|
|
396
|
+
sessionId: string;
|
|
397
|
+
userId: string;
|
|
398
|
+
}): Promise<void>;
|
|
399
|
+
changePassword(options: ChangePasswordOptions): Promise<void>;
|
|
400
|
+
requestPasswordReset({ email }: {
|
|
401
|
+
email: string;
|
|
402
|
+
}): Promise<void>;
|
|
403
|
+
confirmPasswordReset({ resetToken, newPassword }: {
|
|
404
|
+
resetToken: string;
|
|
405
|
+
newPassword: string;
|
|
406
|
+
}): Promise<void>;
|
|
407
|
+
requestEmailVerification({ userId }: {
|
|
408
|
+
userId: string;
|
|
409
|
+
}): Promise<void>;
|
|
410
|
+
confirmEmailVerification({ verifyToken }: {
|
|
411
|
+
verifyToken: string;
|
|
412
|
+
}): Promise<void>;
|
|
273
413
|
}
|
|
274
414
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
415
|
+
/**
|
|
416
|
+
* RecordsClient — CRUD + query for a single bucket.
|
|
417
|
+
* Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* const db = createClient({ authKey: '…', bucketSecurityKey: 'hk_bucket_…', storageKeys: { main: '…' } });
|
|
422
|
+
* const posts = db.records('blog-posts');
|
|
423
|
+
* const post = await posts.create({ title: 'Hello World', status: 'draft' });
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
426
|
+
declare class RecordsClient<T extends RecordData = RecordData> {
|
|
427
|
+
private readonly http;
|
|
428
|
+
private readonly bucketKey;
|
|
429
|
+
private readonly basePath;
|
|
430
|
+
private readonly bucketKey_;
|
|
431
|
+
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
432
|
+
private get key();
|
|
433
|
+
create(data: T): Promise<T & RecordResult>;
|
|
434
|
+
get(id: string): Promise<T & RecordResult>;
|
|
435
|
+
set(id: string, data: T): Promise<T & RecordResult>;
|
|
436
|
+
patch(id: string, data: Partial<T>, options?: PatchRecordOptions): Promise<T & RecordResult>;
|
|
437
|
+
delete(id: string): Promise<void>;
|
|
438
|
+
batchCreate(items: T[]): Promise<(T & RecordResult)[]>;
|
|
439
|
+
batchDelete(ids: string[]): Promise<{
|
|
440
|
+
deleted: number;
|
|
441
|
+
failed: string[];
|
|
442
|
+
}>;
|
|
443
|
+
query(options?: QueryOptions): Promise<QueryResult<T>>;
|
|
444
|
+
getAll(options?: Omit<QueryOptions, 'filters'>): Promise<(T & RecordResult)[]>;
|
|
445
|
+
count(filters?: QueryOptions['filters']): Promise<number>;
|
|
446
|
+
getHistory(id: string): Promise<RecordHistoryEntry[]>;
|
|
447
|
+
restoreVersion(id: string, version: number): Promise<T & RecordResult>;
|
|
289
448
|
}
|
|
290
449
|
|
|
450
|
+
/**
|
|
451
|
+
* AnalyticsClient — BigQuery-powered aggregations for a bucket.
|
|
452
|
+
* Uses the `bucketSecurityKey` (`hk_bucket_…`) sent via `X-Api-Key` header.
|
|
453
|
+
*
|
|
454
|
+
* @example
|
|
455
|
+
* ```ts
|
|
456
|
+
* const db = createClient({ authKey: '…', bucketSecurityKey: 'hk_bucket_…', storageKeys: { main: '…' } });
|
|
457
|
+
* const analytics = db.analytics('orders');
|
|
458
|
+
* const { count } = await analytics.count();
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
291
461
|
declare class AnalyticsClient {
|
|
292
|
-
private readonly
|
|
293
|
-
private readonly
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
462
|
+
private readonly http;
|
|
463
|
+
private readonly bucketSecurityKey;
|
|
464
|
+
private readonly basePath;
|
|
465
|
+
constructor(http: HttpClient, bucketSecurityKey: string, bucketKey: string);
|
|
466
|
+
private run;
|
|
467
|
+
count(opts?: {
|
|
468
|
+
dateRange?: DateRange;
|
|
469
|
+
}): Promise<CountResult>;
|
|
470
|
+
distribution(opts: {
|
|
471
|
+
field: string;
|
|
472
|
+
limit?: number;
|
|
473
|
+
order?: SortOrder;
|
|
474
|
+
dateRange?: DateRange;
|
|
475
|
+
}): Promise<DistributionRow[]>;
|
|
476
|
+
sum(opts: {
|
|
477
|
+
field: string;
|
|
478
|
+
groupBy?: string;
|
|
479
|
+
limit?: number;
|
|
480
|
+
dateRange?: DateRange;
|
|
481
|
+
}): Promise<SumRow[]>;
|
|
482
|
+
timeSeries(opts?: {
|
|
483
|
+
granularity?: Granularity;
|
|
484
|
+
dateRange?: DateRange;
|
|
485
|
+
}): Promise<TimeSeriesRow[]>;
|
|
486
|
+
fieldTimeSeries(opts: {
|
|
487
|
+
field: string;
|
|
488
|
+
aggregation?: Aggregation;
|
|
489
|
+
granularity?: Granularity;
|
|
490
|
+
dateRange?: DateRange;
|
|
491
|
+
}): Promise<FieldTimeSeriesRow[]>;
|
|
492
|
+
topN(opts: {
|
|
493
|
+
field: string;
|
|
494
|
+
n?: number;
|
|
495
|
+
labelField?: string;
|
|
496
|
+
order?: SortOrder;
|
|
497
|
+
dateRange?: DateRange;
|
|
498
|
+
}): Promise<TopNRow[]>;
|
|
499
|
+
stats(opts: {
|
|
500
|
+
field: string;
|
|
501
|
+
dateRange?: DateRange;
|
|
502
|
+
}): Promise<FieldStats>;
|
|
503
|
+
records<T extends RecordData = RecordData>(opts?: {
|
|
504
|
+
filters?: AnalyticsFilter[];
|
|
505
|
+
selectFields?: string[];
|
|
506
|
+
limit?: number;
|
|
507
|
+
offset?: number;
|
|
508
|
+
orderBy?: string;
|
|
509
|
+
order?: SortOrder;
|
|
510
|
+
dateRange?: DateRange;
|
|
511
|
+
}): Promise<(T & RecordResult)[]>;
|
|
512
|
+
multiMetric(opts: {
|
|
513
|
+
metrics: MetricDefinition[];
|
|
514
|
+
dateRange?: DateRange;
|
|
515
|
+
}): Promise<MultiMetricResult>;
|
|
516
|
+
storageStats(opts?: {
|
|
517
|
+
dateRange?: DateRange;
|
|
518
|
+
}): Promise<StorageStatsResult>;
|
|
519
|
+
crossBucket(opts: {
|
|
520
|
+
bucketKeys: string[];
|
|
521
|
+
field: string;
|
|
522
|
+
aggregation?: Aggregation;
|
|
523
|
+
dateRange?: DateRange;
|
|
524
|
+
}): Promise<CrossBucketRow[]>;
|
|
525
|
+
query<T = unknown>(query: AnalyticsQuery): Promise<AnalyticsResult<T>>;
|
|
301
526
|
}
|
|
302
527
|
|
|
303
528
|
/**
|
|
304
|
-
*
|
|
305
|
-
*
|
|
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.
|
|
532
|
+
*
|
|
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`.
|
|
306
535
|
*
|
|
307
|
-
*
|
|
308
|
-
*
|
|
536
|
+
* @example
|
|
537
|
+
* ```ts
|
|
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 });
|
|
541
|
+
* ```
|
|
309
542
|
*/
|
|
310
|
-
declare class
|
|
311
|
-
private readonly
|
|
312
|
-
private readonly
|
|
313
|
-
readonly
|
|
314
|
-
constructor(
|
|
543
|
+
declare class StorageManager {
|
|
544
|
+
private readonly http;
|
|
545
|
+
private readonly storageKey;
|
|
546
|
+
private readonly basePath;
|
|
547
|
+
constructor(http: HttpClient, storageKey: string);
|
|
548
|
+
/** Headers for all storage requests — uses X-Storage-Key, not X-Api-Key. */
|
|
549
|
+
private get authHeaders();
|
|
315
550
|
/**
|
|
316
|
-
* Upload a
|
|
551
|
+
* Upload a file to storage in one step (server-buffered, up to 500 MB).
|
|
552
|
+
* For files >10 MB or when you need upload progress, use `getUploadUrl()` instead.
|
|
317
553
|
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
554
|
+
* @param data File data as a Blob, Buffer, Uint8Array, or ArrayBuffer.
|
|
555
|
+
* @param path Destination path in your storage (e.g. `"avatars/alice.jpg"`).
|
|
556
|
+
* @param options Upload options: isPublic, overwrite, mimeType.
|
|
320
557
|
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
558
|
+
* @example
|
|
559
|
+
* ```ts
|
|
560
|
+
* // Upload a public avatar
|
|
561
|
+
* const result = await storage.upload(file, 'avatars/alice.jpg', { isPublic: true });
|
|
562
|
+
* console.log(result.publicUrl); // → https://...
|
|
323
563
|
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
564
|
+
* // Upload a private document
|
|
565
|
+
* const result = await storage.upload(pdfBuffer, 'docs/contract.pdf');
|
|
566
|
+
* console.log(result.downloadUrl); // → /storage/download/docs/contract.pdf
|
|
567
|
+
* ```
|
|
568
|
+
*/
|
|
569
|
+
upload(data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
570
|
+
/**
|
|
571
|
+
* Upload raw JSON or plain text data as a file.
|
|
327
572
|
*
|
|
328
573
|
* @example
|
|
329
|
-
*
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
* },
|
|
337
|
-
* });
|
|
574
|
+
* ```ts
|
|
575
|
+
* const result = await storage.uploadRaw(
|
|
576
|
+
* { config: { theme: 'dark' } },
|
|
577
|
+
* 'settings/user-config.json',
|
|
578
|
+
* { isPublic: false },
|
|
579
|
+
* );
|
|
580
|
+
* ```
|
|
338
581
|
*/
|
|
339
|
-
|
|
582
|
+
uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
340
583
|
/**
|
|
341
|
-
*
|
|
584
|
+
* Step 1 of the recommended upload flow.
|
|
585
|
+
* Get a signed URL to upload directly to GCS from the client (supports progress).
|
|
342
586
|
*
|
|
343
587
|
* @example
|
|
344
|
-
*
|
|
345
|
-
* await
|
|
346
|
-
* '
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
*
|
|
588
|
+
* ```ts
|
|
589
|
+
* const { uploadUrl, path: confirmedPath } = await storage.getUploadUrl({
|
|
590
|
+
* path: 'videos/intro.mp4',
|
|
591
|
+
* mimeType: 'video/mp4',
|
|
592
|
+
* size: file.size,
|
|
593
|
+
* isPublic: true,
|
|
594
|
+
* });
|
|
595
|
+
*
|
|
596
|
+
* // Upload using XHR for progress tracking
|
|
597
|
+
* await storage.uploadToSignedUrl(uploadUrl, file, 'video/mp4', (pct) => {
|
|
598
|
+
* console.log(`${pct}% uploaded`);
|
|
599
|
+
* });
|
|
600
|
+
*
|
|
601
|
+
* // Step 3: confirm
|
|
602
|
+
* const result = await storage.confirmUpload({ path: confirmedPath, mimeType: 'video/mp4', isPublic: true });
|
|
603
|
+
* ```
|
|
350
604
|
*/
|
|
351
|
-
|
|
352
|
-
|
|
605
|
+
getUploadUrl(opts: {
|
|
606
|
+
path: string;
|
|
607
|
+
mimeType: string;
|
|
608
|
+
size: number;
|
|
609
|
+
isPublic?: boolean;
|
|
353
610
|
overwrite?: boolean;
|
|
354
|
-
|
|
355
|
-
}): Promise<
|
|
611
|
+
expiresInSeconds?: number;
|
|
612
|
+
}): Promise<UploadUrlResult>;
|
|
356
613
|
/**
|
|
357
|
-
* Upload
|
|
614
|
+
* Upload data directly to a signed GCS URL (no auth headers needed).
|
|
615
|
+
* Optionally tracks progress via a callback.
|
|
358
616
|
*
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
617
|
+
* @param signedUrl The URL returned by `getUploadUrl()`.
|
|
618
|
+
* @param data File data.
|
|
619
|
+
* @param mimeType Must match what was used in `getUploadUrl()`.
|
|
620
|
+
* @param onProgress Optional callback called with 0–100 progress percentage.
|
|
621
|
+
*/
|
|
622
|
+
uploadToSignedUrl(signedUrl: string, data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer, mimeType: string, onProgress?: (percent: number) => void): Promise<void>;
|
|
623
|
+
/**
|
|
624
|
+
* Step 3 of the recommended upload flow.
|
|
625
|
+
* Confirm a direct upload and register metadata on the server.
|
|
362
626
|
*
|
|
363
627
|
* @example
|
|
364
|
-
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
628
|
+
* ```ts
|
|
629
|
+
* const result = await storage.confirmUpload({
|
|
630
|
+
* path: 'videos/intro.mp4',
|
|
631
|
+
* mimeType: 'video/mp4',
|
|
632
|
+
* isPublic: true,
|
|
367
633
|
* });
|
|
634
|
+
* console.log(result.publicUrl);
|
|
635
|
+
* ```
|
|
368
636
|
*/
|
|
369
|
-
|
|
637
|
+
confirmUpload(opts: {
|
|
638
|
+
path: string;
|
|
639
|
+
mimeType: string;
|
|
640
|
+
isPublic?: boolean;
|
|
641
|
+
}): Promise<UploadResult>;
|
|
370
642
|
/**
|
|
371
|
-
*
|
|
643
|
+
* Get signed upload URLs for multiple files at once.
|
|
372
644
|
*
|
|
373
645
|
* @example
|
|
374
|
-
*
|
|
375
|
-
* const
|
|
376
|
-
*
|
|
646
|
+
* ```ts
|
|
647
|
+
* const { files } = await storage.getBatchUploadUrls([
|
|
648
|
+
* { path: 'images/photo1.jpg', mimeType: 'image/jpeg', size: 204800 },
|
|
649
|
+
* { path: 'images/photo2.jpg', mimeType: 'image/jpeg', size: 153600 },
|
|
650
|
+
* ]);
|
|
651
|
+
*
|
|
652
|
+
* // Upload each file and confirm
|
|
653
|
+
* for (const f of files) {
|
|
654
|
+
* await storage.uploadToSignedUrl(f.uploadUrl, blobs[f.index], f.mimeType);
|
|
655
|
+
* await storage.confirmUpload({ path: f.path, mimeType: f.mimeType });
|
|
656
|
+
* }
|
|
657
|
+
* ```
|
|
377
658
|
*/
|
|
378
|
-
|
|
659
|
+
getBatchUploadUrls(files: BatchUploadItem[]): Promise<BatchUploadUrlResult>;
|
|
379
660
|
/**
|
|
380
|
-
*
|
|
661
|
+
* Confirm multiple direct uploads at once.
|
|
662
|
+
*/
|
|
663
|
+
batchConfirmUploads(items: Array<{
|
|
664
|
+
path: string;
|
|
665
|
+
mimeType: string;
|
|
666
|
+
isPublic?: boolean;
|
|
667
|
+
}>): Promise<UploadResult[]>;
|
|
668
|
+
/**
|
|
669
|
+
* Download a private file as an ArrayBuffer.
|
|
670
|
+
* For public files, use the `publicUrl` directly — no SDK needed.
|
|
381
671
|
*
|
|
382
|
-
*
|
|
672
|
+
* @example
|
|
673
|
+
* ```ts
|
|
674
|
+
* const buffer = await storage.download('docs/contract.pdf');
|
|
675
|
+
* const blob = new Blob([buffer], { type: 'application/pdf' });
|
|
676
|
+
* // Open in browser:
|
|
677
|
+
* window.open(URL.createObjectURL(blob));
|
|
678
|
+
* ```
|
|
679
|
+
*/
|
|
680
|
+
download(path: string): Promise<ArrayBuffer>;
|
|
681
|
+
/**
|
|
682
|
+
* Download multiple files at once, returned as a JSON map of `{ path: base64 }`.
|
|
383
683
|
*
|
|
384
684
|
* @example
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
* );
|
|
685
|
+
* ```ts
|
|
686
|
+
* const files = await storage.batchDownload(['docs/a.pdf', 'docs/b.pdf']);
|
|
687
|
+
* ```
|
|
389
688
|
*/
|
|
390
|
-
batchDownload(
|
|
689
|
+
batchDownload(paths: string[]): Promise<Record<string, string>>;
|
|
391
690
|
/**
|
|
392
|
-
* List files and folders
|
|
691
|
+
* List files and folders at a given path prefix.
|
|
393
692
|
*
|
|
394
693
|
* @example
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
*
|
|
694
|
+
* ```ts
|
|
695
|
+
* // List everything in the root
|
|
696
|
+
* const { files, folders } = await storage.list();
|
|
697
|
+
*
|
|
698
|
+
* // List a specific folder
|
|
699
|
+
* const { files, folders, hasMore, nextCursor } = await storage.list({
|
|
700
|
+
* prefix: 'avatars/',
|
|
701
|
+
* limit: 20,
|
|
702
|
+
* });
|
|
703
|
+
*
|
|
704
|
+
* // Next page
|
|
705
|
+
* const page2 = await storage.list({ prefix: 'avatars/', cursor: nextCursor });
|
|
706
|
+
* ```
|
|
707
|
+
*/
|
|
708
|
+
list(opts?: ListOptions): Promise<ListResult>;
|
|
709
|
+
/**
|
|
710
|
+
* Get metadata for a file (size, MIME type, visibility, URLs).
|
|
711
|
+
*
|
|
712
|
+
* @example
|
|
713
|
+
* ```ts
|
|
714
|
+
* const meta = await storage.getMetadata('avatars/alice.jpg');
|
|
715
|
+
* console.log(meta.size, meta.isPublic, meta.publicUrl);
|
|
716
|
+
* ```
|
|
717
|
+
*/
|
|
718
|
+
getMetadata(path: string): Promise<FileMetadata>;
|
|
719
|
+
/**
|
|
720
|
+
* Generate a time-limited download URL for a private file.
|
|
721
|
+
* The URL can be shared externally without requiring an `X-Storage-Key`.
|
|
722
|
+
*
|
|
723
|
+
* > **Note:** Downloads via signed URLs bypass the server, so download stats
|
|
724
|
+
* > are NOT tracked. Use `downloadUrl` for tracked downloads.
|
|
725
|
+
*
|
|
726
|
+
* @param path Path to the file.
|
|
727
|
+
* @param expiresIn URL lifetime in seconds (default 3600 = 1 hour).
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```ts
|
|
731
|
+
* const { signedUrl, expiresAt } = await storage.getSignedUrl('docs/invoice.pdf', 1800);
|
|
732
|
+
* // Share signedUrl with the recipient — it expires in 30 minutes.
|
|
733
|
+
* ```
|
|
734
|
+
*/
|
|
735
|
+
getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
|
|
736
|
+
/**
|
|
737
|
+
* Change a file's visibility between public and private after upload.
|
|
738
|
+
*
|
|
739
|
+
* @example
|
|
740
|
+
* ```ts
|
|
741
|
+
* // Make a file public
|
|
742
|
+
* const result = await storage.setVisibility('avatars/alice.jpg', true);
|
|
743
|
+
* console.log(result.publicUrl); // CDN URL
|
|
744
|
+
*
|
|
745
|
+
* // Make a file private
|
|
746
|
+
* const result = await storage.setVisibility('avatars/alice.jpg', false);
|
|
747
|
+
* console.log(result.downloadUrl); // Auth-required URL
|
|
748
|
+
* ```
|
|
749
|
+
*/
|
|
750
|
+
setVisibility(path: string, isPublic: boolean): Promise<{
|
|
751
|
+
path: string;
|
|
752
|
+
isPublic: boolean;
|
|
753
|
+
publicUrl: string | null;
|
|
754
|
+
downloadUrl: string | null;
|
|
755
|
+
}>;
|
|
756
|
+
/**
|
|
757
|
+
* Create a folder (a GCS prefix placeholder).
|
|
758
|
+
*
|
|
759
|
+
* @example
|
|
760
|
+
* ```ts
|
|
761
|
+
* await storage.createFolder('uploads/2025/');
|
|
762
|
+
* ```
|
|
399
763
|
*/
|
|
400
|
-
|
|
764
|
+
createFolder(path: string): Promise<{
|
|
765
|
+
path: string;
|
|
766
|
+
}>;
|
|
401
767
|
/**
|
|
402
|
-
*
|
|
768
|
+
* Delete a single file.
|
|
403
769
|
*
|
|
404
770
|
* @example
|
|
405
|
-
*
|
|
406
|
-
*
|
|
771
|
+
* ```ts
|
|
772
|
+
* await storage.deleteFile('avatars/old-avatar.jpg');
|
|
773
|
+
* ```
|
|
407
774
|
*/
|
|
408
|
-
|
|
409
|
-
/** Delete a single file */
|
|
410
|
-
deleteFile(filePath: string): Promise<HydrousResponse<void>>;
|
|
411
|
-
/** Recursively delete a folder and all its contents */
|
|
412
|
-
deleteFolder(folderPath: string): Promise<HydrousResponse<void>>;
|
|
413
|
-
/** Create an empty folder */
|
|
414
|
-
createFolder(folderPath: string): Promise<HydrousResponse<void>>;
|
|
415
|
-
/** Move (rename) a file */
|
|
416
|
-
move(fromPath: string, toPath: string): Promise<HydrousResponse<void>>;
|
|
417
|
-
/** Copy a file (original is kept) */
|
|
418
|
-
copy(fromPath: string, toPath: string): Promise<HydrousResponse<void>>;
|
|
775
|
+
deleteFile(path: string): Promise<void>;
|
|
419
776
|
/**
|
|
420
|
-
*
|
|
777
|
+
* Delete a folder and all its contents recursively.
|
|
421
778
|
*
|
|
422
779
|
* @example
|
|
423
|
-
*
|
|
424
|
-
*
|
|
780
|
+
* ```ts
|
|
781
|
+
* await storage.deleteFolder('temp/');
|
|
782
|
+
* ```
|
|
783
|
+
*/
|
|
784
|
+
deleteFolder(path: string): Promise<void>;
|
|
785
|
+
/**
|
|
786
|
+
* Move or rename a file.
|
|
787
|
+
*
|
|
788
|
+
* @example
|
|
789
|
+
* ```ts
|
|
790
|
+
* // Rename
|
|
791
|
+
* await storage.move('docs/draft.pdf', 'docs/final.pdf');
|
|
792
|
+
* // Move to a different folder
|
|
793
|
+
* await storage.move('inbox/report.xlsx', 'archive/2025/report.xlsx');
|
|
794
|
+
* ```
|
|
795
|
+
*/
|
|
796
|
+
move(from: string, to: string): Promise<{
|
|
797
|
+
from: string;
|
|
798
|
+
to: string;
|
|
799
|
+
}>;
|
|
800
|
+
/**
|
|
801
|
+
* Copy a file to a new path.
|
|
802
|
+
*
|
|
803
|
+
* @example
|
|
804
|
+
* ```ts
|
|
805
|
+
* await storage.copy('templates/base.html', 'sites/my-site/index.html');
|
|
806
|
+
* ```
|
|
807
|
+
*/
|
|
808
|
+
copy(from: string, to: string): Promise<{
|
|
809
|
+
from: string;
|
|
810
|
+
to: string;
|
|
811
|
+
}>;
|
|
812
|
+
/**
|
|
813
|
+
* Get storage statistics for your key: total files, bytes, operation counts.
|
|
814
|
+
*
|
|
815
|
+
* @example
|
|
816
|
+
* ```ts
|
|
817
|
+
* const stats = await storage.getStats();
|
|
818
|
+
* console.log(`${stats.totalFiles} files, ${(stats.totalBytes / 1e6).toFixed(1)} MB`);
|
|
819
|
+
* ```
|
|
425
820
|
*/
|
|
426
|
-
|
|
821
|
+
getStats(): Promise<StorageStats>;
|
|
427
822
|
/**
|
|
428
|
-
*
|
|
823
|
+
* Ping the storage service. No authentication required.
|
|
429
824
|
*
|
|
430
825
|
* @example
|
|
431
|
-
*
|
|
432
|
-
*
|
|
826
|
+
* ```ts
|
|
827
|
+
* const info = await storage.info();
|
|
828
|
+
* // → { ok: true, storageRoot: 'hydrous-storage' }
|
|
829
|
+
* ```
|
|
433
830
|
*/
|
|
434
|
-
|
|
831
|
+
info(): Promise<{
|
|
832
|
+
ok: boolean;
|
|
833
|
+
storageRoot: string;
|
|
834
|
+
}>;
|
|
435
835
|
}
|
|
436
836
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
837
|
+
/**
|
|
838
|
+
* ScopedStorage — a StorageManager pre-scoped to a specific folder prefix.
|
|
839
|
+
*
|
|
840
|
+
* All paths are automatically prepended with the scope, so you never
|
|
841
|
+
* have to repeat the folder name.
|
|
842
|
+
*
|
|
843
|
+
* @example
|
|
844
|
+
* ```ts
|
|
845
|
+
* const db = createClient({ securityKey: 'sk_...' });
|
|
846
|
+
*
|
|
847
|
+
* // All operations in the "avatars/" folder
|
|
848
|
+
* const avatars = db.storage.scope('avatars');
|
|
849
|
+
*
|
|
850
|
+
* await avatars.upload(file, 'alice.jpg'); // → "avatars/alice.jpg"
|
|
851
|
+
* const list = await avatars.list(); // → files under "avatars/"
|
|
852
|
+
* await avatars.deleteFile('alice.jpg'); // → deletes "avatars/alice.jpg"
|
|
853
|
+
* ```
|
|
854
|
+
*/
|
|
855
|
+
declare class ScopedStorage {
|
|
856
|
+
private readonly manager;
|
|
857
|
+
private readonly prefix;
|
|
858
|
+
constructor(manager: StorageManager, prefix: string);
|
|
859
|
+
private scopedPath;
|
|
860
|
+
/** Upload a file within the scoped folder. */
|
|
861
|
+
upload(data: Blob | Uint8Array<ArrayBuffer> | ArrayBuffer | Buffer, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
862
|
+
/** Upload raw JSON or text within the scoped folder. */
|
|
863
|
+
uploadRaw(data: unknown, path: string, options?: UploadOptions): Promise<UploadResult>;
|
|
864
|
+
/** Get a signed upload URL for a file within the scoped folder. */
|
|
865
|
+
getUploadUrl(opts: {
|
|
866
|
+
path: string;
|
|
867
|
+
mimeType: string;
|
|
868
|
+
size: number;
|
|
869
|
+
isPublic?: boolean;
|
|
870
|
+
overwrite?: boolean;
|
|
871
|
+
}): Promise<UploadUrlResult>;
|
|
872
|
+
/** Confirm a direct upload within the scoped folder. */
|
|
873
|
+
confirmUpload(opts: {
|
|
874
|
+
path: string;
|
|
875
|
+
mimeType: string;
|
|
876
|
+
isPublic?: boolean;
|
|
877
|
+
}): Promise<UploadResult>;
|
|
878
|
+
/** Download a file within the scoped folder. */
|
|
879
|
+
download(path: string): Promise<ArrayBuffer>;
|
|
880
|
+
/**
|
|
881
|
+
* List files within the scoped folder.
|
|
882
|
+
* `prefix` in options is relative to the scope.
|
|
883
|
+
*/
|
|
884
|
+
list(opts?: ListOptions): Promise<ListResult>;
|
|
885
|
+
/** Get metadata for a file within the scoped folder. */
|
|
886
|
+
getMetadata(path: string): Promise<FileMetadata>;
|
|
887
|
+
/** Get a time-limited signed URL for a file within the scoped folder. */
|
|
888
|
+
getSignedUrl(path: string, expiresIn?: number): Promise<SignedUrlResult>;
|
|
889
|
+
/** Change visibility of a file within the scoped folder. */
|
|
890
|
+
setVisibility(path: string, isPublic: boolean): Promise<{
|
|
891
|
+
path: string;
|
|
892
|
+
isPublic: boolean;
|
|
893
|
+
publicUrl: string | null;
|
|
894
|
+
downloadUrl: string | null;
|
|
895
|
+
}>;
|
|
896
|
+
/** Delete a file within the scoped folder. */
|
|
897
|
+
deleteFile(path: string): Promise<void>;
|
|
898
|
+
/** Delete a sub-folder within the scoped folder. */
|
|
899
|
+
deleteFolder(path: string): Promise<void>;
|
|
900
|
+
/** Move a file within the scoped folder. */
|
|
901
|
+
move(from: string, to: string): Promise<{
|
|
902
|
+
from: string;
|
|
903
|
+
to: string;
|
|
904
|
+
}>;
|
|
905
|
+
/** Copy a file within the scoped folder. */
|
|
906
|
+
copy(from: string, to: string): Promise<{
|
|
907
|
+
from: string;
|
|
908
|
+
to: string;
|
|
909
|
+
}>;
|
|
910
|
+
/** Create a sub-folder within the scoped folder. */
|
|
911
|
+
createFolder(path: string): Promise<{
|
|
912
|
+
path: string;
|
|
913
|
+
}>;
|
|
914
|
+
/**
|
|
915
|
+
* Create a further-scoped instance nested within this scope.
|
|
916
|
+
*
|
|
917
|
+
* @example
|
|
918
|
+
* ```ts
|
|
919
|
+
* const uploads = db.storage.scope('user-uploads');
|
|
920
|
+
* const images = uploads.scope('images'); // → "user-uploads/images/"
|
|
921
|
+
* ```
|
|
922
|
+
*/
|
|
923
|
+
scope(subPrefix: string): ScopedStorage;
|
|
444
924
|
}
|
|
925
|
+
|
|
445
926
|
/**
|
|
446
|
-
*
|
|
927
|
+
* HydrousClient — the main entry point for the HydrousDB SDK.
|
|
447
928
|
*
|
|
448
|
-
*
|
|
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')`
|
|
449
933
|
*
|
|
934
|
+
* @example
|
|
450
935
|
* ```ts
|
|
451
936
|
* import { createClient } from 'hydrousdb';
|
|
452
937
|
*
|
|
453
938
|
* const db = createClient({
|
|
454
|
-
* url: 'https://api.myapp.hydrous.app',
|
|
455
939
|
* authKey: 'hk_auth_…',
|
|
456
940
|
* bucketSecurityKey: 'hk_bucket_…',
|
|
457
941
|
* storageKeys: {
|
|
@@ -460,95 +944,137 @@ interface CallableStorage {
|
|
|
460
944
|
* documents: 'ssk_docs_…',
|
|
461
945
|
* },
|
|
462
946
|
* });
|
|
947
|
+
*
|
|
948
|
+
* // Records & Analytics — use bucketSecurityKey automatically
|
|
949
|
+
* const posts = db.records('blog-posts');
|
|
950
|
+
* const analytics = db.analytics('orders');
|
|
951
|
+
*
|
|
952
|
+
* // Auth — uses authKey automatically
|
|
953
|
+
* const auth = db.auth('app-users');
|
|
954
|
+
*
|
|
955
|
+
* // Storage — pick which key to use by name
|
|
956
|
+
* const avatarStorage = db.storage('avatars');
|
|
957
|
+
* const documentStorage = db.storage('documents');
|
|
463
958
|
* ```
|
|
464
959
|
*/
|
|
465
960
|
declare class HydrousClient {
|
|
466
|
-
|
|
467
|
-
readonly
|
|
468
|
-
|
|
469
|
-
readonly
|
|
470
|
-
|
|
471
|
-
readonly
|
|
961
|
+
private readonly http;
|
|
962
|
+
private readonly authKey_;
|
|
963
|
+
private readonly bucketSecurityKey_;
|
|
964
|
+
private readonly storageKeys_;
|
|
965
|
+
private readonly _recordsCache;
|
|
966
|
+
private readonly _authCache;
|
|
967
|
+
private readonly _analyticsCache;
|
|
968
|
+
private readonly _storageCache;
|
|
969
|
+
constructor(config: HydrousConfig);
|
|
472
970
|
/**
|
|
473
|
-
*
|
|
971
|
+
* Get a typed records client for the named bucket.
|
|
972
|
+
* Uses your `bucketSecurityKey` automatically.
|
|
474
973
|
*
|
|
974
|
+
* @example
|
|
475
975
|
* ```ts
|
|
476
|
-
*
|
|
477
|
-
* db.
|
|
478
|
-
*
|
|
976
|
+
* interface Post { title: string; published: boolean }
|
|
977
|
+
* const posts = db.records<Post>('blog-posts');
|
|
978
|
+
* const post = await posts.create({ title: 'Hello', published: false });
|
|
479
979
|
* ```
|
|
480
980
|
*/
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
* db.storage('main').upload(file)
|
|
494
|
-
* db.storage('avatars').list()
|
|
495
|
-
* db.storage('documents').download('report.pdf')
|
|
496
|
-
* ```
|
|
497
|
-
*/
|
|
498
|
-
declare class StorageManager {
|
|
499
|
-
private readonly baseUrl;
|
|
500
|
-
private readonly _keys;
|
|
501
|
-
private readonly cache;
|
|
502
|
-
constructor(config: HydrousConfig);
|
|
981
|
+
records<T extends RecordData = RecordData>(bucketKey: string): RecordsClient<T>;
|
|
982
|
+
/**
|
|
983
|
+
* Get an auth client for the named user bucket.
|
|
984
|
+
* Uses your `authKey` automatically.
|
|
985
|
+
*
|
|
986
|
+
* @example
|
|
987
|
+
* ```ts
|
|
988
|
+
* const auth = db.auth('app-users');
|
|
989
|
+
* const { user, session } = await auth.login({ email: '…', password: '…' });
|
|
990
|
+
* ```
|
|
991
|
+
*/
|
|
992
|
+
auth(bucketKey: string): AuthClient;
|
|
503
993
|
/**
|
|
504
|
-
* Get
|
|
994
|
+
* Get an analytics client for the named bucket.
|
|
995
|
+
* Uses your `bucketSecurityKey` automatically.
|
|
505
996
|
*
|
|
506
|
-
* @
|
|
997
|
+
* @example
|
|
998
|
+
* ```ts
|
|
999
|
+
* const analytics = db.analytics('orders');
|
|
1000
|
+
* const { count } = await analytics.count();
|
|
1001
|
+
* ```
|
|
1002
|
+
*/
|
|
1003
|
+
analytics(bucketKey: string): AnalyticsClient;
|
|
1004
|
+
/**
|
|
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.
|
|
1008
|
+
*
|
|
1009
|
+
* @param keyName The name of the storage key (e.g. `"avatars"`, `"documents"`, `"main"`).
|
|
507
1010
|
*
|
|
508
1011
|
* @example
|
|
509
|
-
*
|
|
510
|
-
* const
|
|
1012
|
+
* ```ts
|
|
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 });
|
|
511
1018
|
*
|
|
512
|
-
*
|
|
513
|
-
* const
|
|
1019
|
+
* // Scope to a sub-folder
|
|
1020
|
+
* const userDocs = db.storage('documents').scope(`users/${userId}`);
|
|
1021
|
+
* await userDocs.upload(pdfBuffer, 'contract.pdf');
|
|
1022
|
+
* ```
|
|
514
1023
|
*/
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
declare const eq: (field: string, value: unknown) => Filter;
|
|
521
|
-
declare const neq: (field: string, value: unknown) => Filter;
|
|
522
|
-
declare const gt: (field: string, value: unknown) => Filter;
|
|
523
|
-
declare const lt: (field: string, value: unknown) => Filter;
|
|
524
|
-
declare const gte: (field: string, value: unknown) => Filter;
|
|
525
|
-
declare const lte: (field: string, value: unknown) => Filter;
|
|
526
|
-
declare const inArray: (field: string, value: unknown[]) => Filter;
|
|
527
|
-
|
|
528
|
-
declare class HydrousDBError extends Error {
|
|
529
|
-
readonly code: string;
|
|
530
|
-
readonly status: number | undefined;
|
|
531
|
-
constructor(message: string, code?: string, status?: number);
|
|
1024
|
+
storage(keyName: string): StorageManager & {
|
|
1025
|
+
scope: (prefix: string) => ScopedStorage;
|
|
1026
|
+
};
|
|
532
1027
|
}
|
|
533
|
-
declare function isHydrousError(err: unknown): err is HydrousDBError;
|
|
534
|
-
|
|
535
1028
|
/**
|
|
536
|
-
* Create a HydrousDB client.
|
|
1029
|
+
* Create a new HydrousDB client.
|
|
537
1030
|
*
|
|
538
1031
|
* @example
|
|
1032
|
+
* ```ts
|
|
539
1033
|
* import { createClient } from 'hydrousdb';
|
|
540
1034
|
*
|
|
541
1035
|
* const db = createClient({
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
* bucketSecurityKey: 'hk_bucket_…',
|
|
1036
|
+
* authKey: process.env.HYDROUS_AUTH_KEY!,
|
|
1037
|
+
* bucketSecurityKey: process.env.HYDROUS_BUCKET_KEY!,
|
|
545
1038
|
* storageKeys: {
|
|
546
|
-
* main:
|
|
547
|
-
* avatars:
|
|
548
|
-
* documents:
|
|
1039
|
+
* main: process.env.HYDROUS_STORAGE_MAIN!,
|
|
1040
|
+
* avatars: process.env.HYDROUS_STORAGE_AVATARS!,
|
|
1041
|
+
* documents: process.env.HYDROUS_STORAGE_DOCS!,
|
|
549
1042
|
* },
|
|
550
1043
|
* });
|
|
1044
|
+
* ```
|
|
551
1045
|
*/
|
|
552
1046
|
declare function createClient(config: HydrousConfig): HydrousClient;
|
|
553
1047
|
|
|
554
|
-
|
|
1048
|
+
declare class HydrousError extends Error {
|
|
1049
|
+
/** Machine-readable error code returned by the API. */
|
|
1050
|
+
readonly code: string;
|
|
1051
|
+
/** HTTP status code (if applicable). */
|
|
1052
|
+
readonly status?: number;
|
|
1053
|
+
/** The original request ID for support tracing. */
|
|
1054
|
+
readonly requestId?: string;
|
|
1055
|
+
/** Additional validation details. */
|
|
1056
|
+
readonly details?: string[];
|
|
1057
|
+
constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
|
|
1058
|
+
toString(): string;
|
|
1059
|
+
}
|
|
1060
|
+
declare class AuthError extends HydrousError {
|
|
1061
|
+
constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
|
|
1062
|
+
}
|
|
1063
|
+
declare class RecordError extends HydrousError {
|
|
1064
|
+
constructor(message: string, code: string, status?: number, requestId?: string, details?: string[]);
|
|
1065
|
+
}
|
|
1066
|
+
declare class StorageError extends HydrousError {
|
|
1067
|
+
constructor(message: string, code: string, status?: number, requestId?: string);
|
|
1068
|
+
}
|
|
1069
|
+
declare class AnalyticsError extends HydrousError {
|
|
1070
|
+
constructor(message: string, code: string, status?: number, requestId?: string);
|
|
1071
|
+
}
|
|
1072
|
+
declare class ValidationError extends HydrousError {
|
|
1073
|
+
constructor(message: string, details?: string[]);
|
|
1074
|
+
}
|
|
1075
|
+
declare class NetworkError extends HydrousError {
|
|
1076
|
+
readonly cause?: unknown;
|
|
1077
|
+
constructor(message: string, cause?: unknown);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
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 };
|