@checkstack/auth-backend 0.2.1 → 0.3.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/src/router.ts CHANGED
@@ -31,6 +31,11 @@ import {
31
31
  PLATFORM_REGISTRATION_CONFIG_ID,
32
32
  } from "./platform-registration-config";
33
33
 
34
+ export const ADMIN_ROLE_ID = "admin";
35
+ export const USERS_ROLE_ID = "users";
36
+ export const ANONYMOUS_ROLE_ID = "anonymous";
37
+ export const APPLICATIONS_ROLE_ID = "applications";
38
+
34
39
  /**
35
40
  * Creates the auth router using contract-based implementation.
36
41
  *
@@ -52,12 +57,12 @@ const os = implement(authContract)
52
57
  */
53
58
  async function getStrategyEnabled(
54
59
  strategyId: string,
55
- configService: ConfigService
60
+ configService: ConfigService,
56
61
  ): Promise<boolean> {
57
62
  const metaConfig = await configService.get(
58
63
  `${strategyId}.meta`,
59
64
  strategyMetaConfigV1,
60
- STRATEGY_META_CONFIG_VERSION
65
+ STRATEGY_META_CONFIG_VERSION,
61
66
  );
62
67
 
63
68
  // Default: credential=true (fresh installs), others=false (require explicit config)
@@ -70,13 +75,13 @@ async function getStrategyEnabled(
70
75
  async function setStrategyEnabled(
71
76
  strategyId: string,
72
77
  enabled: boolean,
73
- configService: ConfigService
78
+ configService: ConfigService,
74
79
  ): Promise<void> {
75
80
  await configService.set(
76
81
  `${strategyId}.meta`,
77
82
  strategyMetaConfigV1,
78
83
  STRATEGY_META_CONFIG_VERSION,
79
- { enabled }
84
+ { enabled },
80
85
  );
81
86
  }
82
87
 
@@ -87,12 +92,12 @@ async function setStrategyEnabled(
87
92
  * @returns true if registration is allowed, false otherwise
88
93
  */
89
94
  async function isRegistrationAllowed(
90
- configService: ConfigService
95
+ configService: ConfigService,
91
96
  ): Promise<boolean> {
92
97
  const config = await configService.get(
93
98
  PLATFORM_REGISTRATION_CONFIG_ID,
94
99
  platformRegistrationConfigV1,
95
- PLATFORM_REGISTRATION_CONFIG_VERSION
100
+ PLATFORM_REGISTRATION_CONFIG_VERSION,
96
101
  );
97
102
  return config?.allowRegistration ?? true;
98
103
  }
@@ -124,7 +129,7 @@ export const createAuthRouter = (
124
129
  isDefault?: boolean;
125
130
  isPublic?: boolean;
126
131
  }[];
127
- }
132
+ },
128
133
  ) => {
129
134
  // Public endpoint for enabled strategies (no authentication required)
130
135
  const getEnabledStrategies = os.getEnabledStrategies.handler(async () => {
@@ -148,7 +153,7 @@ export const createAuthRouter = (
148
153
  icon: strategy.icon,
149
154
  requiresManualRegistration: strategy.requiresManualRegistration,
150
155
  };
151
- })
156
+ }),
152
157
  );
153
158
 
154
159
  // Filter to only return enabled strategies
@@ -173,8 +178,8 @@ export const createAuthRouter = (
173
178
  .where(
174
179
  inArray(
175
180
  schema.userRole.userId,
176
- users.map((u) => u.id)
177
- )
181
+ users.map((u) => u.id),
182
+ ),
178
183
  );
179
184
 
