better-auth
Version:
The most comprehensive authentication framework for TypeScript.
1 lines • 10.7 kB
Source Map (JSON)
{"version":3,"file":"client.mjs","names":[],"sources":["../../../src/plugins/organization/client.ts"],"sourcesContent":["import type { BetterAuthClientPlugin } from \"@better-auth/core\";\nimport type { DBFieldAttribute } from \"@better-auth/core/db\";\nimport { atom } from \"nanostores\";\nimport { useAuthQuery } from \"../../client\";\nimport type {\n\tInferInvitation,\n\tInferMember,\n\tInferOrganization,\n\tInferTeam,\n\tMember,\n} from \"../../plugins/organization/schema\";\nimport type { BetterAuthOptions, BetterAuthPlugin } from \"../../types\";\nimport type { Prettify } from \"../../types/helper\";\nimport type { AccessControl, Role } from \"../access\";\nimport type { defaultStatements } from \"./access\";\nimport { adminAc, defaultRoles, memberAc, ownerAc } from \"./access\";\nimport type { OrganizationPlugin } from \"./organization\";\nimport type { HasPermissionBaseInput } from \"./permission\";\nimport { hasPermissionFn } from \"./permission\";\nimport type { OrganizationOptions } from \"./types\";\n\n/**\n * Using the same `hasPermissionFn` function, but without the need for a `ctx` parameter or the `organizationId` parameter.\n */\nexport const clientSideHasPermission = (input: HasPermissionBaseInput) => {\n\tconst acRoles: {\n\t\t[x: string]: Role<any> | undefined;\n\t} = input.options.roles || defaultRoles;\n\n\treturn hasPermissionFn(input, acRoles);\n};\n\ninterface OrganizationClientOptions {\n\tac?: AccessControl | undefined;\n\troles?:\n\t\t| {\n\t\t\t\t[key in string]: Role;\n\t\t }\n\t\t| undefined;\n\tteams?:\n\t\t| {\n\t\t\t\tenabled: boolean;\n\t\t }\n\t\t| undefined;\n\tschema?:\n\t\t| {\n\t\t\t\torganization?: {\n\t\t\t\t\tadditionalFields?: {\n\t\t\t\t\t\t[key: string]: DBFieldAttribute;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t\tmember?: {\n\t\t\t\t\tadditionalFields?: {\n\t\t\t\t\t\t[key: string]: DBFieldAttribute;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t\tinvitation?: {\n\t\t\t\t\tadditionalFields?: {\n\t\t\t\t\t\t[key: string]: DBFieldAttribute;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t\tteam?: {\n\t\t\t\t\tadditionalFields?: {\n\t\t\t\t\t\t[key: string]: DBFieldAttribute;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t\torganizationRole?: {\n\t\t\t\t\tadditionalFields?: {\n\t\t\t\t\t\t[key: string]: DBFieldAttribute;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t }\n\t\t| undefined;\n\tdynamicAccessControl?:\n\t\t| {\n\t\t\t\tenabled: boolean;\n\t\t }\n\t\t| undefined;\n}\n\nexport const organizationClient = <CO extends OrganizationClientOptions>(\n\toptions?: CO | undefined,\n) => {\n\tconst $listOrg = atom<boolean>(false);\n\tconst $activeOrgSignal = atom<boolean>(false);\n\tconst $activeMemberSignal = atom<boolean>(false);\n\tconst $activeMemberRoleSignal = atom<boolean>(false);\n\n\ttype DefaultStatements = typeof defaultStatements;\n\ttype Statements =\n\t\tCO[\"ac\"] extends AccessControl<infer S> ? S : DefaultStatements;\n\ttype PermissionType = {\n\t\t[key in keyof Statements]?: Array<\n\t\t\tStatements[key] extends readonly unknown[]\n\t\t\t\t? Statements[key][number]\n\t\t\t\t: never\n\t\t>;\n\t};\n\ttype PermissionExclusive =\n\t\t| {\n\t\t\t\t/**\n\t\t\t\t * @deprecated Use `permissions` instead\n\t\t\t\t */\n\t\t\t\tpermission: PermissionType;\n\t\t\t\tpermissions?: never | undefined;\n\t\t }\n\t\t| {\n\t\t\t\tpermissions: PermissionType;\n\t\t\t\tpermission?: never | undefined;\n\t\t };\n\n\tconst roles = {\n\t\tadmin: adminAc,\n\t\tmember: memberAc,\n\t\towner: ownerAc,\n\t\t...options?.roles,\n\t};\n\n\ttype OrganizationReturn = CO[\"teams\"] extends { enabled: true }\n\t\t? {\n\t\t\t\tmembers: InferMember<CO, false>[];\n\t\t\t\tinvitations: InferInvitation<CO>[];\n\t\t\t\tteams: InferTeam<CO, false>[];\n\t\t\t} & InferOrganization<CO, false>\n\t\t: {\n\t\t\t\tmembers: InferMember<CO, false>[];\n\t\t\t\tinvitations: InferInvitation<CO, false>[];\n\t\t\t} & InferOrganization<CO, false>;\n\n\ttype Schema = CO[\"schema\"];\n\treturn {\n\t\tid: \"organization\",\n\t\t$InferServerPlugin: {} as OrganizationPlugin<{\n\t\t\tac: CO[\"ac\"] extends AccessControl\n\t\t\t\t? CO[\"ac\"]\n\t\t\t\t: AccessControl<DefaultStatements>;\n\t\t\troles: CO[\"roles\"] extends Record<string, Role>\n\t\t\t\t? CO[\"roles\"]\n\t\t\t\t: {\n\t\t\t\t\t\tadmin: Role;\n\t\t\t\t\t\tmember: Role;\n\t\t\t\t\t\towner: Role;\n\t\t\t\t\t};\n\t\t\tteams: {\n\t\t\t\tenabled: CO[\"teams\"] extends { enabled: true } ? true : false;\n\t\t\t};\n\t\t\tschema: Schema;\n\t\t\tdynamicAccessControl: {\n\t\t\t\tenabled: CO[\"dynamicAccessControl\"] extends { enabled: true }\n\t\t\t\t\t? true\n\t\t\t\t\t: false;\n\t\t\t};\n\t\t}>,\n\t\tgetActions: ($fetch, _$store, co) => ({\n\t\t\t$Infer: {\n\t\t\t\tActiveOrganization: {} as OrganizationReturn,\n\t\t\t\tOrganization: {} as InferOrganization<CO, false>,\n\t\t\t\tInvitation: {} as InferInvitation<CO, false>,\n\t\t\t\tMember: {} as InferMember<CO, false>,\n\t\t\t\tTeam: {} as InferTeam<CO, false>,\n\t\t\t},\n\t\t\torganization: {\n\t\t\t\tcheckRolePermission: <\n\t\t\t\t\tR extends CO extends { roles: any }\n\t\t\t\t\t\t? keyof CO[\"roles\"]\n\t\t\t\t\t\t: \"admin\" | \"member\" | \"owner\",\n\t\t\t\t>(\n\t\t\t\t\tdata: PermissionExclusive & {\n\t\t\t\t\t\trole: R;\n\t\t\t\t\t},\n\t\t\t\t) => {\n\t\t\t\t\tconst isAuthorized = clientSideHasPermission({\n\t\t\t\t\t\trole: data.role as string,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tac: options?.ac,\n\t\t\t\t\t\t\troles: roles,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tpermissions: (data.permissions ?? data.permission) as any,\n\t\t\t\t\t});\n\t\t\t\t\treturn isAuthorized;\n\t\t\t\t},\n\t\t\t},\n\t\t}),\n\t\tgetAtoms: ($fetch) => {\n\t\t\tconst listOrganizations = useAuthQuery<InferOrganization<CO, false>[]>(\n\t\t\t\t$listOrg,\n\t\t\t\t\"/organization/list\",\n\t\t\t\t$fetch,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst activeOrganization = useAuthQuery<\n\t\t\t\tPrettify<\n\t\t\t\t\tInferOrganization<CO, false> & {\n\t\t\t\t\t\tmembers: InferMember<CO, false>[];\n\t\t\t\t\t\tinvitations: InferInvitation<CO, false>[];\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t>(\n\t\t\t\t[$activeOrgSignal],\n\t\t\t\t\"/organization/get-full-organization\",\n\t\t\t\t$fetch,\n\t\t\t\t() => ({\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t}),\n\t\t\t);\n\n\t\t\tconst activeMember = useAuthQuery<Member>(\n\t\t\t\t[$activeMemberSignal],\n\t\t\t\t\"/organization/get-active-member\",\n\t\t\t\t$fetch,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconst activeMemberRole = useAuthQuery<{ role: string }>(\n\t\t\t\t[$activeMemberRoleSignal],\n\t\t\t\t\"/organization/get-active-member-role\",\n\t\t\t\t$fetch,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t},\n\t\t\t);\n\n\t\t\treturn {\n\t\t\t\t$listOrg,\n\t\t\t\t$activeOrgSignal,\n\t\t\t\t$activeMemberSignal,\n\t\t\t\t$activeMemberRoleSignal,\n\t\t\t\tactiveOrganization,\n\t\t\t\tlistOrganizations,\n\t\t\t\tactiveMember,\n\t\t\t\tactiveMemberRole,\n\t\t\t};\n\t\t},\n\t\tpathMethods: {\n\t\t\t\"/organization/get-full-organization\": \"GET\",\n\t\t\t\"/organization/list-user-teams\": \"GET\",\n\t\t},\n\t\tatomListeners: [\n\t\t\t{\n\t\t\t\tmatcher(path) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tpath === \"/organization/create\" ||\n\t\t\t\t\t\tpath === \"/organization/delete\" ||\n\t\t\t\t\t\tpath === \"/organization/update\"\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tsignal: \"$listOrg\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatcher(path) {\n\t\t\t\t\treturn path.startsWith(\"/organization\");\n\t\t\t\t},\n\t\t\t\tsignal: \"$activeOrgSignal\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatcher(path) {\n\t\t\t\t\treturn path.startsWith(\"/organization/set-active\");\n\t\t\t\t},\n\t\t\t\tsignal: \"$sessionSignal\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatcher(path) {\n\t\t\t\t\treturn path.includes(\"/organization/update-member-role\");\n\t\t\t\t},\n\t\t\t\tsignal: \"$activeMemberSignal\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatcher(path) {\n\t\t\t\t\treturn path.includes(\"/organization/update-member-role\");\n\t\t\t\t},\n\t\t\t\tsignal: \"$activeMemberRoleSignal\",\n\t\t\t},\n\t\t],\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport const inferOrgAdditionalFields = <\n\tO extends {\n\t\toptions: BetterAuthOptions;\n\t},\n\tS extends OrganizationOptions[\"schema\"] = undefined,\n>(\n\tschema?: S | undefined,\n) => {\n\ttype FindById<\n\t\tT extends readonly BetterAuthPlugin[],\n\t\tTargetId extends string,\n\t> = Extract<T[number], { id: TargetId }>;\n\n\ttype Auth = O extends { options: any } ? O : { options: { plugins: [] } };\n\n\ttype OrganizationPlugin = FindById<\n\t\t// @ts-expect-error\n\t\tAuth[\"options\"][\"plugins\"],\n\t\t\"organization\"\n\t>;\n\n\t// The server schema can contain more properties other than additionalFields, but the client only supports additionalFields\n\t// if we don't remove all other properties we may see assignability issues\n\n\ttype ExtractClientOnlyFields<T> = {\n\t\t[K in keyof T]: T[K] extends { additionalFields: infer _AF }\n\t\t\t? T[K]\n\t\t\t: undefined;\n\t};\n\n\ttype Schema = O extends Object\n\t\t? O extends Exclude<OrganizationOptions[\"schema\"], undefined>\n\t\t\t? O\n\t\t\t: OrganizationPlugin extends { options: { schema: infer S } }\n\t\t\t\t? S extends OrganizationOptions[\"schema\"]\n\t\t\t\t\t? ExtractClientOnlyFields<S>\n\t\t\t\t\t: undefined\n\t\t\t\t: undefined\n\t\t: undefined;\n\treturn {} as undefined extends S ? Schema : S;\n};\n\nexport type * from \"./schema\";\n"],"mappings":";;;;;;;;;;;AAwBA,MAAa,2BAA2B,UAAkC;AAKzE,QAAO,gBAAgB,OAFnB,MAAM,QAAQ,SAAS,aAEW;;AAmDvC,MAAa,sBACZ,YACI;CACJ,MAAM,WAAW,KAAc,MAAM;CACrC,MAAM,mBAAmB,KAAc,MAAM;CAC7C,MAAM,sBAAsB,KAAc,MAAM;CAChD,MAAM,0BAA0B,KAAc,MAAM;CAyBpD,MAAM,QAAQ;EACb,OAAO;EACP,QAAQ;EACR,OAAO;EACP,GAAG,SAAS;EACZ;AAcD,QAAO;EACN,IAAI;EACJ,oBAAoB,EAAE;EAqBtB,aAAa,QAAQ,SAAS,QAAQ;GACrC,QAAQ;IACP,oBAAoB,EAAE;IACtB,cAAc,EAAE;IAChB,YAAY,EAAE;IACd,QAAQ,EAAE;IACV,MAAM,EAAE;IACR;GACD,cAAc,EACb,sBAKC,SAGI;AASJ,WARqB,wBAAwB;KAC5C,MAAM,KAAK;KACX,SAAS;MACR,IAAI,SAAS;MACN;MACP;KACD,aAAc,KAAK,eAAe,KAAK;KACvC,CAAC;MAGH;GACD;EACD,WAAW,WAAW;GACrB,MAAM,oBAAoB,aACzB,UACA,sBACA,QACA,EACC,QAAQ,OACR,CACD;AAmCD,UAAO;IACN;IACA;IACA;IACA;IACA,oBAvC0B,aAQ1B,CAAC,iBAAiB,EAClB,uCACA,eACO,EACN,QAAQ,OACR,EACD;IA0BA;IACA,cAzBoB,aACpB,CAAC,oBAAoB,EACrB,mCACA,QACA,EACC,QAAQ,OACR,CACD;IAmBA,kBAjBwB,aACxB,CAAC,wBAAwB,EACzB,wCACA,QACA,EACC,QAAQ,OACR,CACD;IAWA;;EAEF,aAAa;GACZ,uCAAuC;GACvC,iCAAiC;GACjC;EACD,eAAe;GACd;IACC,QAAQ,MAAM;AACb,YACC,SAAS,0BACT,SAAS,0BACT,SAAS;;IAGX,QAAQ;IACR;GACD;IACC,QAAQ,MAAM;AACb,YAAO,KAAK,WAAW,gBAAgB;;IAExC,QAAQ;IACR;GACD;IACC,QAAQ,MAAM;AACb,YAAO,KAAK,WAAW,2BAA2B;;IAEnD,QAAQ;IACR;GACD;IACC,QAAQ,MAAM;AACb,YAAO,KAAK,SAAS,mCAAmC;;IAEzD,QAAQ;IACR;GACD;IACC,QAAQ,MAAM;AACb,YAAO,KAAK,SAAS,mCAAmC;;IAEzD,QAAQ;IACR;GACD;EACD;;AAGF,MAAa,4BAMZ,WACI;AAgCJ,QAAO,EAAE"}