@fluxbase/sdk 0.0.1-rc.2 → 0.0.1-rc.21
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/dist/index.cjs +1371 -349
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1296 -293
- package/dist/index.d.ts +1296 -293
- package/dist/index.js +1370 -350
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -116,6 +116,29 @@ var FluxbaseFetch = class {
|
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
118
|
|
|
119
|
+
// src/utils/error-handling.ts
|
|
120
|
+
async function wrapAsync(operation) {
|
|
121
|
+
try {
|
|
122
|
+
const data = await operation();
|
|
123
|
+
return { data, error: null };
|
|
124
|
+
} catch (error) {
|
|
125
|
+
return {
|
|
126
|
+
data: null,
|
|
127
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function wrapAsyncVoid(operation) {
|
|
132
|
+
try {
|
|
133
|
+
await operation();
|
|
134
|
+
return { error: null };
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return {
|
|
137
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
119
142
|
// src/auth.ts
|
|
120
143
|
var AUTH_STORAGE_KEY = "fluxbase.auth.session";
|
|
121
144
|
var FluxbaseAuth = class {
|
|
@@ -187,83 +210,107 @@ var FluxbaseAuth = class {
|
|
|
187
210
|
* Returns AuthSession if successful, or SignInWith2FAResponse if 2FA is required
|
|
188
211
|
*/
|
|
189
212
|
async signIn(credentials) {
|
|
190
|
-
|
|
191
|
-
"/api/v1/auth/signin",
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
213
|
+
return wrapAsync(async () => {
|
|
214
|
+
const response = await this.fetch.post("/api/v1/auth/signin", credentials);
|
|
215
|
+
if ("requires_2fa" in response && response.requires_2fa) {
|
|
216
|
+
return response;
|
|
217
|
+
}
|
|
218
|
+
const authResponse = response;
|
|
219
|
+
const session = {
|
|
220
|
+
...authResponse,
|
|
221
|
+
expires_at: Date.now() + authResponse.expires_in * 1e3
|
|
222
|
+
};
|
|
223
|
+
this.setSession(session);
|
|
224
|
+
return session;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Sign in with email and password
|
|
229
|
+
* Alias for signIn() to maintain compatibility with common authentication patterns
|
|
230
|
+
* Returns AuthSession if successful, or SignInWith2FAResponse if 2FA is required
|
|
231
|
+
*/
|
|
232
|
+
async signInWithPassword(credentials) {
|
|
233
|
+
return this.signIn(credentials);
|
|
204
234
|
}
|
|
205
235
|
/**
|
|
206
236
|
* Sign up with email and password
|
|
207
237
|
*/
|
|
208
238
|
async signUp(credentials) {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
239
|
+
return wrapAsync(async () => {
|
|
240
|
+
const response = await this.fetch.post(
|
|
241
|
+
"/api/v1/auth/signup",
|
|
242
|
+
credentials
|
|
243
|
+
);
|
|
244
|
+
const session = {
|
|
245
|
+
...response,
|
|
246
|
+
expires_at: Date.now() + response.expires_in * 1e3
|
|
247
|
+
};
|
|
248
|
+
this.setSession(session);
|
|
249
|
+
return { user: session.user, session };
|
|
250
|
+
});
|
|
216
251
|
}
|
|
217
252
|
/**
|
|
218
253
|
* Sign out the current user
|
|
219
254
|
*/
|
|
220
255
|
async signOut() {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
256
|
+
return wrapAsyncVoid(async () => {
|
|
257
|
+
try {
|
|
258
|
+
await this.fetch.post("/api/v1/auth/signout");
|
|
259
|
+
} finally {
|
|
260
|
+
this.clearSession();
|
|
261
|
+
}
|
|
262
|
+
});
|
|
226
263
|
}
|
|
227
264
|
/**
|
|
228
265
|
* Refresh the access token
|
|
229
266
|
*/
|
|
230
267
|
async refreshToken() {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
268
|
+
return wrapAsync(async () => {
|
|
269
|
+
if (!this.session?.refresh_token) {
|
|
270
|
+
throw new Error("No refresh token available");
|
|
271
|
+
}
|
|
272
|
+
const response = await this.fetch.post(
|
|
273
|
+
"/api/v1/auth/refresh",
|
|
274
|
+
{
|
|
275
|
+
refresh_token: this.session.refresh_token
|
|
276
|
+
}
|
|
277
|
+
);
|
|
278
|
+
const session = {
|
|
279
|
+
...response,
|
|
280
|
+
expires_at: Date.now() + response.expires_in * 1e3
|
|
281
|
+
};
|
|
282
|
+
this.setSession(session, "TOKEN_REFRESHED");
|
|
283
|
+
return { session };
|
|
236
284
|
});
|
|
237
|
-
const session = {
|
|
238
|
-
...response,
|
|
239
|
-
expires_at: Date.now() + response.expires_in * 1e3
|
|
240
|
-
};
|
|
241
|
-
this.setSession(session, "TOKEN_REFRESHED");
|
|
242
|
-
return session;
|
|
243
285
|
}
|
|
244
286
|
/**
|
|
245
287
|
* Get the current user from the server
|
|
246
288
|
*/
|
|
247
289
|
async getCurrentUser() {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
290
|
+
return wrapAsync(async () => {
|
|
291
|
+
if (!this.session) {
|
|
292
|
+
throw new Error("Not authenticated");
|
|
293
|
+
}
|
|
294
|
+
const user = await this.fetch.get("/api/v1/auth/user");
|
|
295
|
+
return { user };
|
|
296
|
+
});
|
|
252
297
|
}
|
|
253
298
|
/**
|
|
254
299
|
* Update the current user
|
|
255
300
|
*/
|
|
256
301
|
async updateUser(data) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
this.session
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
302
|
+
return wrapAsync(async () => {
|
|
303
|
+
if (!this.session) {
|
|
304
|
+
throw new Error("Not authenticated");
|
|
305
|
+
}
|
|
306
|
+
const user = await this.fetch.patch("/api/v1/auth/user", data);
|
|
307
|
+
if (this.session) {
|
|
308
|
+
this.session.user = user;
|
|
309
|
+
this.saveSession();
|
|
310
|
+
this.emitAuthChange("USER_UPDATED", this.session);
|
|
311
|
+
}
|
|
312
|
+
return { user };
|
|
313
|
+
});
|
|
267
314
|
}
|
|
268
315
|
/**
|
|
269
316
|
* Set the auth token manually
|
|
@@ -276,55 +323,75 @@ var FluxbaseAuth = class {
|
|
|
276
323
|
* Returns TOTP secret and QR code URL
|
|
277
324
|
*/
|
|
278
325
|
async setup2FA() {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
326
|
+
return wrapAsync(async () => {
|
|
327
|
+
if (!this.session) {
|
|
328
|
+
throw new Error("Not authenticated");
|
|
329
|
+
}
|
|
330
|
+
return await this.fetch.post(
|
|
331
|
+
"/api/v1/auth/2fa/setup"
|
|
332
|
+
);
|
|
333
|
+
});
|
|
283
334
|
}
|
|
284
335
|
/**
|
|
285
336
|
* Enable 2FA after verifying the TOTP code
|
|
286
337
|
* Returns backup codes that should be saved by the user
|
|
287
338
|
*/
|
|
288
339
|
async enable2FA(code) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
340
|
+
return wrapAsync(async () => {
|
|
341
|
+
if (!this.session) {
|
|
342
|
+
throw new Error("Not authenticated");
|
|
343
|
+
}
|
|
344
|
+
return await this.fetch.post(
|
|
345
|
+
"/api/v1/auth/2fa/enable",
|
|
346
|
+
{ code }
|
|
347
|
+
);
|
|
348
|
+
});
|
|
293
349
|
}
|
|
294
350
|
/**
|
|
295
351
|
* Disable 2FA for the current user
|
|
296
352
|
* Requires password confirmation
|
|
297
353
|
*/
|
|
298
354
|
async disable2FA(password) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
355
|
+
return wrapAsync(async () => {
|
|
356
|
+
if (!this.session) {
|
|
357
|
+
throw new Error("Not authenticated");
|
|
358
|
+
}
|
|
359
|
+
return await this.fetch.post(
|
|
360
|
+
"/api/v1/auth/2fa/disable",
|
|
361
|
+
{ password }
|
|
362
|
+
);
|
|
363
|
+
});
|
|
306
364
|
}
|
|
307
365
|
/**
|
|
308
366
|
* Check 2FA status for the current user
|
|
309
367
|
*/
|
|
310
368
|
async get2FAStatus() {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
369
|
+
return wrapAsync(async () => {
|
|
370
|
+
if (!this.session) {
|
|
371
|
+
throw new Error("Not authenticated");
|
|
372
|
+
}
|
|
373
|
+
return await this.fetch.get(
|
|
374
|
+
"/api/v1/auth/2fa/status"
|
|
375
|
+
);
|
|
376
|
+
});
|
|
315
377
|
}
|
|
316
378
|
/**
|
|
317
379
|
* Verify 2FA code during login
|
|
318
380
|
* Call this after signIn returns requires_2fa: true
|
|
319
381
|
*/
|
|
320
382
|
async verify2FA(request) {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
383
|
+
return wrapAsync(async () => {
|
|
384
|
+
const response = await this.fetch.post(
|
|
385
|
+
"/api/v1/auth/2fa/verify",
|
|
386
|
+
request
|
|
387
|
+
);
|
|
388
|
+
const session = {
|
|
389
|
+
...response,
|
|
390
|
+
expires_at: Date.now() + response.expires_in * 1e3
|
|
391
|
+
};
|
|
392
|
+
this.setSession(session, "MFA_CHALLENGE_VERIFIED");
|
|
393
|
+
return { user: session.user, session };
|
|
394
|
+
});
|
|
328
395
|
}
|
|
329
396
|
/**
|
|
330
397
|
* Send password reset email
|
|
@@ -332,7 +399,20 @@ var FluxbaseAuth = class {
|
|
|
332
399
|
* @param email - Email address to send reset link to
|
|
333
400
|
*/
|
|
334
401
|
async sendPasswordReset(email) {
|
|
335
|
-
return
|
|
402
|
+
return wrapAsync(async () => {
|
|
403
|
+
return await this.fetch.post(
|
|
404
|
+
"/api/v1/auth/password/reset",
|
|
405
|
+
{ email }
|
|
406
|
+
);
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Supabase-compatible alias for sendPasswordReset()
|
|
411
|
+
* @param email - Email address to send reset link to
|
|
412
|
+
* @param _options - Optional redirect configuration (currently not used)
|
|
413
|
+
*/
|
|
414
|
+
async resetPasswordForEmail(email, _options) {
|
|
415
|
+
return this.sendPasswordReset(email);
|
|
336
416
|
}
|
|
337
417
|
/**
|
|
338
418
|
* Verify password reset token
|
|
@@ -340,8 +420,13 @@ var FluxbaseAuth = class {
|
|
|
340
420
|
* @param token - Password reset token to verify
|
|
341
421
|
*/
|
|
342
422
|
async verifyResetToken(token) {
|
|
343
|
-
return
|
|
344
|
-
|
|
423
|
+
return wrapAsync(async () => {
|
|
424
|
+
return await this.fetch.post(
|
|
425
|
+
"/api/v1/auth/password/reset/verify",
|
|
426
|
+
{
|
|
427
|
+
token
|
|
428
|
+
}
|
|
429
|
+
);
|
|
345
430
|
});
|
|
346
431
|
}
|
|
347
432
|
/**
|
|
@@ -351,9 +436,14 @@ var FluxbaseAuth = class {
|
|
|
351
436
|
* @param newPassword - New password to set
|
|
352
437
|
*/
|
|
353
438
|
async resetPassword(token, newPassword) {
|
|
354
|
-
return
|
|
355
|
-
|
|
356
|
-
|
|
439
|
+
return wrapAsync(async () => {
|
|
440
|
+
return await this.fetch.post(
|
|
441
|
+
"/api/v1/auth/password/reset/confirm",
|
|
442
|
+
{
|
|
443
|
+
token,
|
|
444
|
+
new_password: newPassword
|
|
445
|
+
}
|
|
446
|
+
);
|
|
357
447
|
});
|
|
358
448
|
}
|
|
359
449
|
/**
|
|
@@ -362,9 +452,14 @@ var FluxbaseAuth = class {
|
|
|
362
452
|
* @param options - Optional configuration for magic link
|
|
363
453
|
*/
|
|
364
454
|
async sendMagicLink(email, options) {
|
|
365
|
-
return
|
|
366
|
-
|
|
367
|
-
|
|
455
|
+
return wrapAsync(async () => {
|
|
456
|
+
return await this.fetch.post(
|
|
457
|
+
"/api/v1/auth/magiclink",
|
|
458
|
+
{
|
|
459
|
+
email,
|
|
460
|
+
redirect_to: options?.redirect_to
|
|
461
|
+
}
|
|
462
|
+
);
|
|
368
463
|
});
|
|
369
464
|
}
|
|
370
465
|
/**
|
|
@@ -372,34 +467,47 @@ var FluxbaseAuth = class {
|
|
|
372
467
|
* @param token - Magic link token from email
|
|
373
468
|
*/
|
|
374
469
|
async verifyMagicLink(token) {
|
|
375
|
-
|
|
376
|
-
|
|
470
|
+
return wrapAsync(async () => {
|
|
471
|
+
const response = await this.fetch.post(
|
|
472
|
+
"/api/v1/auth/magiclink/verify",
|
|
473
|
+
{
|
|
474
|
+
token
|
|
475
|
+
}
|
|
476
|
+
);
|
|
477
|
+
const session = {
|
|
478
|
+
...response,
|
|
479
|
+
expires_at: Date.now() + response.expires_in * 1e3
|
|
480
|
+
};
|
|
481
|
+
this.setSession(session);
|
|
482
|
+
return { user: session.user, session };
|
|
377
483
|
});
|
|
378
|
-
const session = {
|
|
379
|
-
...response,
|
|
380
|
-
expires_at: Date.now() + response.expires_in * 1e3
|
|
381
|
-
};
|
|
382
|
-
this.setSession(session);
|
|
383
|
-
return session;
|
|
384
484
|
}
|
|
385
485
|
/**
|
|
386
486
|
* Sign in anonymously
|
|
387
487
|
* Creates a temporary anonymous user session
|
|
388
488
|
*/
|
|
389
489
|
async signInAnonymously() {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
490
|
+
return wrapAsync(async () => {
|
|
491
|
+
const response = await this.fetch.post(
|
|
492
|
+
"/api/v1/auth/signin/anonymous"
|
|
493
|
+
);
|
|
494
|
+
const session = {
|
|
495
|
+
...response,
|
|
496
|
+
expires_at: Date.now() + response.expires_in * 1e3
|
|
497
|
+
};
|
|
498
|
+
this.setSession(session);
|
|
499
|
+
return { user: session.user, session };
|
|
500
|
+
});
|
|
397
501
|
}
|
|
398
502
|
/**
|
|
399
503
|
* Get list of enabled OAuth providers
|
|
400
504
|
*/
|
|
401
505
|
async getOAuthProviders() {
|
|
402
|
-
return
|
|
506
|
+
return wrapAsync(async () => {
|
|
507
|
+
return await this.fetch.get(
|
|
508
|
+
"/api/v1/auth/oauth/providers"
|
|
509
|
+
);
|
|
510
|
+
});
|
|
403
511
|
}
|
|
404
512
|
/**
|
|
405
513
|
* Get OAuth authorization URL for a provider
|
|
@@ -407,17 +515,19 @@ var FluxbaseAuth = class {
|
|
|
407
515
|
* @param options - Optional OAuth configuration
|
|
408
516
|
*/
|
|
409
517
|
async getOAuthUrl(provider, options) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
518
|
+
return wrapAsync(async () => {
|
|
519
|
+
const params = new URLSearchParams();
|
|
520
|
+
if (options?.redirect_to) {
|
|
521
|
+
params.append("redirect_to", options.redirect_to);
|
|
522
|
+
}
|
|
523
|
+
if (options?.scopes && options.scopes.length > 0) {
|
|
524
|
+
params.append("scopes", options.scopes.join(","));
|
|
525
|
+
}
|
|
526
|
+
const queryString = params.toString();
|
|
527
|
+
const url = queryString ? `/api/v1/auth/oauth/${provider}/authorize?${queryString}` : `/api/v1/auth/oauth/${provider}/authorize`;
|
|
528
|
+
const response = await this.fetch.get(url);
|
|
529
|
+
return response;
|
|
530
|
+
});
|
|
421
531
|
}
|
|
422
532
|
/**
|
|
423
533
|
* Exchange OAuth authorization code for session
|
|
@@ -425,13 +535,18 @@ var FluxbaseAuth = class {
|
|
|
425
535
|
* @param code - Authorization code from OAuth callback
|
|
426
536
|
*/
|
|
427
537
|
async exchangeCodeForSession(code) {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
538
|
+
return wrapAsync(async () => {
|
|
539
|
+
const response = await this.fetch.post(
|
|
540
|
+
"/api/v1/auth/oauth/callback",
|
|
541
|
+
{ code }
|
|
542
|
+
);
|
|
543
|
+
const session = {
|
|
544
|
+
...response,
|
|
545
|
+
expires_at: Date.now() + response.expires_in * 1e3
|
|
546
|
+
};
|
|
547
|
+
this.setSession(session);
|
|
548
|
+
return { user: session.user, session };
|
|
549
|
+
});
|
|
435
550
|
}
|
|
436
551
|
/**
|
|
437
552
|
* Convenience method to initiate OAuth sign-in
|
|
@@ -440,12 +555,21 @@ var FluxbaseAuth = class {
|
|
|
440
555
|
* @param options - Optional OAuth configuration
|
|
441
556
|
*/
|
|
442
557
|
async signInWithOAuth(provider, options) {
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
558
|
+
return wrapAsync(async () => {
|
|
559
|
+
const result = await this.getOAuthUrl(provider, options);
|
|
560
|
+
if (result.error) {
|
|
561
|
+
throw result.error;
|
|
562
|
+
}
|
|
563
|
+
const url = result.data.url;
|
|
564
|
+
if (typeof window !== "undefined") {
|
|
565
|
+
window.location.href = url;
|
|
566
|
+
} else {
|
|
567
|
+
throw new Error(
|
|
568
|
+
"signInWithOAuth can only be called in a browser environment"
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
return { provider, url };
|
|
572
|
+
});
|
|
449
573
|
}
|
|
450
574
|
/**
|
|
451
575
|
* Internal: Set the session and persist it
|
|
@@ -493,11 +617,12 @@ var FluxbaseAuth = class {
|
|
|
493
617
|
const refreshAt = this.session.expires_at - 60 * 1e3;
|
|
494
618
|
const delay = refreshAt - Date.now();
|
|
495
619
|
if (delay > 0) {
|
|
496
|
-
this.refreshTimer = setTimeout(() => {
|
|
497
|
-
this.refreshToken()
|
|
498
|
-
|
|
620
|
+
this.refreshTimer = setTimeout(async () => {
|
|
621
|
+
const result = await this.refreshToken();
|
|
622
|
+
if (result.error) {
|
|
623
|
+
console.error("Failed to refresh token:", result.error);
|
|
499
624
|
this.clearSession();
|
|
500
|
-
}
|
|
625
|
+
}
|
|
501
626
|
}, delay);
|
|
502
627
|
}
|
|
503
628
|
}
|
|
@@ -562,22 +687,55 @@ var RealtimeChannel = class {
|
|
|
562
687
|
}
|
|
563
688
|
/**
|
|
564
689
|
* Subscribe to the channel
|
|
690
|
+
* @param callback - Optional status callback (Supabase-compatible)
|
|
691
|
+
* @param _timeout - Optional timeout in milliseconds (currently unused)
|
|
565
692
|
*/
|
|
566
|
-
subscribe() {
|
|
693
|
+
subscribe(callback, _timeout) {
|
|
567
694
|
this.connect();
|
|
695
|
+
if (callback) {
|
|
696
|
+
const checkConnection = () => {
|
|
697
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
698
|
+
callback("SUBSCRIBED");
|
|
699
|
+
} else if (this.ws && this.ws.readyState === WebSocket.CLOSED) {
|
|
700
|
+
callback("CHANNEL_ERROR", new Error("Failed to connect"));
|
|
701
|
+
} else {
|
|
702
|
+
setTimeout(checkConnection, 100);
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
setTimeout(checkConnection, 100);
|
|
706
|
+
}
|
|
568
707
|
return this;
|
|
569
708
|
}
|
|
570
709
|
/**
|
|
571
710
|
* Unsubscribe from the channel
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
711
|
+
* @param timeout - Optional timeout in milliseconds
|
|
712
|
+
* @returns Promise resolving to status string (Supabase-compatible)
|
|
713
|
+
*/
|
|
714
|
+
async unsubscribe(timeout) {
|
|
715
|
+
return new Promise((resolve) => {
|
|
716
|
+
if (this.ws) {
|
|
717
|
+
this.send({
|
|
718
|
+
type: "unsubscribe",
|
|
719
|
+
channel: this.channelName
|
|
720
|
+
});
|
|
721
|
+
const startTime = Date.now();
|
|
722
|
+
const maxWait = timeout || 5e3;
|
|
723
|
+
const checkDisconnect = () => {
|
|
724
|
+
if (!this.ws || this.ws.readyState === WebSocket.CLOSED) {
|
|
725
|
+
this.disconnect();
|
|
726
|
+
resolve("ok");
|
|
727
|
+
} else if (Date.now() - startTime > maxWait) {
|
|
728
|
+
this.disconnect();
|
|
729
|
+
resolve("timed out");
|
|
730
|
+
} else {
|
|
731
|
+
setTimeout(checkDisconnect, 100);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
setTimeout(checkDisconnect, 100);
|
|
735
|
+
} else {
|
|
736
|
+
resolve("ok");
|
|
737
|
+
}
|
|
738
|
+
});
|
|
581
739
|
}
|
|
582
740
|
/**
|
|
583
741
|
* Internal: Connect to WebSocket
|
|
@@ -666,13 +824,22 @@ var RealtimeChannel = class {
|
|
|
666
824
|
* Internal: Handle broadcast message
|
|
667
825
|
*/
|
|
668
826
|
handleBroadcast(payload) {
|
|
669
|
-
const
|
|
827
|
+
const supabasePayload = {
|
|
828
|
+
eventType: payload.type || payload.eventType,
|
|
829
|
+
schema: payload.schema,
|
|
830
|
+
table: payload.table,
|
|
831
|
+
commit_timestamp: payload.timestamp || payload.commit_timestamp || (/* @__PURE__ */ new Date()).toISOString(),
|
|
832
|
+
new: payload.new_record || payload.new || {},
|
|
833
|
+
old: payload.old_record || payload.old || {},
|
|
834
|
+
errors: payload.errors || null
|
|
835
|
+
};
|
|
836
|
+
const callbacks = this.callbacks.get(supabasePayload.eventType);
|
|
670
837
|
if (callbacks) {
|
|
671
|
-
callbacks.forEach((callback) => callback(
|
|
838
|
+
callbacks.forEach((callback) => callback(supabasePayload));
|
|
672
839
|
}
|
|
673
840
|
const wildcardCallbacks = this.callbacks.get("*");
|
|
674
841
|
if (wildcardCallbacks) {
|
|
675
|
-
wildcardCallbacks.forEach((callback) => callback(
|
|
842
|
+
wildcardCallbacks.forEach((callback) => callback(supabasePayload));
|
|
676
843
|
}
|
|
677
844
|
}
|
|
678
845
|
/**
|
|
@@ -702,7 +869,9 @@ var RealtimeChannel = class {
|
|
|
702
869
|
}
|
|
703
870
|
this.reconnectAttempts++;
|
|
704
871
|
const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1);
|
|
705
|
-
console.log(
|
|
872
|
+
console.log(
|
|
873
|
+
`[Fluxbase Realtime] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`
|
|
874
|
+
);
|
|
706
875
|
setTimeout(() => {
|
|
707
876
|
this.connect();
|
|
708
877
|
}, delay);
|
|
@@ -770,7 +939,7 @@ var StorageBucket = class {
|
|
|
770
939
|
if (options?.upsert !== void 0) {
|
|
771
940
|
formData.append("upsert", String(options.upsert));
|
|
772
941
|
}
|
|
773
|
-
const
|
|
942
|
+
const response = await this.fetch.request(
|
|
774
943
|
`/api/v1/storage/${this.bucketName}/${path}`,
|
|
775
944
|
{
|
|
776
945
|
method: "POST",
|
|
@@ -779,7 +948,14 @@ var StorageBucket = class {
|
|
|
779
948
|
// Let browser set Content-Type for FormData
|
|
780
949
|
}
|
|
781
950
|
);
|
|
782
|
-
return {
|
|
951
|
+
return {
|
|
952
|
+
data: {
|
|
953
|
+
id: response.id || response.key || path,
|
|
954
|
+
path,
|
|
955
|
+
fullPath: `${this.bucketName}/${path}`
|
|
956
|
+
},
|
|
957
|
+
error: null
|
|
958
|
+
};
|
|
783
959
|
} catch (error) {
|
|
784
960
|
return { data: null, error };
|
|
785
961
|
}
|
|
@@ -807,13 +983,24 @@ var StorageBucket = class {
|
|
|
807
983
|
}
|
|
808
984
|
/**
|
|
809
985
|
* List files in the bucket
|
|
810
|
-
*
|
|
986
|
+
* Supports both Supabase-style list(path, options) and Fluxbase-style list(options)
|
|
987
|
+
* @param pathOrOptions - The folder path or list options
|
|
988
|
+
* @param maybeOptions - List options when first param is a path
|
|
811
989
|
*/
|
|
812
|
-
async list(
|
|
990
|
+
async list(pathOrOptions, maybeOptions) {
|
|
813
991
|
try {
|
|
814
992
|
const params = new URLSearchParams();
|
|
815
|
-
|
|
816
|
-
|
|
993
|
+
let prefix;
|
|
994
|
+
let options;
|
|
995
|
+
if (typeof pathOrOptions === "string") {
|
|
996
|
+
prefix = pathOrOptions;
|
|
997
|
+
options = maybeOptions;
|
|
998
|
+
} else {
|
|
999
|
+
options = pathOrOptions;
|
|
1000
|
+
prefix = options?.prefix;
|
|
1001
|
+
}
|
|
1002
|
+
if (prefix) {
|
|
1003
|
+
params.set("prefix", prefix);
|
|
817
1004
|
}
|
|
818
1005
|
if (options?.limit) {
|
|
819
1006
|
params.set("limit", String(options.limit));
|
|
@@ -823,8 +1010,17 @@ var StorageBucket = class {
|
|
|
823
1010
|
}
|
|
824
1011
|
const queryString = params.toString();
|
|
825
1012
|
const path = `/api/v1/storage/${this.bucketName}${queryString ? `?${queryString}` : ""}`;
|
|
826
|
-
const
|
|
827
|
-
|
|
1013
|
+
const response = await this.fetch.get(path);
|
|
1014
|
+
const files = (response.files || []).map((file) => ({
|
|
1015
|
+
name: file.key || file.name,
|
|
1016
|
+
id: file.id,
|
|
1017
|
+
bucket_id: file.bucket || this.bucketName,
|
|
1018
|
+
created_at: file.last_modified || file.created_at,
|
|
1019
|
+
updated_at: file.updated_at,
|
|
1020
|
+
last_accessed_at: file.last_accessed_at,
|
|
1021
|
+
metadata: file.metadata
|
|
1022
|
+
}));
|
|
1023
|
+
return { data: files, error: null };
|
|
828
1024
|
} catch (error) {
|
|
829
1025
|
return { data: null, error };
|
|
830
1026
|
}
|
|
@@ -835,10 +1031,15 @@ var StorageBucket = class {
|
|
|
835
1031
|
*/
|
|
836
1032
|
async remove(paths) {
|
|
837
1033
|
try {
|
|
1034
|
+
const removedFiles = [];
|
|
838
1035
|
for (const path of paths) {
|
|
839
1036
|
await this.fetch.delete(`/api/v1/storage/${this.bucketName}/${path}`);
|
|
1037
|
+
removedFiles.push({
|
|
1038
|
+
name: path,
|
|
1039
|
+
bucket_id: this.bucketName
|
|
1040
|
+
});
|
|
840
1041
|
}
|
|
841
|
-
return { data:
|
|
1042
|
+
return { data: removedFiles, error: null };
|
|
842
1043
|
} catch (error) {
|
|
843
1044
|
return { data: null, error };
|
|
844
1045
|
}
|
|
@@ -875,14 +1076,17 @@ var StorageBucket = class {
|
|
|
875
1076
|
*/
|
|
876
1077
|
async move(fromPath, toPath) {
|
|
877
1078
|
try {
|
|
878
|
-
|
|
1079
|
+
await this.fetch.post(
|
|
879
1080
|
`/api/v1/storage/${this.bucketName}/move`,
|
|
880
1081
|
{
|
|
881
1082
|
from_path: fromPath,
|
|
882
1083
|
to_path: toPath
|
|
883
1084
|
}
|
|
884
1085
|
);
|
|
885
|
-
return {
|
|
1086
|
+
return {
|
|
1087
|
+
data: { message: "Successfully moved" },
|
|
1088
|
+
error: null
|
|
1089
|
+
};
|
|
886
1090
|
} catch (error) {
|
|
887
1091
|
return { data: null, error };
|
|
888
1092
|
}
|
|
@@ -894,14 +1098,65 @@ var StorageBucket = class {
|
|
|
894
1098
|
*/
|
|
895
1099
|
async copy(fromPath, toPath) {
|
|
896
1100
|
try {
|
|
897
|
-
|
|
1101
|
+
await this.fetch.post(
|
|
898
1102
|
`/api/v1/storage/${this.bucketName}/copy`,
|
|
899
1103
|
{
|
|
900
1104
|
from_path: fromPath,
|
|
901
1105
|
to_path: toPath
|
|
902
1106
|
}
|
|
903
1107
|
);
|
|
904
|
-
return {
|
|
1108
|
+
return {
|
|
1109
|
+
data: { path: toPath },
|
|
1110
|
+
error: null
|
|
1111
|
+
};
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
return { data: null, error };
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Share a file with another user (RLS)
|
|
1118
|
+
* @param path - The file path
|
|
1119
|
+
* @param options - Share options (userId and permission)
|
|
1120
|
+
*/
|
|
1121
|
+
async share(path, options) {
|
|
1122
|
+
try {
|
|
1123
|
+
await this.fetch.post(
|
|
1124
|
+
`/api/v1/storage/${this.bucketName}/${path}/share`,
|
|
1125
|
+
{
|
|
1126
|
+
user_id: options.userId,
|
|
1127
|
+
permission: options.permission
|
|
1128
|
+
}
|
|
1129
|
+
);
|
|
1130
|
+
return { data: null, error: null };
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
return { data: null, error };
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Revoke file access from a user (RLS)
|
|
1137
|
+
* @param path - The file path
|
|
1138
|
+
* @param userId - The user ID to revoke access from
|
|
1139
|
+
*/
|
|
1140
|
+
async revokeShare(path, userId) {
|
|
1141
|
+
try {
|
|
1142
|
+
await this.fetch.delete(
|
|
1143
|
+
`/api/v1/storage/${this.bucketName}/${path}/share/${userId}`
|
|
1144
|
+
);
|
|
1145
|
+
return { data: null, error: null };
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
return { data: null, error };
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* List users a file is shared with (RLS)
|
|
1152
|
+
* @param path - The file path
|
|
1153
|
+
*/
|
|
1154
|
+
async listShares(path) {
|
|
1155
|
+
try {
|
|
1156
|
+
const data = await this.fetch.get(
|
|
1157
|
+
`/api/v1/storage/${this.bucketName}/${path}/shares`
|
|
1158
|
+
);
|
|
1159
|
+
return { data: data.shares || [], error: null };
|
|
905
1160
|
} catch (error) {
|
|
906
1161
|
return { data: null, error };
|
|
907
1162
|
}
|
|
@@ -923,9 +1178,7 @@ var FluxbaseStorage = class {
|
|
|
923
1178
|
*/
|
|
924
1179
|
async listBuckets() {
|
|
925
1180
|
try {
|
|
926
|
-
const data = await this.fetch.get(
|
|
927
|
-
"/api/v1/storage/buckets"
|
|
928
|
-
);
|
|
1181
|
+
const data = await this.fetch.get("/api/v1/storage/buckets");
|
|
929
1182
|
return { data: data.buckets || [], error: null };
|
|
930
1183
|
} catch (error) {
|
|
931
1184
|
return { data: null, error };
|
|
@@ -938,7 +1191,7 @@ var FluxbaseStorage = class {
|
|
|
938
1191
|
async createBucket(bucketName) {
|
|
939
1192
|
try {
|
|
940
1193
|
await this.fetch.post(`/api/v1/storage/buckets/${bucketName}`);
|
|
941
|
-
return { data:
|
|
1194
|
+
return { data: { name: bucketName }, error: null };
|
|
942
1195
|
} catch (error) {
|
|
943
1196
|
return { data: null, error };
|
|
944
1197
|
}
|
|
@@ -950,7 +1203,7 @@ var FluxbaseStorage = class {
|
|
|
950
1203
|
async deleteBucket(bucketName) {
|
|
951
1204
|
try {
|
|
952
1205
|
await this.fetch.delete(`/api/v1/storage/buckets/${bucketName}`);
|
|
953
|
-
return { data:
|
|
1206
|
+
return { data: { message: "Successfully deleted" }, error: null };
|
|
954
1207
|
} catch (error) {
|
|
955
1208
|
return { data: null, error };
|
|
956
1209
|
}
|
|
@@ -967,250 +1220,931 @@ var FluxbaseStorage = class {
|
|
|
967
1220
|
return { data: null, error: listError };
|
|
968
1221
|
}
|
|
969
1222
|
if (objects && objects.length > 0) {
|
|
970
|
-
const paths = objects.map((obj) => obj.
|
|
1223
|
+
const paths = objects.map((obj) => obj.name);
|
|
971
1224
|
const { error: removeError } = await bucket.remove(paths);
|
|
972
1225
|
if (removeError) {
|
|
973
1226
|
return { data: null, error: removeError };
|
|
974
1227
|
}
|
|
975
1228
|
}
|
|
1229
|
+
return { data: { message: "Successfully emptied" }, error: null };
|
|
1230
|
+
} catch (error) {
|
|
1231
|
+
return { data: null, error };
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Update bucket settings (RLS - requires admin or service key)
|
|
1236
|
+
* @param bucketName - The name of the bucket
|
|
1237
|
+
* @param settings - Bucket settings to update
|
|
1238
|
+
*/
|
|
1239
|
+
async updateBucketSettings(bucketName, settings) {
|
|
1240
|
+
try {
|
|
1241
|
+
await this.fetch.put(`/api/v1/storage/buckets/${bucketName}`, settings);
|
|
976
1242
|
return { data: null, error: null };
|
|
977
1243
|
} catch (error) {
|
|
978
1244
|
return { data: null, error };
|
|
979
1245
|
}
|
|
980
1246
|
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Get bucket details
|
|
1249
|
+
* @param bucketName - The name of the bucket
|
|
1250
|
+
*/
|
|
1251
|
+
async getBucket(bucketName) {
|
|
1252
|
+
try {
|
|
1253
|
+
const data = await this.fetch.get(
|
|
1254
|
+
`/api/v1/storage/buckets/${bucketName}`
|
|
1255
|
+
);
|
|
1256
|
+
return { data, error: null };
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
return { data: null, error };
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
981
1261
|
};
|
|
982
1262
|
|
|
983
|
-
// src/
|
|
984
|
-
var
|
|
1263
|
+
// src/functions.ts
|
|
1264
|
+
var FluxbaseFunctions = class {
|
|
985
1265
|
constructor(fetch2) {
|
|
986
1266
|
this.fetch = fetch2;
|
|
987
1267
|
}
|
|
988
1268
|
/**
|
|
989
|
-
*
|
|
1269
|
+
* Invoke an edge function
|
|
1270
|
+
*
|
|
1271
|
+
* This method is fully compatible with Supabase's functions.invoke() API.
|
|
1272
|
+
*
|
|
1273
|
+
* @param functionName - The name of the function to invoke
|
|
1274
|
+
* @param options - Invocation options including body, headers, and HTTP method
|
|
1275
|
+
* @returns Promise resolving to { data, error } tuple
|
|
1276
|
+
*
|
|
1277
|
+
* @example
|
|
1278
|
+
* ```typescript
|
|
1279
|
+
* // Simple invocation
|
|
1280
|
+
* const { data, error } = await client.functions.invoke('hello', {
|
|
1281
|
+
* body: { name: 'World' }
|
|
1282
|
+
* })
|
|
1283
|
+
*
|
|
1284
|
+
* // With GET method
|
|
1285
|
+
* const { data, error } = await client.functions.invoke('get-data', {
|
|
1286
|
+
* method: 'GET'
|
|
1287
|
+
* })
|
|
1288
|
+
*
|
|
1289
|
+
* // With custom headers
|
|
1290
|
+
* const { data, error } = await client.functions.invoke('api-proxy', {
|
|
1291
|
+
* body: { query: 'search' },
|
|
1292
|
+
* headers: { 'Authorization': 'Bearer token' },
|
|
1293
|
+
* method: 'POST'
|
|
1294
|
+
* })
|
|
1295
|
+
* ```
|
|
1296
|
+
*/
|
|
1297
|
+
async invoke(functionName, options) {
|
|
1298
|
+
try {
|
|
1299
|
+
const method = options?.method || "POST";
|
|
1300
|
+
const headers = options?.headers || {};
|
|
1301
|
+
const body = options?.body;
|
|
1302
|
+
const endpoint = `/api/v1/functions/${functionName}/invoke`;
|
|
1303
|
+
let response;
|
|
1304
|
+
switch (method) {
|
|
1305
|
+
case "GET":
|
|
1306
|
+
response = await this.fetch.get(endpoint, { headers });
|
|
1307
|
+
break;
|
|
1308
|
+
case "DELETE":
|
|
1309
|
+
response = await this.fetch.delete(endpoint, { headers });
|
|
1310
|
+
break;
|
|
1311
|
+
case "PUT":
|
|
1312
|
+
response = await this.fetch.put(endpoint, body, { headers });
|
|
1313
|
+
break;
|
|
1314
|
+
case "PATCH":
|
|
1315
|
+
response = await this.fetch.patch(endpoint, body, { headers });
|
|
1316
|
+
break;
|
|
1317
|
+
case "POST":
|
|
1318
|
+
default:
|
|
1319
|
+
response = await this.fetch.post(endpoint, body, { headers });
|
|
1320
|
+
break;
|
|
1321
|
+
}
|
|
1322
|
+
return { data: response, error: null };
|
|
1323
|
+
} catch (error) {
|
|
1324
|
+
return { data: null, error };
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
/**
|
|
1328
|
+
* Create a new edge function
|
|
1329
|
+
*
|
|
1330
|
+
* @param request - Function configuration and code
|
|
1331
|
+
* @returns Promise resolving to { data, error } tuple with created function metadata
|
|
1332
|
+
*
|
|
1333
|
+
* @example
|
|
1334
|
+
* ```typescript
|
|
1335
|
+
* const { data, error } = await client.functions.create({
|
|
1336
|
+
* name: 'my-function',
|
|
1337
|
+
* code: 'export default async function handler(req) { return { hello: "world" } }',
|
|
1338
|
+
* enabled: true
|
|
1339
|
+
* })
|
|
1340
|
+
* ```
|
|
1341
|
+
*/
|
|
1342
|
+
async create(request) {
|
|
1343
|
+
try {
|
|
1344
|
+
const data = await this.fetch.post("/api/v1/functions", request);
|
|
1345
|
+
return { data, error: null };
|
|
1346
|
+
} catch (error) {
|
|
1347
|
+
return { data: null, error };
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* List all edge functions
|
|
1352
|
+
*
|
|
1353
|
+
* @returns Promise resolving to { data, error } tuple with array of functions
|
|
1354
|
+
*
|
|
1355
|
+
* @example
|
|
1356
|
+
* ```typescript
|
|
1357
|
+
* const { data, error } = await client.functions.list()
|
|
1358
|
+
* if (data) {
|
|
1359
|
+
* console.log('Functions:', data.map(f => f.name))
|
|
1360
|
+
* }
|
|
1361
|
+
* ```
|
|
1362
|
+
*/
|
|
1363
|
+
async list() {
|
|
1364
|
+
try {
|
|
1365
|
+
const data = await this.fetch.get("/api/v1/functions");
|
|
1366
|
+
return { data, error: null };
|
|
1367
|
+
} catch (error) {
|
|
1368
|
+
return { data: null, error };
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Get details of a specific edge function
|
|
1373
|
+
*
|
|
1374
|
+
* @param name - Function name
|
|
1375
|
+
* @returns Promise resolving to { data, error } tuple with function metadata
|
|
1376
|
+
*
|
|
1377
|
+
* @example
|
|
1378
|
+
* ```typescript
|
|
1379
|
+
* const { data, error } = await client.functions.get('my-function')
|
|
1380
|
+
* if (data) {
|
|
1381
|
+
* console.log('Function version:', data.version)
|
|
1382
|
+
* }
|
|
1383
|
+
* ```
|
|
1384
|
+
*/
|
|
1385
|
+
async get(name) {
|
|
1386
|
+
try {
|
|
1387
|
+
const data = await this.fetch.get(`/api/v1/functions/${name}`);
|
|
1388
|
+
return { data, error: null };
|
|
1389
|
+
} catch (error) {
|
|
1390
|
+
return { data: null, error };
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Update an existing edge function
|
|
1395
|
+
*
|
|
1396
|
+
* @param name - Function name
|
|
1397
|
+
* @param updates - Fields to update
|
|
1398
|
+
* @returns Promise resolving to { data, error } tuple with updated function metadata
|
|
1399
|
+
*
|
|
1400
|
+
* @example
|
|
1401
|
+
* ```typescript
|
|
1402
|
+
* const { data, error } = await client.functions.update('my-function', {
|
|
1403
|
+
* enabled: false,
|
|
1404
|
+
* description: 'Updated description'
|
|
1405
|
+
* })
|
|
1406
|
+
* ```
|
|
1407
|
+
*/
|
|
1408
|
+
async update(name, updates) {
|
|
1409
|
+
try {
|
|
1410
|
+
const data = await this.fetch.put(`/api/v1/functions/${name}`, updates);
|
|
1411
|
+
return { data, error: null };
|
|
1412
|
+
} catch (error) {
|
|
1413
|
+
return { data: null, error };
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
/**
|
|
1417
|
+
* Delete an edge function
|
|
1418
|
+
*
|
|
1419
|
+
* @param name - Function name
|
|
1420
|
+
* @returns Promise resolving to { data, error } tuple
|
|
1421
|
+
*
|
|
1422
|
+
* @example
|
|
1423
|
+
* ```typescript
|
|
1424
|
+
* const { data, error } = await client.functions.delete('my-function')
|
|
1425
|
+
* ```
|
|
1426
|
+
*/
|
|
1427
|
+
async delete(name) {
|
|
1428
|
+
try {
|
|
1429
|
+
await this.fetch.delete(`/api/v1/functions/${name}`);
|
|
1430
|
+
return { data: null, error: null };
|
|
1431
|
+
} catch (error) {
|
|
1432
|
+
return { data: null, error };
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
/**
|
|
1436
|
+
* Get execution history for an edge function
|
|
1437
|
+
*
|
|
1438
|
+
* @param name - Function name
|
|
1439
|
+
* @param limit - Maximum number of executions to return (optional)
|
|
1440
|
+
* @returns Promise resolving to { data, error } tuple with execution records
|
|
1441
|
+
*
|
|
1442
|
+
* @example
|
|
1443
|
+
* ```typescript
|
|
1444
|
+
* const { data, error } = await client.functions.getExecutions('my-function', 10)
|
|
1445
|
+
* if (data) {
|
|
1446
|
+
* data.forEach(exec => {
|
|
1447
|
+
* console.log(`${exec.executed_at}: ${exec.status} (${exec.duration_ms}ms)`)
|
|
1448
|
+
* })
|
|
1449
|
+
* }
|
|
1450
|
+
* ```
|
|
1451
|
+
*/
|
|
1452
|
+
async getExecutions(name, limit) {
|
|
1453
|
+
try {
|
|
1454
|
+
const params = limit ? `?limit=${limit}` : "";
|
|
1455
|
+
const data = await this.fetch.get(
|
|
1456
|
+
`/api/v1/functions/${name}/executions${params}`
|
|
1457
|
+
);
|
|
1458
|
+
return { data, error: null };
|
|
1459
|
+
} catch (error) {
|
|
1460
|
+
return { data: null, error };
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
// src/settings.ts
|
|
1466
|
+
var SystemSettingsManager = class {
|
|
1467
|
+
constructor(fetch2) {
|
|
1468
|
+
this.fetch = fetch2;
|
|
1469
|
+
}
|
|
1470
|
+
/**
|
|
1471
|
+
* List all system settings
|
|
1472
|
+
*
|
|
1473
|
+
* @returns Promise resolving to ListSystemSettingsResponse
|
|
1474
|
+
*
|
|
1475
|
+
* @example
|
|
1476
|
+
* ```typescript
|
|
1477
|
+
* const response = await client.admin.settings.system.list()
|
|
1478
|
+
* console.log(response.settings)
|
|
1479
|
+
* ```
|
|
1480
|
+
*/
|
|
1481
|
+
async list() {
|
|
1482
|
+
const settings = await this.fetch.get(
|
|
1483
|
+
"/api/v1/admin/system/settings"
|
|
1484
|
+
);
|
|
1485
|
+
return { settings: Array.isArray(settings) ? settings : [] };
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Get a specific system setting by key
|
|
1489
|
+
*
|
|
1490
|
+
* @param key - Setting key (e.g., 'app.auth.enable_signup')
|
|
1491
|
+
* @returns Promise resolving to SystemSetting
|
|
1492
|
+
*
|
|
1493
|
+
* @example
|
|
1494
|
+
* ```typescript
|
|
1495
|
+
* const setting = await client.admin.settings.system.get('app.auth.enable_signup')
|
|
1496
|
+
* console.log(setting.value)
|
|
1497
|
+
* ```
|
|
1498
|
+
*/
|
|
1499
|
+
async get(key) {
|
|
1500
|
+
return await this.fetch.get(
|
|
1501
|
+
`/api/v1/admin/system/settings/${key}`
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
/**
|
|
1505
|
+
* Update or create a system setting
|
|
1506
|
+
*
|
|
1507
|
+
* @param key - Setting key
|
|
1508
|
+
* @param request - Update request with value and optional description
|
|
1509
|
+
* @returns Promise resolving to SystemSetting
|
|
1510
|
+
*
|
|
1511
|
+
* @example
|
|
1512
|
+
* ```typescript
|
|
1513
|
+
* const updated = await client.admin.settings.system.update('app.auth.enable_signup', {
|
|
1514
|
+
* value: { value: true },
|
|
1515
|
+
* description: 'Enable user signup'
|
|
1516
|
+
* })
|
|
1517
|
+
* ```
|
|
1518
|
+
*/
|
|
1519
|
+
async update(key, request) {
|
|
1520
|
+
return await this.fetch.put(
|
|
1521
|
+
`/api/v1/admin/system/settings/${key}`,
|
|
1522
|
+
request
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Delete a system setting
|
|
1527
|
+
*
|
|
1528
|
+
* @param key - Setting key to delete
|
|
1529
|
+
* @returns Promise<void>
|
|
1530
|
+
*
|
|
1531
|
+
* @example
|
|
1532
|
+
* ```typescript
|
|
1533
|
+
* await client.admin.settings.system.delete('app.auth.enable_signup')
|
|
1534
|
+
* ```
|
|
1535
|
+
*/
|
|
1536
|
+
async delete(key) {
|
|
1537
|
+
await this.fetch.delete(`/api/v1/admin/system/settings/${key}`);
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
var AppSettingsManager = class {
|
|
1541
|
+
constructor(fetch2) {
|
|
1542
|
+
this.fetch = fetch2;
|
|
1543
|
+
}
|
|
1544
|
+
/**
|
|
1545
|
+
* Get all application settings
|
|
1546
|
+
*
|
|
1547
|
+
* Returns structured settings for authentication, features, email, and security.
|
|
1548
|
+
*
|
|
1549
|
+
* @returns Promise resolving to AppSettings
|
|
1550
|
+
*
|
|
1551
|
+
* @example
|
|
1552
|
+
* ```typescript
|
|
1553
|
+
* const settings = await client.admin.settings.app.get()
|
|
1554
|
+
*
|
|
1555
|
+
* console.log('Signup enabled:', settings.authentication.enable_signup)
|
|
1556
|
+
* console.log('Realtime enabled:', settings.features.enable_realtime)
|
|
1557
|
+
* console.log('Email provider:', settings.email.provider)
|
|
1558
|
+
* ```
|
|
1559
|
+
*/
|
|
1560
|
+
async get() {
|
|
1561
|
+
return await this.fetch.get("/api/v1/admin/app/settings");
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Update application settings
|
|
1565
|
+
*
|
|
1566
|
+
* Supports partial updates - only provide the fields you want to change.
|
|
1567
|
+
*
|
|
1568
|
+
* @param request - Settings to update (partial update supported)
|
|
1569
|
+
* @returns Promise resolving to AppSettings - Updated settings
|
|
1570
|
+
*
|
|
1571
|
+
* @example
|
|
1572
|
+
* ```typescript
|
|
1573
|
+
* // Update authentication settings
|
|
1574
|
+
* const updated = await client.admin.settings.app.update({
|
|
1575
|
+
* authentication: {
|
|
1576
|
+
* enable_signup: true,
|
|
1577
|
+
* password_min_length: 12
|
|
1578
|
+
* }
|
|
1579
|
+
* })
|
|
1580
|
+
*
|
|
1581
|
+
* // Update multiple categories
|
|
1582
|
+
* await client.admin.settings.app.update({
|
|
1583
|
+
* authentication: { enable_signup: false },
|
|
1584
|
+
* features: { enable_realtime: true },
|
|
1585
|
+
* security: { enable_global_rate_limit: true }
|
|
1586
|
+
* })
|
|
1587
|
+
* ```
|
|
1588
|
+
*/
|
|
1589
|
+
async update(request) {
|
|
1590
|
+
return await this.fetch.put(
|
|
1591
|
+
"/api/v1/admin/app/settings",
|
|
1592
|
+
request
|
|
1593
|
+
);
|
|
1594
|
+
}
|
|
1595
|
+
/**
|
|
1596
|
+
* Reset all application settings to defaults
|
|
1597
|
+
*
|
|
1598
|
+
* This will delete all custom settings and return to default values.
|
|
1599
|
+
*
|
|
1600
|
+
* @returns Promise resolving to AppSettings - Default settings
|
|
1601
|
+
*
|
|
1602
|
+
* @example
|
|
1603
|
+
* ```typescript
|
|
1604
|
+
* const defaults = await client.admin.settings.app.reset()
|
|
1605
|
+
* console.log('Settings reset to defaults:', defaults)
|
|
1606
|
+
* ```
|
|
1607
|
+
*/
|
|
1608
|
+
async reset() {
|
|
1609
|
+
return await this.fetch.post(
|
|
1610
|
+
"/api/v1/admin/app/settings/reset",
|
|
1611
|
+
{}
|
|
1612
|
+
);
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* Enable user signup
|
|
1616
|
+
*
|
|
1617
|
+
* Convenience method to enable user registration.
|
|
1618
|
+
*
|
|
1619
|
+
* @returns Promise resolving to AppSettings
|
|
1620
|
+
*
|
|
1621
|
+
* @example
|
|
1622
|
+
* ```typescript
|
|
1623
|
+
* await client.admin.settings.app.enableSignup()
|
|
1624
|
+
* ```
|
|
1625
|
+
*/
|
|
1626
|
+
async enableSignup() {
|
|
1627
|
+
return await this.update({
|
|
1628
|
+
authentication: { enable_signup: true }
|
|
1629
|
+
});
|
|
1630
|
+
}
|
|
1631
|
+
/**
|
|
1632
|
+
* Disable user signup
|
|
1633
|
+
*
|
|
1634
|
+
* Convenience method to disable user registration.
|
|
1635
|
+
*
|
|
1636
|
+
* @returns Promise resolving to AppSettings
|
|
1637
|
+
*
|
|
1638
|
+
* @example
|
|
1639
|
+
* ```typescript
|
|
1640
|
+
* await client.admin.settings.app.disableSignup()
|
|
1641
|
+
* ```
|
|
1642
|
+
*/
|
|
1643
|
+
async disableSignup() {
|
|
1644
|
+
return await this.update({
|
|
1645
|
+
authentication: { enable_signup: false }
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
/**
|
|
1649
|
+
* Update password minimum length
|
|
1650
|
+
*
|
|
1651
|
+
* Convenience method to set password requirements.
|
|
1652
|
+
*
|
|
1653
|
+
* @param length - Minimum password length (8-128 characters)
|
|
1654
|
+
* @returns Promise resolving to AppSettings
|
|
1655
|
+
*
|
|
1656
|
+
* @example
|
|
1657
|
+
* ```typescript
|
|
1658
|
+
* await client.admin.settings.app.setPasswordMinLength(12)
|
|
1659
|
+
* ```
|
|
1660
|
+
*/
|
|
1661
|
+
async setPasswordMinLength(length) {
|
|
1662
|
+
if (length < 8 || length > 128) {
|
|
1663
|
+
throw new Error(
|
|
1664
|
+
"Password minimum length must be between 8 and 128 characters"
|
|
1665
|
+
);
|
|
1666
|
+
}
|
|
1667
|
+
return await this.update({
|
|
1668
|
+
authentication: { password_min_length: length }
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
/**
|
|
1672
|
+
* Enable or disable a feature
|
|
1673
|
+
*
|
|
1674
|
+
* Convenience method to toggle feature flags.
|
|
1675
|
+
*
|
|
1676
|
+
* @param feature - Feature name ('realtime' | 'storage' | 'functions')
|
|
1677
|
+
* @param enabled - Whether to enable or disable the feature
|
|
1678
|
+
* @returns Promise resolving to AppSettings
|
|
1679
|
+
*
|
|
1680
|
+
* @example
|
|
1681
|
+
* ```typescript
|
|
1682
|
+
* // Enable realtime
|
|
1683
|
+
* await client.admin.settings.app.setFeature('realtime', true)
|
|
1684
|
+
*
|
|
1685
|
+
* // Disable storage
|
|
1686
|
+
* await client.admin.settings.app.setFeature('storage', false)
|
|
1687
|
+
* ```
|
|
1688
|
+
*/
|
|
1689
|
+
async setFeature(feature, enabled) {
|
|
1690
|
+
const featureKey = feature === "realtime" ? "enable_realtime" : feature === "storage" ? "enable_storage" : "enable_functions";
|
|
1691
|
+
return await this.update({
|
|
1692
|
+
features: { [featureKey]: enabled }
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Enable or disable global rate limiting
|
|
1697
|
+
*
|
|
1698
|
+
* Convenience method to toggle global rate limiting.
|
|
1699
|
+
*
|
|
1700
|
+
* @param enabled - Whether to enable rate limiting
|
|
1701
|
+
* @returns Promise resolving to AppSettings
|
|
1702
|
+
*
|
|
1703
|
+
* @example
|
|
1704
|
+
* ```typescript
|
|
1705
|
+
* await client.admin.settings.app.setRateLimiting(true)
|
|
1706
|
+
* ```
|
|
1707
|
+
*/
|
|
1708
|
+
async setRateLimiting(enabled) {
|
|
1709
|
+
return await this.update({
|
|
1710
|
+
security: { enable_global_rate_limit: enabled }
|
|
1711
|
+
});
|
|
1712
|
+
}
|
|
1713
|
+
/**
|
|
1714
|
+
* Configure SMTP email provider
|
|
1715
|
+
*
|
|
1716
|
+
* Convenience method to set up SMTP email delivery.
|
|
1717
|
+
*
|
|
1718
|
+
* @param config - SMTP configuration
|
|
1719
|
+
* @returns Promise resolving to AppSettings
|
|
1720
|
+
*
|
|
1721
|
+
* @example
|
|
1722
|
+
* ```typescript
|
|
1723
|
+
* await client.admin.settings.app.configureSMTP({
|
|
1724
|
+
* host: 'smtp.gmail.com',
|
|
1725
|
+
* port: 587,
|
|
1726
|
+
* username: 'your-email@gmail.com',
|
|
1727
|
+
* password: 'your-app-password',
|
|
1728
|
+
* use_tls: true,
|
|
1729
|
+
* from_address: 'noreply@yourapp.com',
|
|
1730
|
+
* from_name: 'Your App'
|
|
1731
|
+
* })
|
|
1732
|
+
* ```
|
|
1733
|
+
*/
|
|
1734
|
+
async configureSMTP(config) {
|
|
1735
|
+
return await this.update({
|
|
1736
|
+
email: {
|
|
1737
|
+
enabled: true,
|
|
1738
|
+
provider: "smtp",
|
|
1739
|
+
from_address: config.from_address,
|
|
1740
|
+
from_name: config.from_name,
|
|
1741
|
+
reply_to_address: config.reply_to_address,
|
|
1742
|
+
smtp: {
|
|
1743
|
+
host: config.host,
|
|
1744
|
+
port: config.port,
|
|
1745
|
+
username: config.username,
|
|
1746
|
+
password: config.password,
|
|
1747
|
+
use_tls: config.use_tls
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Configure SendGrid email provider
|
|
1754
|
+
*
|
|
1755
|
+
* Convenience method to set up SendGrid email delivery.
|
|
1756
|
+
*
|
|
1757
|
+
* @param apiKey - SendGrid API key
|
|
1758
|
+
* @param options - Optional from address, name, and reply-to
|
|
1759
|
+
* @returns Promise resolving to AppSettings
|
|
1760
|
+
*
|
|
1761
|
+
* @example
|
|
1762
|
+
* ```typescript
|
|
1763
|
+
* await client.admin.settings.app.configureSendGrid('SG.xxx', {
|
|
1764
|
+
* from_address: 'noreply@yourapp.com',
|
|
1765
|
+
* from_name: 'Your App'
|
|
1766
|
+
* })
|
|
1767
|
+
* ```
|
|
1768
|
+
*/
|
|
1769
|
+
async configureSendGrid(apiKey, options) {
|
|
1770
|
+
return await this.update({
|
|
1771
|
+
email: {
|
|
1772
|
+
enabled: true,
|
|
1773
|
+
provider: "sendgrid",
|
|
1774
|
+
from_address: options?.from_address,
|
|
1775
|
+
from_name: options?.from_name,
|
|
1776
|
+
reply_to_address: options?.reply_to_address,
|
|
1777
|
+
sendgrid: {
|
|
1778
|
+
api_key: apiKey
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
});
|
|
1782
|
+
}
|
|
1783
|
+
/**
|
|
1784
|
+
* Configure Mailgun email provider
|
|
1785
|
+
*
|
|
1786
|
+
* Convenience method to set up Mailgun email delivery.
|
|
1787
|
+
*
|
|
1788
|
+
* @param apiKey - Mailgun API key
|
|
1789
|
+
* @param domain - Mailgun domain
|
|
1790
|
+
* @param options - Optional EU region flag and email addresses
|
|
1791
|
+
* @returns Promise resolving to AppSettings
|
|
1792
|
+
*
|
|
1793
|
+
* @example
|
|
1794
|
+
* ```typescript
|
|
1795
|
+
* await client.admin.settings.app.configureMailgun('key-xxx', 'mg.yourapp.com', {
|
|
1796
|
+
* eu_region: false,
|
|
1797
|
+
* from_address: 'noreply@yourapp.com',
|
|
1798
|
+
* from_name: 'Your App'
|
|
1799
|
+
* })
|
|
1800
|
+
* ```
|
|
1801
|
+
*/
|
|
1802
|
+
async configureMailgun(apiKey, domain, options) {
|
|
1803
|
+
return await this.update({
|
|
1804
|
+
email: {
|
|
1805
|
+
enabled: true,
|
|
1806
|
+
provider: "mailgun",
|
|
1807
|
+
from_address: options?.from_address,
|
|
1808
|
+
from_name: options?.from_name,
|
|
1809
|
+
reply_to_address: options?.reply_to_address,
|
|
1810
|
+
mailgun: {
|
|
1811
|
+
api_key: apiKey,
|
|
1812
|
+
domain,
|
|
1813
|
+
eu_region: options?.eu_region ?? false
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
});
|
|
1817
|
+
}
|
|
1818
|
+
/**
|
|
1819
|
+
* Configure AWS SES email provider
|
|
1820
|
+
*
|
|
1821
|
+
* Convenience method to set up AWS SES email delivery.
|
|
1822
|
+
*
|
|
1823
|
+
* @param accessKeyId - AWS access key ID
|
|
1824
|
+
* @param secretAccessKey - AWS secret access key
|
|
1825
|
+
* @param region - AWS region (e.g., 'us-east-1')
|
|
1826
|
+
* @param options - Optional email addresses
|
|
1827
|
+
* @returns Promise resolving to AppSettings
|
|
1828
|
+
*
|
|
1829
|
+
* @example
|
|
1830
|
+
* ```typescript
|
|
1831
|
+
* await client.admin.settings.app.configureSES(
|
|
1832
|
+
* 'AKIAIOSFODNN7EXAMPLE',
|
|
1833
|
+
* 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
|
|
1834
|
+
* 'us-east-1',
|
|
1835
|
+
* {
|
|
1836
|
+
* from_address: 'noreply@yourapp.com',
|
|
1837
|
+
* from_name: 'Your App'
|
|
1838
|
+
* }
|
|
1839
|
+
* )
|
|
1840
|
+
* ```
|
|
1841
|
+
*/
|
|
1842
|
+
async configureSES(accessKeyId, secretAccessKey, region, options) {
|
|
1843
|
+
return await this.update({
|
|
1844
|
+
email: {
|
|
1845
|
+
enabled: true,
|
|
1846
|
+
provider: "ses",
|
|
1847
|
+
from_address: options?.from_address,
|
|
1848
|
+
from_name: options?.from_name,
|
|
1849
|
+
reply_to_address: options?.reply_to_address,
|
|
1850
|
+
ses: {
|
|
1851
|
+
access_key_id: accessKeyId,
|
|
1852
|
+
secret_access_key: secretAccessKey,
|
|
1853
|
+
region
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
});
|
|
1857
|
+
}
|
|
1858
|
+
/**
|
|
1859
|
+
* Enable or disable email functionality
|
|
990
1860
|
*
|
|
991
|
-
*
|
|
1861
|
+
* Convenience method to toggle email system on/off.
|
|
1862
|
+
*
|
|
1863
|
+
* @param enabled - Whether to enable email
|
|
1864
|
+
* @returns Promise resolving to AppSettings
|
|
992
1865
|
*
|
|
993
1866
|
* @example
|
|
994
1867
|
* ```typescript
|
|
995
|
-
*
|
|
996
|
-
* console.log(response.settings)
|
|
1868
|
+
* await client.admin.settings.app.setEmailEnabled(true)
|
|
997
1869
|
* ```
|
|
998
1870
|
*/
|
|
999
|
-
async
|
|
1000
|
-
|
|
1001
|
-
|
|
1871
|
+
async setEmailEnabled(enabled) {
|
|
1872
|
+
return await this.update({
|
|
1873
|
+
email: { enabled }
|
|
1874
|
+
});
|
|
1002
1875
|
}
|
|
1003
1876
|
/**
|
|
1004
|
-
*
|
|
1877
|
+
* Configure password complexity requirements
|
|
1005
1878
|
*
|
|
1006
|
-
*
|
|
1007
|
-
*
|
|
1879
|
+
* Convenience method to set password validation rules.
|
|
1880
|
+
*
|
|
1881
|
+
* @param requirements - Password complexity requirements
|
|
1882
|
+
* @returns Promise resolving to AppSettings
|
|
1008
1883
|
*
|
|
1009
1884
|
* @example
|
|
1010
1885
|
* ```typescript
|
|
1011
|
-
*
|
|
1012
|
-
*
|
|
1886
|
+
* await client.admin.settings.app.setPasswordComplexity({
|
|
1887
|
+
* min_length: 12,
|
|
1888
|
+
* require_uppercase: true,
|
|
1889
|
+
* require_lowercase: true,
|
|
1890
|
+
* require_number: true,
|
|
1891
|
+
* require_special: true
|
|
1892
|
+
* })
|
|
1013
1893
|
* ```
|
|
1014
1894
|
*/
|
|
1015
|
-
async
|
|
1016
|
-
return await this.
|
|
1895
|
+
async setPasswordComplexity(requirements) {
|
|
1896
|
+
return await this.update({
|
|
1897
|
+
authentication: {
|
|
1898
|
+
password_min_length: requirements.min_length,
|
|
1899
|
+
password_require_uppercase: requirements.require_uppercase,
|
|
1900
|
+
password_require_lowercase: requirements.require_lowercase,
|
|
1901
|
+
password_require_number: requirements.require_number,
|
|
1902
|
+
password_require_special: requirements.require_special
|
|
1903
|
+
}
|
|
1904
|
+
});
|
|
1017
1905
|
}
|
|
1018
1906
|
/**
|
|
1019
|
-
*
|
|
1907
|
+
* Configure session settings
|
|
1020
1908
|
*
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1023
|
-
* @
|
|
1909
|
+
* Convenience method to set session timeout and limits.
|
|
1910
|
+
*
|
|
1911
|
+
* @param timeoutMinutes - Session timeout in minutes (0 for no timeout)
|
|
1912
|
+
* @param maxSessionsPerUser - Maximum concurrent sessions per user (0 for unlimited)
|
|
1913
|
+
* @returns Promise resolving to AppSettings
|
|
1024
1914
|
*
|
|
1025
1915
|
* @example
|
|
1026
1916
|
* ```typescript
|
|
1027
|
-
*
|
|
1028
|
-
*
|
|
1029
|
-
* description: 'Enable user signup'
|
|
1030
|
-
* })
|
|
1917
|
+
* // 30 minute sessions, max 3 devices per user
|
|
1918
|
+
* await client.admin.settings.app.setSessionSettings(30, 3)
|
|
1031
1919
|
* ```
|
|
1032
1920
|
*/
|
|
1033
|
-
async
|
|
1034
|
-
return await this.
|
|
1921
|
+
async setSessionSettings(timeoutMinutes, maxSessionsPerUser) {
|
|
1922
|
+
return await this.update({
|
|
1923
|
+
authentication: {
|
|
1924
|
+
session_timeout_minutes: timeoutMinutes,
|
|
1925
|
+
max_sessions_per_user: maxSessionsPerUser
|
|
1926
|
+
}
|
|
1927
|
+
});
|
|
1035
1928
|
}
|
|
1036
1929
|
/**
|
|
1037
|
-
*
|
|
1930
|
+
* Enable or disable email verification requirement
|
|
1038
1931
|
*
|
|
1039
|
-
*
|
|
1040
|
-
*
|
|
1932
|
+
* Convenience method to require email verification for new signups.
|
|
1933
|
+
*
|
|
1934
|
+
* @param required - Whether to require email verification
|
|
1935
|
+
* @returns Promise resolving to AppSettings
|
|
1041
1936
|
*
|
|
1042
1937
|
* @example
|
|
1043
1938
|
* ```typescript
|
|
1044
|
-
* await client.admin.settings.
|
|
1939
|
+
* await client.admin.settings.app.setEmailVerificationRequired(true)
|
|
1045
1940
|
* ```
|
|
1046
1941
|
*/
|
|
1047
|
-
async
|
|
1048
|
-
await this.
|
|
1942
|
+
async setEmailVerificationRequired(required) {
|
|
1943
|
+
return await this.update({
|
|
1944
|
+
authentication: { require_email_verification: required }
|
|
1945
|
+
});
|
|
1049
1946
|
}
|
|
1050
1947
|
};
|
|
1051
|
-
var
|
|
1948
|
+
var CustomSettingsManager = class {
|
|
1052
1949
|
constructor(fetch2) {
|
|
1053
1950
|
this.fetch = fetch2;
|
|
1054
1951
|
}
|
|
1055
1952
|
/**
|
|
1056
|
-
*
|
|
1057
|
-
*
|
|
1058
|
-
* Returns structured settings for authentication, features, email, and security.
|
|
1953
|
+
* Create a new custom setting
|
|
1059
1954
|
*
|
|
1060
|
-
* @
|
|
1955
|
+
* @param request - Custom setting creation request
|
|
1956
|
+
* @returns Promise resolving to CustomSetting
|
|
1061
1957
|
*
|
|
1062
1958
|
* @example
|
|
1063
1959
|
* ```typescript
|
|
1064
|
-
* const
|
|
1065
|
-
*
|
|
1066
|
-
*
|
|
1067
|
-
*
|
|
1068
|
-
*
|
|
1960
|
+
* const setting = await client.admin.settings.custom.create({
|
|
1961
|
+
* key: 'api.quotas',
|
|
1962
|
+
* value: { free: 1000, pro: 10000, enterprise: 100000 },
|
|
1963
|
+
* value_type: 'json',
|
|
1964
|
+
* description: 'API request quotas by tier',
|
|
1965
|
+
* metadata: { category: 'billing' }
|
|
1966
|
+
* })
|
|
1069
1967
|
* ```
|
|
1070
1968
|
*/
|
|
1071
|
-
async
|
|
1072
|
-
return await this.fetch.
|
|
1969
|
+
async create(request) {
|
|
1970
|
+
return await this.fetch.post(
|
|
1971
|
+
"/api/v1/admin/settings/custom",
|
|
1972
|
+
request
|
|
1973
|
+
);
|
|
1073
1974
|
}
|
|
1074
1975
|
/**
|
|
1075
|
-
*
|
|
1976
|
+
* List all custom settings
|
|
1076
1977
|
*
|
|
1077
|
-
*
|
|
1978
|
+
* @returns Promise resolving to ListCustomSettingsResponse
|
|
1078
1979
|
*
|
|
1079
|
-
* @
|
|
1080
|
-
*
|
|
1980
|
+
* @example
|
|
1981
|
+
* ```typescript
|
|
1982
|
+
* const response = await client.admin.settings.custom.list()
|
|
1983
|
+
* console.log(response.settings)
|
|
1984
|
+
* ```
|
|
1985
|
+
*/
|
|
1986
|
+
async list() {
|
|
1987
|
+
const settings = await this.fetch.get(
|
|
1988
|
+
"/api/v1/admin/settings/custom"
|
|
1989
|
+
);
|
|
1990
|
+
return { settings: Array.isArray(settings) ? settings : [] };
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* Get a specific custom setting by key
|
|
1994
|
+
*
|
|
1995
|
+
* @param key - Setting key (e.g., 'feature.dark_mode')
|
|
1996
|
+
* @returns Promise resolving to CustomSetting
|
|
1081
1997
|
*
|
|
1082
1998
|
* @example
|
|
1083
1999
|
* ```typescript
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
2000
|
+
* const setting = await client.admin.settings.custom.get('feature.dark_mode')
|
|
2001
|
+
* console.log(setting.value)
|
|
2002
|
+
* ```
|
|
2003
|
+
*/
|
|
2004
|
+
async get(key) {
|
|
2005
|
+
return await this.fetch.get(
|
|
2006
|
+
`/api/v1/admin/settings/custom/${key}`
|
|
2007
|
+
);
|
|
2008
|
+
}
|
|
2009
|
+
/**
|
|
2010
|
+
* Update an existing custom setting
|
|
1091
2011
|
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
2012
|
+
* @param key - Setting key
|
|
2013
|
+
* @param request - Update request with new values
|
|
2014
|
+
* @returns Promise resolving to CustomSetting
|
|
2015
|
+
*
|
|
2016
|
+
* @example
|
|
2017
|
+
* ```typescript
|
|
2018
|
+
* const updated = await client.admin.settings.custom.update('feature.dark_mode', {
|
|
2019
|
+
* value: { enabled: false },
|
|
2020
|
+
* description: 'Updated description'
|
|
1097
2021
|
* })
|
|
1098
2022
|
* ```
|
|
1099
2023
|
*/
|
|
1100
|
-
async update(request) {
|
|
1101
|
-
return await this.fetch.put(
|
|
2024
|
+
async update(key, request) {
|
|
2025
|
+
return await this.fetch.put(
|
|
2026
|
+
`/api/v1/admin/settings/custom/${key}`,
|
|
2027
|
+
request
|
|
2028
|
+
);
|
|
1102
2029
|
}
|
|
1103
2030
|
/**
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1106
|
-
* This will delete all custom settings and return to default values.
|
|
2031
|
+
* Delete a custom setting
|
|
1107
2032
|
*
|
|
1108
|
-
* @
|
|
2033
|
+
* @param key - Setting key to delete
|
|
2034
|
+
* @returns Promise<void>
|
|
1109
2035
|
*
|
|
1110
2036
|
* @example
|
|
1111
2037
|
* ```typescript
|
|
1112
|
-
*
|
|
1113
|
-
* console.log('Settings reset to defaults:', defaults)
|
|
2038
|
+
* await client.admin.settings.custom.delete('feature.dark_mode')
|
|
1114
2039
|
* ```
|
|
1115
2040
|
*/
|
|
1116
|
-
async
|
|
1117
|
-
|
|
2041
|
+
async delete(key) {
|
|
2042
|
+
await this.fetch.delete(`/api/v1/admin/settings/custom/${key}`);
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
2045
|
+
var EmailTemplateManager = class {
|
|
2046
|
+
constructor(fetch2) {
|
|
2047
|
+
this.fetch = fetch2;
|
|
1118
2048
|
}
|
|
1119
2049
|
/**
|
|
1120
|
-
*
|
|
1121
|
-
*
|
|
1122
|
-
* Convenience method to enable user registration.
|
|
2050
|
+
* List all email templates
|
|
1123
2051
|
*
|
|
1124
|
-
* @returns Promise resolving to
|
|
2052
|
+
* @returns Promise resolving to ListEmailTemplatesResponse
|
|
1125
2053
|
*
|
|
1126
2054
|
* @example
|
|
1127
2055
|
* ```typescript
|
|
1128
|
-
* await client.admin.
|
|
2056
|
+
* const response = await client.admin.emailTemplates.list()
|
|
2057
|
+
* console.log(response.templates)
|
|
1129
2058
|
* ```
|
|
1130
2059
|
*/
|
|
1131
|
-
async
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
2060
|
+
async list() {
|
|
2061
|
+
const templates = await this.fetch.get(
|
|
2062
|
+
"/api/v1/admin/email/templates"
|
|
2063
|
+
);
|
|
2064
|
+
return { templates: Array.isArray(templates) ? templates : [] };
|
|
1135
2065
|
}
|
|
1136
2066
|
/**
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
* Convenience method to disable user registration.
|
|
2067
|
+
* Get a specific email template by type
|
|
1140
2068
|
*
|
|
1141
|
-
* @
|
|
2069
|
+
* @param type - Template type (magic_link | verify_email | reset_password | invite_user)
|
|
2070
|
+
* @returns Promise resolving to EmailTemplate
|
|
1142
2071
|
*
|
|
1143
2072
|
* @example
|
|
1144
2073
|
* ```typescript
|
|
1145
|
-
* await client.admin.
|
|
2074
|
+
* const template = await client.admin.emailTemplates.get('magic_link')
|
|
2075
|
+
* console.log(template.subject)
|
|
2076
|
+
* console.log(template.html_body)
|
|
1146
2077
|
* ```
|
|
1147
2078
|
*/
|
|
1148
|
-
async
|
|
1149
|
-
return await this.
|
|
1150
|
-
|
|
1151
|
-
|
|
2079
|
+
async get(type) {
|
|
2080
|
+
return await this.fetch.get(
|
|
2081
|
+
`/api/v1/admin/email/templates/${type}`
|
|
2082
|
+
);
|
|
1152
2083
|
}
|
|
1153
2084
|
/**
|
|
1154
|
-
* Update
|
|
2085
|
+
* Update an email template
|
|
1155
2086
|
*
|
|
1156
|
-
*
|
|
2087
|
+
* Available template variables:
|
|
2088
|
+
* - magic_link: `{{.MagicLink}}`, `{{.AppName}}`, `{{.ExpiryMinutes}}`
|
|
2089
|
+
* - verify_email: `{{.VerificationLink}}`, `{{.AppName}}`
|
|
2090
|
+
* - reset_password: `{{.ResetLink}}`, `{{.AppName}}`, `{{.ExpiryMinutes}}`
|
|
2091
|
+
* - invite_user: `{{.InviteLink}}`, `{{.AppName}}`, `{{.InviterName}}`
|
|
1157
2092
|
*
|
|
1158
|
-
* @param
|
|
1159
|
-
* @
|
|
2093
|
+
* @param type - Template type to update
|
|
2094
|
+
* @param request - Update request with subject, html_body, and optional text_body
|
|
2095
|
+
* @returns Promise resolving to EmailTemplate
|
|
1160
2096
|
*
|
|
1161
2097
|
* @example
|
|
1162
2098
|
* ```typescript
|
|
1163
|
-
* await client.admin.
|
|
2099
|
+
* const updated = await client.admin.emailTemplates.update('magic_link', {
|
|
2100
|
+
* subject: 'Your Magic Link - Sign in to ' + '{{.AppName}}',
|
|
2101
|
+
* html_body: '<html><body><h1>Welcome!</h1><a href="' + '{{.MagicLink}}' + '">Sign In</a></body></html>',
|
|
2102
|
+
* text_body: 'Click here to sign in: ' + '{{.MagicLink}}'
|
|
2103
|
+
* })
|
|
1164
2104
|
* ```
|
|
1165
2105
|
*/
|
|
1166
|
-
async
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
authentication: { password_min_length: length }
|
|
1172
|
-
});
|
|
2106
|
+
async update(type, request) {
|
|
2107
|
+
return await this.fetch.put(
|
|
2108
|
+
`/api/v1/admin/email/templates/${type}`,
|
|
2109
|
+
request
|
|
2110
|
+
);
|
|
1173
2111
|
}
|
|
1174
2112
|
/**
|
|
1175
|
-
*
|
|
2113
|
+
* Reset an email template to default
|
|
1176
2114
|
*
|
|
1177
|
-
*
|
|
2115
|
+
* Removes any customizations and restores the template to its original state.
|
|
1178
2116
|
*
|
|
1179
|
-
* @param
|
|
1180
|
-
* @
|
|
1181
|
-
* @returns Promise resolving to AppSettings
|
|
2117
|
+
* @param type - Template type to reset
|
|
2118
|
+
* @returns Promise resolving to EmailTemplate - The default template
|
|
1182
2119
|
*
|
|
1183
2120
|
* @example
|
|
1184
2121
|
* ```typescript
|
|
1185
|
-
*
|
|
1186
|
-
* await client.admin.settings.app.setFeature('realtime', true)
|
|
1187
|
-
*
|
|
1188
|
-
* // Disable storage
|
|
1189
|
-
* await client.admin.settings.app.setFeature('storage', false)
|
|
2122
|
+
* const defaultTemplate = await client.admin.emailTemplates.reset('magic_link')
|
|
1190
2123
|
* ```
|
|
1191
2124
|
*/
|
|
1192
|
-
async
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
2125
|
+
async reset(type) {
|
|
2126
|
+
return await this.fetch.post(
|
|
2127
|
+
`/api/v1/admin/email/templates/${type}/reset`,
|
|
2128
|
+
{}
|
|
2129
|
+
);
|
|
1197
2130
|
}
|
|
1198
2131
|
/**
|
|
1199
|
-
*
|
|
2132
|
+
* Send a test email using the template
|
|
1200
2133
|
*
|
|
1201
|
-
*
|
|
2134
|
+
* Useful for previewing template changes before deploying to production.
|
|
1202
2135
|
*
|
|
1203
|
-
* @param
|
|
1204
|
-
* @
|
|
2136
|
+
* @param type - Template type to test
|
|
2137
|
+
* @param recipientEmail - Email address to send test to
|
|
2138
|
+
* @returns Promise<void>
|
|
1205
2139
|
*
|
|
1206
2140
|
* @example
|
|
1207
2141
|
* ```typescript
|
|
1208
|
-
* await client.admin.
|
|
2142
|
+
* await client.admin.emailTemplates.test('magic_link', 'test@example.com')
|
|
1209
2143
|
* ```
|
|
1210
2144
|
*/
|
|
1211
|
-
async
|
|
1212
|
-
|
|
1213
|
-
|
|
2145
|
+
async test(type, recipientEmail) {
|
|
2146
|
+
await this.fetch.post(`/api/v1/admin/email/templates/${type}/test`, {
|
|
2147
|
+
recipient_email: recipientEmail
|
|
1214
2148
|
});
|
|
1215
2149
|
}
|
|
1216
2150
|
};
|
|
@@ -1218,6 +2152,7 @@ var FluxbaseSettings = class {
|
|
|
1218
2152
|
constructor(fetch2) {
|
|
1219
2153
|
this.system = new SystemSettingsManager(fetch2);
|
|
1220
2154
|
this.app = new AppSettingsManager(fetch2);
|
|
2155
|
+
this.custom = new CustomSettingsManager(fetch2);
|
|
1221
2156
|
}
|
|
1222
2157
|
};
|
|
1223
2158
|
|
|
@@ -2240,6 +3175,7 @@ var FluxbaseAdmin = class {
|
|
|
2240
3175
|
this.oauth = new FluxbaseOAuth(fetch2);
|
|
2241
3176
|
this.impersonation = new ImpersonationManager(fetch2);
|
|
2242
3177
|
this.management = new FluxbaseManagement(fetch2);
|
|
3178
|
+
this.emailTemplates = new EmailTemplateManager(fetch2);
|
|
2243
3179
|
}
|
|
2244
3180
|
/**
|
|
2245
3181
|
* Set admin authentication token
|
|
@@ -2278,9 +3214,11 @@ var FluxbaseAdmin = class {
|
|
|
2278
3214
|
* ```
|
|
2279
3215
|
*/
|
|
2280
3216
|
async getSetupStatus() {
|
|
2281
|
-
return
|
|
2282
|
-
|
|
2283
|
-
|
|
3217
|
+
return wrapAsync(async () => {
|
|
3218
|
+
return await this.fetch.get(
|
|
3219
|
+
"/api/v1/admin/setup/status"
|
|
3220
|
+
);
|
|
3221
|
+
});
|
|
2284
3222
|
}
|
|
2285
3223
|
/**
|
|
2286
3224
|
* Perform initial admin setup
|
|
@@ -2306,12 +3244,14 @@ var FluxbaseAdmin = class {
|
|
|
2306
3244
|
* ```
|
|
2307
3245
|
*/
|
|
2308
3246
|
async setup(request) {
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
3247
|
+
return wrapAsync(async () => {
|
|
3248
|
+
const response = await this.fetch.post(
|
|
3249
|
+
"/api/v1/admin/setup",
|
|
3250
|
+
request
|
|
3251
|
+
);
|
|
3252
|
+
this.setToken(response.access_token);
|
|
3253
|
+
return response;
|
|
3254
|
+
});
|
|
2315
3255
|
}
|
|
2316
3256
|
/**
|
|
2317
3257
|
* Admin login
|
|
@@ -2334,12 +3274,14 @@ var FluxbaseAdmin = class {
|
|
|
2334
3274
|
* ```
|
|
2335
3275
|
*/
|
|
2336
3276
|
async login(request) {
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
3277
|
+
return wrapAsync(async () => {
|
|
3278
|
+
const response = await this.fetch.post(
|
|
3279
|
+
"/api/v1/admin/login",
|
|
3280
|
+
request
|
|
3281
|
+
);
|
|
3282
|
+
this.setToken(response.access_token);
|
|
3283
|
+
return response;
|
|
3284
|
+
});
|
|
2343
3285
|
}
|
|
2344
3286
|
/**
|
|
2345
3287
|
* Refresh admin access token
|
|
@@ -2358,12 +3300,14 @@ var FluxbaseAdmin = class {
|
|
|
2358
3300
|
* ```
|
|
2359
3301
|
*/
|
|
2360
3302
|
async refreshToken(request) {
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
3303
|
+
return wrapAsync(async () => {
|
|
3304
|
+
const response = await this.fetch.post(
|
|
3305
|
+
"/api/v1/admin/refresh",
|
|
3306
|
+
request
|
|
3307
|
+
);
|
|
3308
|
+
this.setToken(response.access_token);
|
|
3309
|
+
return response;
|
|
3310
|
+
});
|
|
2367
3311
|
}
|
|
2368
3312
|
/**
|
|
2369
3313
|
* Admin logout
|
|
@@ -2377,8 +3321,10 @@ var FluxbaseAdmin = class {
|
|
|
2377
3321
|
* ```
|
|
2378
3322
|
*/
|
|
2379
3323
|
async logout() {
|
|
2380
|
-
|
|
2381
|
-
|
|
3324
|
+
return wrapAsyncVoid(async () => {
|
|
3325
|
+
await this.fetch.post("/api/v1/admin/logout", {});
|
|
3326
|
+
this.clearToken();
|
|
3327
|
+
});
|
|
2382
3328
|
}
|
|
2383
3329
|
/**
|
|
2384
3330
|
* Get current admin user information
|
|
@@ -2393,7 +3339,9 @@ var FluxbaseAdmin = class {
|
|
|
2393
3339
|
* ```
|
|
2394
3340
|
*/
|
|
2395
3341
|
async me() {
|
|
2396
|
-
return
|
|
3342
|
+
return wrapAsync(async () => {
|
|
3343
|
+
return await this.fetch.get("/api/v1/admin/me");
|
|
3344
|
+
});
|
|
2397
3345
|
}
|
|
2398
3346
|
// ============================================================================
|
|
2399
3347
|
// User Management
|
|
@@ -2419,22 +3367,24 @@ var FluxbaseAdmin = class {
|
|
|
2419
3367
|
* ```
|
|
2420
3368
|
*/
|
|
2421
3369
|
async listUsers(options = {}) {
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
3370
|
+
return wrapAsync(async () => {
|
|
3371
|
+
const params = new URLSearchParams();
|
|
3372
|
+
if (options.exclude_admins !== void 0) {
|
|
3373
|
+
params.append("exclude_admins", String(options.exclude_admins));
|
|
3374
|
+
}
|
|
3375
|
+
if (options.search) {
|
|
3376
|
+
params.append("search", options.search);
|
|
3377
|
+
}
|
|
3378
|
+
if (options.limit !== void 0) {
|
|
3379
|
+
params.append("limit", String(options.limit));
|
|
3380
|
+
}
|
|
3381
|
+
if (options.type) {
|
|
3382
|
+
params.append("type", options.type);
|
|
3383
|
+
}
|
|
3384
|
+
const queryString = params.toString();
|
|
3385
|
+
const url = queryString ? `/api/v1/admin/users?${queryString}` : "/api/v1/admin/users";
|
|
3386
|
+
return await this.fetch.get(url);
|
|
3387
|
+
});
|
|
2438
3388
|
}
|
|
2439
3389
|
/**
|
|
2440
3390
|
* Get a user by ID
|
|
@@ -2457,8 +3407,10 @@ var FluxbaseAdmin = class {
|
|
|
2457
3407
|
* ```
|
|
2458
3408
|
*/
|
|
2459
3409
|
async getUserById(userId, type = "app") {
|
|
2460
|
-
|
|
2461
|
-
|
|
3410
|
+
return wrapAsync(async () => {
|
|
3411
|
+
const url = `/api/v1/admin/users/${userId}?type=${type}`;
|
|
3412
|
+
return await this.fetch.get(url);
|
|
3413
|
+
});
|
|
2462
3414
|
}
|
|
2463
3415
|
/**
|
|
2464
3416
|
* Invite a new user
|
|
@@ -2482,8 +3434,10 @@ var FluxbaseAdmin = class {
|
|
|
2482
3434
|
* ```
|
|
2483
3435
|
*/
|
|
2484
3436
|
async inviteUser(request, type = "app") {
|
|
2485
|
-
|
|
2486
|
-
|
|
3437
|
+
return wrapAsync(async () => {
|
|
3438
|
+
const url = `/api/v1/admin/users/invite?type=${type}`;
|
|
3439
|
+
return await this.fetch.post(url, request);
|
|
3440
|
+
});
|
|
2487
3441
|
}
|
|
2488
3442
|
/**
|
|
2489
3443
|
* Delete a user
|
|
@@ -2501,8 +3455,10 @@ var FluxbaseAdmin = class {
|
|
|
2501
3455
|
* ```
|
|
2502
3456
|
*/
|
|
2503
3457
|
async deleteUser(userId, type = "app") {
|
|
2504
|
-
|
|
2505
|
-
|
|
3458
|
+
return wrapAsync(async () => {
|
|
3459
|
+
const url = `/api/v1/admin/users/${userId}?type=${type}`;
|
|
3460
|
+
return await this.fetch.delete(url);
|
|
3461
|
+
});
|
|
2506
3462
|
}
|
|
2507
3463
|
/**
|
|
2508
3464
|
* Update user role
|
|
@@ -2521,8 +3477,10 @@ var FluxbaseAdmin = class {
|
|
|
2521
3477
|
* ```
|
|
2522
3478
|
*/
|
|
2523
3479
|
async updateUserRole(userId, role, type = "app") {
|
|
2524
|
-
|
|
2525
|
-
|
|
3480
|
+
return wrapAsync(async () => {
|
|
3481
|
+
const url = `/api/v1/admin/users/${userId}/role?type=${type}`;
|
|
3482
|
+
return await this.fetch.patch(url, { role });
|
|
3483
|
+
});
|
|
2526
3484
|
}
|
|
2527
3485
|
/**
|
|
2528
3486
|
* Reset user password
|
|
@@ -2540,8 +3498,10 @@ var FluxbaseAdmin = class {
|
|
|
2540
3498
|
* ```
|
|
2541
3499
|
*/
|
|
2542
3500
|
async resetUserPassword(userId, type = "app") {
|
|
2543
|
-
|
|
2544
|
-
|
|
3501
|
+
return wrapAsync(async () => {
|
|
3502
|
+
const url = `/api/v1/admin/users/${userId}/reset-password?type=${type}`;
|
|
3503
|
+
return await this.fetch.post(url, {});
|
|
3504
|
+
});
|
|
2545
3505
|
}
|
|
2546
3506
|
};
|
|
2547
3507
|
|
|
@@ -3099,24 +4059,47 @@ var QueryBuilder = class {
|
|
|
3099
4059
|
var FluxbaseClient = class {
|
|
3100
4060
|
/**
|
|
3101
4061
|
* Create a new Fluxbase client instance
|
|
3102
|
-
*
|
|
4062
|
+
*
|
|
4063
|
+
* @param fluxbaseUrl - The URL of your Fluxbase instance
|
|
4064
|
+
* @param fluxbaseKey - The anon key (JWT token with "anon" role). Generate using scripts/generate-keys.sh
|
|
4065
|
+
* @param options - Additional client configuration options
|
|
4066
|
+
*
|
|
4067
|
+
* @example
|
|
4068
|
+
* ```typescript
|
|
4069
|
+
* const client = new FluxbaseClient(
|
|
4070
|
+
* 'http://localhost:8080',
|
|
4071
|
+
* 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', // Anon JWT token
|
|
4072
|
+
* { timeout: 30000 }
|
|
4073
|
+
* )
|
|
4074
|
+
* ```
|
|
3103
4075
|
*/
|
|
3104
|
-
constructor(options) {
|
|
3105
|
-
this.
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
4076
|
+
constructor(fluxbaseUrl, fluxbaseKey, options) {
|
|
4077
|
+
this.fluxbaseUrl = fluxbaseUrl;
|
|
4078
|
+
this.fluxbaseKey = fluxbaseKey;
|
|
4079
|
+
const headers = {
|
|
4080
|
+
"apikey": fluxbaseKey,
|
|
4081
|
+
"Authorization": `Bearer ${fluxbaseKey}`,
|
|
4082
|
+
...options?.headers
|
|
4083
|
+
};
|
|
4084
|
+
this.fetch = new FluxbaseFetch(fluxbaseUrl, {
|
|
4085
|
+
headers,
|
|
4086
|
+
timeout: options?.timeout,
|
|
4087
|
+
debug: options?.debug
|
|
3109
4088
|
});
|
|
3110
4089
|
this.auth = new FluxbaseAuth(
|
|
3111
4090
|
this.fetch,
|
|
3112
|
-
options
|
|
3113
|
-
options
|
|
4091
|
+
options?.auth?.autoRefresh ?? true,
|
|
4092
|
+
options?.auth?.persist ?? true
|
|
3114
4093
|
);
|
|
3115
|
-
if (options
|
|
4094
|
+
if (options?.auth?.token) {
|
|
3116
4095
|
this.fetch.setAuthToken(options.auth.token);
|
|
3117
4096
|
}
|
|
3118
|
-
this.realtime = new FluxbaseRealtime(
|
|
4097
|
+
this.realtime = new FluxbaseRealtime(
|
|
4098
|
+
fluxbaseUrl,
|
|
4099
|
+
options?.auth?.token || null
|
|
4100
|
+
);
|
|
3119
4101
|
this.storage = new FluxbaseStorage(this.fetch);
|
|
4102
|
+
this.functions = new FluxbaseFunctions(this.fetch);
|
|
3120
4103
|
this.admin = new FluxbaseAdmin(this.fetch);
|
|
3121
4104
|
this.management = new FluxbaseManagement(this.fetch);
|
|
3122
4105
|
this.setupAuthSync();
|
|
@@ -3171,7 +4154,10 @@ var FluxbaseClient = class {
|
|
|
3171
4154
|
*/
|
|
3172
4155
|
async rpc(functionName, params) {
|
|
3173
4156
|
try {
|
|
3174
|
-
const data = await this.fetch.post(
|
|
4157
|
+
const data = await this.fetch.post(
|
|
4158
|
+
`/api/v1/rpc/${functionName}`,
|
|
4159
|
+
params || {}
|
|
4160
|
+
);
|
|
3175
4161
|
return { data, error: null };
|
|
3176
4162
|
} catch (error) {
|
|
3177
4163
|
return { data: null, error };
|
|
@@ -3211,6 +4197,36 @@ var FluxbaseClient = class {
|
|
|
3211
4197
|
this.fetch.setAuthToken(token);
|
|
3212
4198
|
this.realtime.setToken(token);
|
|
3213
4199
|
}
|
|
4200
|
+
/**
|
|
4201
|
+
* Create or get a realtime channel (Supabase-compatible alias)
|
|
4202
|
+
*
|
|
4203
|
+
* This is a convenience method that delegates to client.realtime.channel().
|
|
4204
|
+
* Both patterns work identically:
|
|
4205
|
+
* - client.channel('room-1') - Supabase-style
|
|
4206
|
+
* - client.realtime.channel('room-1') - Fluxbase-style
|
|
4207
|
+
*
|
|
4208
|
+
* @param name - Channel name
|
|
4209
|
+
* @returns RealtimeChannel instance
|
|
4210
|
+
*
|
|
4211
|
+
* @example
|
|
4212
|
+
* ```typescript
|
|
4213
|
+
* // Supabase-compatible usage
|
|
4214
|
+
* const channel = client.channel('room-1')
|
|
4215
|
+
* .on('postgres_changes', {
|
|
4216
|
+
* event: '*',
|
|
4217
|
+
* schema: 'public',
|
|
4218
|
+
* table: 'messages'
|
|
4219
|
+
* }, (payload) => {
|
|
4220
|
+
* console.log('Change:', payload)
|
|
4221
|
+
* })
|
|
4222
|
+
* .subscribe()
|
|
4223
|
+
* ```
|
|
4224
|
+
*
|
|
4225
|
+
* @category Realtime
|
|
4226
|
+
*/
|
|
4227
|
+
channel(name) {
|
|
4228
|
+
return this.realtime.channel(name);
|
|
4229
|
+
}
|
|
3214
4230
|
/**
|
|
3215
4231
|
* Get the internal HTTP client
|
|
3216
4232
|
*
|
|
@@ -3230,18 +4246,24 @@ var FluxbaseClient = class {
|
|
|
3230
4246
|
return this.fetch;
|
|
3231
4247
|
}
|
|
3232
4248
|
};
|
|
3233
|
-
function createClient(options) {
|
|
3234
|
-
return new FluxbaseClient(
|
|
4249
|
+
function createClient(fluxbaseUrl, fluxbaseKey, options) {
|
|
4250
|
+
return new FluxbaseClient(
|
|
4251
|
+
fluxbaseUrl,
|
|
4252
|
+
fluxbaseKey,
|
|
4253
|
+
options
|
|
4254
|
+
);
|
|
3235
4255
|
}
|
|
3236
4256
|
|
|
3237
4257
|
exports.APIKeysManager = APIKeysManager;
|
|
3238
4258
|
exports.AppSettingsManager = AppSettingsManager;
|
|
3239
4259
|
exports.AuthSettingsManager = AuthSettingsManager;
|
|
3240
4260
|
exports.DDLManager = DDLManager;
|
|
4261
|
+
exports.EmailTemplateManager = EmailTemplateManager;
|
|
3241
4262
|
exports.FluxbaseAdmin = FluxbaseAdmin;
|
|
3242
4263
|
exports.FluxbaseAuth = FluxbaseAuth;
|
|
3243
4264
|
exports.FluxbaseClient = FluxbaseClient;
|
|
3244
4265
|
exports.FluxbaseFetch = FluxbaseFetch;
|
|
4266
|
+
exports.FluxbaseFunctions = FluxbaseFunctions;
|
|
3245
4267
|
exports.FluxbaseManagement = FluxbaseManagement;
|
|
3246
4268
|
exports.FluxbaseOAuth = FluxbaseOAuth;
|
|
3247
4269
|
exports.FluxbaseRealtime = FluxbaseRealtime;
|