180
185
  return users.map((u) => ({
@@ -186,9 +191,15 @@ export const createAuthRouter = (
186
191
  });
187
192
 
188
193
  const deleteUser = os.deleteUser.handler(async ({ input: id, context }) => {
189
- if (id === "initial-admin-id") {
194
+ // Check if user has admin role - prevent deletion to avoid lockout
195
+ const userRoles = await internalDb
196
+ .select({ roleId: schema.userRole.roleId })
197
+ .from(schema.userRole)
198
+ .where(eq(schema.userRole.userId, id));
199
+
200
+ if (userRoles.some((ur) => ur.roleId === ADMIN_ROLE_ID)) {
190
201
  throw new ORPCError("FORBIDDEN", {
191
- message: "Cannot delete initial admin",
202
+ message: "Cannot delete users with the admin role",
192
203
  });
193
204
  }
194
205
 
@@ -227,7 +238,7 @@ export const createAuthRouter = (
227
238
  .map((rp) => rp.accessRuleId),
228
239
  isSystem: role.isSystem || false,
229
240
  // Anonymous role cannot be assigned to users - it's for unauthenticated access
230
- isAssignable: role.id !== "anonymous",
241
+ isAssignable: role.id !== ANONYMOUS_ROLE_ID,
231
242
  }));
232
243
  });
233
244
 
@@ -244,12 +255,12 @@ export const createAuthRouter = (
244
255
 
245
256
  // Get active access rules to filter input
246
257
  const activeAccessRules = new Set(
247
- accessRuleRegistry.getAccessRules().map((p) => p.id)
258
+ accessRuleRegistry.getAccessRules().map((p) => p.id),
248
259
  );
249
260
 
250
261
  // Filter to only include active access rules
251
262
  const validAccessRules = inputAccessRules.filter((p) =>
252
- activeAccessRules.has(p)
263
+ activeAccessRules.has(p),
253
264
  );
254
265
 
255
266
  await internalDb.transaction(async (tx) => {
@@ -267,7 +278,7 @@ export const createAuthRouter = (
267
278
  validAccessRules.map((accessRuleId) => ({
268
279
  roleId: id,
269
280
  accessRuleId,
270
- }))
281
+ })),
271
282
  );
272
283
  }
273
284
  });
@@ -292,8 +303,8 @@ export const createAuthRouter = (
292
303
  });
293
304
  }
294
305
 
295
- const isUsersRole = id === "users";
296
- const isAdminRole = id === "admin";
306
+ const isUsersRole = id === USERS_ROLE_ID;
307
+ const isAdminRole = id === ADMIN_ROLE_ID;
297
308
 
298
309
  // System roles can have name/description edited, but not deleted
299
310
  // Admin role: access rules cannot be changed (wildcard access)
@@ -302,12 +313,12 @@ export const createAuthRouter = (
302
313
 
303
314
  // Get active access rules to filter input
304
315
  const activeAccessRules = new Set(
305
- accessRuleRegistry.getAccessRules().map((p) => p.id)
316
+ accessRuleRegistry.getAccessRules().map((p) => p.id),
306
317
  );
307
318
 
308
319
  // Filter to only include active access rules
309
320
  const validAccessRules = inputAccessRules.filter((p) =>
310
- activeAccessRules.has(p)
321
+ activeAccessRules.has(p),
311
322
  );
312
323
 
313
324
  // Track disabled authenticated default access rules for "users" role
@@ -319,7 +330,7 @@ export const createAuthRouter = (
319
330
 
320
331
  // Find authenticated default access rules that are being removed
321
332
  const removedDefaults = defaultPermIds.filter(
322
- (defId) => !validAccessRules.includes(defId)
333
+ (defId) => !validAccessRules.includes(defId),
323
334
  );
324
335
 
325
336
  // Insert into disabled_default_access_rule table
@@ -335,7 +346,7 @@ export const createAuthRouter = (
335
346
 
336
347
  // Remove from disabled table if being re-added
337
348
  const readdedDefaults = validAccessRules.filter((p) =>
338
- defaultPermIds.includes(p)
349
+ defaultPermIds.includes(p),
339
350
  );
340
351
  for (const permId of readdedDefaults) {
341
352
  await internalDb
@@ -345,7 +356,7 @@ export const createAuthRouter = (
345
356
  }
346
357
 
347
358
  // Track disabled public default access rules for "anonymous" role
348
- const isAnonymousRole = id === "anonymous";
359
+ const isAnonymousRole = id === ANONYMOUS_ROLE_ID;
349
360
  if (isAnonymousRole) {
350
361
  const allPerms = accessRuleRegistry.getAccessRules();
351
362
  const publicDefaultPermIds = allPerms
@@ -354,7 +365,7 @@ export const createAuthRouter = (
354
365
 
355
366
  // Find public default access rules that are being removed
356
367
  const removedPublicDefaults = publicDefaultPermIds.filter(
357
- (defId) => !validAccessRules.includes(defId)
368
+ (defId) => !validAccessRules.includes(defId),
358
369
  );
359
370
 
360
371
  // Insert into disabled_public_default_access_rule table
@@ -370,13 +381,13 @@ export const createAuthRouter = (
370
381
 
371
382
  // Remove from disabled table if being re-added
372
383
  const readdedPublicDefaults = validAccessRules.filter((p) =>
373
- publicDefaultPermIds.includes(p)
384
+ publicDefaultPermIds.includes(p),
374
385
  );
375
386
  for (const permId of readdedPublicDefaults) {
376
387
  await internalDb
377
388
  .delete(schema.disabledPublicDefaultAccessRule)
378
389
  .where(
379
- eq(schema.disabledPublicDefaultAccessRule.accessRuleId, permId)
390
+ eq(schema.disabledPublicDefaultAccessRule.accessRuleId, permId),
380
391
  );
381
392
  }
382
393
  }
@@ -406,7 +417,7 @@ export const createAuthRouter = (
406
417
  validAccessRules.map((accessRuleId) => ({
407
418
  roleId: id,
408
419
  accessRuleId,
409
- }))
420
+ })),
410
421
  );
411
422
  }
412
423
  });
