@better-auth/scim 1.5.0-beta.8 → 1.5.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.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  import { base64Url } from "@better-auth/utils/base64";
2
- import { createAuthEndpoint, createAuthMiddleware, defaultKeyHasher } from "better-auth/plugins";
3
- import { APIError, HIDE_METADATA } from "better-auth";
2
+ import { APIError, createAuthEndpoint, createAuthMiddleware, sessionMiddleware } from "better-auth/api";
3
+ import { APIError as APIError$1, HIDE_METADATA } from "better-auth";
4
4
  import { statusCodes } from "better-call";
5
+ import { createHash } from "@better-auth/utils/hash";
5
6
  import { generateRandomString, symmetricDecrypt, symmetricEncrypt } from "better-auth/crypto";
6
- import { APIError as APIError$1, sessionMiddleware } from "better-auth/api";
7
7
  import * as z from "zod";
8
8
 
9
9
  //#region src/scim-error.ts
@@ -11,7 +11,7 @@ import * as z from "zod";
11
11
  * SCIM compliant error
12
12
  * See: https://datatracker.ietf.org/doc/html/rfc7644#section-3.12
13
13
  */
14
- var SCIMAPIError = class extends APIError {
14
+ var SCIMAPIError = class extends APIError$1 {
15
15
  constructor(status = "INTERNAL_SERVER_ERROR", overrides = {}) {
16
16
  const body = {
17
17
  schemas: ["urn:ietf:params:scim:api:messages:2.0:Error"],
@@ -64,9 +64,13 @@ const SCIMErrorOpenAPISchemas = {
64
64
 
65
65
  //#endregion
66
66
  //#region src/scim-tokens.ts
67
+ const defaultKeyHasher = async (token) => {
68
+ const hash = await createHash("SHA-256").digest(new TextEncoder().encode(token));
69
+ return base64Url.encode(new Uint8Array(hash), { padding: false });
70
+ };
67
71
  async function storeSCIMToken(ctx, opts, scimToken) {
68
72
  if (opts.storeSCIMToken === "encrypted") return await symmetricEncrypt({
69
- key: ctx.context.secret,
73
+ key: ctx.context.secretConfig,
70
74
  data: scimToken
71
75
  });
72
76
  if (opts.storeSCIMToken === "hashed") return await defaultKeyHasher(scimToken);
@@ -76,7 +80,7 @@ async function storeSCIMToken(ctx, opts, scimToken) {
76
80
  }
77
81
  async function verifySCIMToken(ctx, opts, storedSCIMToken, scimToken) {
78
82
  if (opts.storeSCIMToken === "encrypted") return await symmetricDecrypt({
79
- key: ctx.context.secret,
83
+ key: ctx.context.secretConfig,
80
84
  data: storedSCIMToken
81
85
  }) === scimToken;
82
86
  if (opts.storeSCIMToken === "hashed") return await defaultKeyHasher(scimToken) === storedSCIMToken;
@@ -155,20 +159,20 @@ const lowerCase = (user, op, resources) => {
155
159
  return op.value.toLowerCase();
156
160
  };
157
161
  const givenName = (user, op, resources) => {
158
- const familyName$1 = (resources.user.name ?? user.name).split(" ").slice(1).join(" ").trim();
159
- const givenName$1 = op.value;
162
+ const familyName = (resources.user.name ?? user.name).split(" ").slice(1).join(" ").trim();
163
+ const givenName = op.value;
160
164
  return getUserFullName(user.email, {
161
- givenName: givenName$1,
162
- familyName: familyName$1
165
+ givenName,
166
+ familyName
163
167
  });
164
168
  };
165
169
  const familyName = (user, op, resources) => {
166
170
  const currentName = resources.user.name ?? user.name;
167
- const givenName$1 = (currentName.split(" ").slice(0, -1).join(" ") || currentName).trim();
168
- const familyName$1 = op.value;
171
+ const givenName = (currentName.split(" ").slice(0, -1).join(" ") || currentName).trim();
172
+ const familyName = op.value;
169
173
  return getUserFullName(user.email, {
170
- givenName: givenName$1,
171
- familyName: familyName$1
174
+ givenName,
175
+ familyName
172
176
  });
173
177
  };
174
178
  const userPatchMappings = {
@@ -618,6 +622,55 @@ const generateSCIMTokenBodySchema = z.object({
618
622
  providerId: z.string().meta({ description: "Unique provider identifier" }),
619
623
  organizationId: z.string().optional().meta({ description: "Optional organization id" })
620
624
  });
625
+ const getSCIMProviderConnectionQuerySchema = z.object({ providerId: z.string() });
626
+ const deleteSCIMProviderConnectionBodySchema = z.object({ providerId: z.string() });
627
+ async function getSCIMUserOrgIds(ctx, userId) {
628
+ const members = await ctx.context.adapter.findMany({
629
+ model: "member",
630
+ where: [{
631
+ field: "userId",
632
+ value: userId
633
+ }]
634
+ });
635
+ return new Set(members.map((m) => m.organizationId));
636
+ }
637
+ function normalizeSCIMProvider(provider) {
638
+ return {
639
+ id: provider.id,
640
+ providerId: provider.providerId,
641
+ organizationId: provider.organizationId ?? null
642
+ };
643
+ }
644
+ async function findOrganizationMember(ctx, userId, organizationId) {
645
+ return ctx.context.adapter.findOne({
646
+ model: "member",
647
+ where: [{
648
+ field: "userId",
649
+ value: userId
650
+ }, {
651
+ field: "organizationId",
652
+ value: organizationId
653
+ }]
654
+ });
655
+ }
656
+ async function assertSCIMProviderAccess(ctx, userId, provider) {
657
+ if (provider.organizationId) {
658
+ if (!ctx.context.hasPlugin("organization")) throw new APIError("FORBIDDEN", { message: "Organization plugin is required to access this SCIM provider" });
659
+ if (!await findOrganizationMember(ctx, userId, provider.organizationId)) throw new APIError("FORBIDDEN", { message: "You must be a member of the organization to access this provider" });
660
+ } else if (provider.userId && provider.userId !== userId) throw new APIError("FORBIDDEN", { message: "You must be the owner to access this provider" });
661
+ }
662
+ async function checkSCIMProviderAccess(ctx, userId, providerId) {
663
+ const provider = await ctx.context.adapter.findOne({
664
+ model: "scimProvider",
665
+ where: [{
666
+ field: "providerId",
667
+ value: providerId
668
+ }]
669
+ });
670
+ if (!provider) throw new APIError("NOT_FOUND", { message: "SCIM provider not found" });
671
+ await assertSCIMProviderAccess(ctx, userId, provider);
672
+ return provider;
673
+ }
621
674
  const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
622
675
  method: "POST",
623
676
  body: generateSCIMTokenBodySchema,
@@ -639,22 +692,12 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
639
692
  }, async (ctx) => {
640
693
  const { providerId, organizationId } = ctx.body;
641
694
  const user = ctx.context.session.user;
642
- if (providerId.includes(":")) throw new APIError$1("BAD_REQUEST", { message: "Provider id contains forbidden characters" });
643
- const isOrgPluginEnabled = ctx.context.options.plugins?.some((p) => p.id === "organization");
644
- if (organizationId && !isOrgPluginEnabled) throw new APIError$1("BAD_REQUEST", { message: "Restricting a token to an organization requires the organization plugin" });
695
+ if (providerId.includes(":")) throw new APIError("BAD_REQUEST", { message: "Provider id contains forbidden characters" });
696
+ if (organizationId && !ctx.context.hasPlugin("organization")) throw new APIError("BAD_REQUEST", { message: "Restricting a token to an organization requires the organization plugin" });
645
697
  let member = null;
646
698
  if (organizationId) {
647
- member = await ctx.context.adapter.findOne({
648
- model: "member",
649
- where: [{
650
- field: "userId",
651
- value: user.id
652
- }, {
653
- field: "organizationId",
654
- value: organizationId
655
- }]
656
- });
657
- if (!member) throw new APIError$1("FORBIDDEN", { message: "You are not a member of the organization" });
699
+ member = await findOrganizationMember(ctx, user.id, organizationId);
700
+ if (!member) throw new APIError("FORBIDDEN", { message: "You are not a member of the organization" });
658
701
  }
659
702
  const scimProvider = await ctx.context.adapter.findOne({
660
703
  model: "scimProvider",
@@ -666,13 +709,16 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
666
709
  value: organizationId
667
710
  }] : []]
668
711
  });
669
- if (scimProvider) await ctx.context.adapter.delete({
670
- model: "scimProvider",
671
- where: [{
672
- field: "id",
673
- value: scimProvider.id
674
- }]
675
- });
712
+ if (scimProvider) {
713
+ await assertSCIMProviderAccess(ctx, user.id, scimProvider);
714
+ await ctx.context.adapter.delete({
715
+ model: "scimProvider",
716
+ where: [{
717
+ field: "id",
718
+ value: scimProvider.id
719
+ }]
720
+ });
721
+ }
676
722
  const baseToken = generateRandomString(24);
677
723
  const scimToken = base64Url.encode(`${baseToken}:${providerId}${organizationId ? `:${organizationId}` : ""}`);
678
724
  if (opts.beforeSCIMTokenGenerated) await opts.beforeSCIMTokenGenerated({
@@ -685,7 +731,8 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
685
731
  data: {
686
732
  providerId,
687
733
  organizationId,
688
- scimToken: await storeSCIMToken(ctx, opts, baseToken)
734
+ scimToken: await storeSCIMToken(ctx, opts, baseToken),
735
+ ...opts.providerOwnership?.enabled ? { userId: user.id } : {}
689
736
  }
690
737
  });
691
738
  if (opts.afterSCIMTokenGenerated) await opts.afterSCIMTokenGenerated({
@@ -697,6 +744,110 @@ const generateSCIMToken = (opts) => createAuthEndpoint("/scim/generate-token", {
697
744
  ctx.setStatus(201);
698
745
  return ctx.json({ scimToken });
699
746
  });
747
+ const listSCIMProviderConnections = () => createAuthEndpoint("/scim/list-provider-connections", {
748
+ method: "GET",
749
+ use: [sessionMiddleware],
750
+ metadata: { openapi: {
751
+ operationId: "listSCIMProviderConnections",
752
+ summary: "List SCIM providers",
753
+ description: "Returns SCIM providers for organizations the user is a member of.",
754
+ responses: { "200": {
755
+ description: "List of SCIM providers",
756
+ content: { "application/json": { schema: {
757
+ type: "object",
758
+ properties: { providers: {
759
+ type: "array",
760
+ items: {
761
+ type: "object",
762
+ properties: {
763
+ id: { type: "string" },
764
+ providerId: { type: "string" },
765
+ organizationId: {
766
+ type: "string",
767
+ nullable: true
768
+ }
769
+ }
770
+ }
771
+ } }
772
+ } } }
773
+ } }
774
+ } }
775
+ }, async (ctx) => {
776
+ const userId = ctx.context.session.user.id;
777
+ const userOrgIds = ctx.context.hasPlugin("organization") ? await getSCIMUserOrgIds(ctx, userId) : /* @__PURE__ */ new Set();
778
+ const providers = (await ctx.context.adapter.findMany({ model: "scimProvider" })).filter((p) => {
779
+ if (p.organizationId) return userOrgIds.has(p.organizationId);
780
+ if (p.userId === userId) return true;
781
+ return !p.userId;
782
+ }).map((p) => normalizeSCIMProvider(p));
783
+ return ctx.json({ providers });
784
+ });
785
+ const getSCIMProviderConnection = () => createAuthEndpoint("/scim/get-provider-connection", {
786
+ method: "GET",
787
+ use: [sessionMiddleware],
788
+ query: getSCIMProviderConnectionQuerySchema,
789
+ metadata: { openapi: {
790
+ operationId: "getSCIMProviderConnection",
791
+ summary: "Get SCIM provider details",
792
+ description: "Returns details for a specific SCIM provider",
793
+ responses: {
794
+ "200": {
795
+ description: "SCIM provider details",
796
+ content: { "application/json": { schema: {
797
+ type: "object",
798
+ properties: {
799
+ id: { type: "string" },
800
+ providerId: { type: "string" },
801
+ organizationId: {
802
+ type: "string",
803
+ nullable: true
804
+ }
805
+ }
806
+ } } }
807
+ },
808
+ "404": { description: "Provider not found" },
809
+ "403": { description: "Access denied" }
810
+ }
811
+ } }
812
+ }, async (ctx) => {
813
+ const { providerId } = ctx.query;
814
+ const userId = ctx.context.session.user.id;
815
+ const provider = await checkSCIMProviderAccess(ctx, userId, providerId);
816
+ return ctx.json(normalizeSCIMProvider(provider));
817
+ });
818
+ const deleteSCIMProviderConnection = () => createAuthEndpoint("/scim/delete-provider-connection", {
819
+ method: "POST",
820
+ use: [sessionMiddleware],
821
+ body: deleteSCIMProviderConnectionBodySchema,
822
+ metadata: { openapi: {
823
+ operationId: "deleteSCIMProviderConnection",
824
+ summary: "Delete SCIM provider",
825
+ description: "Deletes a SCIM provider and invalidates its token",
826
+ responses: {
827
+ "200": {
828
+ description: "SCIM provider deleted successfully",
829
+ content: { "application/json": { schema: {
830
+ type: "object",
831
+ properties: { success: { type: "boolean" } }
832
+ } } }
833
+ },
834
+ "404": { description: "Provider not found" },
835
+ "403": { description: "Access denied" }
836
+ }
837
+ } }
838
+ }, async (ctx) => {
839
+ const { providerId } = ctx.body;
840
+ const userId = ctx.context.session.user.id;
841
+ await checkSCIMProviderAccess(ctx, userId, providerId);
842
+ await ctx.context.adapter.delete({
843
+ model: "scimProvider",
844
+ where: [{
845
+ field: "providerId",
846
+ value: providerId
847
+ }]
848
+ });
849
+ return ctx.json({ success: true });
850
+ });
700
851
  const createSCIMUser = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
701
852
  method: "POST",
702
853
  body: APIUserSchema,
@@ -781,15 +932,15 @@ const createSCIMUser = (authMiddleware) => createAuthEndpoint("/scim/v2/Users",
781
932
  if (existingUser) {
782
933
  user = existingUser;
783
934
  account = await ctx.context.adapter.transaction(async () => {
784
- const account$1 = await createAccount(user.id);
935
+ const account = await createAccount(user.id);
785
936
  await createOrgMembership(user.id);
786
- return account$1;
937
+ return account;
787
938
  });
788
939
  } else [user, account] = await ctx.context.adapter.transaction(async () => {
789
- const user$1 = await createUser();
790
- const account$1 = await createAccount(user$1.id);
791
- await createOrgMembership(user$1.id);
792
- return [user$1, account$1];
940
+ const user = await createUser();
941
+ const account = await createAccount(user.id);
942
+ await createOrgMembership(user.id);
943
+ return [user, account];
793
944
  });
794
945
  const userResource = createUserResource(ctx.context.baseURL, user, account);
795
946
  ctx.setStatus(201);
@@ -873,6 +1024,13 @@ const listSCIMUsers = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
873
1024
  },
874
1025
  use: [authMiddleware]
875
1026
  }, async (ctx) => {
1027
+ const emptyListResponse = {
1028
+ schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
1029
+ totalResults: 0,
1030
+ startIndex: 1,
1031
+ itemsPerPage: 0,
1032
+ Resources: []
1033
+ };
876
1034
  const apiFilters = parseSCIMAPIUserFilter(ctx.query?.filter);
877
1035
  ctx.context.logger.info("Querying result with filters: ", apiFilters);
878
1036
  const providerId = ctx.context.scimProvider.providerId;
@@ -884,15 +1042,15 @@ const listSCIMUsers = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
884
1042
  }]
885
1043
  });
886
1044
  const accountUserIds = accounts.map((account) => account.userId);
1045
+ if (accountUserIds.length === 0) return ctx.json(emptyListResponse);
887
1046
  let userFilters = [{
888
1047
  field: "id",
889
1048
  value: accountUserIds,
890
1049
  operator: "in"
891
1050
  }];
892
1051
  const organizationId = ctx.context.scimProvider.organizationId;
893
- if (organizationId) userFilters = [{
894
- field: "id",
895
- value: (await ctx.context.adapter.findMany({
1052
+ if (organizationId) {
1053
+ const memberUserIds = (await ctx.context.adapter.findMany({
896
1054
  model: "member",
897
1055
  where: [{
898
1056
  field: "organizationId",
@@ -902,9 +1060,14 @@ const listSCIMUsers = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
902
1060
  value: accountUserIds,
903
1061
  operator: "in"
904
1062
  }]
905
- })).map((member) => member.userId),
906
- operator: "in"
907
- }];
1063
+ })).map((member) => member.userId);
1064
+ if (memberUserIds.length === 0) return ctx.json(emptyListResponse);
1065
+ userFilters = [{
1066
+ field: "id",
1067
+ value: memberUserIds,
1068
+ operator: "in"
1069
+ }];
1070
+ }
908
1071
  const users = await ctx.context.adapter.findMany({
909
1072
  model: "user",
910
1073
  where: [...userFilters, ...apiFilters]
@@ -1265,6 +1428,7 @@ const parseSCIMAPIUserFilter = (filter) => {
1265
1428
  const scim = (options) => {
1266
1429
  const opts = {
1267
1430
  storeSCIMToken: "plain",
1431
+ providerOwnership: { enabled: false },
1268
1432
  ...options
1269
1433
  };
1270
1434
  const authMiddleware = authMiddlewareFactory(opts);
@@ -1272,6 +1436,9 @@ const scim = (options) => {
1272
1436
  id: "scim",
1273
1437
  endpoints: {
1274
1438
  generateSCIMToken: generateSCIMToken(opts),
1439
+ listSCIMProviderConnections: listSCIMProviderConnections(),
1440
+ getSCIMProviderConnection: getSCIMProviderConnection(),
1441
+ deleteSCIMProviderConnection: deleteSCIMProviderConnection(),
1275
1442
  getSCIMUser: getSCIMUser(authMiddleware),
1276
1443
  createSCIMUser: createSCIMUser(authMiddleware),
1277
1444
  patchSCIMUser: patchSCIMUser(authMiddleware),
@@ -1298,11 +1465,16 @@ const scim = (options) => {
1298
1465
  organizationId: {
1299
1466
  type: "string",
1300
1467
  required: false
1301
- }
1468
+ },
1469
+ ...opts.providerOwnership?.enabled ? { userId: {
1470
+ type: "string",
1471
+ required: false
1472
+ } } : {}
1302
1473
  } } },
1303
1474
  options
1304
1475
  };
1305
1476
  };
1306
1477
 
1307
1478
  //#endregion
1308
- export { scim };
1479
+ export { scim };
1480
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["APIError"],"sources":["../src/scim-error.ts","../src/scim-tokens.ts","../src/middlewares.ts","../src/mappings.ts","../src/patch-operations.ts","../src/user-schemas.ts","../src/scim-filters.ts","../src/scim-metadata.ts","../src/utils.ts","../src/scim-resources.ts","../src/routes.ts","../src/index.ts"],"sourcesContent":["import type { Status } from \"better-auth\";\nimport { APIError } from \"better-auth\";\nimport { statusCodes } from \"better-call\";\n\n/**\n * SCIM compliant error\n * See: https://datatracker.ietf.org/doc/html/rfc7644#section-3.12\n */\nexport class SCIMAPIError extends APIError {\n\tconstructor(\n\t\tstatus: keyof typeof statusCodes | Status = \"INTERNAL_SERVER_ERROR\",\n\t\toverrides: any = {},\n\t) {\n\t\tconst body = {\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:Error\"],\n\t\t\tstatus: (typeof status === \"number\"\n\t\t\t\t? status\n\t\t\t\t: statusCodes[status]\n\t\t\t).toString(),\n\t\t\tdetail: overrides.detail,\n\t\t\t...overrides,\n\t\t};\n\t\tsuper(status, body);\n\t\tthis.message = body.detail ?? body.message;\n\t}\n}\n\nconst SCIMErrorOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tstatus: {\n\t\t\ttype: \"string\",\n\t\t},\n\t\tdetail: {\n\t\t\ttype: \"string\",\n\t\t},\n\t\tscimType: {\n\t\t\ttype: \"string\",\n\t\t},\n\t},\n} as const;\n\nexport const SCIMErrorOpenAPISchemas = {\n\t\"400\": {\n\t\tdescription:\n\t\t\t\"Bad Request. Usually due to missing parameters, or invalid parameters\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"401\": {\n\t\tdescription: \"Unauthorized. Due to missing or invalid authentication.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"403\": {\n\t\tdescription: \"Unauthorized. Due to missing or invalid authentication.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"404\": {\n\t\tdescription: \"Not Found. The requested resource was not found.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"429\": {\n\t\tdescription:\n\t\t\t\"Too Many Requests. You have exceeded the rate limit. Try again later.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n\t\"500\": {\n\t\tdescription:\n\t\t\t\"Internal Server Error. This is a problem with the server that you cannot fix.\",\n\t\tcontent: {\n\t\t\t\"application/json\": {\n\t\t\t\tschema: SCIMErrorOpenAPISchema,\n\t\t\t},\n\t\t},\n\t},\n};\n","import { base64Url } from \"@better-auth/utils/base64\";\nimport { createHash } from \"@better-auth/utils/hash\";\nimport type { GenericEndpointContext } from \"better-auth\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"better-auth/crypto\";\nimport type { SCIMOptions } from \"./types\";\n\nconst defaultKeyHasher = async (token: string) => {\n\tconst hash = await createHash(\"SHA-256\").digest(\n\t\tnew TextEncoder().encode(token),\n\t);\n\treturn base64Url.encode(new Uint8Array(hash), { padding: false });\n};\n\nexport async function storeSCIMToken(\n\tctx: GenericEndpointContext,\n\topts: SCIMOptions,\n\tscimToken: string,\n) {\n\tif (opts.storeSCIMToken === \"encrypted\") {\n\t\treturn await symmetricEncrypt({\n\t\t\tkey: ctx.context.secretConfig,\n\t\t\tdata: scimToken,\n\t\t});\n\t}\n\tif (opts.storeSCIMToken === \"hashed\") {\n\t\treturn await defaultKeyHasher(scimToken);\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"hash\" in opts.storeSCIMToken\n\t) {\n\t\treturn await opts.storeSCIMToken.hash(scimToken);\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"encrypt\" in opts.storeSCIMToken\n\t) {\n\t\treturn await opts.storeSCIMToken.encrypt(scimToken);\n\t}\n\n\treturn scimToken;\n}\n\nexport async function verifySCIMToken(\n\tctx: GenericEndpointContext,\n\topts: SCIMOptions,\n\tstoredSCIMToken: string,\n\tscimToken: string,\n): Promise<boolean> {\n\tif (opts.storeSCIMToken === \"encrypted\") {\n\t\treturn (\n\t\t\t(await symmetricDecrypt({\n\t\t\t\tkey: ctx.context.secretConfig,\n\t\t\t\tdata: storedSCIMToken,\n\t\t\t})) === scimToken\n\t\t);\n\t}\n\tif (opts.storeSCIMToken === \"hashed\") {\n\t\tconst hashedSCIMToken = await defaultKeyHasher(scimToken);\n\t\treturn hashedSCIMToken === storedSCIMToken;\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"hash\" in opts.storeSCIMToken\n\t) {\n\t\tconst hashedSCIMToken = await opts.storeSCIMToken.hash(scimToken);\n\t\treturn hashedSCIMToken === storedSCIMToken;\n\t}\n\tif (\n\t\ttypeof opts.storeSCIMToken === \"object\" &&\n\t\t\"decrypt\" in opts.storeSCIMToken\n\t) {\n\t\tconst decryptedSCIMToken =\n\t\t\tawait opts.storeSCIMToken.decrypt(storedSCIMToken);\n\t\treturn decryptedSCIMToken === scimToken;\n\t}\n\n\treturn scimToken === storedSCIMToken;\n}\n","import { base64Url } from \"@better-auth/utils/base64\";\nimport { createAuthMiddleware } from \"better-auth/api\";\nimport { SCIMAPIError } from \"./scim-error\";\nimport { verifySCIMToken } from \"./scim-tokens\";\nimport type { SCIMOptions, SCIMProvider } from \"./types\";\n\nexport type AuthMiddleware = ReturnType<typeof authMiddlewareFactory>;\n\n/**\n * The middleware forces the endpoint to have a valid token\n */\nexport const authMiddlewareFactory = (opts: SCIMOptions) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tconst authHeader = ctx.headers?.get(\"Authorization\");\n\t\tconst authSCIMToken = authHeader?.replace(/^Bearer\\s+/i, \"\");\n\n\t\tif (!authSCIMToken) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"SCIM token is required\",\n\t\t\t});\n\t\t}\n\n\t\tconst baseScimTokenParts = new TextDecoder()\n\t\t\t.decode(base64Url.decode(authSCIMToken))\n\t\t\t.split(\":\");\n\n\t\tconst [scimToken, providerId] = baseScimTokenParts;\n\t\tconst organizationId = baseScimTokenParts.slice(2).join(\":\");\n\n\t\tif (!scimToken || !providerId) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\tlet scimProvider: Omit<SCIMProvider, \"id\"> | null =\n\t\t\topts.defaultSCIM?.find((p) => {\n\t\t\t\tif (p.providerId === providerId && !organizationId) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn !!(\n\t\t\t\t\tp.providerId === providerId &&\n\t\t\t\t\torganizationId &&\n\t\t\t\t\tp.organizationId === organizationId\n\t\t\t\t);\n\t\t\t}) ?? null;\n\n\t\tif (scimProvider) {\n\t\t\tif (scimProvider.scimToken === scimToken) {\n\t\t\t\treturn { authSCIMToken: scimProvider.scimToken, scimProvider };\n\t\t\t} else {\n\t\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tscimProvider = await ctx.context.adapter.findOne<SCIMProvider>({\n\t\t\tmodel: \"scimProvider\",\n\t\t\twhere: [\n\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t...(organizationId\n\t\t\t\t\t? [{ field: \"organizationId\", value: organizationId }]\n\t\t\t\t\t: []),\n\t\t\t],\n\t\t});\n\n\t\tif (!scimProvider) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\tconst isValidToken = await verifySCIMToken(\n\t\t\tctx,\n\t\t\topts,\n\t\t\tscimProvider.scimToken,\n\t\t\tscimToken,\n\t\t);\n\n\t\tif (!isValidToken) {\n\t\t\tthrow new SCIMAPIError(\"UNAUTHORIZED\", {\n\t\t\t\tdetail: \"Invalid SCIM token\",\n\t\t\t});\n\t\t}\n\n\t\treturn { authSCIMToken: scimToken, scimProvider };\n\t});\n","import type { SCIMEmail, SCIMName } from \"./types\";\n\nexport const getAccountId = (userName: string, externalId?: string) => {\n\treturn externalId ?? userName;\n};\n\nconst getFormattedName = (name: SCIMName) => {\n\tif (name.givenName && name.familyName) {\n\t\treturn `${name.givenName} ${name.familyName}`;\n\t}\n\n\tif (name.givenName) {\n\t\treturn name.givenName;\n\t}\n\n\treturn name.familyName ?? \"\";\n};\n\nexport const getUserFullName = (email: string, name?: SCIMName) => {\n\tif (name) {\n\t\tconst formatted = name.formatted?.trim() ?? \"\";\n\t\tif (formatted.length > 0) {\n\t\t\treturn formatted;\n\t\t}\n\n\t\treturn getFormattedName(name) || email;\n\t}\n\n\treturn email;\n};\n\nexport const getUserPrimaryEmail = (userName: string, emails?: SCIMEmail[]) => {\n\treturn (\n\t\temails?.find((email) => email.primary)?.value ??\n\t\temails?.[0]?.value ??\n\t\tuserName\n\t);\n};\n","import type { User } from \"better-auth\";\nimport { getUserFullName } from \"./mappings\";\n\ntype Operation = {\n\top: \"add\" | \"remove\" | \"replace\";\n\tvalue: any;\n\tpath?: string;\n};\n\ntype Mapping = {\n\ttarget: string;\n\tresource: \"user\" | \"account\";\n\tmap: (user: User, op: Operation, resources: Resources) => any;\n};\n\ntype Resources = {\n\tuser: Record<string, any>;\n\taccount: Record<string, any>;\n};\n\nconst identity = (user: User, op: Operation, resources: Resources) => {\n\treturn op.value;\n};\n\nconst lowerCase = (user: User, op: Operation, resources: Resources) => {\n\treturn op.value.toLowerCase();\n};\n\nconst givenName = (user: User, op: Operation, resources: Resources) => {\n\tconst currentName = (resources.user.name as string) ?? user.name;\n\tconst familyName = currentName.split(\" \").slice(1).join(\" \").trim();\n\tconst givenName = op.value;\n\n\treturn getUserFullName(user.email, {\n\t\tgivenName,\n\t\tfamilyName,\n\t});\n};\n\nconst familyName = (user: User, op: Operation, resources: Resources) => {\n\tconst currentName = (resources.user.name as string) ?? user.name;\n\tconst givenName = (\n\t\tcurrentName.split(\" \").slice(0, -1).join(\" \") || currentName\n\t).trim();\n\tconst familyName = op.value;\n\treturn getUserFullName(user.email, {\n\t\tgivenName,\n\t\tfamilyName,\n\t});\n};\n\nconst userPatchMappings: Record<string, Mapping> = {\n\t\"/name/formatted\": { resource: \"user\", target: \"name\", map: identity },\n\t\"/name/givenName\": { resource: \"user\", target: \"name\", map: givenName },\n\t\"/name/familyName\": {\n\t\tresource: \"user\",\n\t\ttarget: \"name\",\n\t\tmap: familyName,\n\t},\n\t\"/externalId\": {\n\t\tresource: \"account\",\n\t\ttarget: \"accountId\",\n\t\tmap: identity,\n\t},\n\t\"/userName\": { resource: \"user\", target: \"email\", map: lowerCase },\n};\n\nconst normalizePath = (path: string): string => {\n\tconst withoutLeadingSlash = path.startsWith(\"/\") ? path.slice(1) : path;\n\treturn `/${withoutLeadingSlash.replaceAll(\".\", \"/\")}`;\n};\n\nconst isNestedObject = (value: unknown): value is Record<string, unknown> => {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nconst applyMapping = (\n\tuser: User,\n\tresources: Resources,\n\tpath: string,\n\tvalue: unknown,\n\top: \"add\" | \"replace\",\n) => {\n\tconst normalizedPath = normalizePath(path);\n\tconst mapping = userPatchMappings[normalizedPath];\n\n\tif (!mapping) {\n\t\treturn;\n\t}\n\n\tconst newValue = mapping.map(\n\t\tuser,\n\t\t{\n\t\t\top,\n\t\t\tvalue,\n\t\t\tpath: normalizedPath,\n\t\t},\n\t\tresources,\n\t);\n\n\tif (op === \"add\" && mapping.resource === \"user\") {\n\t\tconst currentValue = (user as Record<string, unknown>)[mapping.target];\n\t\tif (currentValue === newValue) {\n\t\t\treturn;\n\t\t}\n\t}\n\n\tresources[mapping.resource][mapping.target] = newValue;\n};\n\nconst applyPatchValue = (\n\tuser: User,\n\tresources: Resources,\n\tvalue: unknown,\n\top: \"add\" | \"replace\",\n\tpath?: string | undefined,\n) => {\n\tif (isNestedObject(value)) {\n\t\tfor (const [key, nestedValue] of Object.entries(value)) {\n\t\t\tconst nestedPath = path ? `${path}.${key}` : key;\n\t\t\tapplyPatchValue(user, resources, nestedValue, op, nestedPath);\n\t\t}\n\t} else if (path) {\n\t\tapplyMapping(user, resources, path, value, op);\n\t}\n};\n\nexport const buildUserPatch = (user: User, operations: Operation[]) => {\n\tconst userPatch: Record<string, any> = {};\n\tconst accountPatch: Record<string, any> = {};\n\tconst resources: Resources = { user: userPatch, account: accountPatch };\n\n\tfor (const operation of operations) {\n\t\tif (operation.op !== \"add\" && operation.op !== \"replace\") {\n\t\t\tcontinue;\n\t\t}\n\n\t\tapplyPatchValue(\n\t\t\tuser,\n\t\t\tresources,\n\t\t\toperation.value,\n\t\t\toperation.op,\n\t\t\toperation.path,\n\t\t);\n\t}\n\n\treturn resources;\n};\n","import * as z from \"zod\";\n\nexport const APIUserSchema = z.object({\n\tuserName: z.string().lowercase(),\n\texternalId: z.string().optional(),\n\tname: z\n\t\t.object({\n\t\t\tformatted: z.string().optional(),\n\t\t\tgivenName: z.string().optional(),\n\t\t\tfamilyName: z.string().optional(),\n\t\t})\n\t\t.optional(),\n\temails: z\n\t\t.array(\n\t\t\tz.object({\n\t\t\t\tvalue: z.email(),\n\t\t\t\tprimary: z.boolean().optional(),\n\t\t\t}),\n\t\t)\n\t\t.optional(),\n});\n\nexport const OpenAPIUserResourceSchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tid: { type: \"string\" },\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tcreated: { type: \"string\", format: \"date-time\" },\n\t\t\t\tlastModified: { type: \"string\", format: \"date-time\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tuserName: { type: \"string\" },\n\t\tname: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tformatted: { type: \"string\" },\n\t\t\t\tgivenName: { type: \"string\" },\n\t\t\t\tfamilyName: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t\tdisplayName: { type: \"string\" },\n\t\tactive: { type: \"boolean\" },\n\t\temails: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: {\n\t\t\t\t\tvalue: { type: \"string\" },\n\t\t\t\t\tprimary: { type: \"boolean\" },\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t},\n} as const;\n\nexport const SCIMUserResourceSchema = {\n\tid: \"urn:ietf:params:scim:schemas:core:2.0:User\",\n\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:Schema\"],\n\tname: \"User\",\n\tdescription: \"User Account\",\n\tattributes: [\n\t\t{\n\t\t\tname: \"id\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription: \"Unique opaque identifier for the User\",\n\t\t\trequired: false,\n\t\t\tcaseExact: true,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"server\",\n\t\t},\n\t\t{\n\t\t\tname: \"userName\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"Unique identifier for the User, typically used by the user to directly authenticate to the service provider\",\n\t\t\trequired: true,\n\t\t\tcaseExact: false,\n\t\t\tmutability: \"readWrite\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"server\",\n\t\t},\n\t\t{\n\t\t\tname: \"displayName\",\n\t\t\ttype: \"string\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"The name of the User, suitable for display to end-users. The name SHOULD be the full name of the User being described, if known.\",\n\t\t\trequired: false,\n\t\t\tcaseExact: true,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"none\",\n\t\t},\n\t\t{\n\t\t\tname: \"active\",\n\t\t\ttype: \"boolean\",\n\t\t\tmultiValued: false,\n\t\t\tdescription:\n\t\t\t\t\"A Boolean value indicating the User's administrative status.\",\n\t\t\trequired: false,\n\t\t\tmutability: \"readOnly\",\n\t\t\treturned: \"default\",\n\t\t},\n\t\t{\n\t\t\tname: \"name\",\n\t\t\ttype: \"complex\",\n\t\t\tmultiValued: false,\n\t\t\tdescription: \"The components of the user's real name.\",\n\t\t\trequired: false,\n\t\t\tsubAttributes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"formatted\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The full name, including all middlenames, titles, and suffixes as appropriate, formatted for display(e.g., 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"familyName\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The family name of the User, or last name in most Western languages (e.g., 'Jensen' given the fullname 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"givenName\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The given name of the User, or first name in most Western languages (e.g., 'Barbara' given the full name 'Ms. Barbara J Jensen, III').\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"none\",\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\t{\n\t\t\tname: \"emails\",\n\t\t\ttype: \"complex\",\n\t\t\tmultiValued: true,\n\t\t\tdescription:\n\t\t\t\t\"Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.\",\n\t\t\trequired: false,\n\t\t\tsubAttributes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"value\",\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Email addresses for the user. The value SHOULD be canonicalized by the service provider, e.g., 'bjensen@example.com' instead of 'bjensen@EXAMPLE.COM'. Canonical type values of 'work', 'home', and 'other'.\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tcaseExact: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t\tuniqueness: \"server\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tname: \"primary\",\n\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\tmultiValued: false,\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"A Boolean value indicating the 'primary' or preferred attribute value for this attribute, e.g., the preferred mailing address or primary email address. The primary attribute value 'true' MUST appear no more than once.\",\n\t\t\t\t\trequired: false,\n\t\t\t\t\tmutability: \"readWrite\",\n\t\t\t\t\treturned: \"default\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tmutability: \"readWrite\",\n\t\t\treturned: \"default\",\n\t\t\tuniqueness: \"none\",\n\t\t},\n\t],\n\tmeta: {\n\t\tresourceType: \"Schema\",\n\t\tlocation: \"/scim/v2/Schemas/urn:ietf:params:scim:schemas:core:2.0:User\",\n\t},\n};\n\nexport const SCIMUserResourceType = {\n\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:ResourceType\"],\n\tid: \"User\",\n\tname: \"User\",\n\tendpoint: \"/Users\",\n\tdescription: \"User Account\",\n\tschema: \"urn:ietf:params:scim:schemas:core:2.0:User\",\n\tmeta: {\n\t\tresourceType: \"ResourceType\",\n\t\tlocation: \"/scim/v2/ResourceTypes/User\",\n\t},\n};\n","import { SCIMUserResourceSchema } from \"./user-schemas\";\n\nexport type DBFilter = {\n\tfield: string;\n\tvalue: string | string[];\n\toperator?: any;\n};\n\nconst SCIMOperators: Record<string, string | undefined> = {\n\teq: \"eq\",\n};\n\nconst SCIMUserAttributes: Record<string, string | undefined> = {\n\tuserName: \"email\",\n};\n\nexport class SCIMParseError extends Error {}\n\nconst SCIMFilterRegex =\n\t/^\\s*(?<attribute>[^\\s]+)\\s+(?<op>eq|ne|co|sw|ew|pr)\\s*(?:(?<value>\"[^\"]*\"|[^\\s]+))?\\s*$/i;\n\nconst parseSCIMFilter = (filter: string) => {\n\tconst match = filter.match(SCIMFilterRegex);\n\tif (!match) {\n\t\tthrow new SCIMParseError(\"Invalid filter expression\");\n\t}\n\n\tconst attribute = match.groups?.attribute;\n\tconst op = match.groups?.op?.toLowerCase();\n\tconst value = match.groups?.value;\n\n\tif (!attribute || !op || !value) {\n\t\tthrow new SCIMParseError(\"Invalid filter expression\");\n\t}\n\n\tconst operator = SCIMOperators[op];\n\tif (!operator) {\n\t\tthrow new SCIMParseError(`The operator \"${op}\" is not supported`);\n\t}\n\n\treturn { attribute, operator, value };\n};\n\nexport const parseSCIMUserFilter = (filter: string) => {\n\tconst { attribute, operator, value } = parseSCIMFilter(filter);\n\n\tconst filters: DBFilter[] = [];\n\tconst targetAttribute = SCIMUserAttributes[attribute];\n\tconst resourceAttribute = SCIMUserResourceSchema.attributes.find(\n\t\t(attr) => attr.name === attribute,\n\t);\n\n\tif (!targetAttribute || !resourceAttribute) {\n\t\tthrow new SCIMParseError(`The attribute \"${attribute}\" is not supported`);\n\t}\n\n\tlet finalValue = value.replaceAll('\"', \"\");\n\tif (!resourceAttribute.caseExact) {\n\t\tfinalValue = finalValue.toLowerCase();\n\t}\n\n\tfilters.push({\n\t\tfield: targetAttribute,\n\t\tvalue: finalValue,\n\t\toperator,\n\t});\n\n\treturn filters;\n};\n","const MetadataFieldSupportOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tsupported: {\n\t\t\ttype: \"boolean\",\n\t\t},\n\t},\n};\n\nexport const ServiceProviderOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tpatch: MetadataFieldSupportOpenAPISchema,\n\t\tbulk: MetadataFieldSupportOpenAPISchema,\n\t\tfilter: MetadataFieldSupportOpenAPISchema,\n\t\tchangePassword: MetadataFieldSupportOpenAPISchema,\n\t\tsort: MetadataFieldSupportOpenAPISchema,\n\t\tetag: MetadataFieldSupportOpenAPISchema,\n\t\tauthenticationSchemes: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: {\n\t\t\t\t\tname: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tdescription: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tspecUri: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\ttype: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t},\n\t\t\t\t\tprimary: {\n\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\ttype: \"string\",\n\t\t\t},\n\t\t},\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n} as const;\n\nexport const ResourceTypeOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tid: { type: \"string\" },\n\t\tname: { type: \"string\" },\n\t\tendpoint: { type: \"string\" },\n\t\tdescription: { type: \"string\" },\n\t\tschema: { type: \"string\" },\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t},\n\t},\n} as const;\n\nconst SCIMSchemaAttributesOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tname: { type: \"string\" },\n\t\ttype: { type: \"string\" },\n\t\tmultiValued: { type: \"boolean\" },\n\t\tdescription: { type: \"string\" },\n\t\trequired: { type: \"boolean\" },\n\t\tcaseExact: { type: \"boolean\" },\n\t\tmutability: { type: \"string\" },\n\t\treturned: { type: \"string\" },\n\t\tuniqueness: { type: \"string\" },\n\t},\n} as const;\n\nexport const SCIMSchemaOpenAPISchema = {\n\ttype: \"object\",\n\tproperties: {\n\t\tid: { type: \"string\" },\n\t\tschemas: {\n\t\t\ttype: \"array\",\n\t\t\titems: { type: \"string\" },\n\t\t},\n\t\tname: { type: \"string\" },\n\t\tdescription: { type: \"string\" },\n\t\tattributes: {\n\t\t\ttype: \"array\",\n\t\t\titems: {\n\t\t\t\t...SCIMSchemaAttributesOpenAPISchema,\n\t\t\t\tproperties: {\n\t\t\t\t\t...SCIMSchemaAttributesOpenAPISchema.properties,\n\t\t\t\t\tsubAttributes: {\n\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\titems: SCIMSchemaAttributesOpenAPISchema,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tmeta: {\n\t\t\ttype: \"object\",\n\t\t\tproperties: {\n\t\t\t\tresourceType: { type: \"string\" },\n\t\t\t\tlocation: { type: \"string\" },\n\t\t\t},\n\t\t\trequired: [\"resourceType\", \"location\"],\n\t\t},\n\t},\n} as const;\n","export const getResourceURL = (path: string, baseURL: string) => {\n\tconst normalizedBaseURL = baseURL.endsWith(\"/\") ? baseURL : `${baseURL}/`;\n\tconst normalizedPath = path.replace(/^\\/+/, \"\");\n\treturn new URL(normalizedPath, normalizedBaseURL).toString();\n};\n","import type { Account, User } from \"better-auth\";\nimport { SCIMUserResourceSchema } from \"./user-schemas\";\nimport { getResourceURL } from \"./utils\";\n\nexport const createUserResource = (\n\tbaseURL: string,\n\tuser: User,\n\taccount?: Account | null,\n) => {\n\treturn {\n\t\t// Common attributes\n\t\t// See https://datatracker.ietf.org/doc/html/rfc7643#section-3.1\n\n\t\tid: user.id,\n\t\texternalId: account?.accountId,\n\t\tmeta: {\n\t\t\tresourceType: \"User\",\n\t\t\tcreated: user.createdAt,\n\t\t\tlastModified: user.updatedAt,\n\t\t\tlocation: getResourceURL(`/scim/v2/Users/${user.id}`, baseURL),\n\t\t},\n\n\t\t// SCIM user resource\n\t\t// See https://datatracker.ietf.org/doc/html/rfc7643#section-4.1\n\n\t\tuserName: user.email,\n\t\tname: {\n\t\t\tformatted: user.name,\n\t\t},\n\t\tdisplayName: user.name,\n\t\tactive: true,\n\t\temails: [{ primary: true, value: user.email }],\n\t\tschemas: [SCIMUserResourceSchema.id],\n\t};\n};\n","import { base64Url } from \"@better-auth/utils/base64\";\nimport type {\n\tAccount,\n\tDBAdapter,\n\tGenericEndpointContext,\n\tUser,\n} from \"better-auth\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport {\n\tAPIError,\n\tcreateAuthEndpoint,\n\tsessionMiddleware,\n} from \"better-auth/api\";\nimport { generateRandomString } from \"better-auth/crypto\";\nimport type { Member } from \"better-auth/plugins\";\nimport * as z from \"zod\";\nimport { getAccountId, getUserFullName, getUserPrimaryEmail } from \"./mappings\";\nimport type { AuthMiddleware } from \"./middlewares\";\nimport { buildUserPatch } from \"./patch-operations\";\nimport { SCIMAPIError, SCIMErrorOpenAPISchemas } from \"./scim-error\";\nimport type { DBFilter } from \"./scim-filters\";\nimport { parseSCIMUserFilter, SCIMParseError } from \"./scim-filters\";\nimport {\n\tResourceTypeOpenAPISchema,\n\tSCIMSchemaOpenAPISchema,\n\tServiceProviderOpenAPISchema,\n} from \"./scim-metadata\";\nimport { createUserResource } from \"./scim-resources\";\nimport { storeSCIMToken } from \"./scim-tokens\";\nimport type { SCIMOptions, SCIMProvider } from \"./types\";\nimport {\n\tAPIUserSchema,\n\tOpenAPIUserResourceSchema,\n\tSCIMUserResourceSchema,\n\tSCIMUserResourceType,\n} from \"./user-schemas\";\nimport { getResourceURL } from \"./utils\";\n\nconst supportedSCIMSchemas = [SCIMUserResourceSchema];\nconst supportedSCIMResourceTypes = [SCIMUserResourceType];\nconst supportedMediaTypes = [\"application/json\", \"application/scim+json\"];\n\nconst generateSCIMTokenBodySchema = z.object({\n\tproviderId: z.string().meta({ description: \"Unique provider identifier\" }),\n\torganizationId: z\n\t\t.string()\n\t\t.optional()\n\t\t.meta({ description: \"Optional organization id\" }),\n});\n\nconst getSCIMProviderConnectionQuerySchema = z.object({\n\tproviderId: z.string(),\n});\n\nconst deleteSCIMProviderConnectionBodySchema = z.object({\n\tproviderId: z.string(),\n});\n\nasync function getSCIMUserOrgIds(\n\tctx: GenericEndpointContext,\n\tuserId: string,\n): Promise<Set<string>> {\n\tconst members = await ctx.context.adapter.findMany<Member>({\n\t\tmodel: \"member\",\n\t\twhere: [{ field: \"userId\", value: userId }],\n\t});\n\treturn new Set(members.map((m) => m.organizationId));\n}\n\nfunction normalizeSCIMProvider(provider: SCIMProvider) {\n\treturn {\n\t\tid: provider.id,\n\t\tproviderId: provider.providerId,\n\t\torganizationId: provider.organizationId ?? null,\n\t};\n}\n\nasync function findOrganizationMember(\n\tctx: GenericEndpointContext,\n\tuserId: string,\n\torganizationId: string,\n): Promise<Member | null> {\n\treturn ctx.context.adapter.findOne<Member>({\n\t\tmodel: \"member\",\n\t\twhere: [\n\t\t\t{\n\t\t\t\tfield: \"userId\",\n\t\t\t\tvalue: userId,\n\t\t\t},\n\t\t\t{\n\t\t\t\tfield: \"organizationId\",\n\t\t\t\tvalue: organizationId,\n\t\t\t},\n\t\t],\n\t});\n}\n\nasync function assertSCIMProviderAccess(\n\tctx: GenericEndpointContext,\n\tuserId: string,\n\tprovider: SCIMProvider,\n): Promise<void> {\n\tif (provider.organizationId) {\n\t\tif (!ctx.context.hasPlugin(\"organization\")) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage: \"Organization plugin is required to access this SCIM provider\",\n\t\t\t});\n\t\t}\n\n\t\tconst member = await findOrganizationMember(\n\t\t\tctx,\n\t\t\tuserId,\n\t\t\tprovider.organizationId,\n\t\t);\n\n\t\tif (!member) {\n\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\tmessage:\n\t\t\t\t\t\"You must be a member of the organization to access this provider\",\n\t\t\t});\n\t\t}\n\t} else if (provider.userId && provider.userId !== userId) {\n\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\tmessage: \"You must be the owner to access this provider\",\n\t\t});\n\t}\n}\n\nasync function checkSCIMProviderAccess(\n\tctx: GenericEndpointContext,\n\tuserId: string,\n\tproviderId: string,\n): Promise<SCIMProvider> {\n\tconst provider = await ctx.context.adapter.findOne<SCIMProvider>({\n\t\tmodel: \"scimProvider\",\n\t\twhere: [{ field: \"providerId\", value: providerId }],\n\t});\n\n\tif (!provider) {\n\t\tthrow new APIError(\"NOT_FOUND\", {\n\t\t\tmessage: \"SCIM provider not found\",\n\t\t});\n\t}\n\n\tawait assertSCIMProviderAccess(ctx, userId, provider);\n\n\treturn provider;\n}\n\nexport const generateSCIMToken = (opts: SCIMOptions) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/generate-token\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: generateSCIMTokenBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Generates a new SCIM token for the given provider\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Generates a new SCIM token to be used for SCIM operations\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\tdescription: \"SCIM token response\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tscimToken: {\n\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"SCIM token\",\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [sessionMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { providerId, organizationId } = ctx.body;\n\t\t\tconst user = ctx.context.session.user;\n\n\t\t\tif (providerId.includes(\":\")) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Provider id contains forbidden characters\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (organizationId && !ctx.context.hasPlugin(\"organization\")) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t\"Restricting a token to an organization requires the organization plugin\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet member: Member | null = null;\n\t\t\tif (organizationId) {\n\t\t\t\tmember = await findOrganizationMember(ctx, user.id, organizationId);\n\n\t\t\t\tif (!member) {\n\t\t\t\t\tthrow new APIError(\"FORBIDDEN\", {\n\t\t\t\t\t\tmessage: \"You are not a member of the organization\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst scimProvider = await ctx.context.adapter.findOne<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\twhere: [\n\t\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t\t...(organizationId\n\t\t\t\t\t\t? [{ field: \"organizationId\", value: organizationId }]\n\t\t\t\t\t\t: []),\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (scimProvider) {\n\t\t\t\tawait assertSCIMProviderAccess(ctx, user.id, scimProvider);\n\t\t\t\tawait ctx.context.adapter.delete<SCIMProvider>({\n\t\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\t\twhere: [{ field: \"id\", value: scimProvider.id }],\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst baseToken = generateRandomString(24);\n\t\t\tconst scimToken = base64Url.encode(\n\t\t\t\t`${baseToken}:${providerId}${organizationId ? `:${organizationId}` : \"\"}`,\n\t\t\t);\n\n\t\t\tif (opts.beforeSCIMTokenGenerated) {\n\t\t\t\tawait opts.beforeSCIMTokenGenerated({\n\t\t\t\t\tuser,\n\t\t\t\t\tmember,\n\t\t\t\t\tscimToken,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst newSCIMProvider = await ctx.context.adapter.create<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\tdata: {\n\t\t\t\t\tproviderId: providerId,\n\t\t\t\t\torganizationId: organizationId,\n\t\t\t\t\tscimToken: await storeSCIMToken(ctx, opts, baseToken),\n\t\t\t\t\t...(opts.providerOwnership?.enabled ? { userId: user.id } : {}),\n\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (opts.afterSCIMTokenGenerated) {\n\t\t\t\tawait opts.afterSCIMTokenGenerated({\n\t\t\t\t\tuser,\n\t\t\t\t\tmember,\n\t\t\t\t\tscimToken,\n\t\t\t\t\tscimProvider: newSCIMProvider,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tctx.setStatus(201);\n\n\t\t\treturn ctx.json({\n\t\t\t\tscimToken,\n\t\t\t});\n\t\t},\n\t);\n\nexport const listSCIMProviderConnections = () =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/list-provider-connections\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tuse: [sessionMiddleware],\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"listSCIMProviderConnections\",\n\t\t\t\t\tsummary: \"List SCIM providers\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Returns SCIM providers for organizations the user is a member of.\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"List of SCIM providers\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tproviders: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\titems: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tid: { type: \"string\" },\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tproviderId: { type: \"string\" },\n\t\t\t\t\t\t\t\t\t\t\t\t\t\torganizationId: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.context.session.user.id;\n\t\t\tconst userOrgIds: Set<string> = ctx.context.hasPlugin(\"organization\")\n\t\t\t\t? await getSCIMUserOrgIds(ctx, userId)\n\t\t\t\t: new Set();\n\n\t\t\tconst allProviders = await ctx.context.adapter.findMany<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t});\n\n\t\t\tconst accessibleProviders = allProviders.filter((p) => {\n\t\t\t\tif (p.organizationId) return userOrgIds.has(p.organizationId); // org level access\n\t\t\t\tif (p.userId === userId) return true; // owner access\n\t\t\t\treturn !p.userId; // no org and no owner\n\t\t\t});\n\n\t\t\tconst providers = accessibleProviders.map((p) =>\n\t\t\t\tnormalizeSCIMProvider(p),\n\t\t\t);\n\n\t\t\treturn ctx.json({ providers });\n\t\t},\n\t);\n\nexport const getSCIMProviderConnection = () =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/get-provider-connection\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tuse: [sessionMiddleware],\n\t\t\tquery: getSCIMProviderConnectionQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"getSCIMProviderConnection\",\n\t\t\t\t\tsummary: \"Get SCIM provider details\",\n\t\t\t\t\tdescription: \"Returns details for a specific SCIM provider\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM provider details\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tid: { type: \"string\" },\n\t\t\t\t\t\t\t\t\t\t\tproviderId: { type: \"string\" },\n\t\t\t\t\t\t\t\t\t\t\torganizationId: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\tdescription: \"Provider not found\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\tdescription: \"Access denied\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { providerId } = ctx.query;\n\t\t\tconst userId = ctx.context.session.user.id;\n\n\t\t\tconst provider = await checkSCIMProviderAccess(ctx, userId, providerId);\n\n\t\t\treturn ctx.json(normalizeSCIMProvider(provider));\n\t\t},\n\t);\n\nexport const deleteSCIMProviderConnection = () =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/delete-provider-connection\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tuse: [sessionMiddleware],\n\t\t\tbody: deleteSCIMProviderConnectionBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"deleteSCIMProviderConnection\",\n\t\t\t\t\tsummary: \"Delete SCIM provider\",\n\t\t\t\t\tdescription: \"Deletes a SCIM provider and invalidates its token\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM provider deleted successfully\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tsuccess: { type: \"boolean\" },\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"404\": {\n\t\t\t\t\t\t\tdescription: \"Provider not found\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"403\": {\n\t\t\t\t\t\t\tdescription: \"Access denied\",\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { providerId } = ctx.body;\n\t\t\tconst userId = ctx.context.session.user.id;\n\n\t\t\tawait checkSCIMProviderAccess(ctx, userId, providerId);\n\n\t\t\tawait ctx.context.adapter.delete<SCIMProvider>({\n\t\t\t\tmodel: \"scimProvider\",\n\t\t\t\twhere: [{ field: \"providerId\", value: providerId }],\n\t\t\t});\n\n\t\t\treturn ctx.json({ success: true });\n\t\t},\n\t);\n\nexport const createSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: APIUserSchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Create SCIM user.\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Provision a new user into the linked organization via SCIM. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.3\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"201\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst accountId = getAccountId(body.userName, body.externalId);\n\n\t\t\tconst existingAccount = await ctx.context.adapter.findOne<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [\n\t\t\t\t\t{ field: \"accountId\", value: accountId },\n\t\t\t\t\t{ field: \"providerId\", value: providerId },\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tif (existingAccount) {\n\t\t\t\tthrow new SCIMAPIError(\"CONFLICT\", {\n\t\t\t\t\tdetail: \"User already exists\",\n\t\t\t\t\tscimType: \"uniqueness\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst email = getUserPrimaryEmail(body.userName, body.emails);\n\t\t\tconst name = getUserFullName(email, body.name);\n\n\t\t\tconst existingUser = await ctx.context.adapter.findOne<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [{ field: \"email\", value: email }],\n\t\t\t});\n\n\t\t\tconst createAccount = (userId: string) =>\n\t\t\t\tctx.context.internalAdapter.createAccount({\n\t\t\t\t\tuserId: userId,\n\t\t\t\t\tproviderId: providerId,\n\t\t\t\t\taccountId: accountId,\n\t\t\t\t\taccessToken: \"\",\n\t\t\t\t\trefreshToken: \"\",\n\t\t\t\t});\n\n\t\t\tconst createUser = () =>\n\t\t\t\tctx.context.internalAdapter.createUser({\n\t\t\t\t\temail,\n\t\t\t\t\tname,\n\t\t\t\t});\n\n\t\t\tconst createOrgMembership = async (userId: string) => {\n\t\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\t\tif (organizationId) {\n\t\t\t\t\tconst isOrgMember = await ctx.context.adapter.findOne({\n\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t\t\t\t{ field: \"userId\", value: userId },\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\n\t\t\t\t\tif (!isOrgMember) {\n\t\t\t\t\t\treturn await ctx.context.adapter.create<Member>({\n\t\t\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tuserId: userId,\n\t\t\t\t\t\t\t\trole: \"member\",\n\t\t\t\t\t\t\t\tcreatedAt: new Date(),\n\t\t\t\t\t\t\t\torganizationId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\n\t\t\tlet user: User;\n\t\t\tlet account: Account;\n\n\t\t\tif (existingUser) {\n\t\t\t\tuser = existingUser;\n\t\t\t\taccount = await ctx.context.adapter.transaction<Account>(async () => {\n\t\t\t\t\tconst account = await createAccount(user.id);\n\t\t\t\t\tawait createOrgMembership(user.id);\n\t\t\t\t\treturn account;\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t[user, account] = await ctx.context.adapter.transaction<\n\t\t\t\t\t[User, Account]\n\t\t\t\t>(async () => {\n\t\t\t\t\tconst user = await createUser();\n\t\t\t\t\tconst account = await createAccount(user.id);\n\t\t\t\t\tawait createOrgMembership(user.id);\n\t\t\t\t\treturn [user, account];\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst userResource = createUserResource(\n\t\t\t\tctx.context.baseURL,\n\t\t\t\tuser,\n\t\t\t\taccount,\n\t\t\t);\n\n\t\t\tctx.setStatus(201);\n\t\t\tctx.setHeader(\"location\", userResource.meta.location);\n\t\t\treturn ctx.json(userResource);\n\t\t},\n\t);\n\nexport const updateSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"PUT\",\n\t\t\tbody: APIUserSchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Update SCIM user.\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Updates an existing user into the linked organization via SCIM. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.3\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body;\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst { organizationId, providerId } = ctx.context.scimProvider;\n\t\t\tconst accountId = getAccountId(body.userName, body.externalId);\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst [updatedUser, updatedAccount] =\n\t\t\t\tawait ctx.context.adapter.transaction<[User | null, Account | null]>(\n\t\t\t\t\tasync () => {\n\t\t\t\t\t\tconst email = getUserPrimaryEmail(body.userName, body.emails);\n\t\t\t\t\t\tconst name = getUserFullName(email, body.name);\n\n\t\t\t\t\t\tconst updatedUser = await ctx.context.internalAdapter.updateUser(\n\t\t\t\t\t\t\tuserId,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\temail,\n\t\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tconst updatedAccount =\n\t\t\t\t\t\t\tawait ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\t\t\t\t\t\taccountId,\n\t\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\treturn [updatedUser, updatedAccount];\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\tconst userResource = createUserResource(\n\t\t\t\tctx.context.baseURL,\n\t\t\t\tupdatedUser!,\n\t\t\t\tupdatedAccount,\n\t\t\t);\n\n\t\t\treturn ctx.json(userResource);\n\t\t},\n\t);\n\nconst listSCIMUsersQuerySchema = z\n\t.object({\n\t\tfilter: z.string().optional(),\n\t})\n\t.optional();\n\nexport const listSCIMUsers = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: listSCIMUsersQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"List SCIM users\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Returns all users provisioned via SCIM for the linked organization. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.2\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user list\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\ttotalResults: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\titemsPerPage: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\tstartIndex: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\t\tResources: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\t\titems: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst emptyListResponse = {\n\t\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\t\ttotalResults: 0,\n\t\t\t\tstartIndex: 1,\n\t\t\t\titemsPerPage: 0,\n\t\t\t\tResources: [],\n\t\t\t} as const;\n\n\t\t\tconst apiFilters: DBFilter[] = parseSCIMAPIUserFilter(ctx.query?.filter);\n\n\t\t\tctx.context.logger.info(\"Querying result with filters: \", apiFilters);\n\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst accounts = await ctx.context.adapter.findMany<Account>({\n\t\t\t\tmodel: \"account\",\n\t\t\t\twhere: [{ field: \"providerId\", value: providerId }],\n\t\t\t});\n\n\t\t\tconst accountUserIds = accounts.map((account) => account.userId);\n\n\t\t\t// No accounts exist for this provider\n\n\t\t\tif (accountUserIds.length === 0) {\n\t\t\t\treturn ctx.json(emptyListResponse);\n\t\t\t}\n\n\t\t\tlet userFilters: DBFilter[] = [\n\t\t\t\t{ field: \"id\", value: accountUserIds, operator: \"in\" },\n\t\t\t];\n\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\t\t\tif (organizationId) {\n\t\t\t\tconst members = await ctx.context.adapter.findMany<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t\t\t{ field: \"userId\", value: accountUserIds, operator: \"in\" },\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tconst memberUserIds = members.map((member) => member.userId);\n\n\t\t\t\t// No members exist for this organization\n\n\t\t\t\tif (memberUserIds.length === 0) {\n\t\t\t\t\treturn ctx.json(emptyListResponse);\n\t\t\t\t}\n\n\t\t\t\tuserFilters = [{ field: \"id\", value: memberUserIds, operator: \"in\" }];\n\t\t\t}\n\n\t\t\tconst users = await ctx.context.adapter.findMany<User>({\n\t\t\t\tmodel: \"user\",\n\t\t\t\twhere: [...userFilters, ...apiFilters],\n\t\t\t});\n\n\t\t\treturn ctx.json({\n\t\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\t\ttotalResults: users.length,\n\t\t\t\tstartIndex: 1,\n\t\t\t\titemsPerPage: users.length,\n\t\t\t\tResources: users.map((user) => {\n\t\t\t\t\tconst account = accounts.find((a) => a.userId === user.id);\n\t\t\t\t\treturn createUserResource(ctx.context.baseURL, user, account);\n\t\t\t\t}),\n\t\t\t});\n\t\t},\n\t);\n\nexport const getSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Get SCIM user details\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Returns the provisioned SCIM user details. See https://datatracker.ietf.org/doc/html/rfc7644#section-3.4.1\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"SCIM user resource\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: OpenAPIUserResourceSchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn ctx.json(createUserResource(ctx.context.baseURL, user, account));\n\t\t},\n\t);\n\nconst patchSCIMUserBodySchema = z.object({\n\tschemas: z\n\t\t.array(z.string())\n\t\t.refine(\n\t\t\t(s) => s.includes(\"urn:ietf:params:scim:api:messages:2.0:PatchOp\"),\n\t\t\t{\n\t\t\t\tmessage: \"Invalid schemas for PatchOp\",\n\t\t\t},\n\t\t),\n\tOperations: z.array(\n\t\tz.object({\n\t\t\top: z\n\t\t\t\t.string()\n\t\t\t\t.toLowerCase()\n\t\t\t\t.default(\"replace\")\n\t\t\t\t.pipe(z.enum([\"replace\", \"add\", \"remove\"])),\n\t\t\tpath: z.string().optional(),\n\t\t\tvalue: z.any(),\n\t\t}),\n\t),\n});\n\nexport const patchSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"PATCH\",\n\t\t\tbody: patchSCIMUserBodySchema,\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Patch SCIM user\",\n\t\t\t\t\tdescription: \"Updates fields on a SCIM user record\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"204\": {\n\t\t\t\t\t\t\tdescription: \"Patch update applied correctly\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\n\t\t\tconst { user, account } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst { user: userPatch, account: accountPatch } = buildUserPatch(\n\t\t\t\tuser,\n\t\t\t\tctx.body.Operations,\n\t\t\t);\n\n\t\t\tif (\n\t\t\t\tObject.keys(userPatch).length === 0 &&\n\t\t\t\tObject.keys(accountPatch).length === 0\n\t\t\t) {\n\t\t\t\tthrow new SCIMAPIError(\"BAD_REQUEST\", {\n\t\t\t\t\tdetail: \"No valid fields to update\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait Promise.all([\n\t\t\t\tObject.keys(userPatch).length > 0\n\t\t\t\t\t? ctx.context.internalAdapter.updateUser(userId, {\n\t\t\t\t\t\t\t...userPatch,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(),\n\t\t\t\tObject.keys(accountPatch).length > 0\n\t\t\t\t\t? ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\t\t\t\t\t...accountPatch,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t})\n\t\t\t\t\t: Promise.resolve(),\n\t\t\t]);\n\n\t\t\tctx.setStatus(204);\n\t\t\treturn;\n\t\t},\n\t);\n\nexport const deleteSCIMUser = (authMiddleware: AuthMiddleware) =>\n\tcreateAuthEndpoint(\n\t\t\"/scim/v2/Users/:userId\",\n\t\t{\n\t\t\tmethod: \"DELETE\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\tallowedMediaTypes: [...supportedMediaTypes, \"\"],\n\t\t\t\topenapi: {\n\t\t\t\t\tsummary: \"Delete SCIM user\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Deletes (or deactivates) a user within the linked organization.\",\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"204\": {\n\t\t\t\t\t\t\tdescription: \"Delete applied successfully\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [authMiddleware],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst userId = ctx.params.userId;\n\t\t\tconst providerId = ctx.context.scimProvider.providerId;\n\t\t\tconst organizationId = ctx.context.scimProvider.organizationId;\n\n\t\t\tconst { user } = await findUserById(ctx.context.adapter, {\n\t\t\t\tuserId,\n\t\t\t\tproviderId,\n\t\t\t\torganizationId,\n\t\t\t});\n\n\t\t\tif (!user) {\n\t\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\t\tdetail: \"User not found\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tawait ctx.context.internalAdapter.deleteUser(userId);\n\n\t\t\tctx.setStatus(204);\n\t\t\treturn;\n\t\t},\n\t);\n\nexport const getSCIMServiceProviderConfig = createAuthEndpoint(\n\t\"/scim/v2/ServiceProviderConfig\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Configuration\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: ServiceProviderOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\tpatch: { supported: true },\n\t\t\tbulk: { supported: false },\n\t\t\tfilter: { supported: true },\n\t\t\tchangePassword: { supported: false },\n\t\t\tsort: { supported: false },\n\t\t\tetag: { supported: false },\n\t\t\tauthenticationSchemes: [\n\t\t\t\t{\n\t\t\t\t\tname: \"OAuth Bearer Token\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Authentication scheme using the Authorization header with a bearer token tied to an organization.\",\n\t\t\t\t\tspecUri: \"http://www.rfc-editor.org/info/rfc6750\",\n\t\t\t\t\ttype: \"oauthbearertoken\",\n\t\t\t\t\tprimary: true,\n\t\t\t\t},\n\t\t\t],\n\t\t\tschemas: [\"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\"],\n\t\t\tmeta: {\n\t\t\t\tresourceType: \"ServiceProviderConfig\",\n\t\t\t},\n\t\t});\n\t},\n);\n\nexport const getSCIMSchemas = createAuthEndpoint(\n\t\"/scim/v2/Schemas\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Configuration Schemas\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to acquire information about supported schemas. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\titems: SCIMSchemaOpenAPISchema,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\ttotalResults: supportedSCIMSchemas.length,\n\t\t\titemsPerPage: supportedSCIMSchemas.length,\n\t\t\tstartIndex: 1,\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\tResources: supportedSCIMSchemas.map((s) => {\n\t\t\t\treturn {\n\t\t\t\t\t...s,\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\t...s.meta,\n\t\t\t\t\t\tlocation: getResourceURL(s.meta.location, ctx.context.baseURL),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t},\n);\n\nexport const getSCIMSchema = createAuthEndpoint(\n\t\"/scim/v2/Schemas/:schemaId\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM a Service Provider Configuration Schema\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to acquire information about a given schema. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: SCIMSchemaOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst schema = supportedSCIMSchemas.find(\n\t\t\t(s) => s.id === ctx.params.schemaId,\n\t\t);\n\n\t\tif (!schema) {\n\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\tdetail: \"Schema not found\",\n\t\t\t});\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\t...schema,\n\t\t\tmeta: {\n\t\t\t\t...schema.meta,\n\t\t\t\tlocation: getResourceURL(schema.meta.location, ctx.context.baseURL),\n\t\t\t},\n\t\t});\n\t},\n);\n\nexport const getSCIMResourceTypes = createAuthEndpoint(\n\t\"/scim/v2/ResourceTypes\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Supported Resource Types\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to get a list of server supported types. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttotalResults: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\titemsPerPage: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\tstartIndex: { type: \"number\" },\n\t\t\t\t\t\t\t\t\t\tResources: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"array\",\n\t\t\t\t\t\t\t\t\t\t\titems: ResourceTypeOpenAPISchema,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\treturn ctx.json({\n\t\t\ttotalResults: supportedSCIMResourceTypes.length,\n\t\t\titemsPerPage: supportedSCIMResourceTypes.length,\n\t\t\tstartIndex: 1,\n\t\t\tschemas: [\"urn:ietf:params:scim:api:messages:2.0:ListResponse\"],\n\t\t\tResources: supportedSCIMResourceTypes.map((s) => {\n\t\t\t\treturn {\n\t\t\t\t\t...s,\n\t\t\t\t\tmeta: {\n\t\t\t\t\t\t...s.meta,\n\t\t\t\t\t\tlocation: getResourceURL(s.meta.location, ctx.context.baseURL),\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}),\n\t\t});\n\t},\n);\n\nexport const getSCIMResourceType = createAuthEndpoint(\n\t\"/scim/v2/ResourceTypes/:resourceTypeId\",\n\t{\n\t\tmethod: \"GET\",\n\t\tmetadata: {\n\t\t\t...HIDE_METADATA,\n\t\t\tallowedMediaTypes: supportedMediaTypes,\n\t\t\topenapi: {\n\t\t\t\tsummary: \"SCIM Service Provider Supported Resource Type\",\n\t\t\t\tdescription:\n\t\t\t\t\t\"Standard SCIM metadata endpoint used by identity providers to get a server supported type. See https://datatracker.ietf.org/doc/html/rfc7644#section-4\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"SCIM metadata object\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: ResourceTypeOpenAPISchema,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t...SCIMErrorOpenAPISchemas,\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst resourceType = supportedSCIMResourceTypes.find(\n\t\t\t(s) => s.id === ctx.params.resourceTypeId,\n\t\t);\n\n\t\tif (!resourceType) {\n\t\t\tthrow new SCIMAPIError(\"NOT_FOUND\", {\n\t\t\t\tdetail: \"Resource type not found\",\n\t\t\t});\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\t...resourceType,\n\t\t\tmeta: {\n\t\t\t\t...resourceType.meta,\n\t\t\t\tlocation: getResourceURL(\n\t\t\t\t\tresourceType.meta.location,\n\t\t\t\t\tctx.context.baseURL,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t},\n);\n\nconst findUserById = async (\n\tadapter: DBAdapter,\n\t{\n\t\tuserId,\n\t\tproviderId,\n\t\torganizationId,\n\t}: { userId: string; providerId: string; organizationId?: string },\n) => {\n\tconst account = await adapter.findOne<Account>({\n\t\tmodel: \"account\",\n\t\twhere: [\n\t\t\t{ field: \"userId\", value: userId },\n\t\t\t{ field: \"providerId\", value: providerId },\n\t\t],\n\t});\n\n\t// Disallows access to the resource\n\t// Account is not associated to the provider\n\n\tif (!account) {\n\t\treturn { user: null, account: null };\n\t}\n\n\tlet member: Member | null = null;\n\tif (organizationId) {\n\t\tmember = await adapter.findOne<Member>({\n\t\t\tmodel: \"member\",\n\t\t\twhere: [\n\t\t\t\t{ field: \"organizationId\", value: organizationId },\n\t\t\t\t{ field: \"userId\", value: userId },\n\t\t\t],\n\t\t});\n\t}\n\n\t// Disallows access to the resource\n\t// Token is restricted to an org and the member is not part of it\n\n\tif (organizationId && !member) {\n\t\treturn { user: null, account: null };\n\t}\n\n\tconst user = await adapter.findOne<User>({\n\t\tmodel: \"user\",\n\t\twhere: [{ field: \"id\", value: userId }],\n\t});\n\n\tif (!user) {\n\t\treturn { user: null, account: null };\n\t}\n\n\treturn { user, account };\n};\n\nconst parseSCIMAPIUserFilter = (filter?: string) => {\n\tlet filters: DBFilter[] = [];\n\n\ttry {\n\t\tfilters = filter ? parseSCIMUserFilter(filter) : [];\n\t} catch (error) {\n\t\tthrow new SCIMAPIError(\"BAD_REQUEST\", {\n\t\t\tdetail:\n\t\t\t\terror instanceof SCIMParseError ? error.message : \"Invalid SCIM filter\",\n\t\t\tscimType: \"invalidFilter\",\n\t\t});\n\t}\n\n\treturn filters;\n};\n","import type { BetterAuthPlugin } from \"better-auth\";\nimport { authMiddlewareFactory } from \"./middlewares\";\nimport {\n\tcreateSCIMUser,\n\tdeleteSCIMProviderConnection,\n\tdeleteSCIMUser,\n\tgenerateSCIMToken,\n\tgetSCIMProviderConnection,\n\tgetSCIMResourceType,\n\tgetSCIMResourceTypes,\n\tgetSCIMSchema,\n\tgetSCIMSchemas,\n\tgetSCIMServiceProviderConfig,\n\tgetSCIMUser,\n\tlistSCIMProviderConnections,\n\tlistSCIMUsers,\n\tpatchSCIMUser,\n\tupdateSCIMUser,\n} from \"./routes\";\nimport type { SCIMOptions } from \"./types\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\tscim: {\n\t\t\tcreator: typeof scim;\n\t\t};\n\t}\n}\n\nexport const scim = (options?: SCIMOptions) => {\n\tconst opts = {\n\t\tstoreSCIMToken: \"plain\",\n\t\tproviderOwnership: { enabled: false },\n\t\t...options,\n\t} satisfies SCIMOptions;\n\n\tconst authMiddleware = authMiddlewareFactory(opts);\n\n\treturn {\n\t\tid: \"scim\",\n\t\tendpoints: {\n\t\t\tgenerateSCIMToken: generateSCIMToken(opts),\n\t\t\tlistSCIMProviderConnections: listSCIMProviderConnections(),\n\t\t\tgetSCIMProviderConnection: getSCIMProviderConnection(),\n\t\t\tdeleteSCIMProviderConnection: deleteSCIMProviderConnection(),\n\t\t\tgetSCIMUser: getSCIMUser(authMiddleware),\n\t\t\tcreateSCIMUser: createSCIMUser(authMiddleware),\n\t\t\tpatchSCIMUser: patchSCIMUser(authMiddleware),\n\t\t\tdeleteSCIMUser: deleteSCIMUser(authMiddleware),\n\t\t\tupdateSCIMUser: updateSCIMUser(authMiddleware),\n\t\t\tlistSCIMUsers: listSCIMUsers(authMiddleware),\n\t\t\tgetSCIMServiceProviderConfig,\n\t\t\tgetSCIMSchemas,\n\t\t\tgetSCIMSchema,\n\t\t\tgetSCIMResourceTypes,\n\t\t\tgetSCIMResourceType,\n\t\t},\n\t\tschema: {\n\t\t\tscimProvider: {\n\t\t\t\tfields: {\n\t\t\t\t\tproviderId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t},\n\t\t\t\t\tscimToken: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: true,\n\t\t\t\t\t\tunique: true,\n\t\t\t\t\t},\n\t\t\t\t\torganizationId: {\n\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\trequired: false,\n\t\t\t\t\t},\n\t\t\t\t\t...(opts.providerOwnership?.enabled\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\tuserId: {\n\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\trequired: false,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport * from \"./types\";\n"],"mappings":";;;;;;;;;;;;;AAQA,IAAa,eAAb,cAAkCA,WAAS;CAC1C,YACC,SAA4C,yBAC5C,YAAiB,EAAE,EAClB;EACD,MAAM,OAAO;GACZ,SAAS,CAAC,8CAA8C;GACxD,SAAS,OAAO,WAAW,WACxB,SACA,YAAY,SACb,UAAU;GACZ,QAAQ,UAAU;GAClB,GAAG;GACH;AACD,QAAM,QAAQ,KAAK;AACnB,OAAK,UAAU,KAAK,UAAU,KAAK;;;AAIrC,MAAM,yBAAyB;CAC9B,MAAM;CACN,YAAY;EACX,SAAS;GACR,MAAM;GACN,OAAO,EAAE,MAAM,UAAU;GACzB;EACD,QAAQ,EACP,MAAM,UACN;EACD,QAAQ,EACP,MAAM,UACN;EACD,UAAU,EACT,MAAM,UACN;EACD;CACD;AAED,MAAa,0BAA0B;CACtC,OAAO;EACN,aACC;EACD,SAAS,EACR,oBAAoB,EACnB,QAAQ,wBACR,EACD;EACD;CACD,OAAO;EACN,aAAa;EACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,wBACR,EACD;EACD;CACD,OAAO;EACN,aAAa;EACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,wBACR,EACD;EACD;CACD,OAAO;EACN,aAAa;EACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,wBACR,EACD;EACD;CACD,OAAO;EACN,aACC;EACD,SAAS,EACR,oBAAoB,EACnB,QAAQ,wBACR,EACD;EACD;CACD,OAAO;EACN,aACC;EACD,SAAS,EACR,oBAAoB,EACnB,QAAQ,wBACR,EACD;EACD;CACD;;;;AC5FD,MAAM,mBAAmB,OAAO,UAAkB;CACjD,MAAM,OAAO,MAAM,WAAW,UAAU,CAAC,OACxC,IAAI,aAAa,CAAC,OAAO,MAAM,CAC/B;AACD,QAAO,UAAU,OAAO,IAAI,WAAW,KAAK,EAAE,EAAE,SAAS,OAAO,CAAC;;AAGlE,eAAsB,eACrB,KACA,MACA,WACC;AACD,KAAI,KAAK,mBAAmB,YAC3B,QAAO,MAAM,iBAAiB;EAC7B,KAAK,IAAI,QAAQ;EACjB,MAAM;EACN,CAAC;AAEH,KAAI,KAAK,mBAAmB,SAC3B,QAAO,MAAM,iBAAiB,UAAU;AAEzC,KACC,OAAO,KAAK,mBAAmB,YAC/B,UAAU,KAAK,eAEf,QAAO,MAAM,KAAK,eAAe,KAAK,UAAU;AAEjD,KACC,OAAO,KAAK,mBAAmB,YAC/B,aAAa,KAAK,eAElB,QAAO,MAAM,KAAK,eAAe,QAAQ,UAAU;AAGpD,QAAO;;AAGR,eAAsB,gBACrB,KACA,MACA,iBACA,WACmB;AACnB,KAAI,KAAK,mBAAmB,YAC3B,QACE,MAAM,iBAAiB;EACvB,KAAK,IAAI,QAAQ;EACjB,MAAM;EACN,CAAC,KAAM;AAGV,KAAI,KAAK,mBAAmB,SAE3B,QADwB,MAAM,iBAAiB,UAAU,KAC9B;AAE5B,KACC,OAAO,KAAK,mBAAmB,YAC/B,UAAU,KAAK,eAGf,QADwB,MAAM,KAAK,eAAe,KAAK,UAAU,KACtC;AAE5B,KACC,OAAO,KAAK,mBAAmB,YAC/B,aAAa,KAAK,eAIlB,QADC,MAAM,KAAK,eAAe,QAAQ,gBAAgB,KACrB;AAG/B,QAAO,cAAc;;;;;;;;AClEtB,MAAa,yBAAyB,SACrC,qBAAqB,OAAO,QAAQ;CAEnC,MAAM,iBADa,IAAI,SAAS,IAAI,gBAAgB,GAClB,QAAQ,eAAe,GAAG;AAE5D,KAAI,CAAC,cACJ,OAAM,IAAI,aAAa,gBAAgB,EACtC,QAAQ,0BACR,CAAC;CAGH,MAAM,qBAAqB,IAAI,aAAa,CAC1C,OAAO,UAAU,OAAO,cAAc,CAAC,CACvC,MAAM,IAAI;CAEZ,MAAM,CAAC,WAAW,cAAc;CAChC,MAAM,iBAAiB,mBAAmB,MAAM,EAAE,CAAC,KAAK,IAAI;AAE5D,KAAI,CAAC,aAAa,CAAC,WAClB,OAAM,IAAI,aAAa,gBAAgB,EACtC,QAAQ,sBACR,CAAC;CAGH,IAAI,eACH,KAAK,aAAa,MAAM,MAAM;AAC7B,MAAI,EAAE,eAAe,cAAc,CAAC,eACnC,QAAO;AAGR,SAAO,CAAC,EACP,EAAE,eAAe,cACjB,kBACA,EAAE,mBAAmB;GAErB,IAAI;AAEP,KAAI,aACH,KAAI,aAAa,cAAc,UAC9B,QAAO;EAAE,eAAe,aAAa;EAAW;EAAc;KAE9D,OAAM,IAAI,aAAa,gBAAgB,EACtC,QAAQ,sBACR,CAAC;AAIJ,gBAAe,MAAM,IAAI,QAAQ,QAAQ,QAAsB;EAC9D,OAAO;EACP,OAAO,CACN;GAAE,OAAO;GAAc,OAAO;GAAY,EAC1C,GAAI,iBACD,CAAC;GAAE,OAAO;GAAkB,OAAO;GAAgB,CAAC,GACpD,EAAE,CACL;EACD,CAAC;AAEF,KAAI,CAAC,aACJ,OAAM,IAAI,aAAa,gBAAgB,EACtC,QAAQ,sBACR,CAAC;AAUH,KAAI,CAPiB,MAAM,gBAC1B,KACA,MACA,aAAa,WACb,UACA,CAGA,OAAM,IAAI,aAAa,gBAAgB,EACtC,QAAQ,sBACR,CAAC;AAGH,QAAO;EAAE,eAAe;EAAW;EAAc;EAChD;;;;ACtFH,MAAa,gBAAgB,UAAkB,eAAwB;AACtE,QAAO,cAAc;;AAGtB,MAAM,oBAAoB,SAAmB;AAC5C,KAAI,KAAK,aAAa,KAAK,WAC1B,QAAO,GAAG,KAAK,UAAU,GAAG,KAAK;AAGlC,KAAI,KAAK,UACR,QAAO,KAAK;AAGb,QAAO,KAAK,cAAc;;AAG3B,MAAa,mBAAmB,OAAe,SAAoB;AAClE,KAAI,MAAM;EACT,MAAM,YAAY,KAAK,WAAW,MAAM,IAAI;AAC5C,MAAI,UAAU,SAAS,EACtB,QAAO;AAGR,SAAO,iBAAiB,KAAK,IAAI;;AAGlC,QAAO;;AAGR,MAAa,uBAAuB,UAAkB,WAAyB;AAC9E,QACC,QAAQ,MAAM,UAAU,MAAM,QAAQ,EAAE,SACxC,SAAS,IAAI,SACb;;;;;ACfF,MAAM,YAAY,MAAY,IAAe,cAAyB;AACrE,QAAO,GAAG;;AAGX,MAAM,aAAa,MAAY,IAAe,cAAyB;AACtE,QAAO,GAAG,MAAM,aAAa;;AAG9B,MAAM,aAAa,MAAY,IAAe,cAAyB;CAEtE,MAAM,cADe,UAAU,KAAK,QAAmB,KAAK,MAC7B,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC,MAAM;CACnE,MAAM,YAAY,GAAG;AAErB,QAAO,gBAAgB,KAAK,OAAO;EAClC;EACA;EACA,CAAC;;AAGH,MAAM,cAAc,MAAY,IAAe,cAAyB;CACvE,MAAM,cAAe,UAAU,KAAK,QAAmB,KAAK;CAC5D,MAAM,aACL,YAAY,MAAM,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,IAAI,aAChD,MAAM;CACR,MAAM,aAAa,GAAG;AACtB,QAAO,gBAAgB,KAAK,OAAO;EAClC;EACA;EACA,CAAC;;AAGH,MAAM,oBAA6C;CAClD,mBAAmB;EAAE,UAAU;EAAQ,QAAQ;EAAQ,KAAK;EAAU;CACtE,mBAAmB;EAAE,UAAU;EAAQ,QAAQ;EAAQ,KAAK;EAAW;CACvE,oBAAoB;EACnB,UAAU;EACV,QAAQ;EACR,KAAK;EACL;CACD,eAAe;EACd,UAAU;EACV,QAAQ;EACR,KAAK;EACL;CACD,aAAa;EAAE,UAAU;EAAQ,QAAQ;EAAS,KAAK;EAAW;CAClE;AAED,MAAM,iBAAiB,SAAyB;AAE/C,QAAO,KADqB,KAAK,WAAW,IAAI,GAAG,KAAK,MAAM,EAAE,GAAG,MACpC,WAAW,KAAK,IAAI;;AAGpD,MAAM,kBAAkB,UAAqD;AAC5E,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,MAAM,gBACL,MACA,WACA,MACA,OACA,OACI;CACJ,MAAM,iBAAiB,cAAc,KAAK;CAC1C,MAAM,UAAU,kBAAkB;AAElC,KAAI,CAAC,QACJ;CAGD,MAAM,WAAW,QAAQ,IACxB,MACA;EACC;EACA;EACA,MAAM;EACN,EACD,UACA;AAED,KAAI,OAAO,SAAS,QAAQ,aAAa,QAExC;MADsB,KAAiC,QAAQ,YAC1C,SACpB;;AAIF,WAAU,QAAQ,UAAU,QAAQ,UAAU;;AAG/C,MAAM,mBACL,MACA,WACA,OACA,IACA,SACI;AACJ,KAAI,eAAe,MAAM,CACxB,MAAK,MAAM,CAAC,KAAK,gBAAgB,OAAO,QAAQ,MAAM,CAErD,iBAAgB,MAAM,WAAW,aAAa,IAD3B,OAAO,GAAG,KAAK,GAAG,QAAQ,IACgB;UAEpD,KACV,cAAa,MAAM,WAAW,MAAM,OAAO,GAAG;;AAIhD,MAAa,kBAAkB,MAAY,eAA4B;CAGtE,MAAM,YAAuB;EAAE,MAFQ,EAAE;EAEO,SADN,EAAE;EAC2B;AAEvE,MAAK,MAAM,aAAa,YAAY;AACnC,MAAI,UAAU,OAAO,SAAS,UAAU,OAAO,UAC9C;AAGD,kBACC,MACA,WACA,UAAU,OACV,UAAU,IACV,UAAU,KACV;;AAGF,QAAO;;;;;AChJR,MAAa,gBAAgB,EAAE,OAAO;CACrC,UAAU,EAAE,QAAQ,CAAC,WAAW;CAChC,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,MAAM,EACJ,OAAO;EACP,WAAW,EAAE,QAAQ,CAAC,UAAU;EAChC,WAAW,EAAE,QAAQ,CAAC,UAAU;EAChC,YAAY,EAAE,QAAQ,CAAC,UAAU;EACjC,CAAC,CACD,UAAU;CACZ,QAAQ,EACN,MACA,EAAE,OAAO;EACR,OAAO,EAAE,OAAO;EAChB,SAAS,EAAE,SAAS,CAAC,UAAU;EAC/B,CAAC,CACF,CACA,UAAU;CACZ,CAAC;AAEF,MAAa,4BAA4B;CACxC,MAAM;CACN,YAAY;EACX,IAAI,EAAE,MAAM,UAAU;EACtB,MAAM;GACL,MAAM;GACN,YAAY;IACX,cAAc,EAAE,MAAM,UAAU;IAChC,SAAS;KAAE,MAAM;KAAU,QAAQ;KAAa;IAChD,cAAc;KAAE,MAAM;KAAU,QAAQ;KAAa;IACrD,UAAU,EAAE,MAAM,UAAU;IAC5B;GACD;EACD,UAAU,EAAE,MAAM,UAAU;EAC5B,MAAM;GACL,MAAM;GACN,YAAY;IACX,WAAW,EAAE,MAAM,UAAU;IAC7B,WAAW,EAAE,MAAM,UAAU;IAC7B,YAAY,EAAE,MAAM,UAAU;IAC9B;GACD;EACD,aAAa,EAAE,MAAM,UAAU;EAC/B,QAAQ,EAAE,MAAM,WAAW;EAC3B,QAAQ;GACP,MAAM;GACN,OAAO;IACN,MAAM;IACN,YAAY;KACX,OAAO,EAAE,MAAM,UAAU;KACzB,SAAS,EAAE,MAAM,WAAW;KAC5B;IACD;GACD;EACD,SAAS;GACR,MAAM;GACN,OAAO,EAAE,MAAM,UAAU;GACzB;EACD;CACD;AAED,MAAa,yBAAyB;CACrC,IAAI;CACJ,SAAS,CAAC,+CAA+C;CACzD,MAAM;CACN,aAAa;CACb,YAAY;EACX;GACC,MAAM;GACN,MAAM;GACN,aAAa;GACb,aAAa;GACb,UAAU;GACV,WAAW;GACX,YAAY;GACZ,UAAU;GACV,YAAY;GACZ;EACD;GACC,MAAM;GACN,MAAM;GACN,aAAa;GACb,aACC;GACD,UAAU;GACV,WAAW;GACX,YAAY;GACZ,UAAU;GACV,YAAY;GACZ;EACD;GACC,MAAM;GACN,MAAM;GACN,aAAa;GACb,aACC;GACD,UAAU;GACV,WAAW;GACX,YAAY;GACZ,UAAU;GACV,YAAY;GACZ;EACD;GACC,MAAM;GACN,MAAM;GACN,aAAa;GACb,aACC;GACD,UAAU;GACV,YAAY;GACZ,UAAU;GACV;EACD;GACC,MAAM;GACN,MAAM;GACN,aAAa;GACb,aAAa;GACb,UAAU;GACV,eAAe;IACd;KACC,MAAM;KACN,MAAM;KACN,aAAa;KACb,aACC;KACD,UAAU;KACV,WAAW;KACX,YAAY;KACZ,UAAU;KACV,YAAY;KACZ;IACD;KACC,MAAM;KACN,MAAM;KACN,aAAa;KACb,aACC;KACD,UAAU;KACV,WAAW;KACX,YAAY;KACZ,UAAU;KACV,YAAY;KACZ;IACD;KACC,MAAM;KACN,MAAM;KACN,aAAa;KACb,aACC;KACD,UAAU;KACV,WAAW;KACX,YAAY;KACZ,UAAU;KACV,YAAY;KACZ;IACD;GACD;EACD;GACC,MAAM;GACN,MAAM;GACN,aAAa;GACb,aACC;GACD,UAAU;GACV,eAAe,CACd;IACC,MAAM;IACN,MAAM;IACN,aAAa;IACb,aACC;IACD,UAAU;IACV,WAAW;IACX,YAAY;IACZ,UAAU;IACV,YAAY;IACZ,EACD;IACC,MAAM;IACN,MAAM;IACN,aAAa;IACb,aACC;IACD,UAAU;IACV,YAAY;IACZ,UAAU;IACV,CACD;GACD,YAAY;GACZ,UAAU;GACV,YAAY;GACZ;EACD;CACD,MAAM;EACL,cAAc;EACd,UAAU;EACV;CACD;AAED,MAAa,uBAAuB;CACnC,SAAS,CAAC,qDAAqD;CAC/D,IAAI;CACJ,MAAM;CACN,UAAU;CACV,aAAa;CACb,QAAQ;CACR,MAAM;EACL,cAAc;EACd,UAAU;EACV;CACD;;;;AC5MD,MAAM,gBAAoD,EACzD,IAAI,MACJ;AAED,MAAM,qBAAyD,EAC9D,UAAU,SACV;AAED,IAA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"}