@picobase_app/client 0.1.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/README.md +233 -0
- package/dist/index.d.mts +491 -0
- package/dist/index.d.ts +491 -0
- package/dist/index.js +531 -0
- package/dist/index.mjs +485 -0
- package/package.json +46 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
AuthorizationError: () => AuthorizationError,
|
|
34
|
+
InstanceUnavailableError: () => InstanceUnavailableError,
|
|
35
|
+
PicoBaseAuth: () => PicoBaseAuth,
|
|
36
|
+
PicoBaseClient: () => PicoBaseClient,
|
|
37
|
+
PicoBaseCollection: () => PicoBaseCollection,
|
|
38
|
+
PicoBaseError: () => PicoBaseError,
|
|
39
|
+
PicoBaseRealtime: () => PicoBaseRealtime,
|
|
40
|
+
PicoBaseStorage: () => PicoBaseStorage,
|
|
41
|
+
RequestError: () => RequestError,
|
|
42
|
+
createClient: () => createClient
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(index_exports);
|
|
45
|
+
|
|
46
|
+
// src/client.ts
|
|
47
|
+
var import_pocketbase = __toESM(require("pocketbase"));
|
|
48
|
+
|
|
49
|
+
// src/auth.ts
|
|
50
|
+
var PicoBaseAuth = class {
|
|
51
|
+
constructor(pb) {
|
|
52
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
53
|
+
this._collection = "users";
|
|
54
|
+
this.pb = pb;
|
|
55
|
+
this.pb.authStore.onChange((token) => {
|
|
56
|
+
const record = this.pb.authStore.record ?? null;
|
|
57
|
+
const event = token ? "SIGNED_IN" : "SIGNED_OUT";
|
|
58
|
+
this._notify(event, record);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Set which collection to authenticate against.
|
|
63
|
+
* Defaults to 'users'. Use this if you have a custom auth collection.
|
|
64
|
+
*/
|
|
65
|
+
setCollection(name) {
|
|
66
|
+
this._collection = name;
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a new user account.
|
|
71
|
+
*/
|
|
72
|
+
async signUp(options) {
|
|
73
|
+
const { email, password, passwordConfirm, ...rest } = options;
|
|
74
|
+
const record = await this.pb.collection(this._collection).create({
|
|
75
|
+
email,
|
|
76
|
+
password,
|
|
77
|
+
passwordConfirm: passwordConfirm ?? password,
|
|
78
|
+
...rest
|
|
79
|
+
});
|
|
80
|
+
const authResult = await this.pb.collection(this._collection).authWithPassword(email, password);
|
|
81
|
+
return {
|
|
82
|
+
token: authResult.token,
|
|
83
|
+
record: authResult.record
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Sign in with email and password.
|
|
88
|
+
*/
|
|
89
|
+
async signIn(options) {
|
|
90
|
+
const result = await this.pb.collection(this._collection).authWithPassword(options.email, options.password);
|
|
91
|
+
return {
|
|
92
|
+
token: result.token,
|
|
93
|
+
record: result.record
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Sign in with an OAuth2 provider (Google, GitHub, etc.).
|
|
98
|
+
*
|
|
99
|
+
* In browser environments this opens a popup/redirect to the provider.
|
|
100
|
+
* Configure providers in your PicoBase dashboard.
|
|
101
|
+
*/
|
|
102
|
+
async signInWithOAuth(options) {
|
|
103
|
+
const result = await this.pb.collection(this._collection).authWithOAuth2({
|
|
104
|
+
provider: options.provider,
|
|
105
|
+
scopes: options.scopes,
|
|
106
|
+
createData: options.createData,
|
|
107
|
+
urlCallback: options.urlCallback
|
|
108
|
+
});
|
|
109
|
+
return {
|
|
110
|
+
token: result.token,
|
|
111
|
+
record: result.record
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Refresh the current auth token.
|
|
116
|
+
*/
|
|
117
|
+
async refreshToken() {
|
|
118
|
+
const result = await this.pb.collection(this._collection).authRefresh();
|
|
119
|
+
this._notify("TOKEN_REFRESHED", result.record);
|
|
120
|
+
return {
|
|
121
|
+
token: result.token,
|
|
122
|
+
record: result.record
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Send a password reset email.
|
|
127
|
+
*/
|
|
128
|
+
async requestPasswordReset(email) {
|
|
129
|
+
await this.pb.collection(this._collection).requestPasswordReset(email);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Confirm a password reset with the token from the reset email.
|
|
133
|
+
*/
|
|
134
|
+
async confirmPasswordReset(token, password, passwordConfirm) {
|
|
135
|
+
await this.pb.collection(this._collection).confirmPasswordReset(token, password, passwordConfirm ?? password);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Send an email verification email.
|
|
139
|
+
*/
|
|
140
|
+
async requestVerification(email) {
|
|
141
|
+
await this.pb.collection(this._collection).requestVerification(email);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Confirm email verification with the token from the verification email.
|
|
145
|
+
*/
|
|
146
|
+
async confirmVerification(token) {
|
|
147
|
+
await this.pb.collection(this._collection).confirmVerification(token);
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Sign out the current user. Clears the local auth store.
|
|
151
|
+
*/
|
|
152
|
+
signOut() {
|
|
153
|
+
this.pb.authStore.clear();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Get the currently authenticated user record, or `null` if not signed in.
|
|
157
|
+
*/
|
|
158
|
+
get user() {
|
|
159
|
+
return this.pb.authStore.record;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Get the current auth token, or empty string if not signed in.
|
|
163
|
+
*/
|
|
164
|
+
get token() {
|
|
165
|
+
return this.pb.authStore.token;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Check if the current auth session is valid (token exists and not expired).
|
|
169
|
+
*/
|
|
170
|
+
get isValid() {
|
|
171
|
+
return this.pb.authStore.isValid;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Listen to auth state changes. Returns an unsubscribe function.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```ts
|
|
178
|
+
* const unsubscribe = pb.auth.onStateChange((event, record) => {
|
|
179
|
+
* if (event === 'SIGNED_IN') {
|
|
180
|
+
* console.log('Welcome', record.email)
|
|
181
|
+
* }
|
|
182
|
+
* })
|
|
183
|
+
*
|
|
184
|
+
* // Later:
|
|
185
|
+
* unsubscribe()
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
onStateChange(callback) {
|
|
189
|
+
this.listeners.add(callback);
|
|
190
|
+
return () => {
|
|
191
|
+
this.listeners.delete(callback);
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
_notify(event, record) {
|
|
195
|
+
for (const cb of this.listeners) {
|
|
196
|
+
try {
|
|
197
|
+
cb(event, record);
|
|
198
|
+
} catch {
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/collection.ts
|
|
205
|
+
var PicoBaseCollection = class {
|
|
206
|
+
constructor(pb, name) {
|
|
207
|
+
this.pb = pb;
|
|
208
|
+
this.name = name;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Fetch a paginated list of records.
|
|
212
|
+
*
|
|
213
|
+
* @param page - Page number (1-indexed). Default: 1.
|
|
214
|
+
* @param perPage - Records per page. Default: 30.
|
|
215
|
+
* @param options - Filter, sort, expand, fields.
|
|
216
|
+
*/
|
|
217
|
+
async getList(page = 1, perPage = 30, options = {}) {
|
|
218
|
+
return this.pb.collection(this.name).getList(page, perPage, options);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Fetch all records matching the filter (auto-paginates).
|
|
222
|
+
*
|
|
223
|
+
* **Warning:** Use with caution on large collections. Prefer `getList()` with pagination.
|
|
224
|
+
*/
|
|
225
|
+
async getFullList(options = {}) {
|
|
226
|
+
return this.pb.collection(this.name).getFullList(options);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Fetch a single record by ID.
|
|
230
|
+
*/
|
|
231
|
+
async getOne(id, options = {}) {
|
|
232
|
+
return this.pb.collection(this.name).getOne(id, options);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Fetch the first record matching a filter.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```ts
|
|
239
|
+
* const admin = await pb.collection('users').getFirstListItem('role = "admin"')
|
|
240
|
+
* ```
|
|
241
|
+
*/
|
|
242
|
+
async getFirstListItem(filter, options = {}) {
|
|
243
|
+
return this.pb.collection(this.name).getFirstListItem(filter, options);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Create a new record.
|
|
247
|
+
*
|
|
248
|
+
* @param data - Record data. Can be a plain object or `FormData` (for file uploads).
|
|
249
|
+
*/
|
|
250
|
+
async create(data, options = {}) {
|
|
251
|
+
return this.pb.collection(this.name).create(data, options);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Update an existing record.
|
|
255
|
+
*
|
|
256
|
+
* @param id - Record ID.
|
|
257
|
+
* @param data - Fields to update. Can be a plain object or `FormData`.
|
|
258
|
+
*/
|
|
259
|
+
async update(id, data, options = {}) {
|
|
260
|
+
return this.pb.collection(this.name).update(id, data, options);
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Delete a record by ID.
|
|
264
|
+
*/
|
|
265
|
+
async delete(id) {
|
|
266
|
+
return this.pb.collection(this.name).delete(id);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Subscribe to realtime changes on this collection.
|
|
270
|
+
*
|
|
271
|
+
* @param callback - Called on every create/update/delete event.
|
|
272
|
+
* @param filter - Optional: only receive events matching this filter.
|
|
273
|
+
* @returns Unsubscribe function.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* const unsubscribe = await pb.collection('posts').subscribe((e) => {
|
|
278
|
+
* console.log(e.action, e.record)
|
|
279
|
+
* })
|
|
280
|
+
*
|
|
281
|
+
* // Later:
|
|
282
|
+
* await unsubscribe()
|
|
283
|
+
* ```
|
|
284
|
+
*/
|
|
285
|
+
async subscribe(callback, filter) {
|
|
286
|
+
const topic = "*";
|
|
287
|
+
await this.pb.collection(this.name).subscribe(topic, callback, filter ? { filter } : void 0);
|
|
288
|
+
return () => this.pb.collection(this.name).unsubscribe(topic);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Subscribe to changes on a specific record.
|
|
292
|
+
*
|
|
293
|
+
* @param id - Record ID.
|
|
294
|
+
* @param callback - Called on update/delete events.
|
|
295
|
+
* @returns Unsubscribe function.
|
|
296
|
+
*/
|
|
297
|
+
async subscribeOne(id, callback) {
|
|
298
|
+
await this.pb.collection(this.name).subscribe(id, callback);
|
|
299
|
+
return () => this.pb.collection(this.name).unsubscribe(id);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// src/realtime.ts
|
|
304
|
+
var PicoBaseRealtime = class {
|
|
305
|
+
constructor(pb) {
|
|
306
|
+
this.pb = pb;
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Subscribe to realtime events on a collection.
|
|
310
|
+
*
|
|
311
|
+
* @param collection - Collection name (e.g. 'posts').
|
|
312
|
+
* @param callback - Called on every create/update/delete event.
|
|
313
|
+
* @returns Unsubscribe function.
|
|
314
|
+
*/
|
|
315
|
+
async subscribe(collection, callback) {
|
|
316
|
+
await this.pb.collection(collection).subscribe("*", callback);
|
|
317
|
+
return () => this.pb.collection(collection).unsubscribe("*");
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Subscribe to realtime events on a specific record.
|
|
321
|
+
*
|
|
322
|
+
* @param collection - Collection name.
|
|
323
|
+
* @param recordId - Record ID.
|
|
324
|
+
* @param callback - Called on update/delete events.
|
|
325
|
+
* @returns Unsubscribe function.
|
|
326
|
+
*/
|
|
327
|
+
async subscribeRecord(collection, recordId, callback) {
|
|
328
|
+
await this.pb.collection(collection).subscribe(recordId, callback);
|
|
329
|
+
return () => this.pb.collection(collection).unsubscribe(recordId);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Unsubscribe from all realtime events on a collection.
|
|
333
|
+
*/
|
|
334
|
+
async unsubscribe(collection) {
|
|
335
|
+
await this.pb.collection(collection).unsubscribe();
|
|
336
|
+
}
|
|
337
|
+
/**
|
|
338
|
+
* Unsubscribe from ALL realtime events. The SSE connection will be
|
|
339
|
+
* automatically closed when there are no remaining subscriptions.
|
|
340
|
+
*/
|
|
341
|
+
async disconnectAll() {
|
|
342
|
+
await this.pb.realtime.unsubscribe();
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
// src/storage.ts
|
|
347
|
+
var PicoBaseStorage = class {
|
|
348
|
+
constructor(pb) {
|
|
349
|
+
this.pb = pb;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Get the public URL for a file attached to a record.
|
|
353
|
+
*
|
|
354
|
+
* @param record - The record that owns the file.
|
|
355
|
+
* @param filename - The filename (as stored in the record's file field).
|
|
356
|
+
* @param options - Optional: thumb size, token for protected files, download flag.
|
|
357
|
+
*/
|
|
358
|
+
getFileUrl(record, filename, options = {}) {
|
|
359
|
+
const queryParams = {};
|
|
360
|
+
if (options.thumb) {
|
|
361
|
+
queryParams["thumb"] = options.thumb;
|
|
362
|
+
}
|
|
363
|
+
if (options.token) {
|
|
364
|
+
queryParams["token"] = options.token;
|
|
365
|
+
}
|
|
366
|
+
if (options.download) {
|
|
367
|
+
queryParams["download"] = "1";
|
|
368
|
+
}
|
|
369
|
+
return this.pb.files.getURL(record, filename, queryParams);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Generate a temporary file access token.
|
|
373
|
+
*
|
|
374
|
+
* Use this for accessing protected files. Tokens are short-lived.
|
|
375
|
+
*/
|
|
376
|
+
async getFileToken() {
|
|
377
|
+
return this.pb.files.getToken();
|
|
378
|
+
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// src/errors.ts
|
|
382
|
+
var PicoBaseError = class extends Error {
|
|
383
|
+
constructor(message, code, status, details) {
|
|
384
|
+
super(message);
|
|
385
|
+
this.code = code;
|
|
386
|
+
this.status = status;
|
|
387
|
+
this.details = details;
|
|
388
|
+
this.name = "PicoBaseError";
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
var InstanceUnavailableError = class extends PicoBaseError {
|
|
392
|
+
constructor(message = "Instance is not available. It may be stopped or starting up.") {
|
|
393
|
+
super(message, "INSTANCE_UNAVAILABLE", 503);
|
|
394
|
+
this.name = "InstanceUnavailableError";
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
var AuthorizationError = class extends PicoBaseError {
|
|
398
|
+
constructor(message = "Invalid or missing API key.") {
|
|
399
|
+
super(message, "UNAUTHORIZED", 401);
|
|
400
|
+
this.name = "AuthorizationError";
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
var RequestError = class extends PicoBaseError {
|
|
404
|
+
constructor(message, status, details) {
|
|
405
|
+
super(message, "REQUEST_FAILED", status, details);
|
|
406
|
+
this.name = "RequestError";
|
|
407
|
+
}
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
// src/client.ts
|
|
411
|
+
var DEFAULT_OPTIONS = {
|
|
412
|
+
timeout: 3e4,
|
|
413
|
+
maxColdStartRetries: 3,
|
|
414
|
+
lang: "en-US"
|
|
415
|
+
};
|
|
416
|
+
var PicoBaseClient = class {
|
|
417
|
+
constructor(url, apiKey, options = {}) {
|
|
418
|
+
this.apiKey = apiKey;
|
|
419
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
420
|
+
const baseUrl = url.replace(/\/+$/, "");
|
|
421
|
+
this.pb = new import_pocketbase.default(baseUrl);
|
|
422
|
+
this.pb.autoCancellation(false);
|
|
423
|
+
if (this.options.lang) {
|
|
424
|
+
this.pb.lang = this.options.lang;
|
|
425
|
+
}
|
|
426
|
+
this.pb.beforeSend = (url2, reqInit) => {
|
|
427
|
+
const headers = reqInit.headers ?? {};
|
|
428
|
+
headers["X-PicoBase-Key"] = this.apiKey;
|
|
429
|
+
reqInit.headers = headers;
|
|
430
|
+
return { url: url2, options: reqInit };
|
|
431
|
+
};
|
|
432
|
+
this._wrapSendWithRetry();
|
|
433
|
+
this.auth = new PicoBaseAuth(this.pb);
|
|
434
|
+
this.realtime = new PicoBaseRealtime(this.pb);
|
|
435
|
+
this.storage = new PicoBaseStorage(this.pb);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* Access a collection for CRUD operations.
|
|
439
|
+
*
|
|
440
|
+
* @example
|
|
441
|
+
* ```ts
|
|
442
|
+
* const posts = await pb.collection('posts').getList(1, 20)
|
|
443
|
+
* ```
|
|
444
|
+
*/
|
|
445
|
+
collection(name) {
|
|
446
|
+
return new PicoBaseCollection(this.pb, name);
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Call a server-side function (PocketBase custom API endpoint).
|
|
450
|
+
* Proxies to PocketBase's send() method.
|
|
451
|
+
*/
|
|
452
|
+
async send(path, options) {
|
|
453
|
+
return this.pb.send(path, options ?? {});
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Get the current auth token (if signed in), or empty string.
|
|
457
|
+
*/
|
|
458
|
+
get token() {
|
|
459
|
+
return this.pb.authStore.token;
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Check if a user is currently authenticated.
|
|
463
|
+
*/
|
|
464
|
+
get isAuthenticated() {
|
|
465
|
+
return this.pb.authStore.isValid;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Monkey-patch pb.send to retry on 503 (cold start).
|
|
469
|
+
*
|
|
470
|
+
* When an instance is stopped or starting, the proxy returns 503.
|
|
471
|
+
* The SDK automatically retries with exponential backoff so the developer
|
|
472
|
+
* doesn't have to handle cold-start logic.
|
|
473
|
+
*/
|
|
474
|
+
_wrapSendWithRetry() {
|
|
475
|
+
const originalSend = this.pb.send.bind(this.pb);
|
|
476
|
+
const maxRetries = this.options.maxColdStartRetries;
|
|
477
|
+
this.pb.send = async (path, options) => {
|
|
478
|
+
let lastError;
|
|
479
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
480
|
+
try {
|
|
481
|
+
return await originalSend(path, options);
|
|
482
|
+
} catch (err) {
|
|
483
|
+
lastError = err;
|
|
484
|
+
const status = err?.status;
|
|
485
|
+
if (status === 503 && attempt < maxRetries) {
|
|
486
|
+
const delay = Math.pow(2, attempt + 1) * 1e3;
|
|
487
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (status === 401) {
|
|
491
|
+
const data = err?.data;
|
|
492
|
+
if (data?.code === "INVALID_API_KEY") {
|
|
493
|
+
throw new AuthorizationError();
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
throw err;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
throw new InstanceUnavailableError(
|
|
500
|
+
`Instance unavailable after ${maxRetries} retries. Original error: ${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
501
|
+
);
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
function createClient(urlOrOptions, apiKeyOrUndefined, options) {
|
|
506
|
+
if (typeof urlOrOptions !== "string") {
|
|
507
|
+
const env = typeof process !== "undefined" ? process.env : {};
|
|
508
|
+
const url = env.PICOBASE_URL || env.NEXT_PUBLIC_PICOBASE_URL;
|
|
509
|
+
const apiKey = env.PICOBASE_API_KEY || env.NEXT_PUBLIC_PICOBASE_API_KEY;
|
|
510
|
+
if (!url || !apiKey) {
|
|
511
|
+
throw new Error(
|
|
512
|
+
"createClient() called without arguments, but PICOBASE_URL and PICOBASE_API_KEY environment variables are not set. Either pass them explicitly or add them to your .env file."
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
return new PicoBaseClient(url, apiKey, urlOrOptions);
|
|
516
|
+
}
|
|
517
|
+
return new PicoBaseClient(urlOrOptions, apiKeyOrUndefined, options);
|
|
518
|
+
}
|
|
519
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
520
|
+
0 && (module.exports = {
|
|
521
|
+
AuthorizationError,
|
|
522
|
+
InstanceUnavailableError,
|
|
523
|
+
PicoBaseAuth,
|
|
524
|
+
PicoBaseClient,
|
|
525
|
+
PicoBaseCollection,
|
|
526
|
+
PicoBaseError,
|
|
527
|
+
PicoBaseRealtime,
|
|
528
|
+
PicoBaseStorage,
|
|
529
|
+
RequestError,
|
|
530
|
+
createClient
|
|
531
|
+
});
|