@banata-auth/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,1281 @@
1
+ 'use strict';
2
+
3
+ var shared = require('@banata-auth/shared');
4
+
5
+ // src/client.ts
6
+
7
+ // src/resources/api-keys.ts
8
+ var ApiKeys = class {
9
+ constructor(http) {
10
+ this.http = http;
11
+ }
12
+ /**
13
+ * Create a new API key.
14
+ *
15
+ * @returns The created key metadata **plus** the raw `key` value.
16
+ * The raw key is only returned at creation time and cannot be retrieved later.
17
+ */
18
+ async create(options) {
19
+ return this.http.post("/api/auth/api-key/create", {
20
+ name: options.name,
21
+ organizationId: options.organizationId,
22
+ permissions: options.permissions,
23
+ expiresAt: options.expiresAt instanceof Date ? options.expiresAt.toISOString() : options.expiresAt
24
+ });
25
+ }
26
+ /**
27
+ * List all API keys. The raw key value is **not** included.
28
+ */
29
+ async list() {
30
+ return this.http.get("/api/auth/api-key/list");
31
+ }
32
+ /**
33
+ * Delete (revoke) an API key by its ID.
34
+ */
35
+ async delete(keyId) {
36
+ return this.http.post("/api/auth/api-key/delete", { keyId });
37
+ }
38
+ };
39
+
40
+ // src/resources/audit-logs.ts
41
+ var AuditLogs = class {
42
+ constructor(http) {
43
+ this.http = http;
44
+ }
45
+ async createEvent(options) {
46
+ return this.http.post("/api/auth/banata/audit-logs/create", {
47
+ action: options.action,
48
+ actorType: options.actorType,
49
+ actorId: options.actorId,
50
+ actorName: options.actorName,
51
+ actorEmail: options.actorEmail,
52
+ targets: options.targets ? JSON.stringify(options.targets) : void 0,
53
+ organizationId: options.organizationId,
54
+ ipAddress: options.ipAddress,
55
+ userAgent: options.userAgent,
56
+ changes: options.changes ? JSON.stringify(options.changes) : void 0,
57
+ idempotencyKey: options.idempotencyKey,
58
+ metadata: options.metadata ? JSON.stringify(options.metadata) : void 0,
59
+ occurredAt: options.occurredAt?.getTime()
60
+ });
61
+ }
62
+ async listEvents(options) {
63
+ return this.http.post("/api/auth/banata/audit-logs/list", {
64
+ organizationId: options?.organizationId,
65
+ action: options?.action,
66
+ actorId: options?.actorId,
67
+ after: options?.after,
68
+ before: options?.before,
69
+ limit: options?.limit
70
+ });
71
+ }
72
+ async exportEvents(options) {
73
+ return this.http.post("/api/auth/banata/audit-logs/export", {
74
+ organizationId: options.organizationId,
75
+ format: options.format,
76
+ startDate: options.startDate?.getTime(),
77
+ endDate: options.endDate?.getTime(),
78
+ action: options.action,
79
+ limit: options.limit,
80
+ cursor: options.cursor
81
+ });
82
+ }
83
+ };
84
+
85
+ // src/resources/directory-sync.ts
86
+ var DirectorySync = class {
87
+ constructor(http) {
88
+ this.http = http;
89
+ }
90
+ async listDirectories(options) {
91
+ return this.http.post(
92
+ "/api/auth/banata/scim/list-providers",
93
+ this.http.withProjectScope(
94
+ {
95
+ organizationId: options?.organizationId,
96
+ limit: options?.limit,
97
+ before: options?.before,
98
+ after: options?.after
99
+ },
100
+ options?.projectId
101
+ )
102
+ );
103
+ }
104
+ async getDirectory(directoryId, options) {
105
+ return this.http.post(
106
+ "/api/auth/banata/scim/get-provider",
107
+ this.http.withProjectScope(
108
+ {
109
+ providerId: directoryId
110
+ },
111
+ options?.projectId
112
+ )
113
+ );
114
+ }
115
+ async createDirectory(options) {
116
+ return this.http.post(
117
+ "/api/auth/banata/scim/register",
118
+ this.http.withProjectScope(
119
+ {
120
+ organizationId: options.organizationId,
121
+ name: options.name,
122
+ provider: options.provider
123
+ },
124
+ options.projectId
125
+ )
126
+ );
127
+ }
128
+ async deleteDirectory(directoryId, options) {
129
+ return this.http.post(
130
+ "/api/auth/banata/scim/delete-provider",
131
+ this.http.withProjectScope(
132
+ {
133
+ providerId: directoryId
134
+ },
135
+ options?.projectId
136
+ )
137
+ );
138
+ }
139
+ async listUsers(options) {
140
+ return this.http.post(
141
+ "/api/auth/banata/scim/list-users",
142
+ this.http.withProjectScope(
143
+ {
144
+ providerId: options.directoryId,
145
+ state: options.state,
146
+ limit: options.limit,
147
+ before: options.before,
148
+ after: options.after
149
+ },
150
+ options.projectId
151
+ )
152
+ );
153
+ }
154
+ async getUser(directoryUserId, options) {
155
+ return this.http.post(
156
+ "/api/auth/banata/scim/get-user",
157
+ this.http.withProjectScope(
158
+ {
159
+ userId: directoryUserId
160
+ },
161
+ options?.projectId
162
+ )
163
+ );
164
+ }
165
+ async listGroups(options) {
166
+ return this.http.post(
167
+ "/api/auth/banata/scim/list-groups",
168
+ this.http.withProjectScope(
169
+ {
170
+ providerId: options.directoryId,
171
+ limit: options.limit,
172
+ before: options.before,
173
+ after: options.after
174
+ },
175
+ options.projectId
176
+ )
177
+ );
178
+ }
179
+ async getGroup(directoryGroupId, options) {
180
+ return this.http.post(
181
+ "/api/auth/banata/scim/get-group",
182
+ this.http.withProjectScope(
183
+ {
184
+ groupId: directoryGroupId
185
+ },
186
+ options?.projectId
187
+ )
188
+ );
189
+ }
190
+ };
191
+
192
+ // src/resources/domains.ts
193
+ var Domains = class {
194
+ constructor(http) {
195
+ this.http = http;
196
+ }
197
+ async createVerification(options) {
198
+ return this.http.post(
199
+ "/api/auth/banata/domains/create",
200
+ this.http.withProjectScope(
201
+ {
202
+ organizationId: options.organizationId,
203
+ domain: options.domain
204
+ },
205
+ options.projectId
206
+ )
207
+ );
208
+ }
209
+ async getVerification(verificationId, options) {
210
+ return this.http.post(
211
+ "/api/auth/banata/domains/get",
212
+ this.http.withProjectScope(
213
+ {
214
+ id: verificationId
215
+ },
216
+ options?.projectId
217
+ )
218
+ );
219
+ }
220
+ async verify(verificationId, options) {
221
+ return this.http.post(
222
+ "/api/auth/banata/domains/verify",
223
+ this.http.withProjectScope(
224
+ {
225
+ id: verificationId
226
+ },
227
+ options?.projectId
228
+ )
229
+ );
230
+ }
231
+ async list(options) {
232
+ return this.http.post(
233
+ "/api/auth/banata/domains/list",
234
+ this.http.withProjectScope(
235
+ {
236
+ organizationId: options.organizationId,
237
+ limit: options.limit,
238
+ before: options.before,
239
+ after: options.after
240
+ },
241
+ options.projectId
242
+ )
243
+ );
244
+ }
245
+ async delete(verificationId, options) {
246
+ return this.http.post(
247
+ "/api/auth/banata/domains/delete",
248
+ this.http.withProjectScope(
249
+ {
250
+ id: verificationId
251
+ },
252
+ options?.projectId
253
+ )
254
+ );
255
+ }
256
+ };
257
+
258
+ // src/resources/emails.ts
259
+ var Emails = class {
260
+ constructor(http) {
261
+ this.http = http;
262
+ this.templates = new EmailTemplates(http);
263
+ }
264
+ templates;
265
+ /**
266
+ * Send a transactional email using a built-in or custom template.
267
+ *
268
+ * The email is rendered using the configured branding (colors, logo,
269
+ * app name) and sent via the active email provider configured in the
270
+ * dashboard.
271
+ */
272
+ async send(options) {
273
+ return this.http.post("/api/auth/banata/emails/send", {
274
+ to: options.to,
275
+ template: options.template,
276
+ data: options.data
277
+ });
278
+ }
279
+ /**
280
+ * Preview a rendered email template.
281
+ *
282
+ * Returns the subject, HTML, and plain text of the template with
283
+ * the current branding applied. Uses sample data if none provided.
284
+ */
285
+ async preview(template, data) {
286
+ return this.http.post("/api/auth/banata/emails/preview", {
287
+ template,
288
+ data
289
+ });
290
+ }
291
+ /**
292
+ * Send a test email to verify the email provider configuration.
293
+ *
294
+ * Uses the "welcome" template by default with sample data.
295
+ */
296
+ async sendTest(to, template) {
297
+ return this.http.post("/api/auth/banata/test-email", {
298
+ to,
299
+ template
300
+ });
301
+ }
302
+ };
303
+ var EmailTemplates = class {
304
+ constructor(http) {
305
+ this.http = http;
306
+ }
307
+ /**
308
+ * List all email templates, optionally filtered by category.
309
+ */
310
+ async list(category) {
311
+ const payload = await this.http.post(
312
+ "/api/auth/banata/emails/templates/list",
313
+ { category }
314
+ );
315
+ return payload.templates ?? [];
316
+ }
317
+ /**
318
+ * Get a single email template by ID or slug.
319
+ */
320
+ async get(idOrSlug) {
321
+ const payload = await this.http.post(
322
+ "/api/auth/banata/emails/templates/get",
323
+ { idOrSlug }
324
+ );
325
+ return payload.template ?? null;
326
+ }
327
+ /**
328
+ * Create a new custom email template.
329
+ */
330
+ async create(options) {
331
+ const payload = await this.http.post("/api/auth/banata/emails/templates/create", options);
332
+ if (!payload.success) {
333
+ throw new Error(payload.error ?? "Failed to create template");
334
+ }
335
+ return payload.template;
336
+ }
337
+ /**
338
+ * Update an existing email template.
339
+ */
340
+ async update(id, options) {
341
+ const payload = await this.http.post("/api/auth/banata/emails/templates/update", { id, ...options });
342
+ if (!payload.success) {
343
+ throw new Error(payload.error ?? "Failed to update template");
344
+ }
345
+ return payload.template;
346
+ }
347
+ /**
348
+ * Delete a custom email template.
349
+ * Built-in templates cannot be deleted.
350
+ */
351
+ async delete(id) {
352
+ const payload = await this.http.post(
353
+ "/api/auth/banata/emails/templates/delete",
354
+ { id }
355
+ );
356
+ if (!payload.success) {
357
+ throw new Error(payload.error ?? "Failed to delete template");
358
+ }
359
+ }
360
+ };
361
+
362
+ // src/resources/events.ts
363
+ var Events = class {
364
+ constructor(http) {
365
+ this.http = http;
366
+ }
367
+ /**
368
+ * List events with optional filters and cursor-based pagination.
369
+ */
370
+ async listEvents(options) {
371
+ return this.http.post("/api/auth/banata/events/list", {
372
+ eventTypes: options?.eventTypes,
373
+ after: options?.after,
374
+ limit: options?.limit,
375
+ organizationId: options?.organizationId,
376
+ rangeStart: options?.rangeStart?.getTime(),
377
+ rangeEnd: options?.rangeEnd?.getTime()
378
+ });
379
+ }
380
+ };
381
+
382
+ // src/resources/organizations.ts
383
+ var Organizations = class {
384
+ constructor(http) {
385
+ this.http = http;
386
+ }
387
+ async listOrganizations(options) {
388
+ return this.http.post("/api/auth/organization/list", {
389
+ limit: options?.limit,
390
+ before: options?.before,
391
+ after: options?.after,
392
+ order: options?.order
393
+ });
394
+ }
395
+ async getOrganization(organizationId) {
396
+ return this.http.post("/api/auth/organization/get-full-organization", {
397
+ organizationId
398
+ });
399
+ }
400
+ async createOrganization(options) {
401
+ return this.http.post("/api/auth/organization/create", options);
402
+ }
403
+ async updateOrganization(options) {
404
+ const { organizationId, ...data } = options;
405
+ return this.http.post("/api/auth/organization/update", {
406
+ organizationId,
407
+ data
408
+ });
409
+ }
410
+ async deleteOrganization(organizationId) {
411
+ return this.http.post("/api/auth/organization/delete", {
412
+ organizationId
413
+ });
414
+ }
415
+ // ─── Members ───────────────────────────────────────────────────────────
416
+ async listMembers(options) {
417
+ return this.http.post(
418
+ "/api/auth/organization/list-members",
419
+ {
420
+ organizationId: options.organizationId,
421
+ role: options.role,
422
+ limit: options.limit,
423
+ before: options.before,
424
+ after: options.after
425
+ }
426
+ );
427
+ }
428
+ async removeMember(options) {
429
+ return this.http.post("/api/auth/organization/remove-member", options);
430
+ }
431
+ async updateMemberRole(options) {
432
+ return this.http.post("/api/auth/organization/update-member-role", options);
433
+ }
434
+ // ─── Invitations ───────────────────────────────────────────────────────
435
+ async sendInvitation(options) {
436
+ return this.http.post("/api/auth/organization/invite-member", options);
437
+ }
438
+ async revokeInvitation(invitationId) {
439
+ return this.http.post("/api/auth/organization/cancel-invitation", {
440
+ invitationId
441
+ });
442
+ }
443
+ async listInvitations(options) {
444
+ return this.http.post(
445
+ "/api/auth/organization/list-invitations",
446
+ {
447
+ organizationId: options.organizationId,
448
+ status: options.status,
449
+ limit: options.limit,
450
+ before: options.before,
451
+ after: options.after
452
+ }
453
+ );
454
+ }
455
+ };
456
+
457
+ // src/resources/portal.ts
458
+ var Portal = class {
459
+ constructor(http) {
460
+ this.http = http;
461
+ }
462
+ /**
463
+ * Generate a short-lived admin portal link for an organization's IT admin.
464
+ *
465
+ * @param options - Portal link generation options
466
+ * @returns The generated portal link and session metadata
467
+ */
468
+ async generateLink(options) {
469
+ return this.http.post("/banata/portal/generate-link", options);
470
+ }
471
+ };
472
+
473
+ // src/resources/projects.ts
474
+ var Projects = class {
475
+ constructor(http) {
476
+ this.http = http;
477
+ }
478
+ /**
479
+ * List all projects.
480
+ */
481
+ async listProjects() {
482
+ const res = await this.http.post("/api/auth/banata/projects/list");
483
+ return res.projects;
484
+ }
485
+ /**
486
+ * Get a single project by ID.
487
+ */
488
+ async getProject(id) {
489
+ const res = await this.http.post(
490
+ "/api/auth/banata/projects/get",
491
+ { id }
492
+ );
493
+ return res.project;
494
+ }
495
+ /**
496
+ * Create a new project.
497
+ * Returns the project and seeds RBAC permissions + super_admin role.
498
+ */
499
+ async createProject(data) {
500
+ return this.http.post("/api/auth/banata/projects/create", data);
501
+ }
502
+ /**
503
+ * Update a project's metadata.
504
+ */
505
+ async updateProject(id, update) {
506
+ return this.http.post("/api/auth/banata/projects/update", { id, ...update });
507
+ }
508
+ /**
509
+ * Delete a project.
510
+ *
511
+ * Note: This deletes the project record only. Project-scoped data (users,
512
+ * organizations, etc.) is not automatically cascade-deleted. Use the
513
+ * `clearAllData` migration for a full reset.
514
+ */
515
+ async deleteProject(id) {
516
+ return this.http.post("/api/auth/banata/projects/delete", { id });
517
+ }
518
+ /**
519
+ * Ensure at least one project exists. If none exist, creates a
520
+ * "Default Project" with seeded RBAC permissions.
521
+ */
522
+ async ensureDefaultProject() {
523
+ return this.http.post("/api/auth/banata/projects/ensure-default");
524
+ }
525
+ };
526
+
527
+ // src/resources/rbac.ts
528
+ function normalizePermission(permission) {
529
+ if (typeof permission === "string") return permission;
530
+ return `${permission.resource}.${permission.action}`;
531
+ }
532
+ var Rbac = class {
533
+ constructor(http) {
534
+ this.http = http;
535
+ }
536
+ async listRoles() {
537
+ const result = await this.http.post(
538
+ "/api/auth/banata/config/roles/list",
539
+ {}
540
+ );
541
+ return result.roles ?? [];
542
+ }
543
+ async createRole(options) {
544
+ const result = await this.http.post(
545
+ "/api/auth/banata/config/roles/create",
546
+ options
547
+ );
548
+ return result.role;
549
+ }
550
+ async deleteRole(id) {
551
+ await this.http.post("/api/auth/banata/config/roles/delete", { id });
552
+ }
553
+ async listPermissions() {
554
+ const result = await this.http.post(
555
+ "/api/auth/banata/config/permissions/list",
556
+ {}
557
+ );
558
+ return result.permissions ?? [];
559
+ }
560
+ async createPermission(options) {
561
+ const result = await this.http.post(
562
+ "/api/auth/banata/config/permissions/create",
563
+ options
564
+ );
565
+ return result.permission;
566
+ }
567
+ async deletePermission(id) {
568
+ await this.http.post("/api/auth/banata/config/permissions/delete", { id });
569
+ }
570
+ async assignRole(options) {
571
+ await this.http.post("/api/auth/organization/update-member-role", {
572
+ memberIdOrUserId: options.userId,
573
+ role: options.role,
574
+ organizationId: options.organizationId
575
+ });
576
+ }
577
+ async checkPermission(options) {
578
+ return this.http.post("/api/auth/banata/rbac/check-permission", {
579
+ projectId: options.projectId,
580
+ permission: normalizePermission(options.permission)
581
+ });
582
+ }
583
+ async checkPermissions(options) {
584
+ return this.http.post("/api/auth/banata/rbac/check-permissions", {
585
+ projectId: options.projectId,
586
+ permissions: options.permissions.map(normalizePermission),
587
+ operator: options.operator ?? "all"
588
+ });
589
+ }
590
+ async getMyPermissions(projectId) {
591
+ const result = await this.http.post(
592
+ "/api/auth/banata/rbac/my-permissions",
593
+ {
594
+ projectId
595
+ }
596
+ );
597
+ return result.permissions ?? [];
598
+ }
599
+ async hasPermission(projectId, permission) {
600
+ const result = await this.checkPermission({
601
+ projectId,
602
+ permission
603
+ });
604
+ return result.allowed;
605
+ }
606
+ async requirePermission(projectId, permission) {
607
+ const allowed = await this.hasPermission(projectId, permission);
608
+ if (!allowed) {
609
+ throw new Error(`Missing permission: ${normalizePermission(permission)}`);
610
+ }
611
+ }
612
+ async revokeRole(options) {
613
+ await this.http.post("/api/auth/organization/update-member-role", {
614
+ memberIdOrUserId: options.userId,
615
+ role: options.fallbackRole ?? "super_admin",
616
+ organizationId: options.organizationId
617
+ });
618
+ }
619
+ };
620
+
621
+ // src/resources/sso.ts
622
+ var SSO = class {
623
+ constructor(http) {
624
+ this.http = http;
625
+ }
626
+ /**
627
+ * Get the authorization URL to redirect the user to for SSO.
628
+ * Supports routing by organization ID or callback URL.
629
+ */
630
+ async getAuthorizationUrl(options) {
631
+ return this.http.post("/api/auth/sign-in/sso", {
632
+ providerId: options.connectionId,
633
+ organizationId: options.organizationId,
634
+ issuer: options.provider,
635
+ loginHint: options.loginHint,
636
+ domain: options.domainHint,
637
+ callbackURL: options.redirectUri
638
+ });
639
+ }
640
+ /**
641
+ * @deprecated Better Auth handles SSO token exchange internally via callback.
642
+ * This method is kept for backward compatibility but will throw.
643
+ */
644
+ async getProfileAndToken(_options) {
645
+ throw new Error(
646
+ "getProfileAndToken() is not supported with Better Auth. SSO token exchange is handled internally via the callback URL."
647
+ );
648
+ }
649
+ // ─── Connection Management ─────────────────────────────────────────────
650
+ async listConnections(options) {
651
+ return this.http.post(
652
+ "/api/auth/banata/sso/list-providers",
653
+ this.http.withProjectScope(
654
+ {
655
+ organizationId: options?.organizationId,
656
+ connectionType: options?.connectionType,
657
+ limit: options?.limit,
658
+ before: options?.before,
659
+ after: options?.after
660
+ },
661
+ options?.projectId
662
+ )
663
+ );
664
+ }
665
+ async getConnection(connectionId, options) {
666
+ return this.http.post(
667
+ "/api/auth/banata/sso/get-provider",
668
+ this.http.withProjectScope(
669
+ {
670
+ providerId: connectionId
671
+ },
672
+ options?.projectId
673
+ )
674
+ );
675
+ }
676
+ async createConnection(options) {
677
+ return this.http.post(
678
+ "/api/auth/banata/sso/register",
679
+ this.http.withProjectScope(
680
+ {
681
+ organizationId: options.organizationId,
682
+ type: options.type,
683
+ domain: options.domains?.[0],
684
+ name: options.name,
685
+ domains: options.domains,
686
+ samlConfig: options.samlConfig,
687
+ oidcConfig: options.oidcConfig
688
+ },
689
+ options.projectId
690
+ )
691
+ );
692
+ }
693
+ async updateConnection(options) {
694
+ const { connectionId, projectId, ...body } = options;
695
+ return this.http.post(
696
+ "/api/auth/banata/sso/update-provider",
697
+ this.http.withProjectScope(
698
+ {
699
+ providerId: connectionId,
700
+ ...body
701
+ },
702
+ projectId
703
+ )
704
+ );
705
+ }
706
+ async deleteConnection(connectionId, options) {
707
+ return this.http.post(
708
+ "/api/auth/banata/sso/delete-provider",
709
+ this.http.withProjectScope(
710
+ {
711
+ providerId: connectionId
712
+ },
713
+ options?.projectId
714
+ )
715
+ );
716
+ }
717
+ async activateConnection(connectionId, options) {
718
+ return this.http.post(
719
+ "/api/auth/banata/sso/update-provider",
720
+ this.http.withProjectScope(
721
+ {
722
+ providerId: connectionId,
723
+ active: true
724
+ },
725
+ options?.projectId
726
+ )
727
+ );
728
+ }
729
+ async deactivateConnection(connectionId, options) {
730
+ return this.http.post(
731
+ "/api/auth/banata/sso/update-provider",
732
+ this.http.withProjectScope(
733
+ {
734
+ providerId: connectionId,
735
+ active: false
736
+ },
737
+ options?.projectId
738
+ )
739
+ );
740
+ }
741
+ };
742
+
743
+ // src/resources/user-management.ts
744
+ function emptyListMetadata() {
745
+ return {
746
+ before: null,
747
+ after: null
748
+ };
749
+ }
750
+ var UserManagement = class {
751
+ constructor(http) {
752
+ this.http = http;
753
+ }
754
+ /**
755
+ * List users with optional filtering and pagination.
756
+ */
757
+ async listUsers(options) {
758
+ const payload = await this.http.post("/api/auth/admin/list-users", {
759
+ projectId: options?.projectId,
760
+ email: options?.email,
761
+ organizationId: options?.organizationId,
762
+ role: options?.role,
763
+ limit: options?.limit,
764
+ before: options?.before,
765
+ after: options?.after,
766
+ order: options?.order
767
+ });
768
+ return {
769
+ data: payload.data ?? payload.users ?? [],
770
+ listMetadata: emptyListMetadata()
771
+ };
772
+ }
773
+ /**
774
+ * Get a user by ID.
775
+ */
776
+ async getUser(userId, options) {
777
+ return this.http.post("/api/auth/admin/get-user", {
778
+ userId,
779
+ projectId: options?.projectId
780
+ });
781
+ }
782
+ /**
783
+ * Create a new user.
784
+ */
785
+ async createUser(options) {
786
+ const payload = await this.http.post("/api/auth/admin/create-user", {
787
+ projectId: options.projectId,
788
+ email: options.email,
789
+ password: options.password,
790
+ name: options.name,
791
+ image: options.image,
792
+ username: options.username,
793
+ phoneNumber: options.phoneNumber,
794
+ emailVerified: options.emailVerified,
795
+ role: options.role ?? "user",
796
+ metadata: options.metadata,
797
+ data: options.data
798
+ });
799
+ return payload.user;
800
+ }
801
+ /**
802
+ * Update an existing user.
803
+ */
804
+ async updateUser(options) {
805
+ const { userId, ...body } = options;
806
+ return this.http.post("/api/auth/admin/update-user", {
807
+ userId,
808
+ ...body
809
+ });
810
+ }
811
+ /**
812
+ * Delete a user.
813
+ */
814
+ async deleteUser(userId, options) {
815
+ return this.http.post("/api/auth/admin/remove-user", {
816
+ userId,
817
+ projectId: options?.projectId
818
+ });
819
+ }
820
+ /**
821
+ * Ban a user.
822
+ */
823
+ async banUser(options) {
824
+ const payload = await this.http.post("/api/auth/admin/ban-user", {
825
+ userId: options.userId,
826
+ projectId: options.projectId,
827
+ banReason: options.reason,
828
+ banExpires: options.expiresAt?.getTime()
829
+ });
830
+ return payload.user;
831
+ }
832
+ /**
833
+ * Unban a user.
834
+ */
835
+ async unbanUser(userId, options) {
836
+ const payload = await this.http.post("/api/auth/admin/unban-user", {
837
+ userId,
838
+ projectId: options?.projectId
839
+ });
840
+ return payload.user;
841
+ }
842
+ /**
843
+ * List active sessions for a user.
844
+ */
845
+ async listUserSessions(userId, options) {
846
+ const payload = await this.http.post(
847
+ "/api/auth/admin/list-user-sessions",
848
+ {
849
+ userId,
850
+ projectId: options?.projectId
851
+ }
852
+ );
853
+ return {
854
+ data: payload.data ?? payload.sessions ?? [],
855
+ listMetadata: emptyListMetadata()
856
+ };
857
+ }
858
+ /**
859
+ * Start impersonating a user.
860
+ */
861
+ async impersonateUser(userId, options) {
862
+ return this.http.post("/api/auth/admin/impersonate-user", {
863
+ userId,
864
+ projectId: options?.projectId
865
+ });
866
+ }
867
+ /**
868
+ * Stop impersonating the current user.
869
+ */
870
+ async stopImpersonating() {
871
+ return this.http.post("/api/auth/admin/stop-impersonating");
872
+ }
873
+ /**
874
+ * Revoke a specific session.
875
+ */
876
+ async revokeSession(sessionId, options) {
877
+ return this.http.post("/api/auth/admin/revoke-user-session", {
878
+ sessionId,
879
+ projectId: options?.projectId
880
+ });
881
+ }
882
+ /**
883
+ * Revoke all sessions for a user.
884
+ */
885
+ async revokeAllSessions(userId, options) {
886
+ return this.http.post("/api/auth/admin/revoke-user-sessions", {
887
+ userId,
888
+ projectId: options?.projectId
889
+ });
890
+ }
891
+ /**
892
+ * Set a user's global role.
893
+ */
894
+ async setRole(userId, role, options) {
895
+ const payload = await this.http.post("/api/auth/admin/set-role", {
896
+ userId,
897
+ role,
898
+ projectId: options?.projectId
899
+ });
900
+ return payload.user;
901
+ }
902
+ /**
903
+ * Force-set a user's password.
904
+ */
905
+ async setUserPassword(userId, newPassword, options) {
906
+ const payload = await this.http.post("/api/auth/admin/set-user-password", {
907
+ userId,
908
+ newPassword,
909
+ projectId: options?.projectId
910
+ });
911
+ return payload.status === true;
912
+ }
913
+ /**
914
+ * Check whether a user or role has the requested permissions.
915
+ */
916
+ async hasPermission(options) {
917
+ const payload = await this.http.post("/api/auth/admin/has-permission", {
918
+ ...options
919
+ });
920
+ return payload.success === true;
921
+ }
922
+ };
923
+
924
+ // src/resources/vault.ts
925
+ var Vault = class {
926
+ constructor(http) {
927
+ this.http = http;
928
+ }
929
+ /**
930
+ * Encrypt and store a secret.
931
+ *
932
+ * @returns The ID of the stored secret.
933
+ */
934
+ async encrypt(options) {
935
+ return this.http.post("/api/auth/banata/vault/encrypt", options);
936
+ }
937
+ /**
938
+ * Decrypt and return a secret by ID.
939
+ *
940
+ * @param options.context - Must match the context used during encryption.
941
+ */
942
+ async decrypt(options) {
943
+ return this.http.post("/api/auth/banata/vault/decrypt", options);
944
+ }
945
+ /**
946
+ * List vault secrets (metadata only — decrypted values are never returned).
947
+ */
948
+ async list(options) {
949
+ return this.http.post("/api/auth/banata/vault/list", {
950
+ organizationId: options?.organizationId,
951
+ limit: options?.limit,
952
+ before: options?.before,
953
+ after: options?.after
954
+ });
955
+ }
956
+ /**
957
+ * Delete a vault secret by ID.
958
+ */
959
+ async delete(options) {
960
+ return this.http.post("/api/auth/banata/vault/delete", {
961
+ id: options.secretId
962
+ });
963
+ }
964
+ /**
965
+ * Rotate the encryption key by re-encrypting all secrets
966
+ * with the next version's derived key.
967
+ *
968
+ * @returns Status and count of rotated/failed secrets.
969
+ */
970
+ async rotateKey(options) {
971
+ return this.http.post("/api/auth/banata/vault/rotate-key", {
972
+ batchSize: options?.batchSize
973
+ });
974
+ }
975
+ };
976
+
977
+ // src/resources/webhooks.ts
978
+ var Webhooks = class {
979
+ constructor(http) {
980
+ this.http = http;
981
+ }
982
+ // ─── Endpoint Management ───────────────────────────────────────────────
983
+ async listEndpoints(options) {
984
+ return this.http.post("/api/auth/banata/webhooks/list", {
985
+ limit: options?.limit,
986
+ before: options?.before,
987
+ after: options?.after
988
+ });
989
+ }
990
+ async createEndpoint(options) {
991
+ return this.http.post("/api/auth/banata/webhooks/create", options);
992
+ }
993
+ async updateEndpoint(options) {
994
+ const { endpointId, ...body } = options;
995
+ return this.http.post("/api/auth/banata/webhooks/update", {
996
+ id: endpointId,
997
+ ...body
998
+ });
999
+ }
1000
+ async deleteEndpoint(endpointId) {
1001
+ return this.http.post("/api/auth/banata/webhooks/delete", {
1002
+ id: endpointId
1003
+ });
1004
+ }
1005
+ // ─── Signature Verification ────────────────────────────────────────────
1006
+ /**
1007
+ * Verify a webhook signature and construct the event payload.
1008
+ * Uses the Web Crypto API for HMAC-SHA256 signature verification.
1009
+ *
1010
+ * @example
1011
+ * ```ts
1012
+ * const event = await banataAuth.webhooks.constructEvent({
1013
+ * payload: req.body,
1014
+ * sigHeader: req.headers["x-banataauth-signature"],
1015
+ * secret: webhookSecret,
1016
+ * });
1017
+ * ```
1018
+ */
1019
+ async constructEvent(options) {
1020
+ const { payload, sigHeader, secret, tolerance = 300 } = options;
1021
+ if (!await this.verifySignature({ payload, sigHeader, secret, tolerance })) {
1022
+ throw new Error("Invalid webhook signature");
1023
+ }
1024
+ return JSON.parse(payload);
1025
+ }
1026
+ /**
1027
+ * Verify a webhook signature using the Web Crypto API (HMAC-SHA256).
1028
+ */
1029
+ async verifySignature(options) {
1030
+ const { payload, sigHeader, secret, tolerance = 300 } = options;
1031
+ const parts = sigHeader.split(",");
1032
+ const timestampPart = parts.find((p) => p.startsWith("t="));
1033
+ const signaturePart = parts.find((p) => p.startsWith("v1="));
1034
+ if (!timestampPart || !signaturePart) {
1035
+ return false;
1036
+ }
1037
+ const timestamp = Number.parseInt(timestampPart.slice(2), 10);
1038
+ const signature = signaturePart.slice(3);
1039
+ const now = Math.floor(Date.now() / 1e3);
1040
+ if (Math.abs(now - timestamp) > tolerance) {
1041
+ return false;
1042
+ }
1043
+ const signedPayload = `${timestamp}.${payload}`;
1044
+ const expectedSignature = await this.computeHmacAsync(secret, signedPayload);
1045
+ return this.timingSafeEqual(signature, expectedSignature);
1046
+ }
1047
+ async computeHmacAsync(secret, payload) {
1048
+ const encoder = new TextEncoder();
1049
+ const key = await crypto.subtle.importKey(
1050
+ "raw",
1051
+ encoder.encode(secret),
1052
+ { name: "HMAC", hash: "SHA-256" },
1053
+ false,
1054
+ ["sign"]
1055
+ );
1056
+ const signatureBuffer = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
1057
+ return Array.from(new Uint8Array(signatureBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
1058
+ }
1059
+ timingSafeEqual(a, b) {
1060
+ if (a.length !== b.length) return false;
1061
+ let result = 0;
1062
+ for (let i = 0; i < a.length; i++) {
1063
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
1064
+ }
1065
+ return result === 0;
1066
+ }
1067
+ };
1068
+
1069
+ // src/client.ts
1070
+ var HttpClient = class {
1071
+ apiKey;
1072
+ baseUrl;
1073
+ timeout;
1074
+ maxRetries;
1075
+ projectId;
1076
+ constructor(options) {
1077
+ this.apiKey = options.apiKey;
1078
+ this.baseUrl = (options.baseUrl ?? "").replace(/\/$/, "");
1079
+ this.timeout = options.timeout ?? 3e4;
1080
+ this.maxRetries = options.retries ?? 3;
1081
+ this.projectId = options.projectId;
1082
+ if (this.baseUrl && !this.baseUrl.startsWith("https://") && !this.baseUrl.startsWith("http://localhost") && !this.baseUrl.startsWith("http://127.0.0.1")) {
1083
+ console.warn(
1084
+ "[BanataAuth SDK] WARNING: baseUrl does not use HTTPS. API keys will be transmitted in plaintext. Use HTTPS in production to protect your credentials."
1085
+ );
1086
+ }
1087
+ }
1088
+ withProjectScope(body, projectId) {
1089
+ const resolvedProjectId = projectId ?? this.projectId;
1090
+ if (!resolvedProjectId) {
1091
+ return body;
1092
+ }
1093
+ return {
1094
+ ...body,
1095
+ projectId: resolvedProjectId
1096
+ };
1097
+ }
1098
+ async request(method, path, options) {
1099
+ const url = new URL(`${this.baseUrl}${path}`);
1100
+ if (options?.query) {
1101
+ for (const [key, value] of Object.entries(options.query)) {
1102
+ if (value !== void 0) {
1103
+ url.searchParams.set(key, String(value));
1104
+ }
1105
+ }
1106
+ }
1107
+ const headers = {
1108
+ Authorization: `Bearer ${this.apiKey}`,
1109
+ "Content-Type": "application/json",
1110
+ "User-Agent": "banata-auth-sdk/0.1.0",
1111
+ ...options?.headers
1112
+ };
1113
+ let lastError = null;
1114
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
1115
+ try {
1116
+ const controller = new AbortController();
1117
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1118
+ const response = await fetch(url.toString(), {
1119
+ method,
1120
+ headers,
1121
+ body: options?.body ? JSON.stringify(options.body) : void 0,
1122
+ signal: controller.signal
1123
+ });
1124
+ clearTimeout(timeoutId);
1125
+ const requestId = response.headers.get("x-request-id") ?? "";
1126
+ if (response.ok) {
1127
+ if (response.status === 204) {
1128
+ return void 0;
1129
+ }
1130
+ return await response.json();
1131
+ }
1132
+ const errorBody = await response.json().catch(() => ({}));
1133
+ const error = shared.createErrorFromStatus(
1134
+ response.status,
1135
+ errorBody,
1136
+ requestId
1137
+ );
1138
+ if ((response.status >= 500 || response.status === 429) && attempt < this.maxRetries) {
1139
+ lastError = error;
1140
+ let delayMs = 200 * 2 ** attempt;
1141
+ if (response.status === 429) {
1142
+ const retryAfter = response.headers.get("retry-after");
1143
+ if (retryAfter) {
1144
+ const parsed = Number(retryAfter);
1145
+ delayMs = Number.isNaN(parsed) ? Math.max(0, new Date(retryAfter).getTime() - Date.now()) : parsed * 1e3;
1146
+ delayMs = Math.min(delayMs, 6e4);
1147
+ }
1148
+ }
1149
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
1150
+ continue;
1151
+ }
1152
+ throw error;
1153
+ } catch (error) {
1154
+ if (error instanceof Error && error.name === "AbortError") {
1155
+ lastError = new Error(`Request timed out after ${this.timeout}ms`);
1156
+ if (attempt < this.maxRetries) {
1157
+ await new Promise((resolve) => setTimeout(resolve, 200 * 2 ** attempt));
1158
+ continue;
1159
+ }
1160
+ }
1161
+ throw error;
1162
+ }
1163
+ }
1164
+ throw lastError ?? new Error("Request failed after all retries");
1165
+ }
1166
+ get(path, query) {
1167
+ return this.request("GET", path, { query });
1168
+ }
1169
+ post(path, body) {
1170
+ return this.request("POST", path, { body });
1171
+ }
1172
+ put(path, body) {
1173
+ return this.request("PUT", path, { body });
1174
+ }
1175
+ patch(path, body) {
1176
+ return this.request("PATCH", path, { body });
1177
+ }
1178
+ delete(path) {
1179
+ return this.request("DELETE", path);
1180
+ }
1181
+ };
1182
+ var BanataAuth = class {
1183
+ httpClient;
1184
+ apiKeys;
1185
+ userManagement;
1186
+ organizations;
1187
+ sso;
1188
+ directorySync;
1189
+ auditLogs;
1190
+ emails;
1191
+ events;
1192
+ webhooks;
1193
+ portal;
1194
+ vault;
1195
+ domains;
1196
+ rbac;
1197
+ projects;
1198
+ constructor(options) {
1199
+ const opts = typeof options === "string" ? { apiKey: options } : options;
1200
+ if (!opts.apiKey) {
1201
+ throw new Error(
1202
+ "Banata Auth API key is required. Pass it as a string or as { apiKey: '...' }"
1203
+ );
1204
+ }
1205
+ this.httpClient = new HttpClient(opts);
1206
+ this.apiKeys = new ApiKeys(this.httpClient);
1207
+ this.userManagement = new UserManagement(this.httpClient);
1208
+ this.organizations = new Organizations(this.httpClient);
1209
+ this.sso = new SSO(this.httpClient);
1210
+ this.directorySync = new DirectorySync(this.httpClient);
1211
+ this.auditLogs = new AuditLogs(this.httpClient);
1212
+ this.emails = new Emails(this.httpClient);
1213
+ this.events = new Events(this.httpClient);
1214
+ this.webhooks = new Webhooks(this.httpClient);
1215
+ this.portal = new Portal(this.httpClient);
1216
+ this.vault = new Vault(this.httpClient);
1217
+ this.domains = new Domains(this.httpClient);
1218
+ this.rbac = new Rbac(this.httpClient);
1219
+ this.projects = new Projects(this.httpClient);
1220
+ }
1221
+ // Convenience aliases (WorkOS-compatible)
1222
+ get users() {
1223
+ return this.userManagement;
1224
+ }
1225
+ get directories() {
1226
+ return this.directorySync;
1227
+ }
1228
+ get orgs() {
1229
+ return this.organizations;
1230
+ }
1231
+ };
1232
+
1233
+ Object.defineProperty(exports, "AuthenticationError", {
1234
+ enumerable: true,
1235
+ get: function () { return shared.AuthenticationError; }
1236
+ });
1237
+ Object.defineProperty(exports, "BanataAuthError", {
1238
+ enumerable: true,
1239
+ get: function () { return shared.BanataAuthError; }
1240
+ });
1241
+ Object.defineProperty(exports, "ConflictError", {
1242
+ enumerable: true,
1243
+ get: function () { return shared.ConflictError; }
1244
+ });
1245
+ Object.defineProperty(exports, "ForbiddenError", {
1246
+ enumerable: true,
1247
+ get: function () { return shared.ForbiddenError; }
1248
+ });
1249
+ Object.defineProperty(exports, "InternalError", {
1250
+ enumerable: true,
1251
+ get: function () { return shared.InternalError; }
1252
+ });
1253
+ Object.defineProperty(exports, "NotFoundError", {
1254
+ enumerable: true,
1255
+ get: function () { return shared.NotFoundError; }
1256
+ });
1257
+ Object.defineProperty(exports, "RateLimitError", {
1258
+ enumerable: true,
1259
+ get: function () { return shared.RateLimitError; }
1260
+ });
1261
+ Object.defineProperty(exports, "ValidationError", {
1262
+ enumerable: true,
1263
+ get: function () { return shared.ValidationError; }
1264
+ });
1265
+ exports.ApiKeys = ApiKeys;
1266
+ exports.AuditLogs = AuditLogs;
1267
+ exports.BanataAuth = BanataAuth;
1268
+ exports.DirectorySync = DirectorySync;
1269
+ exports.Domains = Domains;
1270
+ exports.Emails = Emails;
1271
+ exports.Events = Events;
1272
+ exports.Organizations = Organizations;
1273
+ exports.Portal = Portal;
1274
+ exports.Projects = Projects;
1275
+ exports.Rbac = Rbac;
1276
+ exports.SSO = SSO;
1277
+ exports.UserManagement = UserManagement;
1278
+ exports.Vault = Vault;
1279
+ exports.Webhooks = Webhooks;
1280
+ //# sourceMappingURL=index.cjs.map
1281
+ //# sourceMappingURL=index.cjs.map