@baasix/sdk 0.1.19 → 0.1.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/README.md +147 -4
- package/dist/index.cjs +161 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +19 -5
- package/dist/index.d.ts +19 -5
- package/dist/index.js +161 -10
- package/dist/index.js.map +1 -1
- package/dist/modules/auth.cjs +140 -3
- package/dist/modules/auth.cjs.map +1 -1
- package/dist/modules/auth.d.cts +104 -4
- package/dist/modules/auth.d.ts +104 -4
- package/dist/modules/auth.js +140 -4
- package/dist/modules/auth.js.map +1 -1
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -3,7 +3,7 @@ export { a as HttpClientConfig, R as RequestOptions } from './client-BHbM3KOy.cj
|
|
|
3
3
|
import { S as StorageAdapter } from './types-BdjsGANq.cjs';
|
|
4
4
|
export { a as STORAGE_KEYS, b as StorageKey } from './types-BdjsGANq.cjs';
|
|
5
5
|
import { AuthModule } from './modules/auth.cjs';
|
|
6
|
-
export { InviteOptions, OAuthOptions, OAuthProvider, VerifyInviteResult } from './modules/auth.cjs';
|
|
6
|
+
export { AuthMethods, InviteOptions, LoginResult, OAuthOptions, OAuthProvider, SOCIAL_PROVIDERS, TwoFactorChallengeResponse, TwoFactorEnableResult, VerifyInviteResult } from './modules/auth.cjs';
|
|
7
7
|
import { ItemsModule } from './modules/items.cjs';
|
|
8
8
|
export { ImportResult, QueryBuilder } from './modules/items.cjs';
|
|
9
9
|
import { FilesModule } from './modules/files.cjs';
|
|
@@ -318,9 +318,21 @@ declare class PermissionsModule {
|
|
|
318
318
|
* action: 'update',
|
|
319
319
|
* fields: ['title', 'content', 'status'],
|
|
320
320
|
* conditions: {
|
|
321
|
-
* author_Id: { eq: '$CURRENT_USER' }
|
|
321
|
+
* author_Id: { eq: '$CURRENT_USER' } // USING: which rows may be updated
|
|
322
|
+
* },
|
|
323
|
+
* checkConditions: {
|
|
324
|
+
* author_Id: { eq: '$CURRENT_USER' } // WITH CHECK: what they may become
|
|
322
325
|
* }
|
|
323
326
|
* });
|
|
327
|
+
*
|
|
328
|
+
* // Create grants use checkConditions (conditions is rejected on create):
|
|
329
|
+
* await baasix.permissions.create({
|
|
330
|
+
* role_Id: 'user-role-uuid',
|
|
331
|
+
* collection: 'tasks',
|
|
332
|
+
* action: 'create',
|
|
333
|
+
* fields: ['*'],
|
|
334
|
+
* checkConditions: { owner_Id: { eq: '$CURRENT_USER' } }
|
|
335
|
+
* });
|
|
324
336
|
* ```
|
|
325
337
|
*/
|
|
326
338
|
create(data: CreatePermissionData): Promise<Permission>;
|
|
@@ -360,17 +372,18 @@ declare class PermissionsModule {
|
|
|
360
372
|
* @example
|
|
361
373
|
* ```typescript
|
|
362
374
|
* await baasix.permissions.createCrudPermissions('role-uuid', 'products', {
|
|
363
|
-
* create: { fields: ['name', 'price', '
|
|
375
|
+
* create: { fields: ['name', 'price'], checkConditions: { owner_Id: { eq: '$CURRENT_USER' } } },
|
|
364
376
|
* read: { fields: ['*'] },
|
|
365
|
-
* update: { fields: ['name', 'price', '
|
|
377
|
+
* update: { fields: ['name', 'price'], conditions: { owner_Id: { eq: '$CURRENT_USER' } } },
|
|
366
378
|
* delete: false
|
|
367
379
|
* });
|
|
368
380
|
* ```
|
|
369
381
|
*/
|
|
370
382
|
createCrudPermissions(roleId: string, collection: string, config: {
|
|
383
|
+
/** Create grants scope writes via checkConditions — `conditions` is rejected by the API on create. */
|
|
371
384
|
create?: {
|
|
372
385
|
fields?: string[];
|
|
373
|
-
|
|
386
|
+
checkConditions?: Permission["checkConditions"];
|
|
374
387
|
} | false;
|
|
375
388
|
read?: {
|
|
376
389
|
fields?: string[];
|
|
@@ -379,6 +392,7 @@ declare class PermissionsModule {
|
|
|
379
392
|
update?: {
|
|
380
393
|
fields?: string[];
|
|
381
394
|
conditions?: Permission["conditions"];
|
|
395
|
+
checkConditions?: Permission["checkConditions"];
|
|
382
396
|
} | false;
|
|
383
397
|
delete?: {
|
|
384
398
|
conditions?: Permission["conditions"];
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { a as HttpClientConfig, R as RequestOptions } from './client-D67LK80v.js
|
|
|
3
3
|
import { S as StorageAdapter } from './types-BdjsGANq.js';
|
|
4
4
|
export { a as STORAGE_KEYS, b as StorageKey } from './types-BdjsGANq.js';
|
|
5
5
|
import { AuthModule } from './modules/auth.js';
|
|
6
|
-
export { InviteOptions, OAuthOptions, OAuthProvider, VerifyInviteResult } from './modules/auth.js';
|
|
6
|
+
export { AuthMethods, InviteOptions, LoginResult, OAuthOptions, OAuthProvider, SOCIAL_PROVIDERS, TwoFactorChallengeResponse, TwoFactorEnableResult, VerifyInviteResult } from './modules/auth.js';
|
|
7
7
|
import { ItemsModule } from './modules/items.js';
|
|
8
8
|
export { ImportResult, QueryBuilder } from './modules/items.js';
|
|
9
9
|
import { FilesModule } from './modules/files.js';
|
|
@@ -318,9 +318,21 @@ declare class PermissionsModule {
|
|
|
318
318
|
* action: 'update',
|
|
319
319
|
* fields: ['title', 'content', 'status'],
|
|
320
320
|
* conditions: {
|
|
321
|
-
* author_Id: { eq: '$CURRENT_USER' }
|
|
321
|
+
* author_Id: { eq: '$CURRENT_USER' } // USING: which rows may be updated
|
|
322
|
+
* },
|
|
323
|
+
* checkConditions: {
|
|
324
|
+
* author_Id: { eq: '$CURRENT_USER' } // WITH CHECK: what they may become
|
|
322
325
|
* }
|
|
323
326
|
* });
|
|
327
|
+
*
|
|
328
|
+
* // Create grants use checkConditions (conditions is rejected on create):
|
|
329
|
+
* await baasix.permissions.create({
|
|
330
|
+
* role_Id: 'user-role-uuid',
|
|
331
|
+
* collection: 'tasks',
|
|
332
|
+
* action: 'create',
|
|
333
|
+
* fields: ['*'],
|
|
334
|
+
* checkConditions: { owner_Id: { eq: '$CURRENT_USER' } }
|
|
335
|
+
* });
|
|
324
336
|
* ```
|
|
325
337
|
*/
|
|
326
338
|
create(data: CreatePermissionData): Promise<Permission>;
|
|
@@ -360,17 +372,18 @@ declare class PermissionsModule {
|
|
|
360
372
|
* @example
|
|
361
373
|
* ```typescript
|
|
362
374
|
* await baasix.permissions.createCrudPermissions('role-uuid', 'products', {
|
|
363
|
-
* create: { fields: ['name', 'price', '
|
|
375
|
+
* create: { fields: ['name', 'price'], checkConditions: { owner_Id: { eq: '$CURRENT_USER' } } },
|
|
364
376
|
* read: { fields: ['*'] },
|
|
365
|
-
* update: { fields: ['name', 'price', '
|
|
377
|
+
* update: { fields: ['name', 'price'], conditions: { owner_Id: { eq: '$CURRENT_USER' } } },
|
|
366
378
|
* delete: false
|
|
367
379
|
* });
|
|
368
380
|
* ```
|
|
369
381
|
*/
|
|
370
382
|
createCrudPermissions(roleId: string, collection: string, config: {
|
|
383
|
+
/** Create grants scope writes via checkConditions — `conditions` is rejected by the API on create. */
|
|
371
384
|
create?: {
|
|
372
385
|
fields?: string[];
|
|
373
|
-
|
|
386
|
+
checkConditions?: Permission["checkConditions"];
|
|
374
387
|
} | false;
|
|
375
388
|
read?: {
|
|
376
389
|
fields?: string[];
|
|
@@ -379,6 +392,7 @@ declare class PermissionsModule {
|
|
|
379
392
|
update?: {
|
|
380
393
|
fields?: string[];
|
|
381
394
|
conditions?: Permission["conditions"];
|
|
395
|
+
checkConditions?: Permission["checkConditions"];
|
|
382
396
|
} | false;
|
|
383
397
|
delete?: {
|
|
384
398
|
conditions?: Permission["conditions"];
|
package/dist/index.js
CHANGED
|
@@ -190,7 +190,7 @@ var HttpClient = class {
|
|
|
190
190
|
} catch {
|
|
191
191
|
}
|
|
192
192
|
const message = errorData.error?.message || errorData.message || response.statusText || "Request failed";
|
|
193
|
-
const code = errorData.error?.code;
|
|
193
|
+
const code = errorData.error?.code ?? errorData.code;
|
|
194
194
|
const details = errorData.details;
|
|
195
195
|
return new BaasixError(message, response.status, code, details);
|
|
196
196
|
}
|
|
@@ -474,17 +474,123 @@ var MemoryStorageAdapter = class {
|
|
|
474
474
|
};
|
|
475
475
|
|
|
476
476
|
// src/modules/auth.ts
|
|
477
|
+
var SOCIAL_PROVIDERS = ["apple", "atlassian", "cognito", "discord", "dropbox", "facebook", "figma", "github", "gitlab", "google", "huggingface", "kakao", "kick", "line", "linear", "linkedin", "microsoft", "naver", "notion", "paybin", "paypal", "polar", "railway", "reddit", "roblox", "salesforce", "slack", "spotify", "tiktok", "twitch", "twitter", "vercel", "vk", "wechat", "zoom"];
|
|
477
478
|
var AuthModule = class {
|
|
478
479
|
client;
|
|
479
480
|
storage;
|
|
480
481
|
authMode;
|
|
481
482
|
onAuthStateChange;
|
|
482
483
|
currentUser = null;
|
|
484
|
+
authMethodsCache = null;
|
|
485
|
+
/**
|
|
486
|
+
* Two-factor authentication (TOTP) helpers.
|
|
487
|
+
*
|
|
488
|
+
* @example
|
|
489
|
+
* ```typescript
|
|
490
|
+
* const result = await baasix.auth.login({ email, password });
|
|
491
|
+
* if ("twoFactorRequired" in result && result.twoFactorRequired) {
|
|
492
|
+
* const { user, token } = await baasix.auth.twoFactor.verify(result.twoFactorToken, code);
|
|
493
|
+
* }
|
|
494
|
+
* ```
|
|
495
|
+
*/
|
|
496
|
+
twoFactor;
|
|
497
|
+
/**
|
|
498
|
+
* Passkey (WebAuthn) registration and authentication helpers.
|
|
499
|
+
* Browser-only: throws a `BaasixError` when called outside a browser
|
|
500
|
+
* environment (no `window`/`PublicKeyCredential`).
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* ```typescript
|
|
504
|
+
* // Register a passkey for the currently logged-in user
|
|
505
|
+
* await baasix.auth.passkey.register("My Laptop");
|
|
506
|
+
*
|
|
507
|
+
* // Authenticate with a passkey (no prior login required)
|
|
508
|
+
* const { user, token } = await baasix.auth.passkey.authenticate();
|
|
509
|
+
*
|
|
510
|
+
* // List and remove registered passkeys
|
|
511
|
+
* const passkeys = await baasix.auth.passkey.list();
|
|
512
|
+
* await baasix.auth.passkey.remove(passkeys[0].id);
|
|
513
|
+
* ```
|
|
514
|
+
*/
|
|
515
|
+
passkey = {
|
|
516
|
+
register: async (name) => {
|
|
517
|
+
this.assertBrowser();
|
|
518
|
+
const { startRegistration } = await import('@simplewebauthn/browser');
|
|
519
|
+
const options = await this.client.post("/auth/passkey/register/options", {});
|
|
520
|
+
const attestation = await startRegistration({ optionsJSON: options });
|
|
521
|
+
await this.client.post("/auth/passkey/register/verify", {
|
|
522
|
+
response: attestation,
|
|
523
|
+
name: name || null
|
|
524
|
+
});
|
|
525
|
+
return { verified: true };
|
|
526
|
+
},
|
|
527
|
+
authenticate: async (opts) => {
|
|
528
|
+
this.assertBrowser();
|
|
529
|
+
const { startAuthentication } = await import('@simplewebauthn/browser');
|
|
530
|
+
const { options, challengeId } = await this.client.post(
|
|
531
|
+
"/auth/passkey/authenticate/options",
|
|
532
|
+
{},
|
|
533
|
+
{ skipAuth: true }
|
|
534
|
+
);
|
|
535
|
+
const assertion = await startAuthentication({ optionsJSON: options });
|
|
536
|
+
const response = await this.client.post(
|
|
537
|
+
"/auth/passkey/authenticate/verify",
|
|
538
|
+
{ challengeId, response: assertion, authMode: opts?.authMode },
|
|
539
|
+
{ skipAuth: true }
|
|
540
|
+
);
|
|
541
|
+
await this.storeTokens(response);
|
|
542
|
+
this.emitAuthStateChange("SIGNED_IN", response.user);
|
|
543
|
+
return response;
|
|
544
|
+
},
|
|
545
|
+
list: async () => (await this.client.get("/auth/passkey")).passkeys,
|
|
546
|
+
remove: async (id) => {
|
|
547
|
+
await this.client.delete(`/auth/passkey/${encodeURIComponent(id)}`);
|
|
548
|
+
}
|
|
549
|
+
};
|
|
483
550
|
constructor(config) {
|
|
484
551
|
this.client = config.client;
|
|
485
552
|
this.storage = config.storage;
|
|
486
553
|
this.authMode = config.authMode;
|
|
487
554
|
this.onAuthStateChange = config.onAuthStateChange;
|
|
555
|
+
this.twoFactor = {
|
|
556
|
+
verify: async (twoFactorToken, code, opts) => {
|
|
557
|
+
const response = await this.client.post(
|
|
558
|
+
"/auth/2fa/verify",
|
|
559
|
+
{
|
|
560
|
+
twoFactorToken,
|
|
561
|
+
code,
|
|
562
|
+
authMode: opts?.authMode,
|
|
563
|
+
authType: opts?.authType
|
|
564
|
+
},
|
|
565
|
+
{ skipAuth: true }
|
|
566
|
+
);
|
|
567
|
+
await this.storeTokens(response);
|
|
568
|
+
this.emitAuthStateChange("SIGNED_IN", response.user);
|
|
569
|
+
return response;
|
|
570
|
+
},
|
|
571
|
+
enable: () => {
|
|
572
|
+
return this.client.post("/auth/2fa/enable");
|
|
573
|
+
},
|
|
574
|
+
verifySetup: (code) => {
|
|
575
|
+
return this.client.post("/auth/2fa/verify-setup", {
|
|
576
|
+
code
|
|
577
|
+
});
|
|
578
|
+
},
|
|
579
|
+
disable: (password) => {
|
|
580
|
+
return this.client.post("/auth/2fa/disable", {
|
|
581
|
+
password
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Assert that we're running in a browser environment with WebAuthn support.
|
|
588
|
+
* Throws a `BaasixError` otherwise.
|
|
589
|
+
*/
|
|
590
|
+
assertBrowser() {
|
|
591
|
+
if (typeof window === "undefined" || !window.PublicKeyCredential) {
|
|
592
|
+
throw new BaasixError("Passkeys are only available in a browser", 400);
|
|
593
|
+
}
|
|
488
594
|
}
|
|
489
595
|
/**
|
|
490
596
|
* Emit an authentication state change event
|
|
@@ -581,9 +687,39 @@ var AuthModule = class {
|
|
|
581
687
|
},
|
|
582
688
|
{ skipAuth: true }
|
|
583
689
|
);
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
690
|
+
if ("twoFactorRequired" in response && response.twoFactorRequired) {
|
|
691
|
+
return response;
|
|
692
|
+
}
|
|
693
|
+
const authResponse = response;
|
|
694
|
+
await this.storeTokens(authResponse);
|
|
695
|
+
this.emitAuthStateChange("SIGNED_IN", authResponse.user);
|
|
696
|
+
return authResponse;
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Discover which authentication methods are enabled for this project
|
|
700
|
+
* (registration, email/password, magic link, passkey, 2FA, and the list
|
|
701
|
+
* of configured social/OAuth providers). Result is cached per instance;
|
|
702
|
+
* pass `force: true` to bypass the cache and refetch.
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```typescript
|
|
706
|
+
* const methods = await baasix.auth.getAuthMethods();
|
|
707
|
+
* if (methods.socialProviders.includes("google")) {
|
|
708
|
+
* // show "Sign in with Google"
|
|
709
|
+
* }
|
|
710
|
+
* ```
|
|
711
|
+
*/
|
|
712
|
+
async getAuthMethods(force = false) {
|
|
713
|
+
if (this.authMethodsCache && !force) {
|
|
714
|
+
return this.authMethodsCache;
|
|
715
|
+
}
|
|
716
|
+
const response = await this.client.get(
|
|
717
|
+
"/",
|
|
718
|
+
{ skipAuth: true }
|
|
719
|
+
);
|
|
720
|
+
const authMethods = response?.project?.auth;
|
|
721
|
+
this.authMethodsCache = authMethods;
|
|
722
|
+
return authMethods;
|
|
587
723
|
}
|
|
588
724
|
/**
|
|
589
725
|
* Logout the current user
|
|
@@ -2572,9 +2708,21 @@ var PermissionsModule = class {
|
|
|
2572
2708
|
* action: 'update',
|
|
2573
2709
|
* fields: ['title', 'content', 'status'],
|
|
2574
2710
|
* conditions: {
|
|
2575
|
-
* author_Id: { eq: '$CURRENT_USER' }
|
|
2711
|
+
* author_Id: { eq: '$CURRENT_USER' } // USING: which rows may be updated
|
|
2712
|
+
* },
|
|
2713
|
+
* checkConditions: {
|
|
2714
|
+
* author_Id: { eq: '$CURRENT_USER' } // WITH CHECK: what they may become
|
|
2576
2715
|
* }
|
|
2577
2716
|
* });
|
|
2717
|
+
*
|
|
2718
|
+
* // Create grants use checkConditions (conditions is rejected on create):
|
|
2719
|
+
* await baasix.permissions.create({
|
|
2720
|
+
* role_Id: 'user-role-uuid',
|
|
2721
|
+
* collection: 'tasks',
|
|
2722
|
+
* action: 'create',
|
|
2723
|
+
* fields: ['*'],
|
|
2724
|
+
* checkConditions: { owner_Id: { eq: '$CURRENT_USER' } }
|
|
2725
|
+
* });
|
|
2578
2726
|
* ```
|
|
2579
2727
|
*/
|
|
2580
2728
|
async create(data) {
|
|
@@ -2632,9 +2780,9 @@ var PermissionsModule = class {
|
|
|
2632
2780
|
* @example
|
|
2633
2781
|
* ```typescript
|
|
2634
2782
|
* await baasix.permissions.createCrudPermissions('role-uuid', 'products', {
|
|
2635
|
-
* create: { fields: ['name', 'price', '
|
|
2783
|
+
* create: { fields: ['name', 'price'], checkConditions: { owner_Id: { eq: '$CURRENT_USER' } } },
|
|
2636
2784
|
* read: { fields: ['*'] },
|
|
2637
|
-
* update: { fields: ['name', 'price', '
|
|
2785
|
+
* update: { fields: ['name', 'price'], conditions: { owner_Id: { eq: '$CURRENT_USER' } } },
|
|
2638
2786
|
* delete: false
|
|
2639
2787
|
* });
|
|
2640
2788
|
* ```
|
|
@@ -2645,12 +2793,15 @@ var PermissionsModule = class {
|
|
|
2645
2793
|
for (const action of actions) {
|
|
2646
2794
|
const actionConfig = config[action];
|
|
2647
2795
|
if (actionConfig === false) continue;
|
|
2796
|
+
const cfg = actionConfig;
|
|
2648
2797
|
const permission = await this.create({
|
|
2649
2798
|
role_Id: roleId,
|
|
2650
2799
|
collection,
|
|
2651
2800
|
action,
|
|
2652
|
-
fields:
|
|
2653
|
-
conditions
|
|
2801
|
+
fields: cfg?.fields || ["*"],
|
|
2802
|
+
// `conditions` filters existing rows (USING) — never sent for create
|
|
2803
|
+
conditions: action === "create" ? void 0 : cfg?.conditions,
|
|
2804
|
+
checkConditions: action === "create" || action === "update" ? cfg?.checkConditions : void 0
|
|
2654
2805
|
});
|
|
2655
2806
|
permissions.push(permission);
|
|
2656
2807
|
}
|
|
@@ -5086,6 +5237,6 @@ function createBaasix(config) {
|
|
|
5086
5237
|
return new Baasix(config);
|
|
5087
5238
|
}
|
|
5088
5239
|
|
|
5089
|
-
export { AsyncStorageAdapter, AuthModule, Baasix, BaasixError, FilesModule, HttpClient, ItemsModule, LocalStorageAdapter, MemoryStorageAdapter, MigrationsModule, NotificationsModule, PermissionsModule, QueryBuilder, RealtimeChannel, RealtimeModule, ReportsModule, RolesModule, STORAGE_KEYS, SchemasModule, SettingsModule, UsersModule, WorkflowsModule, createBaasix };
|
|
5240
|
+
export { AsyncStorageAdapter, AuthModule, Baasix, BaasixError, FilesModule, HttpClient, ItemsModule, LocalStorageAdapter, MemoryStorageAdapter, MigrationsModule, NotificationsModule, PermissionsModule, QueryBuilder, RealtimeChannel, RealtimeModule, ReportsModule, RolesModule, SOCIAL_PROVIDERS, STORAGE_KEYS, SchemasModule, SettingsModule, UsersModule, WorkflowsModule, createBaasix };
|
|
5090
5241
|
//# sourceMappingURL=index.js.map
|
|
5091
5242
|
//# sourceMappingURL=index.js.map
|