@better-auth/scim 1.5.0-beta.10 → 1.5.0-beta.12
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/.turbo/turbo-build.log +6 -6
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +18 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -6
- package/src/routes.ts +22 -0
- package/src/scim.test.ts +107 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @better-auth/scim@1.5.0-beta.
|
|
2
|
+
> @better-auth/scim@1.5.0-beta.12 build /home/runner/work/better-auth/better-auth/packages/scim
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
5
|
[34mℹ[39m tsdown [2mv0.20.1[22m powered by rolldown [2mv1.0.0-rc.1[22m
|
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
[34mℹ[39m entry: [34msrc/index.ts, src/client.ts[39m
|
|
8
8
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
9
|
[34mℹ[39m Build start
|
|
10
|
-
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m 39.
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m 39.71 kB[22m [2m│ gzip: 8.09 kB[22m
|
|
11
11
|
[34mℹ[39m [2mdist/[22m[1mclient.mjs[22m [2m 0.19 kB[22m [2m│ gzip: 0.17 kB[22m
|
|
12
|
-
[34mℹ[39m [2mdist/[22mindex.mjs.map [2m 78.
|
|
12
|
+
[34mℹ[39m [2mdist/[22mindex.mjs.map [2m 78.91 kB[22m [2m│ gzip: 15.31 kB[22m
|
|
13
13
|
[34mℹ[39m [2mdist/[22mclient.mjs.map [2m 0.46 kB[22m [2m│ gzip: 0.30 kB[22m
|
|
14
|
-
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m108.
|
|
14
|
+
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m108.99 kB[22m [2m│ gzip: 4.52 kB[22m
|
|
15
15
|
[34mℹ[39m [2mdist/[22m[32m[1mclient.d.mts[22m[39m [2m 0.24 kB[22m [2m│ gzip: 0.20 kB[22m
|
|
16
|
-
[34mℹ[39m 6 files, total:
|
|
16
|
+
[34mℹ[39m 6 files, total: 228.50 kB
|
|
17
17
|
[33m[PLUGIN_TIMINGS] Warning:[0m Your build spent significant time in plugin `rolldown-plugin-dts:generate`. See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
18
18
|
|
|
19
|
-
[32m✔[39m Build complete in [
|
|
19
|
+
[32m✔[39m Build complete in [32m9246ms[39m
|
package/dist/index.d.mts
CHANGED
|
@@ -1639,6 +1639,12 @@ declare const scim: (options?: SCIMOptions) => {
|
|
|
1639
1639
|
scimProvider: Omit<SCIMProvider, "id">;
|
|
1640
1640
|
}>)[];
|
|
1641
1641
|
}, {
|
|
1642
|
+
readonly schemas: readonly ["urn:ietf:params:scim:api:messages:2.0:ListResponse"];
|
|
1643
|
+
readonly totalResults: 0;
|
|
1644
|
+
readonly startIndex: 1;
|
|
1645
|
+
readonly itemsPerPage: 0;
|
|
1646
|
+
readonly Resources: readonly [];
|
|
1647
|
+
} | {
|
|
1642
1648
|
schemas: string[];
|
|
1643
1649
|
totalResults: number;
|
|
1644
1650
|
startIndex: number;
|
package/dist/index.mjs
CHANGED
|
@@ -872,6 +872,13 @@ const listSCIMUsers = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
|
|
|
872
872
|
},
|
|
873
873
|
use: [authMiddleware]
|
|
874
874
|
}, async (ctx) => {
|
|
875
|
+
const emptyListResponse = {
|
|
876
|
+
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
|
877
|
+
totalResults: 0,
|
|
878
|
+
startIndex: 1,
|
|
879
|
+
itemsPerPage: 0,
|
|
880
|
+
Resources: []
|
|
881
|
+
};
|
|
875
882
|
const apiFilters = parseSCIMAPIUserFilter(ctx.query?.filter);
|
|
876
883
|
ctx.context.logger.info("Querying result with filters: ", apiFilters);
|
|
877
884
|
const providerId = ctx.context.scimProvider.providerId;
|
|
@@ -883,15 +890,15 @@ const listSCIMUsers = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
|
|
|
883
890
|
}]
|
|
884
891
|
});
|
|
885
892
|
const accountUserIds = accounts.map((account) => account.userId);
|
|
893
|
+
if (accountUserIds.length === 0) return ctx.json(emptyListResponse);
|
|
886
894
|
let userFilters = [{
|
|
887
895
|
field: "id",
|
|
888
896
|
value: accountUserIds,
|
|
889
897
|
operator: "in"
|
|
890
898
|
}];
|
|
891
899
|
const organizationId = ctx.context.scimProvider.organizationId;
|
|
892
|
-
if (organizationId)
|
|
893
|
-
|
|
894
|
-
value: (await ctx.context.adapter.findMany({
|
|
900
|
+
if (organizationId) {
|
|
901
|
+
const memberUserIds = (await ctx.context.adapter.findMany({
|
|
895
902
|
model: "member",
|
|
896
903
|
where: [{
|
|
897
904
|
field: "organizationId",
|
|
@@ -901,9 +908,14 @@ const listSCIMUsers = (authMiddleware) => createAuthEndpoint("/scim/v2/Users", {
|
|
|
901
908
|
value: accountUserIds,
|
|
902
909
|
operator: "in"
|
|
903
910
|
}]
|
|
904
|
-
})).map((member) => member.userId)
|
|
905
|
-
|
|
906
|
-
|
|
911
|
+
})).map((member) => member.userId);
|
|
912
|
+
if (memberUserIds.length === 0) return ctx.json(emptyListResponse);
|
|
913
|
+
userFilters = [{
|
|
914
|
+
field: "id",
|
|
915
|
+
value: memberUserIds,
|
|
916
|
+
operator: "in"
|
|
917
|
+
}];
|
|
918
|
+
}
|
|
907
919
|
const users = await ctx.context.adapter.findMany({
|
|
908
920
|
model: "user",
|
|
909
921
|
where: [...userFilters, ...apiFilters]
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +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 type { GenericEndpointContext } from \"better-auth\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"better-auth/crypto\";\nimport { defaultKeyHasher } from \"better-auth/plugins\";\nimport type { SCIMOptions } from \"./types\";\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.secret,\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.secret,\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 { Account, DBAdapter, User } 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\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 ctx.context.adapter.findOne<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\t\tvalue: organizationId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\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 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},\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 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 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\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\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\tdeleteSCIMUser,\n\tgenerateSCIMToken,\n\tgetSCIMResourceType,\n\tgetSCIMResourceTypes,\n\tgetSCIMSchema,\n\tgetSCIMSchemas,\n\tgetSCIMServiceProviderConfig,\n\tgetSCIMUser,\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\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\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},\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;;;;AC7FD,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;;;;;;;;AC1DtB,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,IAAa,iBAAb,cAAoC,MAAM;AAE1C,MAAM,kBACL;AAED,MAAM,mBAAmB,WAAmB;CAC3C,MAAM,QAAQ,OAAO,MAAM,gBAAgB;AAC3C,KAAI,CAAC,MACJ,OAAM,IAAI,eAAe,4BAA4B;CAGtD,MAAM,YAAY,MAAM,QAAQ;CAChC,MAAM,KAAK,MAAM,QAAQ,IAAI,aAAa;CAC1C,MAAM,QAAQ,MAAM,QAAQ;AAE5B,KAAI,CAAC,aAAa,CAAC,MAAM,CAAC,MACzB,OAAM,IAAI,eAAe,4BAA4B;CAGtD,MAAM,WAAW,cAAc;AAC/B,KAAI,CAAC,SACJ,OAAM,IAAI,eAAe,iBAAiB,GAAG,oBAAoB;AAGlE,QAAO;EAAE;EAAW;EAAU;EAAO;;AAGtC,MAAa,uBAAuB,WAAmB;CACtD,MAAM,EAAE,WAAW,UAAU,UAAU,gBAAgB,OAAO;CAE9D,MAAM,UAAsB,EAAE;CAC9B,MAAM,kBAAkB,mBAAmB;CAC3C,MAAM,oBAAoB,uBAAuB,WAAW,MAC1D,SAAS,KAAK,SAAS,UACxB;AAED,KAAI,CAAC,mBAAmB,CAAC,kBACxB,OAAM,IAAI,eAAe,kBAAkB,UAAU,oBAAoB;CAG1E,IAAI,aAAa,MAAM,WAAW,MAAK,GAAG;AAC1C,KAAI,CAAC,kBAAkB,UACtB,cAAa,WAAW,aAAa;AAGtC,SAAQ,KAAK;EACZ,OAAO;EACP,OAAO;EACP;EACA,CAAC;AAEF,QAAO;;;;;ACnER,MAAM,oCAAoC;CACzC,MAAM;CACN,YAAY,EACX,WAAW,EACV,MAAM,WACN,EACD;CACD;AAED,MAAa,+BAA+B;CAC3C,MAAM;CACN,YAAY;EACX,OAAO;EACP,MAAM;EACN,QAAQ;EACR,gBAAgB;EAChB,MAAM;EACN,MAAM;EACN,uBAAuB;GACtB,MAAM;GACN,OAAO;IACN,MAAM;IACN,YAAY;KACX,MAAM,EACL,MAAM,UACN;KACD,aAAa,EACZ,MAAM,UACN;KACD,SAAS,EACR,MAAM,UACN;KACD,MAAM,EACL,MAAM,UACN;KACD,SAAS,EACR,MAAM,WACN;KACD;IACD;GACD;EACD,SAAS;GACR,MAAM;GACN,OAAO,EACN,MAAM,UACN;GACD;EACD,MAAM;GACL,MAAM;GACN,YAAY,EACX,cAAc,EACb,MAAM,UACN,EACD;GACD;EACD;CACD;AAED,MAAa,4BAA4B;CACxC,MAAM;CACN,YAAY;EACX,SAAS;GACR,MAAM;GACN,OAAO,EAAE,MAAM,UAAU;GACzB;EACD,IAAI,EAAE,MAAM,UAAU;EACtB,MAAM,EAAE,MAAM,UAAU;EACxB,UAAU,EAAE,MAAM,UAAU;EAC5B,aAAa,EAAE,MAAM,UAAU;EAC/B,QAAQ,EAAE,MAAM,UAAU;EAC1B,MAAM;GACL,MAAM;GACN,YAAY;IACX,cAAc,EAAE,MAAM,UAAU;IAChC,UAAU,EAAE,MAAM,UAAU;IAC5B;GACD;EACD;CACD;AAED,MAAM,oCAAoC;CACzC,MAAM;CACN,YAAY;EACX,MAAM,EAAE,MAAM,UAAU;EACxB,MAAM,EAAE,MAAM,UAAU;EACxB,aAAa,EAAE,MAAM,WAAW;EAChC,aAAa,EAAE,MAAM,UAAU;EAC/B,UAAU,EAAE,MAAM,WAAW;EAC7B,WAAW,EAAE,MAAM,WAAW;EAC9B,YAAY,EAAE,MAAM,UAAU;EAC9B,UAAU,EAAE,MAAM,UAAU;EAC5B,YAAY,EAAE,MAAM,UAAU;EAC9B;CACD;AAED,MAAa,0BAA0B;CACtC,MAAM;CACN,YAAY;EACX,IAAI,EAAE,MAAM,UAAU;EACtB,SAAS;GACR,MAAM;GACN,OAAO,EAAE,MAAM,UAAU;GACzB;EACD,MAAM,EAAE,MAAM,UAAU;EACxB,aAAa,EAAE,MAAM,UAAU;EAC/B,YAAY;GACX,MAAM;GACN,OAAO;IACN,GAAG;IACH,YAAY;KACX,GAAG,kCAAkC;KACrC,eAAe;MACd,MAAM;MACN,OAAO;MACP;KACD;IACD;GACD;EACD,MAAM;GACL,MAAM;GACN,YAAY;IACX,cAAc,EAAE,MAAM,UAAU;IAChC,UAAU,EAAE,MAAM,UAAU;IAC5B;GACD,UAAU,CAAC,gBAAgB,WAAW;GACtC;EACD;CACD;;;;AC/HD,MAAa,kBAAkB,MAAc,YAAoB;CAChE,MAAM,oBAAoB,QAAQ,SAAS,IAAI,GAAG,UAAU,GAAG,QAAQ;CACvE,MAAM,iBAAiB,KAAK,QAAQ,QAAQ,GAAG;AAC/C,QAAO,IAAI,IAAI,gBAAgB,kBAAkB,CAAC,UAAU;;;;;ACC7D,MAAa,sBACZ,SACA,MACA,YACI;AACJ,QAAO;EAIN,IAAI,KAAK;EACT,YAAY,SAAS;EACrB,MAAM;GACL,cAAc;GACd,SAAS,KAAK;GACd,cAAc,KAAK;GACnB,UAAU,eAAe,kBAAkB,KAAK,MAAM,QAAQ;GAC9D;EAKD,UAAU,KAAK;EACf,MAAM,EACL,WAAW,KAAK,MAChB;EACD,aAAa,KAAK;EAClB,QAAQ;EACR,QAAQ,CAAC;GAAE,SAAS;GAAM,OAAO,KAAK;GAAO,CAAC;EAC9C,SAAS,CAAC,uBAAuB,GAAG;EACpC;;;;;ACAF,MAAM,uBAAuB,CAAC,uBAAuB;AACrD,MAAM,6BAA6B,CAAC,qBAAqB;AACzD,MAAM,sBAAsB,CAAC,oBAAoB,wBAAwB;AAEzE,MAAM,8BAA8B,EAAE,OAAO;CAC5C,YAAY,EAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,8BAA8B,CAAC;CAC1E,gBAAgB,EACd,QAAQ,CACR,UAAU,CACV,KAAK,EAAE,aAAa,4BAA4B,CAAC;CACnD,CAAC;AAEF,MAAa,qBAAqB,SACjC,mBACC,wBACA;CACC,QAAQ;CACR,MAAM;CACN,UAAU,EACT,SAAS;EACR,SAAS;EACT,aACC;EACD,WAAW,EACV,OAAO;GACN,aAAa;GACb,SAAS,EACR,oBAAoB,EACnB,QAAQ;IACP,MAAM;IACN,YAAY,EACX,WAAW;KACV,aAAa;KACb,MAAM;KACN,EACD;IACD,EACD,EACD;GACD,EACD;EACD,EACD;CACD,KAAK,CAAC,kBAAkB;CACxB,EACD,OAAO,QAAQ;CACd,MAAM,EAAE,YAAY,mBAAmB,IAAI;CAC3C,MAAM,OAAO,IAAI,QAAQ,QAAQ;AAEjC,KAAI,WAAW,SAAS,IAAI,CAC3B,OAAM,IAAI,SAAS,eAAe,EACjC,SAAS,6CACT,CAAC;AAGH,KAAI,kBAAkB,CAAC,IAAI,QAAQ,UAAU,eAAe,CAC3D,OAAM,IAAI,SAAS,eAAe,EACjC,SACC,2EACD,CAAC;CAGH,IAAI,SAAwB;AAC5B,KAAI,gBAAgB;AACnB,WAAS,MAAM,IAAI,QAAQ,QAAQ,QAAgB;GAClD,OAAO;GACP,OAAO,CACN;IACC,OAAO;IACP,OAAO,KAAK;IACZ,EACD;IACC,OAAO;IACP,OAAO;IACP,CACD;GACD,CAAC;AAEF,MAAI,CAAC,OACJ,OAAM,IAAI,SAAS,aAAa,EAC/B,SAAS,4CACT,CAAC;;CAIJ,MAAM,eAAe,MAAM,IAAI,QAAQ,QAAQ,QAAsB;EACpE,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,aACH,OAAM,IAAI,QAAQ,QAAQ,OAAqB;EAC9C,OAAO;EACP,OAAO,CAAC;GAAE,OAAO;GAAM,OAAO,aAAa;GAAI,CAAC;EAChD,CAAC;CAGH,MAAM,YAAY,qBAAqB,GAAG;CAC1C,MAAM,YAAY,UAAU,OAC3B,GAAG,UAAU,GAAG,aAAa,iBAAiB,IAAI,mBAAmB,KACrE;AAED,KAAI,KAAK,yBACR,OAAM,KAAK,yBAAyB;EACnC;EACA;EACA;EACA,CAAC;CAGH,MAAM,kBAAkB,MAAM,IAAI,QAAQ,QAAQ,OAAqB;EACtE,OAAO;EACP,MAAM;GACO;GACI;GAChB,WAAW,MAAM,eAAe,KAAK,MAAM,UAAU;GACrD;EACD,CAAC;AAEF,KAAI,KAAK,wBACR,OAAM,KAAK,wBAAwB;EAClC;EACA;EACA;EACA,cAAc;EACd,CAAC;AAGH,KAAI,UAAU,IAAI;AAElB,QAAO,IAAI,KAAK,EACf,WACA,CAAC;EAEH;AAEF,MAAa,kBAAkB,mBAC9B,mBACC,kBACA;CACC,QAAQ;CACR,MAAM;CACN,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,2BACR,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,KAAK,CAAC,eAAe;CACrB,EACD,OAAO,QAAQ;CACd,MAAM,OAAO,IAAI;CACjB,MAAM,aAAa,IAAI,QAAQ,aAAa;CAC5C,MAAM,YAAY,aAAa,KAAK,UAAU,KAAK,WAAW;AAU9D,KARwB,MAAM,IAAI,QAAQ,QAAQ,QAAiB;EAClE,OAAO;EACP,OAAO,CACN;GAAE,OAAO;GAAa,OAAO;GAAW,EACxC;GAAE,OAAO;GAAc,OAAO;GAAY,CAC1C;EACD,CAAC,CAGD,OAAM,IAAI,aAAa,YAAY;EAClC,QAAQ;EACR,UAAU;EACV,CAAC;CAGH,MAAM,QAAQ,oBAAoB,KAAK,UAAU,KAAK,OAAO;CAC7D,MAAM,OAAO,gBAAgB,OAAO,KAAK,KAAK;CAE9C,MAAM,eAAe,MAAM,IAAI,QAAQ,QAAQ,QAAc;EAC5D,OAAO;EACP,OAAO,CAAC;GAAE,OAAO;GAAS,OAAO;GAAO,CAAC;EACzC,CAAC;CAEF,MAAM,iBAAiB,WACtB,IAAI,QAAQ,gBAAgB,cAAc;EACjC;EACI;EACD;EACX,aAAa;EACb,cAAc;EACd,CAAC;CAEH,MAAM,mBACL,IAAI,QAAQ,gBAAgB,WAAW;EACtC;EACA;EACA,CAAC;CAEH,MAAM,sBAAsB,OAAO,WAAmB;EACrD,MAAM,iBAAiB,IAAI,QAAQ,aAAa;AAEhD,MAAI,gBASH;OAAI,CARgB,MAAM,IAAI,QAAQ,QAAQ,QAAQ;IACrD,OAAO;IACP,OAAO,CACN;KAAE,OAAO;KAAkB,OAAO;KAAgB,EAClD;KAAE,OAAO;KAAU,OAAO;KAAQ,CAClC;IACD,CAAC,CAGD,QAAO,MAAM,IAAI,QAAQ,QAAQ,OAAe;IAC/C,OAAO;IACP,MAAM;KACG;KACR,MAAM;KACN,2BAAW,IAAI,MAAM;KACrB;KACA;IACD,CAAC;;;CAKL,IAAI;CACJ,IAAI;AAEJ,KAAI,cAAc;AACjB,SAAO;AACP,YAAU,MAAM,IAAI,QAAQ,QAAQ,YAAqB,YAAY;GACpE,MAAM,UAAU,MAAM,cAAc,KAAK,GAAG;AAC5C,SAAM,oBAAoB,KAAK,GAAG;AAClC,UAAO;IACN;OAEF,EAAC,MAAM,WAAW,MAAM,IAAI,QAAQ,QAAQ,YAE1C,YAAY;EACb,MAAM,OAAO,MAAM,YAAY;EAC/B,MAAM,UAAU,MAAM,cAAc,KAAK,GAAG;AAC5C,QAAM,oBAAoB,KAAK,GAAG;AAClC,SAAO,CAAC,MAAM,QAAQ;GACrB;CAGH,MAAM,eAAe,mBACpB,IAAI,QAAQ,SACZ,MACA,QACA;AAED,KAAI,UAAU,IAAI;AAClB,KAAI,UAAU,YAAY,aAAa,KAAK,SAAS;AACrD,QAAO,IAAI,KAAK,aAAa;EAE9B;AAEF,MAAa,kBAAkB,mBAC9B,mBACC,0BACA;CACC,QAAQ;CACR,MAAM;CACN,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,2BACR,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,KAAK,CAAC,eAAe;CACrB,EACD,OAAO,QAAQ;CACd,MAAM,OAAO,IAAI;CACjB,MAAM,SAAS,IAAI,OAAO;CAC1B,MAAM,EAAE,gBAAgB,eAAe,IAAI,QAAQ;CACnD,MAAM,YAAY,aAAa,KAAK,UAAU,KAAK,WAAW;CAE9D,MAAM,EAAE,MAAM,YAAY,MAAM,aAAa,IAAI,QAAQ,SAAS;EACjE;EACA;EACA;EACA,CAAC;AAEF,KAAI,CAAC,KACJ,OAAM,IAAI,aAAa,aAAa,EACnC,QAAQ,kBACR,CAAC;CAGH,MAAM,CAAC,aAAa,kBACnB,MAAM,IAAI,QAAQ,QAAQ,YACzB,YAAY;EACX,MAAM,QAAQ,oBAAoB,KAAK,UAAU,KAAK,OAAO;EAC7D,MAAM,OAAO,gBAAgB,OAAO,KAAK,KAAK;AAiB9C,SAAO,CAfa,MAAM,IAAI,QAAQ,gBAAgB,WACrD,QACA;GACC;GACA;GACA,2BAAW,IAAI,MAAM;GACrB,CACD,EAGA,MAAM,IAAI,QAAQ,gBAAgB,cAAc,QAAQ,IAAI;GAC3D;GACA,2BAAW,IAAI,MAAM;GACrB,CAAC,CAEiC;GAErC;CAEF,MAAM,eAAe,mBACpB,IAAI,QAAQ,SACZ,aACA,eACA;AAED,QAAO,IAAI,KAAK,aAAa;EAE9B;AAEF,MAAM,2BAA2B,EAC/B,OAAO,EACP,QAAQ,EAAE,QAAQ,CAAC,UAAU,EAC7B,CAAC,CACD,UAAU;AAEZ,MAAa,iBAAiB,mBAC7B,mBACC,kBACA;CACC,QAAQ;CACR,OAAO;CACP,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ;MACP,MAAM;MACN,YAAY;OACX,cAAc,EAAE,MAAM,UAAU;OAChC,cAAc,EAAE,MAAM,UAAU;OAChC,YAAY,EAAE,MAAM,UAAU;OAC9B,WAAW;QACV,MAAM;QACN,OAAO;QACP;OACD;MACD,EACD,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,KAAK,CAAC,eAAe;CACrB,EACD,OAAO,QAAQ;CACd,MAAM,aAAyB,uBAAuB,IAAI,OAAO,OAAO;AAExE,KAAI,QAAQ,OAAO,KAAK,kCAAkC,WAAW;CAErE,MAAM,aAAa,IAAI,QAAQ,aAAa;CAC5C,MAAM,WAAW,MAAM,IAAI,QAAQ,QAAQ,SAAkB;EAC5D,OAAO;EACP,OAAO,CAAC;GAAE,OAAO;GAAc,OAAO;GAAY,CAAC;EACnD,CAAC;CAEF,MAAM,iBAAiB,SAAS,KAAK,YAAY,QAAQ,OAAO;CAChE,IAAI,cAA0B,CAC7B;EAAE,OAAO;EAAM,OAAO;EAAgB,UAAU;EAAM,CACtD;CAED,MAAM,iBAAiB,IAAI,QAAQ,aAAa;AAChD,KAAI,eAUH,eAAc,CAAC;EAAE,OAAO;EAAM,QATd,MAAM,IAAI,QAAQ,QAAQ,SAAiB;GAC1D,OAAO;GACP,OAAO,CACN;IAAE,OAAO;IAAkB,OAAO;IAAgB,EAClD;IAAE,OAAO;IAAU,OAAO;IAAgB,UAAU;IAAM,CAC1D;GACD,CAAC,EAE4B,KAAK,WAAW,OAAO,OAAO;EACR,UAAU;EAAM,CAAC;CAGtE,MAAM,QAAQ,MAAM,IAAI,QAAQ,QAAQ,SAAe;EACtD,OAAO;EACP,OAAO,CAAC,GAAG,aAAa,GAAG,WAAW;EACtC,CAAC;AAEF,QAAO,IAAI,KAAK;EACf,SAAS,CAAC,qDAAqD;EAC/D,cAAc,MAAM;EACpB,YAAY;EACZ,cAAc,MAAM;EACpB,WAAW,MAAM,KAAK,SAAS;GAC9B,MAAM,UAAU,SAAS,MAAM,MAAM,EAAE,WAAW,KAAK,GAAG;AAC1D,UAAO,mBAAmB,IAAI,QAAQ,SAAS,MAAM,QAAQ;IAC5D;EACF,CAAC;EAEH;AAEF,MAAa,eAAe,mBAC3B,mBACC,0BACA;CACC,QAAQ;CACR,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,2BACR,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,KAAK,CAAC,eAAe;CACrB,EACD,OAAO,QAAQ;CACd,MAAM,SAAS,IAAI,OAAO;CAC1B,MAAM,aAAa,IAAI,QAAQ,aAAa;CAC5C,MAAM,iBAAiB,IAAI,QAAQ,aAAa;CAEhD,MAAM,EAAE,MAAM,YAAY,MAAM,aAAa,IAAI,QAAQ,SAAS;EACjE;EACA;EACA;EACA,CAAC;AAEF,KAAI,CAAC,KACJ,OAAM,IAAI,aAAa,aAAa,EACnC,QAAQ,kBACR,CAAC;AAGH,QAAO,IAAI,KAAK,mBAAmB,IAAI,QAAQ,SAAS,MAAM,QAAQ,CAAC;EAExE;AAEF,MAAM,0BAA0B,EAAE,OAAO;CACxC,SAAS,EACP,MAAM,EAAE,QAAQ,CAAC,CACjB,QACC,MAAM,EAAE,SAAS,gDAAgD,EAClE,EACC,SAAS,+BACT,CACD;CACF,YAAY,EAAE,MACb,EAAE,OAAO;EACR,IAAI,EACF,QAAQ,CACR,aAAa,CACb,QAAQ,UAAU,CAClB,KAAK,EAAE,KAAK;GAAC;GAAW;GAAO;GAAS,CAAC,CAAC;EAC5C,MAAM,EAAE,QAAQ,CAAC,UAAU;EAC3B,OAAO,EAAE,KAAK;EACd,CAAC,CACF;CACD,CAAC;AAEF,MAAa,iBAAiB,mBAC7B,mBACC,0BACA;CACC,QAAQ;CACR,MAAM;CACN,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aAAa;GACb,WAAW;IACV,OAAO,EACN,aAAa,kCACb;IACD,GAAG;IACH;GACD;EACD;CACD,KAAK,CAAC,eAAe;CACrB,EACD,OAAO,QAAQ;CACd,MAAM,SAAS,IAAI,OAAO;CAC1B,MAAM,iBAAiB,IAAI,QAAQ,aAAa;CAChD,MAAM,aAAa,IAAI,QAAQ,aAAa;CAE5C,MAAM,EAAE,MAAM,YAAY,MAAM,aAAa,IAAI,QAAQ,SAAS;EACjE;EACA;EACA;EACA,CAAC;AAEF,KAAI,CAAC,KACJ,OAAM,IAAI,aAAa,aAAa,EACnC,QAAQ,kBACR,CAAC;CAGH,MAAM,EAAE,MAAM,WAAW,SAAS,iBAAiB,eAClD,MACA,IAAI,KAAK,WACT;AAED,KACC,OAAO,KAAK,UAAU,CAAC,WAAW,KAClC,OAAO,KAAK,aAAa,CAAC,WAAW,EAErC,OAAM,IAAI,aAAa,eAAe,EACrC,QAAQ,6BACR,CAAC;AAGH,OAAM,QAAQ,IAAI,CACjB,OAAO,KAAK,UAAU,CAAC,SAAS,IAC7B,IAAI,QAAQ,gBAAgB,WAAW,QAAQ;EAC/C,GAAG;EACH,2BAAW,IAAI,MAAM;EACrB,CAAC,GACD,QAAQ,SAAS,EACpB,OAAO,KAAK,aAAa,CAAC,SAAS,IAChC,IAAI,QAAQ,gBAAgB,cAAc,QAAQ,IAAI;EACtD,GAAG;EACH,2BAAW,IAAI,MAAM;EACrB,CAAC,GACD,QAAQ,SAAS,CACpB,CAAC;AAEF,KAAI,UAAU,IAAI;EAGnB;AAEF,MAAa,kBAAkB,mBAC9B,mBACC,0BACA;CACC,QAAQ;CACR,UAAU;EACT,GAAG;EACH,mBAAmB,CAAC,GAAG,qBAAqB,GAAG;EAC/C,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO,EACN,aAAa,+BACb;IACD,GAAG;IACH;GACD;EACD;CACD,KAAK,CAAC,eAAe;CACrB,EACD,OAAO,QAAQ;CACd,MAAM,SAAS,IAAI,OAAO;CAC1B,MAAM,aAAa,IAAI,QAAQ,aAAa;CAC5C,MAAM,iBAAiB,IAAI,QAAQ,aAAa;CAEhD,MAAM,EAAE,SAAS,MAAM,aAAa,IAAI,QAAQ,SAAS;EACxD;EACA;EACA;EACA,CAAC;AAEF,KAAI,CAAC,KACJ,OAAM,IAAI,aAAa,aAAa,EACnC,QAAQ,kBACR,CAAC;AAGH,OAAM,IAAI,QAAQ,gBAAgB,WAAW,OAAO;AAEpD,KAAI,UAAU,IAAI;EAGnB;AAEF,MAAa,+BAA+B,mBAC3C,kCACA;CACC,QAAQ;CACR,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,8BACR,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,EACD,OAAO,QAAQ;AACd,QAAO,IAAI,KAAK;EACf,OAAO,EAAE,WAAW,MAAM;EAC1B,MAAM,EAAE,WAAW,OAAO;EAC1B,QAAQ,EAAE,WAAW,MAAM;EAC3B,gBAAgB,EAAE,WAAW,OAAO;EACpC,MAAM,EAAE,WAAW,OAAO;EAC1B,MAAM,EAAE,WAAW,OAAO;EAC1B,uBAAuB,CACtB;GACC,MAAM;GACN,aACC;GACD,SAAS;GACT,MAAM;GACN,SAAS;GACT,CACD;EACD,SAAS,CAAC,8DAA8D;EACxE,MAAM,EACL,cAAc,yBACd;EACD,CAAC;EAEH;AAED,MAAa,iBAAiB,mBAC7B,oBACA;CACC,QAAQ;CACR,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ;MACP,MAAM;MACN,OAAO;MACP,EACD,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,EACD,OAAO,QAAQ;AACd,QAAO,IAAI,KAAK;EACf,cAAc,qBAAqB;EACnC,cAAc,qBAAqB;EACnC,YAAY;EACZ,SAAS,CAAC,qDAAqD;EAC/D,WAAW,qBAAqB,KAAK,MAAM;AAC1C,UAAO;IACN,GAAG;IACH,MAAM;KACL,GAAG,EAAE;KACL,UAAU,eAAe,EAAE,KAAK,UAAU,IAAI,QAAQ,QAAQ;KAC9D;IACD;IACA;EACF,CAAC;EAEH;AAED,MAAa,gBAAgB,mBAC5B,8BACA;CACC,QAAQ;CACR,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,yBACR,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,EACD,OAAO,QAAQ;CACd,MAAM,SAAS,qBAAqB,MAClC,MAAM,EAAE,OAAO,IAAI,OAAO,SAC3B;AAED,KAAI,CAAC,OACJ,OAAM,IAAI,aAAa,aAAa,EACnC,QAAQ,oBACR,CAAC;AAGH,QAAO,IAAI,KAAK;EACf,GAAG;EACH,MAAM;GACL,GAAG,OAAO;GACV,UAAU,eAAe,OAAO,KAAK,UAAU,IAAI,QAAQ,QAAQ;GACnE;EACD,CAAC;EAEH;AAED,MAAa,uBAAuB,mBACnC,0BACA;CACC,QAAQ;CACR,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ;MACP,MAAM;MACN,YAAY;OACX,cAAc,EAAE,MAAM,UAAU;OAChC,cAAc,EAAE,MAAM,UAAU;OAChC,YAAY,EAAE,MAAM,UAAU;OAC9B,WAAW;QACV,MAAM;QACN,OAAO;QACP;OACD;MACD,EACD,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,EACD,OAAO,QAAQ;AACd,QAAO,IAAI,KAAK;EACf,cAAc,2BAA2B;EACzC,cAAc,2BAA2B;EACzC,YAAY;EACZ,SAAS,CAAC,qDAAqD;EAC/D,WAAW,2BAA2B,KAAK,MAAM;AAChD,UAAO;IACN,GAAG;IACH,MAAM;KACL,GAAG,EAAE;KACL,UAAU,eAAe,EAAE,KAAK,UAAU,IAAI,QAAQ,QAAQ;KAC9D;IACD;IACA;EACF,CAAC;EAEH;AAED,MAAa,sBAAsB,mBAClC,0CACA;CACC,QAAQ;CACR,UAAU;EACT,GAAG;EACH,mBAAmB;EACnB,SAAS;GACR,SAAS;GACT,aACC;GACD,WAAW;IACV,OAAO;KACN,aAAa;KACb,SAAS,EACR,oBAAoB,EACnB,QAAQ,2BACR,EACD;KACD;IACD,GAAG;IACH;GACD;EACD;CACD,EACD,OAAO,QAAQ;CACd,MAAM,eAAe,2BAA2B,MAC9C,MAAM,EAAE,OAAO,IAAI,OAAO,eAC3B;AAED,KAAI,CAAC,aACJ,OAAM,IAAI,aAAa,aAAa,EACnC,QAAQ,2BACR,CAAC;AAGH,QAAO,IAAI,KAAK;EACf,GAAG;EACH,MAAM;GACL,GAAG,aAAa;GAChB,UAAU,eACT,aAAa,KAAK,UAClB,IAAI,QAAQ,QACZ;GACD;EACD,CAAC;EAEH;AAED,MAAM,eAAe,OACpB,SACA,EACC,QACA,YACA,qBAEG;CACJ,MAAM,UAAU,MAAM,QAAQ,QAAiB;EAC9C,OAAO;EACP,OAAO,CACN;GAAE,OAAO;GAAU,OAAO;GAAQ,EAClC;GAAE,OAAO;GAAc,OAAO;GAAY,CAC1C;EACD,CAAC;AAKF,KAAI,CAAC,QACJ,QAAO;EAAE,MAAM;EAAM,SAAS;EAAM;CAGrC,IAAI,SAAwB;AAC5B,KAAI,eACH,UAAS,MAAM,QAAQ,QAAgB;EACtC,OAAO;EACP,OAAO,CACN;GAAE,OAAO;GAAkB,OAAO;GAAgB,EAClD;GAAE,OAAO;GAAU,OAAO;GAAQ,CAClC;EACD,CAAC;AAMH,KAAI,kBAAkB,CAAC,OACtB,QAAO;EAAE,MAAM;EAAM,SAAS;EAAM;CAGrC,MAAM,OAAO,MAAM,QAAQ,QAAc;EACxC,OAAO;EACP,OAAO,CAAC;GAAE,OAAO;GAAM,OAAO;GAAQ,CAAC;EACvC,CAAC;AAEF,KAAI,CAAC,KACJ,QAAO;EAAE,MAAM;EAAM,SAAS;EAAM;AAGrC,QAAO;EAAE;EAAM;EAAS;;AAGzB,MAAM,0BAA0B,WAAoB;CACnD,IAAI,UAAsB,EAAE;AAE5B,KAAI;AACH,YAAU,SAAS,oBAAoB,OAAO,GAAG,EAAE;UAC3C,OAAO;AACf,QAAM,IAAI,aAAa,eAAe;GACrC,QACC,iBAAiB,iBAAiB,MAAM,UAAU;GACnD,UAAU;GACV,CAAC;;AAGH,QAAO;;;;;AC37BR,MAAa,QAAQ,YAA0B;CAC9C,MAAM,OAAO;EACZ,gBAAgB;EAChB,GAAG;EACH;CAED,MAAM,iBAAiB,sBAAsB,KAAK;AAElD,QAAO;EACN,IAAI;EACJ,WAAW;GACV,mBAAmB,kBAAkB,KAAK;GAC1C,aAAa,YAAY,eAAe;GACxC,gBAAgB,eAAe,eAAe;GAC9C,eAAe,cAAc,eAAe;GAC5C,gBAAgB,eAAe,eAAe;GAC9C,gBAAgB,eAAe,eAAe;GAC9C,eAAe,cAAc,eAAe;GAC5C;GACA;GACA;GACA;GACA;GACA;EACD,QAAQ,EACP,cAAc,EACb,QAAQ;GACP,YAAY;IACX,MAAM;IACN,UAAU;IACV,QAAQ;IACR;GACD,WAAW;IACV,MAAM;IACN,UAAU;IACV,QAAQ;IACR;GACD,gBAAgB;IACf,MAAM;IACN,UAAU;IACV;GACD,EACD,EACD;EACD;EACA"}
|
|
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 type { GenericEndpointContext } from \"better-auth\";\nimport { symmetricDecrypt, symmetricEncrypt } from \"better-auth/crypto\";\nimport { defaultKeyHasher } from \"better-auth/plugins\";\nimport type { SCIMOptions } from \"./types\";\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.secret,\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.secret,\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 { Account, DBAdapter, User } 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\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 ctx.context.adapter.findOne<Member>({\n\t\t\t\t\tmodel: \"member\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"userId\",\n\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"organizationId\",\n\t\t\t\t\t\t\tvalue: organizationId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\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 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},\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 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\tdeleteSCIMUser,\n\tgenerateSCIMToken,\n\tgetSCIMResourceType,\n\tgetSCIMResourceTypes,\n\tgetSCIMSchema,\n\tgetSCIMSchemas,\n\tgetSCIMServiceProviderConfig,\n\tgetSCIMUser,\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\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\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},\n\t\t\t},\n\t\t},\n\t\toptions,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport * from \"./types\";\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/scim",
|
|
3
3
|
"author": "Jonathan Samines",
|
|
4
|
-
"version": "1.5.0-beta.
|
|
4
|
+
"version": "1.5.0-beta.12",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.mts",
|
|
@@ -44,17 +44,17 @@
|
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@better-auth/utils": "0.3.1",
|
|
47
|
-
"better-call": "1.2.
|
|
47
|
+
"better-call": "1.2.1",
|
|
48
48
|
"zod": "^4.3.6"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"tsdown": "^0.20.1",
|
|
52
|
-
"@better-auth/core": "1.5.0-beta.
|
|
53
|
-
"@better-auth/sso": "1.5.0-beta.
|
|
52
|
+
"@better-auth/core": "1.5.0-beta.12",
|
|
53
|
+
"@better-auth/sso": "1.5.0-beta.12"
|
|
54
54
|
},
|
|
55
55
|
"peerDependencies": {
|
|
56
|
-
"@better-auth/core": "1.5.0-beta.
|
|
57
|
-
"better-auth": "1.5.0-beta.
|
|
56
|
+
"@better-auth/core": "1.5.0-beta.12",
|
|
57
|
+
"better-auth": "1.5.0-beta.12"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"test": "vitest",
|
package/src/routes.ts
CHANGED
|
@@ -429,6 +429,14 @@ export const listSCIMUsers = (authMiddleware: AuthMiddleware) =>
|
|
|
429
429
|
use: [authMiddleware],
|
|
430
430
|
},
|
|
431
431
|
async (ctx) => {
|
|
432
|
+
const emptyListResponse = {
|
|
433
|
+
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
|
434
|
+
totalResults: 0,
|
|
435
|
+
startIndex: 1,
|
|
436
|
+
itemsPerPage: 0,
|
|
437
|
+
Resources: [],
|
|
438
|
+
} as const;
|
|
439
|
+
|
|
432
440
|
const apiFilters: DBFilter[] = parseSCIMAPIUserFilter(ctx.query?.filter);
|
|
433
441
|
|
|
434
442
|
ctx.context.logger.info("Querying result with filters: ", apiFilters);
|
|
@@ -440,6 +448,13 @@ export const listSCIMUsers = (authMiddleware: AuthMiddleware) =>
|
|
|
440
448
|
});
|
|
441
449
|
|
|
442
450
|
const accountUserIds = accounts.map((account) => account.userId);
|
|
451
|
+
|
|
452
|
+
// No accounts exist for this provider
|
|
453
|
+
|
|
454
|
+
if (accountUserIds.length === 0) {
|
|
455
|
+
return ctx.json(emptyListResponse);
|
|
456
|
+
}
|
|
457
|
+
|
|
443
458
|
let userFilters: DBFilter[] = [
|
|
444
459
|
{ field: "id", value: accountUserIds, operator: "in" },
|
|
445
460
|
];
|
|
@@ -455,6 +470,13 @@ export const listSCIMUsers = (authMiddleware: AuthMiddleware) =>
|
|
|
455
470
|
});
|
|
456
471
|
|
|
457
472
|
const memberUserIds = members.map((member) => member.userId);
|
|
473
|
+
|
|
474
|
+
// No members exist for this organization
|
|
475
|
+
|
|
476
|
+
if (memberUserIds.length === 0) {
|
|
477
|
+
return ctx.json(emptyListResponse);
|
|
478
|
+
}
|
|
479
|
+
|
|
458
480
|
userFilters = [{ field: "id", value: memberUserIds, operator: "in" }];
|
|
459
481
|
}
|
|
460
482
|
|
package/src/scim.test.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { memoryAdapter } from "better-auth/adapters/memory";
|
|
|
4
4
|
import { createAuthClient } from "better-auth/client";
|
|
5
5
|
import { setCookieToHeader } from "better-auth/cookies";
|
|
6
6
|
import { bearer, organization } from "better-auth/plugins";
|
|
7
|
+
import { getTestInstance } from "better-auth/test";
|
|
7
8
|
import { describe, expect, it } from "vitest";
|
|
8
9
|
import { scim } from ".";
|
|
9
10
|
import { scimClient } from "./client";
|
|
@@ -101,6 +102,56 @@ const createTestInstance = (scimOptions?: SCIMOptions) => {
|
|
|
101
102
|
};
|
|
102
103
|
};
|
|
103
104
|
|
|
105
|
+
const createSqlTestInstance = async (
|
|
106
|
+
testWith: "sqlite" | "postgres",
|
|
107
|
+
scimOptions?: SCIMOptions,
|
|
108
|
+
) => {
|
|
109
|
+
const { auth, client, signInWithTestUser } = await getTestInstance(
|
|
110
|
+
{
|
|
111
|
+
plugins: [scim(scimOptions), organization()],
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
testWith,
|
|
115
|
+
},
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
async function getSCIMToken(
|
|
119
|
+
providerId: string = "the-saml-provider-1",
|
|
120
|
+
organizationId?: string,
|
|
121
|
+
) {
|
|
122
|
+
const { headers } = await signInWithTestUser();
|
|
123
|
+
const { scimToken } = await auth.api.generateSCIMToken({
|
|
124
|
+
body: {
|
|
125
|
+
providerId,
|
|
126
|
+
organizationId,
|
|
127
|
+
},
|
|
128
|
+
headers,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return scimToken;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function registerOrganization(org: string) {
|
|
135
|
+
const { headers } = await signInWithTestUser();
|
|
136
|
+
|
|
137
|
+
return await auth.api.createOrganization({
|
|
138
|
+
body: {
|
|
139
|
+
slug: `the-${org}`,
|
|
140
|
+
name: `the organization ${org}`,
|
|
141
|
+
},
|
|
142
|
+
headers,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
auth,
|
|
148
|
+
client,
|
|
149
|
+
registerOrganization,
|
|
150
|
+
getSCIMToken,
|
|
151
|
+
signInWithTestUser,
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
|
|
104
155
|
describe("SCIM", () => {
|
|
105
156
|
describe("POST /scim/generate-token", () => {
|
|
106
157
|
it("should require user session", async () => {
|
|
@@ -1960,6 +2011,62 @@ describe("SCIM", () => {
|
|
|
1960
2011
|
});
|
|
1961
2012
|
});
|
|
1962
2013
|
|
|
2014
|
+
it("should return an empty list when no users have been provisioned or belong to the organization", async () => {
|
|
2015
|
+
const { auth, getSCIMToken, registerOrganization } =
|
|
2016
|
+
await createSqlTestInstance("postgres");
|
|
2017
|
+
const scimToken = await getSCIMToken();
|
|
2018
|
+
|
|
2019
|
+
const createUser = (userName: string, scimToken: string) => {
|
|
2020
|
+
return auth.api.createSCIMUser({
|
|
2021
|
+
body: {
|
|
2022
|
+
userName,
|
|
2023
|
+
},
|
|
2024
|
+
headers: {
|
|
2025
|
+
authorization: `Bearer ${scimToken}`,
|
|
2026
|
+
},
|
|
2027
|
+
});
|
|
2028
|
+
};
|
|
2029
|
+
|
|
2030
|
+
const listUsers = (scimToken: string) => {
|
|
2031
|
+
return auth.api.listSCIMUsers({
|
|
2032
|
+
headers: {
|
|
2033
|
+
authorization: `Bearer ${scimToken}`,
|
|
2034
|
+
},
|
|
2035
|
+
});
|
|
2036
|
+
};
|
|
2037
|
+
|
|
2038
|
+
const users = await listUsers(scimToken);
|
|
2039
|
+
|
|
2040
|
+
expect(users).toMatchObject({
|
|
2041
|
+
itemsPerPage: 0,
|
|
2042
|
+
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
|
2043
|
+
startIndex: 1,
|
|
2044
|
+
totalResults: 0,
|
|
2045
|
+
Resources: [],
|
|
2046
|
+
});
|
|
2047
|
+
|
|
2048
|
+
const [organizationA, organizationB] = await Promise.all([
|
|
2049
|
+
registerOrganization("org-a"),
|
|
2050
|
+
registerOrganization("org-b"),
|
|
2051
|
+
]);
|
|
2052
|
+
|
|
2053
|
+
const [scimTokenOrgA, scimTokenOrgB] = await Promise.all([
|
|
2054
|
+
getSCIMToken("provider-org-a", organizationA?.id),
|
|
2055
|
+
getSCIMToken("provider-org-b", organizationB?.id),
|
|
2056
|
+
]);
|
|
2057
|
+
|
|
2058
|
+
await createUser("user-a", scimTokenOrgA);
|
|
2059
|
+
const orgBUsers = await listUsers(scimTokenOrgB);
|
|
2060
|
+
|
|
2061
|
+
expect(orgBUsers).toMatchObject({
|
|
2062
|
+
itemsPerPage: 0,
|
|
2063
|
+
schemas: ["urn:ietf:params:scim:api:messages:2.0:ListResponse"],
|
|
2064
|
+
startIndex: 1,
|
|
2065
|
+
totalResults: 0,
|
|
2066
|
+
Resources: [],
|
|
2067
|
+
});
|
|
2068
|
+
});
|
|
2069
|
+
|
|
1963
2070
|
it("should only allow access to users that belong to the same provider", async () => {
|
|
1964
2071
|
const { auth, getSCIMToken } = createTestInstance();
|
|
1965
2072
|
const [scimTokenProviderA, scimTokenProviderB] = await Promise.all([
|