@@ -468,7 +479,7 @@ export const createAuthRouter = (
468
479
  }
469
480
 
470
481
  // Prevent assignment of the "anonymous" role - it's reserved for unauthenticated users
471
- if (roles.includes("anonymous")) {
482
+ if (roles.includes(ANONYMOUS_ROLE_ID)) {
472
483
  throw new ORPCError("BAD_REQUEST", {
473
484
  message: "The 'anonymous' role cannot be assigned to users",
474
485
  });
@@ -483,11 +494,11 @@ export const createAuthRouter = (
483
494
  roles.map((roleId) => ({
484
495
  userId,
485
496
  roleId,
486
- }))
497
+ })),
487
498
  );
488
499
  }
489
500
  });
490
- }
501
+ },
491
502
  );
492
503
 
493
504
  const getStrategies = os.getStrategies.handler(async () => {
@@ -500,7 +511,7 @@ export const createAuthRouter = (
500
511
  strategy.id,
501
512
  strategy.configSchema,
502
513
  strategy.configVersion,
503
- strategy.migrations
514
+ strategy.migrations,
504
515
  );
505
516
 
506
517
  // Convert Zod schema to JSON Schema with automatic secret metadata
@@ -520,7 +531,7 @@ export const createAuthRouter = (
520
531
  config,
521
532
  adminInstructions: strategy.adminInstructions,
522
533
  };
523
- })
534
+ }),
524
535
  );
525
536
  });
526
537
 
@@ -541,7 +552,7 @@ export const createAuthRouter = (
541
552
  strategy.configSchema,
542
553
  strategy.configVersion,
543
554
  config, // Just the config, no enabled mixed in
544
- strategy.migrations
555
+ strategy.migrations,
545
556
  );
546
557
  }
547
558
 
@@ -574,12 +585,208 @@ export const createAuthRouter = (
574
585
  PLATFORM_REGISTRATION_CONFIG_ID,
575
586
  platformRegistrationConfigV1,
576
587
  PLATFORM_REGISTRATION_CONFIG_VERSION,
577
- { allowRegistration: input.allowRegistration }
588
+ { allowRegistration: input.allowRegistration },
578
589
  );
579
590
  // Trigger auth reload to apply new settings
580
591
  await reloadAuthFn();
581
592
  return { success: true };
582
- }
593
+ },
594
+ );
595
+
596
+ // ==========================================================================
597
+ // ONBOARDING ENDPOINTS
598
+ // ==========================================================================
599
+
600
+ const getOnboardingStatus = os.getOnboardingStatus.handler(async () => {
601
+ // Check if any users exist in the database
602
+ const users = await internalDb
603
+ .select({ id: schema.user.id })
604
+ .from(schema.user)
605
+ .limit(1);
606
+ return { needsOnboarding: users.length === 0 };
607
+ });
608
+
609
+ const completeOnboarding = os.completeOnboarding.handler(
610
+ async ({ input }) => {
611
+ const { name, email, password } = input;
612
+
613
+ // Security check: only allow if no users exist
614
+ const existingUsers = await internalDb
615
+ .select({ id: schema.user.id })
616
+ .from(schema.user)
617
+ .limit(1);
618
+
619
+ if (existingUsers.length > 0) {
620
+ throw new ORPCError("FORBIDDEN", {
621
+ message: "Onboarding has already been completed.",
622
+ });
623
+ }
624
+
625
+ // Validate password against platform's password schema
626
+ const passwordValidation = passwordSchema.safeParse(password);
627
+ if (!passwordValidation.success) {
628
+ throw new ORPCError("BAD_REQUEST", {
629
+ message: passwordValidation.error.issues
630
+ .map((issue) => issue.message)
631
+ .join(", "),
632
+ });
633
+ }
634
+
635
+ // Create the first admin user
636
+ const userId = crypto.randomUUID();
637
+ const accountId = crypto.randomUUID();
638
+ const hashedPassword = await hashPassword(password);
639
+ const now = new Date();
640
+
641
+ await internalDb.transaction(async (tx) => {
642
+ // Create user
643
+ await tx.insert(schema.user).values({
644
+ id: userId,
645
+ email,
646
+ name,
647
+ emailVerified: true,
648
+ createdAt: now,
649
+ updatedAt: now,
650
+ });
651
+
652
+ // Create credential account
653
+ await tx.insert(schema.account).values({
654
+ id: accountId,
655
+ accountId: email,
656
+ providerId: "credential",
657
+ userId,
658
+ password: hashedPassword,
659
+ createdAt: now,
660
+ updatedAt: now,
661
+ });
662
+
663
+ // Assign admin role
664
+ await tx.insert(schema.userRole).values({
665
+ userId,
666
+ roleId: ADMIN_ROLE_ID,
667
+ });
668
+ });
669
+
670
+ return { success: true };
671
+ },
672
+ );
673
+
674
+ // ==========================================================================
675
+ // USER PROFILE ENDPOINTS
676
+ // ==========================================================================
677
+
678
+ const getCurrentUserProfile = os.getCurrentUserProfile.handler(
679
+ async ({ context }) => {
680
+ const user = context.user;
681
+ if (!isRealUser(user)) {
682
+ throw new ORPCError("UNAUTHORIZED", {
683
+ message: "Not authenticated",
684
+ });
685
+ }
686
+
687
+ // Get user data
688
+ const users = await internalDb
689
+ .select()
690
+ .from(schema.user)
691
+ .where(eq(schema.user.id, user.id))
692
+ .limit(1);
693
+
694
+ if (users.length === 0) {
695
+ throw new ORPCError("NOT_FOUND", {
696
+ message: "User not found",
697
+ });
698
+ }
699
+
700
+ // Check if user has a credential account
701
+ const accounts = await internalDb
702
+ .select()
703
+ .from(schema.account)
704
+ .where(
705
+ and(
706
+ eq(schema.account.userId, user.id),
707
+ eq(schema.account.providerId, "credential"),
708
+ ),
709
+ )
710
+ .limit(1);
711
+
712
+ return {
713
+ id: users[0].id,
714
+ name: users[0].name,
715
+ email: users[0].email,
716
+ hasCredentialAccount: accounts.length > 0,
717
+ };
718
+ },
719
+ );
720
+
721
+ const updateCurrentUser = os.updateCurrentUser.handler(
722
+ async ({ input, context }) => {
723
+ const user = context.user;
724
+ if (!isRealUser(user)) {
725
+ throw new ORPCError("UNAUTHORIZED", {
726
+ message: "Not authenticated",
727
+ });
728
+ }
729
+
730
+ const { name, email } = input;
731
+
732
+ // If email is being updated, check if user has a credential account
733
+ if (email !== undefined) {
734
+ const accounts = await internalDb
735
+ .select()
736
+ .from(schema.account)
737
+ .where(
738
+ and(
739
+ eq(schema.account.userId, user.id),
740
+ eq(schema.account.providerId, "credential"),
741
+ ),
742
+ )
743
+ .limit(1);
744
+
745
+ if (accounts.length === 0) {
746
+ throw new ORPCError("FORBIDDEN", {
747
+ message: "Email can only be updated for credential-based accounts.",
748
+ });
749
+ }
750
+
751
+ // Check email uniqueness
752
+ const existingUsers = await internalDb
753
+ .select({ id: schema.user.id })
754
+ .from(schema.user)
755
+ .where(eq(schema.user.email, email))
756
+ .limit(1);
757
+
758
+ if (existingUsers.length > 0 && existingUsers[0].id !== user.id) {
759
+ throw new ORPCError("CONFLICT", {
760
+ message: "A user with this email already exists.",
761
+ });
762
+ }
763
+ }
764
+
765
+ // Build update object
766
+ const updates: { name?: string; email?: string; updatedAt: Date } = {
767
+ updatedAt: new Date(),
768
+ };
769
+ if (name !== undefined) updates.name = name;
770
+ if (email !== undefined) updates.email = email;
771
+
772
+ await internalDb
773
+ .update(schema.user)
774
+ .set(updates)
775
+ .where(eq(schema.user.id, user.id));
776
+
777
+ // If email was updated, also update the credential account's accountId
778
+ if (email !== undefined) {
779
+ await internalDb
780
+ .update(schema.account)
781
+ .set({ accountId: email, updatedAt: new Date() })
782
+ .where(
783
+ and(
784
+ eq(schema.account.userId, user.id),
785
+ eq(schema.account.providerId, "credential"),
786
+ ),
787
+ );
788
+ }
789
+ },
583
790
  );
584
791
 
585
792
  const getAnonymousAccessRules = os.getAnonymousAccessRules.handler(
@@ -587,9 +794,9 @@ export const createAuthRouter = (
587
794
  const rolePerms = await internalDb
588
795
  .select()
589
796
  .from(schema.roleAccessRule)
590
- .where(eq(schema.roleAccessRule.roleId, "anonymous"));
797
+ .where(eq(schema.roleAccessRule.roleId, ANONYMOUS_ROLE_ID));
591
798
  return rolePerms.map((rp) => rp.accessRuleId);
592
- }
799
+ },
593
800
  );
594
801
 
595
802
  const filterUsersByAccessRule = os.filterUsersByAccessRule.handler(
@@ -605,18 +812,18 @@ export const createAuthRouter = (
605
812
  .from(schema.userRole)
606
813
  .innerJoin(
607
814
  schema.roleAccessRule,
608
- eq(schema.userRole.roleId, schema.roleAccessRule.roleId)
815
+ eq(schema.userRole.roleId, schema.roleAccessRule.roleId),
609
816
  )
610
817
  .where(
611
818
  and(
612
819
  inArray(schema.userRole.userId, userIds),
613
- eq(schema.roleAccessRule.accessRuleId, accessRule)
614
- )
820
+ eq(schema.roleAccessRule.accessRuleId, accessRule),
821
+ ),
615
822
  )
616
823
  .groupBy(schema.userRole.userId);
617
824
 
618
825
  return usersWithAccess.map((row) => row.userId);
619
- }
826
+ },
620
827
  );
621
828
 
622
829
  // ==========================================================================
@@ -712,7 +919,7 @@ export const createAuthRouter = (
712
919
  context.logger.info(`Created new user from ${providerId}: ${email}`);
713
920
 
714
921
  return { userId, created: true };
715
- }
922
+ },
716
923
  );
717
924
 
718
925
  const createSession = os.createSession.handler(async ({ input }) => {
@@ -753,7 +960,7 @@ export const createAuthRouter = (
753
960
  // Check if credential strategy is enabled
754
961
  const credentialEnabled = await getStrategyEnabled(
755
962
  "credential",
756
- configService
963
+ configService,
757
964
  );
758
965
  if (!credentialEnabled) {
759
966
  throw new ORPCError("BAD_REQUEST", {
@@ -806,16 +1013,16 @@ export const createAuthRouter = (
806
1013
  // Assign "users" role to new user
807
1014
  await tx.insert(schema.userRole).values({
808
1015
  userId,
809
- roleId: "users",
1016
+ roleId: USERS_ROLE_ID,
810
1017
  });
811
1018
  });
812
1019
 
813
1020
  context.logger.info(
814
- `[auth-backend] Admin created credential user: ${email}`
1021
+ `[auth-backend] Admin created credential user: ${email}`,
815
1022
  );
816
1023
 
817
1024
  return { userId };
818
- }
1025
+ },
819
1026
  );
820
1027
 
821
1028
  // ==========================================================================
@@ -833,8 +1040,8 @@ export const createAuthRouter = (
833
1040
  .where(
834
1041
  inArray(
835
1042
  schema.applicationRole.applicationId,
836
- apps.map((a) => a.id)
837
- )
1043
+ apps.map((a) => a.id),
1044
+ ),
838
1045
  );
839
1046
 
840
1047
  return apps.map((app) => ({
@@ -868,7 +1075,7 @@ export const createAuthRouter = (
868
1075
  const now = new Date();
869
1076
 
870
1077
  // Default role for all applications
871
- const defaultRole = "applications";
1078
+ const defaultRole = APPLICATIONS_ROLE_ID;
872
1079
 
873
1080
  await internalDb.transaction(async (tx) => {
874
1081
  // Create application
@@ -890,7 +1097,7 @@ export const createAuthRouter = (
890
1097
  });
891
1098
 
892
1099
  context.logger.info(
893
- `[auth-backend] Created application: ${name} (${id})`
1100
+ `[auth-backend] Created application: ${name} (${id})`,
894
1101
  );
895
1102
 
896
1103
  return {
@@ -904,7 +1111,7 @@ export const createAuthRouter = (
904
1111
  },
905
1112
  secret: `ck_${id}_${secret}`, // Full secret - only shown once!
906
1113
  };
907
- }
1114
+ },
908
1115
  );
909
1116
 
910
1117
  const updateApplication = os.updateApplication.handler(async ({ input }) => {
@@ -953,7 +1160,7 @@ export const createAuthRouter = (
953
1160
  roles.map((roleId) => ({
954
1161
  applicationId: id,
955
1162
  roleId,
956
- }))
1163
+ })),
957
1164
  );
958
1165
  }
959
1166
  }
@@ -982,7 +1189,7 @@ export const createAuthRouter = (
982
1189
  .where(eq(schema.application.id, id));
983
1190
 
984
1191
  context.logger.info(`[auth-backend] Deleted application: ${id}`);
985
- }
1192
+ },
986
1193
  );
987
1194
 
988
1195
  const regenerateApplicationSecret = os.regenerateApplicationSecret.handler(
@@ -1009,11 +1216,11 @@ export const createAuthRouter = (
1009
1216
  .where(eq(schema.application.id, id));
1010
1217
 
1011
1218
  context.logger.info(
1012
- `[auth-backend] Regenerated secret for application: ${id}`
1219
+ `[auth-backend] Regenerated secret for application: ${id}`,
1013
1220
  );
1014
1221
 
1015
1222
  return { secret: `ck_${id}_${secret}` };
1016
- }
1223
+ },
1017
1224
  );
1018
1225
 
1019
1226
  // ==========================================================================
@@ -1158,10 +1365,10 @@ export const createAuthRouter = (
1158
1365
  .where(
1159
1366
  and(
1160
1367
  eq(schema.userTeam.userId, input.userId),
1161
- eq(schema.userTeam.teamId, input.teamId)
1162
- )
1368
+ eq(schema.userTeam.teamId, input.teamId),
1369
+ ),
1163
1370
  );
1164
- }
1371
+ },
1165
1372
  );
1166
1373
 
1167
1374
  const addTeamManager = os.addTeamManager.handler(async ({ input }) => {
@@ -1177,8 +1384,8 @@ export const createAuthRouter = (
1177
1384
  .where(
1178
1385
  and(
1179
1386
  eq(schema.teamManager.userId, input.userId),
1180
- eq(schema.teamManager.teamId, input.teamId)
1181
- )
1387
+ eq(schema.teamManager.teamId, input.teamId),
1388
+ ),
1182
1389
  );
1183
1390
  });
1184
1391
 
@@ -1189,13 +1396,13 @@ export const createAuthRouter = (
1189
1396
  .from(schema.resourceTeamAccess)
1190
1397
  .innerJoin(
1191
1398
  schema.team,
1192
- eq(schema.resourceTeamAccess.teamId, schema.team.id)
1399
+ eq(schema.resourceTeamAccess.teamId, schema.team.id),
1193
1400
  )
1194
1401
  .where(
1195
1402
  and(
1196
1403
  eq(schema.resourceTeamAccess.resourceType, input.resourceType),
1197
- eq(schema.resourceTeamAccess.resourceId, input.resourceId)
1198
- )
1404
+ eq(schema.resourceTeamAccess.resourceId, input.resourceId),
1405
+ ),
1199
1406
  );
1200
1407
  return rows.map((r) => ({
1201
1408
  teamId: r.resource_team_access.teamId,
@@ -1203,7 +1410,7 @@ export const createAuthRouter = (
1203
1410
  canRead: r.resource_team_access.canRead,
1204
1411
  canManage: r.resource_team_access.canManage,
1205
1412
  }));
1206
- }
1413
+ },
1207
1414
  );
1208
1415
 
1209
1416
  const setResourceTeamAccess = os.setResourceTeamAccess.handler(
@@ -1229,7 +1436,7 @@ export const createAuthRouter = (
1229
1436
  canManage: canManage ?? false,
1230
1437
  },
1231
1438
  });
1232
- }
1439
+ },
1233
1440
  );
1234
1441
 
1235
1442
  const removeResourceTeamAccess = os.removeResourceTeamAccess.handler(
@@ -1240,10 +1447,10 @@ export const createAuthRouter = (
1240
1447
  and(
1241
1448
  eq(schema.resourceTeamAccess.resourceType, input.resourceType),
1242
1449
  eq(schema.resourceTeamAccess.resourceId, input.resourceId),
1243
- eq(schema.resourceTeamAccess.teamId, input.teamId)
1244
- )
1450
+ eq(schema.resourceTeamAccess.teamId, input.teamId),
1451
+ ),
1245
1452
  );
1246
- }
1453
+ },
1247
1454
  );
1248
1455
 
1249
1456
  // Resource-level access settings
@@ -1255,12 +1462,12 @@ export const createAuthRouter = (
1255
1462
  .where(
1256
1463
  and(
1257
1464
  eq(schema.resourceAccessSettings.resourceType, input.resourceType),
1258
- eq(schema.resourceAccessSettings.resourceId, input.resourceId)
1259
- )
1465
+ eq(schema.resourceAccessSettings.resourceId, input.resourceId),
1466
+ ),
1260
1467
  )
1261
1468
  .limit(1);
1262
1469
  return { teamOnly: rows[0]?.teamOnly ?? false };
1263
- }
1470
+ },
1264
1471
  );
1265
1472
 
1266
1473
  const setResourceAccessSettings = os.setResourceAccessSettings.handler(
@@ -1276,7 +1483,7 @@ export const createAuthRouter = (
1276
1483
  ],
1277
1484
  set: { teamOnly },
1278
1485
  });
1279
- }
1486
+ },
1280
1487
  );
1281
1488
 
1282
1489
  // S2S Endpoints for middleware
@@ -1297,8 +1504,8 @@ export const createAuthRouter = (
1297
1504
  .where(
1298
1505
  and(
1299
1506
  eq(schema.resourceTeamAccess.resourceType, resourceType),
1300
- eq(schema.resourceTeamAccess.resourceId, resourceId)
1301
- )
1507
+ eq(schema.resourceTeamAccess.resourceId, resourceId),
1508
+ ),
1302
1509
  );
1303
1510
 
1304
1511
  // No grants = global access applies
@@ -1311,8 +1518,8 @@ export const createAuthRouter = (
1311
1518
  .where(
1312
1519
  and(
1313
1520
  eq(schema.resourceAccessSettings.resourceType, resourceType),
1314
- eq(schema.resourceAccessSettings.resourceId, resourceId)
1315
- )
1521
+ eq(schema.resourceAccessSettings.resourceId, resourceId),
1522
+ ),
1316
1523
  )
1317
1524
  .limit(1);
1318
1525
  const isTeamOnly = settingsRows[0]?.teamOnly ?? false;
@@ -1339,10 +1546,10 @@ export const createAuthRouter = (
1339
1546
 
1340
1547
  const field = action === "manage" ? "canManage" : "canRead";
1341
1548
  const hasAccess = grants.some(
1342
- (g) => userTeamIds.has(g.teamId) && g[field]
1549
+ (g) => userTeamIds.has(g.teamId) && g[field],
1343
1550
  );
1344
1551
  return { hasAccess };
1345
- }
1552
+ },
1346
1553
  );
1347
1554
 
1348
1555
  const getAccessibleResourceIds = os.getAccessibleResourceIds.handler(
@@ -1364,8 +1571,8 @@ export const createAuthRouter = (
1364
1571
  .where(
1365
1572
  and(
1366
1573
  eq(schema.resourceTeamAccess.resourceType, resourceType),
1367
- inArray(schema.resourceTeamAccess.resourceId, resourceIds)
1368
- )
1574
+ inArray(schema.resourceTeamAccess.resourceId, resourceIds),
1575
+ ),
1369
1576
  );
1370
1577
 
1371
1578
  // Get resource-level settings for teamOnly
@@ -1375,11 +1582,11 @@ export const createAuthRouter = (
1375
1582
  .where(
1376
1583
  and(
1377
1584
  eq(schema.resourceAccessSettings.resourceType, resourceType),
1378
- inArray(schema.resourceAccessSettings.resourceId, resourceIds)
1379
- )
1585
+ inArray(schema.resourceAccessSettings.resourceId, resourceIds),
1586
+ ),
1380
1587
  );
1381
1588
  const teamOnlyByResource = new Map(
1382
- settingsRows.map((s) => [s.resourceId, s.teamOnly])
1589
+ settingsRows.map((s) => [s.resourceId, s.teamOnly]),
1383
1590
  );
1384
1591
 
1385
1592
  // Get user's teams
@@ -1414,10 +1621,10 @@ export const createAuthRouter = (
1414
1621
  const isTeamOnly = teamOnlyByResource.get(id) ?? false;
1415
1622
  if (!isTeamOnly && hasGlobalAccess) return true;
1416
1623
  return resourceGrants.some(
1417
- (g) => userTeamIds.has(g.teamId) && g[field]
1624
+ (g) => userTeamIds.has(g.teamId) && g[field],
1418
1625
  );
1419
1626
  });
1420
- }
1627
+ },
1421
1628
  );
1422
1629
 
1423
1630
  const deleteResourceGrants = os.deleteResourceGrants.handler(
@@ -1427,10 +1634,10 @@ export const createAuthRouter = (
1427
1634
  .where(
1428
1635
  and(
1429
1636
  eq(schema.resourceTeamAccess.resourceType, input.resourceType),
1430
- eq(schema.resourceTeamAccess.resourceId, input.resourceId)
1431
- )
1637
+ eq(schema.resourceTeamAccess.resourceId, input.resourceId),
1638
+ ),
1432
1639
  );
1433
- }
1640
+ },
1434
1641
  );
1435
1642
 
1436
1643
  return os.router({
@@ -1450,6 +1657,10 @@ export const createAuthRouter = (
1450
1657
  getRegistrationSchema,
1451
1658
  getRegistrationStatus,
1452
1659
  setRegistrationStatus,
1660
+ getOnboardingStatus,
1661
+ completeOnboarding,
1662
+ getCurrentUserProfile,
1663
+ updateCurrentUser,
1453
1664
  getAnonymousAccessRules,
1454
1665
  getUserById,
1455
1666
  filterUsersByAccessRule,