@fragno-dev/auth 0.0.14 → 0.0.16

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.
Files changed (36) hide show
  1. package/README.md +196 -9
  2. package/dist/browser/client/react.d.ts +1194 -64
  3. package/dist/browser/client/react.d.ts.map +1 -1
  4. package/dist/browser/client/react.js +1 -1
  5. package/dist/browser/client/react.js.map +1 -1
  6. package/dist/browser/client/solid.d.ts +1446 -64
  7. package/dist/browser/client/solid.d.ts.map +1 -1
  8. package/dist/browser/client/solid.js +1 -1
  9. package/dist/browser/client/solid.js.map +1 -1
  10. package/dist/browser/client/svelte.d.ts +1194 -64
  11. package/dist/browser/client/svelte.d.ts.map +1 -1
  12. package/dist/browser/client/svelte.js +1 -1
  13. package/dist/browser/client/svelte.js.map +1 -1
  14. package/dist/browser/client/vanilla.d.ts +1194 -64
  15. package/dist/browser/client/vanilla.d.ts.map +1 -1
  16. package/dist/browser/client/vanilla.js +1 -1
  17. package/dist/browser/client/vanilla.js.map +1 -1
  18. package/dist/browser/client/vue.d.ts +1150 -20
  19. package/dist/browser/client/vue.d.ts.map +1 -1
  20. package/dist/browser/client/vue.js +1 -1
  21. package/dist/browser/client/vue.js.map +1 -1
  22. package/dist/browser/index-m_5zsra2.d.ts +7141 -0
  23. package/dist/browser/index-m_5zsra2.d.ts.map +1 -0
  24. package/dist/browser/index.d.ts +2 -600
  25. package/dist/browser/index.js +2 -2
  26. package/dist/browser/src-Ck4bl2NH.js +1892 -0
  27. package/dist/browser/src-Ck4bl2NH.js.map +1 -0
  28. package/dist/node/index.d.ts +6806 -265
  29. package/dist/node/index.d.ts.map +1 -1
  30. package/dist/node/index.js +5532 -266
  31. package/dist/node/index.js.map +1 -1
  32. package/dist/tsconfig.tsbuildinfo +1 -1
  33. package/package.json +20 -39
  34. package/dist/browser/index.d.ts.map +0 -1
  35. package/dist/browser/src-DNrh9CQq.js +0 -184
  36. package/dist/browser/src-DNrh9CQq.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-Ck4bl2NH.js","names":["atom","computed","onMount","ReadableAtom","Store","AuthMeLike","organizations","Array","organization","id","name","member","organizationId","activeOrganization","DefaultOrganizationEntry","TMe","DefaultOrganizationResolutionStatus","DefaultOrganizationResolution","status","storedOrganizationId","resolvedOrganizationId","entry","DEFAULT_ORGANIZATION_STORAGE_KEY","DEFAULT_ORGANIZATION_CHANGE_EVENT","NO_ORGANIZATIONS_ERROR_MESSAGE","StorageLike","Pick","Storage","WindowLike","Window","DefaultOrganizationMeStore","loading","error","data","DefaultOrganizationPreferenceStore","storageKey","resolution","defaultOrganizationId","defaultOrganization","me","readDefaultOrganizationId","writeDefaultOrganizationId","clearDefaultOrganizationId","syncPreference","setDefaultOrganization","DefaultOrganizationPreferenceState","params","sessionId","Promise","read","write","clear","resolve","sync","setForMe","store","getStorage","storage","window","localStorage","getWindow","win","toNonEmptyString","value","trimmed","trim","length","readCurrentDefaultOrganizationId","s","getItem","getDefaultOrganizationStorageKey","_accountId","getDefaultOrganizationChangeEventName","eventName","setItem","dispatchEvent","Event","removeItem","subscribeToDefaultOrganizationPreference","onChange","options","windowObject","handleChange","handleStorage","e","StorageEvent","key","addEventListener","removeEventListener","findOrganizationEntry","find","toResolution","storedId","resolveDefaultOrganization","Error","stored","active","fallback","syncDefaultOrganizationPreference","setDefaultOrganizationForMe","createDefaultOrganizationPreferenceState","meStore","readMe","getAccountId","storageVersion","refresh","set","get","getCurrentStorageKey","ok","syncForMe","meState","orgId","listen","next","effectiveMe","r","z","defineRoute","defineRoutes","authFragmentDefinition","AnyOAuthProvider","oauthRoutesFactory","create","services","config","method","path","queryParameters","outputSchema","object","url","string","errorCodes","handler","sessionId","userId","email","role","enum","returnTo","nullable","COOKIE_NAME","MAX_AGE","CookieOptions","httpOnly","secure","sameSite","maxAge","path","parseCookies","cookieHeader","Record","cookies","pairs","split","pair","key","valueParts","trimmedKey","trim","value","join","decodeURIComponent","buildSetCookieHeader","options","effectiveSecure","parts","encodeURIComponent","push","buildClearCookieHeader","extractSessionId","headers","Headers","queryParam","bodySessionId","get","sessionIdFromCookie","z","organizationSchema","object","id","string","name","slug","logoUrl","nullable","metadata","record","unknown","createdBy","createdAt","updatedAt","deletedAt","memberSchema","organizationId","userId","roles","array","invitationSchema","email","status","enum","token","inviterId","expiresAt","respondedAt","invitationSummarySchema","omit","OrganizationInvitation","OrganizationMember","OrganizationLike","id","name","slug","logoUrl","metadata","Record","createdBy","createdAt","Date","updatedAt","deletedAt","SerializableOrganization","SerializableMember","organizationId","userId","roles","SerializableInvitation","email","status","token","inviterId","expiresAt","respondedAt","SerializableInvitationSummary","Omit","normalizeMetadata","value","Array","isArray","serializeOrganization","organization","toISOString","serializeMember","member","TRole","serializeInvitation","invitation","serializeInvitationSummary","_token","rest","Cursor","decodeCursor","z","defineRoute","defineRoutes","authFragmentDefinition","extractSessionId","invitationSchema","memberSchema","organizationSchema","serializeInvitation","serializeMember","serializeOrganization","createOrganizationInputSchema","object","name","string","min","max","slug","logoUrl","nullable","optional","metadata","record","unknown","updateOrganizationInputSchema","refine","value","Object","keys","length","message","pageQuerySchema","pageSize","coerce","number","int","default","parseCursor","cursorParam","undefined","organizationRoutesFactory","create","config","services","defineOrganizationRoute","route","Parameters","errorCodes","Array","from","Set","handler","method","path","inputSchema","outputSchema","organization","member","input","headers","query","json","error","sessionId","get","code","body","infer","inputError","valid","err","result","handlerTx","withServiceCalls","createOrganizationWithSession","execute","ok","queryParameters","organizations","array","cursor","hasNextPage","boolean","parsed","safeParse","fromEntries","entries","success","rawCursor","indexName","getOrganizationsForSession","data","map","entry","getActiveOrganizationForSession","organizationId","setActiveOrganizationForSession","invitations","invitation","listInvitationsForSession","action","enum","token","pathParams","respondToInvitationWithSession","invitationId","getOrganizationForSession","updateOrganizationWithSession","patch","deleteOrganizationWithSession","members","listOrganizationMembersWithSession","userId","roles","createOrganizationMemberWithSession","updateOrganizationMemberRolesWithSession","memberId","deleteOrganizationMemberWithSession","listOrganizationInvitationsWithSession","email","createOrganizationInvitationWithSession","column","idColumn","referenceColumn","schema","authSchema","s","addTable","t","addColumn","defaultTo","b","now","createIndex","unique","alterTable","nullable","addReference","from","table","to","type","foreignKey","alterColumn","z","toExternalId","sessionSeedSchema","object","activeOrganizationId","string","trim","min","optional","strict","SessionSeedInput","input","SessionSeed","output","ResolvedSessionSeed","status","requestedActiveOrganizationId","normalizeSessionSeed","session","parsed","safeParse","success","data","parseSessionSeed","value","resolveSessionSeedFromMembers","createdAt","Date","organization","id","deletedAt","members","TMember","normalizedSession","validMembers","filter","member","sort","left","right","getTime","requestedMember","find","repairedMember","parseSessionSeedFromQuery","JSON","parse","serializeSessionSeedForQuery","normalized","stringify","undefined","FragnoId","z","defineRoute","defineRoutes","DatabaseServiceContext","authFragmentDefinition","AuthHooksMap","invitationSummarySchema","memberSchema","organizationSchema","Organization","OrganizationInvitation","OrganizationMember","authSchema","mapUserSummary","buildSetCookieHeader","extractSessionId","CookieOptions","resolveSessionSeedFromMembers","SessionSeedInput","AuthServiceContext","requiredOrganizationServiceNames","const","assertOrganizationServices","services","Record","args","missing","filter","name","length","Error","join","OrganizationRow","id","slug","logoUrl","metadata","createdBy","createdAt","Date","updatedAt","deletedAt","ActiveOrganizationRow","OrganizationMemberRoleRow","role","OrganizationMemberRow","organization","roles","OrganizationInvitationRow","organizationId","email","status","token","inviterId","expiresAt","respondedAt","SessionOwnerRow","Role","SessionMemberRow","sessionOwner","sessionActiveOrganization","sessionMembers","SessionInvitationRow","invitations","SessionExpiryRow","SessionSeedMemberRow","organizationMemberOrganization","createSessionServices","cookieOptions","resolveSessionSeedForUser","this","userId","session","serviceTx","retrieve","uow","find","b","whereIndex","eb","j","ob","select","transformRetrieve","members","map","member","mutate","retrieveResult","build","buildSessionCookie","sessionId","createSession","options","activeOrganizationId","findFirst","user","ok","code","bannedAt","now","plus","days","create","userSummary","triggerHook","valueOf","actor","validateSession","and","expiredSession","delete","check","invalidateSession","String","getSession","headers","Headers","undefined","sessionRoutesFactory","config","method","path","inputSchema","object","string","optional","outputSchema","success","boolean","errorCodes","handler","queryParameters","enum","organizations","array","activeOrganization","nullable","invitation","z","defineRoute","defineRoutes","DatabaseServiceContext","authFragmentDefinition","AuthHooksMap","BeforeCreateUserHook","authSchema","sessionSeedSchema","createAutoOrganization","AutoCreateOrganizationOptions","mapUserSummary","AuthServiceContext","SessionSeedMemberRow","createdAt","Date","organizationMemberOrganization","id","deletedAt","createUserServices","options","beforeCreateUser","runBeforeCreateUser","email","role","createUserUnvalidated","this","passwordHash","autoCreateOptions","serviceTx","mutate","uow","now","create","userSummary","valueOf","bannedAt","autoOrganization","userId","triggerHook","user","actor","organization","member","build","getUserByEmail","retrieve","findFirst","b","whereIndex","eb","transformRetrieve","updateUserRole","retrieveResult","update","set","success","updateUserPassword","signUpWithSession","expiresAt","setDate","getDate","existingUser","ok","const","code","sessionId","activeOrganizationId","session","updateUserRoleWithSession","join","j","sessionOwner","select","delete","check","actorSummary","changePasswordWithSession","userActionsRoutesFactory","services","config","method","path","inputSchema","object","enum","outputSchema","boolean","errorCodes","handler","password","string","min","max","optional","newPassword","Cursor","z","defineRoute","defineRoutes","DatabaseServiceContext","authFragmentDefinition","authSchema","SortField","SortOrder","GetUsersParams","search","sortBy","sortOrder","pageSize","cursor","UserResult","id","email","role","createdAt","Date","AuthServiceContext","createUserOverviewServices","mapUser","user","String","getUsersWithCursor","this","params","effectiveSortBy","indexName","effectiveSortOrder","orderDirection","effectivePageSize","serviceTx","retrieve","uow","findWithCursor","b","query","whereIndex","eb","orderByIndex","after","transformRetrieve","result","users","items","map","hasNextPage","build","sortBySchema","enum","userOverviewRoutesFactory","create","services","method","path","queryParameters","outputSchema","object","array","string","optional","boolean","errorCodes","handler","bytesToBase64Url","randomBytes","AnyOAuthProvider","AuthOAuthConfig","OAuth2Tokens","DEFAULT_STATE_TTL_MS","createOAuthState","bytes","createAuthorizationURL","params","authorizationEndpoint","clientId","redirectURI","state","scopes","prompt","loginHint","codeChallenge","codeChallengeMethod","extraParams","Record","URL","url","searchParams","set","length","join","key","value","Object","entries","parseScopes","scopeValue","undefined","split","map","scope","trim","filter","Boolean","readNumber","Number","isFinite","parsed","normalizeOAuthTokens","response","accessToken","refreshToken","tokenType","idToken","expiresIn","accessTokenExpiresAt","Date","now","raw","parseOAuthTokenResponse","Response","Promise","ok","data","status","error","contentType","headers","get","includes","json","text","fromEntries","URLSearchParams","err","Error","message","error_description","normalizeOAuthProvider","provider","providerOptions","options","disableSignUp","disableImplicitSignUp","normalizeOAuthConfig","config","providers","changed","normalizedProviders","normalized","OAuthProvider","ProviderOptions","OAuth2Tokens","createAuthorizationURL","normalizeOAuthTokens","parseOAuthTokenResponse","GithubOAuthClient","GithubProfile","login","id","node_id","avatar_url","gravatar_id","url","html_url","followers_url","following_url","gists_url","starred_url","subscriptions_url","organizations_url","repos_url","events_url","received_events_url","type","site_admin","name","company","blog","location","email","hireable","bio","twitter_username","public_repos","public_gists","followers","following","created_at","updated_at","private_gists","total_private_repos","owned_private_repos","disk_usage","collaborators","two_factor_authentication","plan","space","private_repos","GithubEmail","primary","verified","visibility","GithubOptions","clientId","clientSecret","client","defaultScopes","defaultUserAgent","tokenEndpoint","profileEndpoint","emailsEndpoint","createGithubOAuthClient","options","fetcher","fetch","userAgent","exchangeCode","code","redirectURI","codeVerifier","body","URLSearchParams","client_id","client_secret","redirect_uri","set","response","method","headers","accept","parsed","ok","data","fetchProfile","accessToken","authorization","json","fetchEmails","github","authorizationEndpoint","state","scopes","loginHint","resolvedScopes","disableDefaultScope","scope","push","prompt","undefined","extraParams","validateAuthorizationCode","refreshAccessToken","getUserInfo","token","profile","emails","length","find","entry","emailVerified","mapped","mapProfileToUser","user","image","createClientBuilder","FragnoPublicClientConfig","defineFragment","clearDefaultOrganizationId","createDefaultOrganizationPreferenceState","DEFAULT_ORGANIZATION_CHANGE_EVENT","DEFAULT_ORGANIZATION_STORAGE_KEY","findOrganizationEntry","getDefaultOrganizationChangeEventName","getDefaultOrganizationStorageKey","NO_ORGANIZATIONS_ERROR_MESSAGE","readDefaultOrganizationId","resolveDefaultOrganization","setDefaultOrganizationForMe","subscribeToDefaultOrganizationPreference","syncDefaultOrganizationPreference","writeDefaultOrganizationId","AuthMeLike","AuthDefaultOrganizationMeLike","DefaultOrganizationEntry","AuthDefaultOrganizationEntry","DefaultOrganizationResolution","AuthDefaultOrganizationResolution","DefaultOrganizationResolutionStatus","AuthHooks","BeforeCreateUserHook","oauthRoutesFactory","AuthOAuthConfig","organizationRoutesFactory","DefaultOrganizationRole","sessionRoutesFactory","serializeSessionSeedForQuery","Role","userActionsRoutesFactory","userOverviewRoutesFactory","GetUsersParams","UserResult","SortField","SortOrder","CookieOptions","AuthConfig","cookieOptions","hooks","beforeCreateUser","organizations","OrganizationConfig","TRole","emailAndPassword","enabled","oauth","authFragmentDefinition","extend","x","providesBaseService","build","AuthFragment","createAuthFragment","config","fragnoConfig","FragnoPublicConfigWithDatabase","createAuthFragmentClients","b","type","options","credentials","useMe","createHook","useSignUp","createMutator","useSignIn","useSignOut","invalidate","useUsers","useUpdateUserRole","useChangePassword","useOrganizations","useOrganization","useCreateOrganization","useUpdateOrganization","params","organizationId","pathParams","useDeleteOrganization","useActiveOrganization","useSetActiveOrganization","useOrganizationMembers","useAddOrganizationMember","useUpdateOrganizationMemberRoles","useRemoveOrganizationMember","useOrganizationInvitations","useInviteOrganizationMember","useRespondOrganizationInvitation","useUserInvitations","useOAuthAuthorize","useOAuthCallback","readRawMe","sessionId","query","defaultOrganizationPreference","meStore","store","readMe","getAccountId","me","user","id","useDefaultOrganizationPreference","createStore","signIn","email","password","session","rememberMe","_rememberMe","activeOrganizationId","mutateQuery","body","signUp","signOut","defaultOrganization","getAuthorizationUrl","provider","returnTo","link","redirectUri","scope","loginHint","path","undefined","callback","code","state","requestSignUp","FragnoRouteConfig","AuthMeData","Awaited","ReturnType","BeforeCreateUserPayload","InvitationExpiredHookPayload","SessionHookPayload","UserHookPayload","SessionSummary","UserSummary","AnyOAuthProvider","OAuthProvider","OAuth2Tokens","OAuth2UserInfo","GithubOAuthClient","GithubEmail","GithubProfile","createGithubOAuthClient","github","AuthMeResponse","AutoCreateOrganizationConfig","Organization","OrganizationHookPayload","OrganizationHooks","OrganizationInvitation","OrganizationInvitationSummary","OrganizationInvitationHookPayload","OrganizationInvitationStatus","OrganizationMember","OrganizationMemberSummary","OrganizationMemberHookPayload","OrganizationRoleName","TMe","DefaultOrganizationPreferenceStore"],"sources":["../../src/client/default-organization.ts","../../src/oauth/routes.ts","../../src/utils/cookie.ts","../../src/organization/schemas.ts","../../src/organization/serializers.ts","../../src/organization/routes.ts","../../src/schema.ts","../../src/session/session-seed.ts","../../src/session/session.ts","../../src/user/user-actions.ts","../../src/user/user-overview.ts","../../src/oauth/utils.ts","../../src/oauth/providers/github/github.ts","../../src/index.ts"],"sourcesContent":["import { atom, computed, onMount, type ReadableAtom, type Store } from \"nanostores\";\n\nexport interface AuthMeLike {\n organizations: Array<{\n organization: {\n id: string;\n name: string;\n };\n member: {\n organizationId: string;\n };\n }>;\n activeOrganization: {\n organization: {\n id: string;\n name: string;\n };\n member: {\n organizationId: string;\n };\n } | null;\n}\n\nexport type DefaultOrganizationEntry<TMe extends AuthMeLike> = TMe[\"organizations\"][number];\nexport type DefaultOrganizationResolutionStatus = \"reused\" | \"initialized\" | \"repaired\";\nexport type DefaultOrganizationResolution<TMe extends AuthMeLike> = {\n status: DefaultOrganizationResolutionStatus;\n storedOrganizationId: string | null;\n resolvedOrganizationId: string;\n entry: DefaultOrganizationEntry<TMe>;\n organization: DefaultOrganizationEntry<TMe>[\"organization\"];\n member: DefaultOrganizationEntry<TMe>[\"member\"];\n};\n\nexport const DEFAULT_ORGANIZATION_STORAGE_KEY = \"fragno-auth.default-organization-id\";\nexport const DEFAULT_ORGANIZATION_CHANGE_EVENT = \"fragno-auth:default-organization-change\";\nexport const NO_ORGANIZATIONS_ERROR_MESSAGE =\n \"Authenticated users must always have at least one organization.\";\n\ntype StorageLike = Pick<Storage, \"getItem\" | \"setItem\" | \"removeItem\">;\ntype WindowLike = Pick<Window, \"addEventListener\" | \"removeEventListener\" | \"dispatchEvent\">;\n\nexport type DefaultOrganizationMeStore<TMe extends AuthMeLike> = Store<{\n loading: boolean;\n error?: unknown;\n data?: TMe;\n}>;\n\nexport type DefaultOrganizationPreferenceStore<TMe extends AuthMeLike> = {\n storageKey: string | null;\n storedOrganizationId: ReadableAtom<string | null>;\n resolution: ReadableAtom<DefaultOrganizationResolution<TMe> | null>;\n status: ReadableAtom<DefaultOrganizationResolutionStatus | null>;\n defaultOrganizationId: ReadableAtom<string | null>;\n defaultOrganization: ReadableAtom<DefaultOrganizationEntry<TMe> | null>;\n me: ReadableAtom<TMe | null>;\n loading: ReadableAtom<boolean>;\n error: ReadableAtom<unknown>;\n readDefaultOrganizationId: () => string | null;\n writeDefaultOrganizationId: (organizationId: string) => boolean;\n clearDefaultOrganizationId: () => boolean;\n syncPreference: () => DefaultOrganizationResolution<TMe> | null;\n setDefaultOrganization: (organizationId: string) => DefaultOrganizationResolution<TMe>;\n};\n\nexport type DefaultOrganizationPreferenceState<TMe extends AuthMeLike> = {\n me: (params?: { sessionId?: string }) => Promise<TMe>;\n defaultOrganization: {\n storageKey: string | null;\n read: () => string | null;\n write: (organizationId: string) => boolean;\n clear: () => boolean;\n resolve: (me: TMe, storedOrganizationId: string | null) => DefaultOrganizationResolution<TMe>;\n sync: (me: TMe) => DefaultOrganizationResolution<TMe>;\n setForMe: (me: TMe, organizationId: string) => DefaultOrganizationResolution<TMe>;\n };\n store: DefaultOrganizationPreferenceStore<TMe>;\n};\n\nfunction getStorage(storage?: StorageLike | null): StorageLike | null {\n if (storage != null) {\n return storage;\n }\n if (typeof window === \"undefined\") {\n return null;\n }\n\n try {\n return window.localStorage;\n } catch {\n return null;\n }\n}\n\nfunction getWindow(win?: WindowLike | null): WindowLike | null {\n if (win != null) {\n return win;\n }\n return typeof window !== \"undefined\" ? window : null;\n}\n\nfunction toNonEmptyString(value: string | null | undefined): string | null {\n const trimmed = value?.trim();\n return trimmed && trimmed.length > 0 ? trimmed : null;\n}\n\nfunction readCurrentDefaultOrganizationId(storage?: StorageLike | null): string | null {\n const s = getStorage(storage);\n if (!s) {\n return null;\n }\n\n return toNonEmptyString(s.getItem(getDefaultOrganizationStorageKey()));\n}\n\nexport function getDefaultOrganizationStorageKey(_accountId?: string): string {\n return DEFAULT_ORGANIZATION_STORAGE_KEY;\n}\n\nexport function getDefaultOrganizationChangeEventName(_accountId?: string): string {\n return DEFAULT_ORGANIZATION_CHANGE_EVENT;\n}\n\nexport function readDefaultOrganizationId(\n _accountId?: string | null,\n storage?: StorageLike | null,\n): string | null {\n const s = getStorage(storage);\n if (!s) {\n return null;\n }\n\n try {\n return readCurrentDefaultOrganizationId(s);\n } catch {\n return null;\n }\n}\n\nexport function writeDefaultOrganizationId(\n _accountId: string | null | undefined,\n organizationId: string,\n storage?: StorageLike | null,\n win?: WindowLike | null,\n): boolean {\n const trimmed = toNonEmptyString(organizationId);\n if (!trimmed) {\n return clearDefaultOrganizationId(_accountId, storage, win);\n }\n\n const s = getStorage(storage);\n const storageKey = getDefaultOrganizationStorageKey();\n const eventName = getDefaultOrganizationChangeEventName();\n if (!s) {\n return false;\n }\n if (readCurrentDefaultOrganizationId(s) === trimmed) {\n return false;\n }\n\n try {\n s.setItem(storageKey, trimmed);\n } catch {\n return false;\n }\n\n getWindow(win)?.dispatchEvent(new Event(eventName));\n return true;\n}\n\nexport function clearDefaultOrganizationId(\n _accountId?: string | null,\n storage?: StorageLike | null,\n win?: WindowLike | null,\n): boolean {\n const s = getStorage(storage);\n const storageKey = getDefaultOrganizationStorageKey();\n const eventName = getDefaultOrganizationChangeEventName();\n if (!s) {\n return false;\n }\n\n if (!readCurrentDefaultOrganizationId(s)) {\n return false;\n }\n\n try {\n s.removeItem(storageKey);\n } catch {\n return false;\n }\n\n getWindow(win)?.dispatchEvent(new Event(eventName));\n return true;\n}\n\nexport function subscribeToDefaultOrganizationPreference(\n _accountId: string | null | undefined,\n onChange: () => void,\n options?: { windowObject?: WindowLike | null },\n): () => void {\n const win = getWindow(options?.windowObject);\n const storageKey = getDefaultOrganizationStorageKey();\n const eventName = getDefaultOrganizationChangeEventName();\n if (!win) {\n return () => {};\n }\n\n const handleChange = () => onChange();\n const handleStorage = (e: Event) => {\n if (typeof StorageEvent === \"undefined\") {\n return onChange();\n }\n if (e instanceof StorageEvent && (!e.key || e.key === storageKey)) {\n onChange();\n }\n };\n\n win.addEventListener(eventName, handleChange);\n win.addEventListener(\"storage\", handleStorage);\n return () => {\n win.removeEventListener(eventName, handleChange);\n win.removeEventListener(\"storage\", handleStorage);\n };\n}\n\nexport function findOrganizationEntry<TMe extends AuthMeLike>(\n me: TMe,\n organizationId: string | null | undefined,\n): DefaultOrganizationEntry<TMe> | null {\n const id = toNonEmptyString(organizationId);\n if (!id) {\n return null;\n }\n return me.organizations.find((e) => e.organization.id === id) ?? null;\n}\n\nfunction toResolution<TMe extends AuthMeLike>(\n entry: DefaultOrganizationEntry<TMe>,\n status: DefaultOrganizationResolutionStatus,\n storedId: string | null,\n): DefaultOrganizationResolution<TMe> {\n return {\n status,\n storedOrganizationId: storedId,\n resolvedOrganizationId: entry.organization.id,\n entry,\n organization: entry.organization,\n member: entry.member,\n };\n}\n\nexport function resolveDefaultOrganization<TMe extends AuthMeLike>(\n me: TMe,\n storedOrganizationId: string | null,\n): DefaultOrganizationResolution<TMe> {\n if (me.organizations.length === 0) {\n throw new Error(NO_ORGANIZATIONS_ERROR_MESSAGE);\n }\n\n const stored = findOrganizationEntry(me, storedOrganizationId);\n if (stored) {\n return toResolution(stored, \"reused\", storedOrganizationId);\n }\n\n const active = findOrganizationEntry(me, me.activeOrganization?.organization.id ?? null);\n const fallback = active ?? me.organizations[0];\n return toResolution(\n fallback,\n storedOrganizationId ? \"repaired\" : \"initialized\",\n storedOrganizationId,\n );\n}\n\nexport function syncDefaultOrganizationPreference<TMe extends AuthMeLike>(\n _accountId: string | null | undefined,\n me: TMe,\n storage?: StorageLike | null,\n win?: WindowLike | null,\n): DefaultOrganizationResolution<TMe> {\n const resolution = resolveDefaultOrganization(me, readDefaultOrganizationId(_accountId, storage));\n if (resolution.status !== \"reused\") {\n writeDefaultOrganizationId(_accountId, resolution.resolvedOrganizationId, storage, win);\n }\n return resolution;\n}\n\nexport function setDefaultOrganizationForMe<TMe extends AuthMeLike>(\n _accountId: string | null | undefined,\n me: TMe,\n organizationId: string,\n storage?: StorageLike | null,\n win?: WindowLike | null,\n): DefaultOrganizationResolution<TMe> {\n const entry = findOrganizationEntry(me, organizationId);\n if (!entry) {\n throw new Error(\"The selected organization is no longer available for this account.\");\n }\n writeDefaultOrganizationId(_accountId, entry.organization.id, storage, win);\n return resolveDefaultOrganization(me, entry.organization.id);\n}\n\nexport function createDefaultOrganizationPreferenceState<TMe extends AuthMeLike>(options: {\n meStore: DefaultOrganizationMeStore<TMe>;\n readMe: (params?: { sessionId?: string }) => Promise<TMe>;\n getAccountId?: (me: TMe) => string | null | undefined;\n storage?: StorageLike | null;\n windowObject?: WindowLike | null;\n}): DefaultOrganizationPreferenceState<TMe> {\n const { meStore, readMe, storage, windowObject } = options;\n const storageVersion = atom(0);\n\n const refresh = () => storageVersion.set(storageVersion.get() + 1);\n const getCurrentStorageKey = () => getDefaultOrganizationStorageKey();\n const storedOrganizationId = computed(storageVersion, () =>\n readDefaultOrganizationId(null, storage),\n );\n\n const write = (id: string) => {\n const ok = writeDefaultOrganizationId(null, id, storage, windowObject);\n if (ok) {\n refresh();\n }\n return ok;\n };\n\n const clear = () => {\n const ok = clearDefaultOrganizationId(null, storage, windowObject);\n if (ok) {\n refresh();\n }\n return ok;\n };\n\n const syncForMe = (me: TMe) => {\n const resolution = syncDefaultOrganizationPreference(null, me, storage, windowObject);\n refresh();\n return resolution;\n };\n\n const setForMe = (me: TMe, id: string) => {\n const entry = findOrganizationEntry(me, id);\n if (!entry) {\n throw new Error(\"The selected organization is no longer available for this account.\");\n }\n const resolution = setDefaultOrganizationForMe(null, me, id, storage, windowObject);\n refresh();\n return resolution;\n };\n\n onMount(storedOrganizationId, () =>\n subscribeToDefaultOrganizationPreference(null, refresh, { windowObject }),\n );\n\n const resolution = computed([meStore, storedOrganizationId], (meState, orgId) => {\n if (!meState.data) {\n return null;\n }\n return resolveDefaultOrganization(meState.data, orgId);\n });\n\n onMount(resolution, () =>\n resolution.listen((next) => {\n if (!next || next.status === \"reused\") {\n return;\n }\n if (writeDefaultOrganizationId(null, next.resolvedOrganizationId, storage, windowObject)) {\n refresh();\n }\n }),\n );\n\n const effectiveMe = computed([meStore, resolution], (meState) => meState.data ?? null);\n\n return {\n me: async (params) => {\n const me = await readMe(params);\n if (getWindow(windowObject)) {\n syncForMe(me);\n }\n return me;\n },\n defaultOrganization: {\n get storageKey() {\n return getCurrentStorageKey();\n },\n read: () => readDefaultOrganizationId(null, storage),\n write,\n clear,\n resolve: resolveDefaultOrganization,\n sync: syncForMe,\n setForMe,\n },\n store: {\n get storageKey() {\n return getCurrentStorageKey();\n },\n storedOrganizationId,\n resolution,\n status: computed(resolution, (r) => r?.status ?? null),\n defaultOrganizationId: computed(resolution, (r) => r?.resolvedOrganizationId ?? null),\n defaultOrganization: computed(resolution, (r) => r?.entry ?? null),\n me: effectiveMe,\n loading: computed(meStore, (s) => s.loading),\n error: computed(meStore, (s) => s.error),\n readDefaultOrganizationId: () => readDefaultOrganizationId(null, storage),\n writeDefaultOrganizationId: write,\n clearDefaultOrganizationId: clear,\n syncPreference: () => {\n const me = effectiveMe.get();\n return me ? syncForMe(me) : null;\n },\n setDefaultOrganization: (id) => {\n const me = effectiveMe.get();\n if (!me) {\n throw new Error(\"Cannot set a default organization without an authenticated user.\");\n }\n return setForMe(me, id);\n },\n },\n };\n}\n","import { z } from \"zod\";\n\nimport { defineRoute, defineRoutes } from \"@fragno-dev/core\";\n\nimport type { authFragmentDefinition } from \"..\";\nimport { parseSessionSeedFromQuery } from \"../session/session-seed\";\nimport { buildSetCookieHeader, extractSessionId } from \"../utils/cookie\";\nimport type { AnyOAuthProvider } from \"./types\";\nimport { normalizeOAuthConfig } from \"./utils\";\n\nconst parseScopes = (value: string | null): string[] | undefined => {\n if (!value) {\n return undefined;\n }\n const scopes = value\n .split(/[,\\s]+/)\n .map((scope) => scope.trim())\n .filter(Boolean);\n return scopes.length > 0 ? scopes : undefined;\n};\n\nconst resolveRedirectUri = (\n provider: AnyOAuthProvider | undefined,\n fallback?: string,\n): string | null => {\n const providerRedirect = provider?.options?.redirectURI;\n if (typeof providerRedirect === \"string\" && providerRedirect.length > 0) {\n return providerRedirect;\n }\n if (typeof fallback === \"string\" && fallback.length > 0) {\n return fallback;\n }\n return null;\n};\n\nexport const oauthRoutesFactory = defineRoutes<typeof authFragmentDefinition>().create(\n ({ services, config }) => {\n const oauthConfig = normalizeOAuthConfig(config.oauth);\n\n return [\n defineRoute({\n method: \"GET\",\n path: \"/oauth/:provider/authorize\",\n queryParameters: [\n \"redirectUri\",\n \"returnTo\",\n \"link\",\n \"sessionId\",\n \"scope\",\n \"loginHint\",\n \"session\",\n ],\n outputSchema: z.object({\n url: z.string(),\n }),\n errorCodes: [\n \"oauth_disabled\",\n \"provider_not_found\",\n \"missing_redirect_uri\",\n \"redirect_uri_mismatch\",\n \"invalid_input\",\n \"session_invalid\",\n ],\n handler: async function ({ query, headers, pathParams }, { json, error }) {\n if (!oauthConfig) {\n return error({ message: \"OAuth is not configured\", code: \"oauth_disabled\" }, 400);\n }\n\n const providerId = pathParams.provider;\n const provider = oauthConfig.providers[providerId];\n if (!provider) {\n return error({ message: \"Unknown provider\", code: \"provider_not_found\" }, 404);\n }\n\n const redirectUri = resolveRedirectUri(provider, oauthConfig.defaultRedirectUri);\n if (!redirectUri) {\n return error({ message: \"Missing redirect URI\", code: \"missing_redirect_uri\" }, 400);\n }\n\n const requestedRedirect = query.get(\"redirectUri\");\n if (requestedRedirect && requestedRedirect !== redirectUri) {\n return error({ message: \"Redirect URI mismatch\", code: \"redirect_uri_mismatch\" }, 400);\n }\n\n const link = query.get(\"link\") === \"true\";\n const sessionId = link ? extractSessionId(headers, query.get(\"sessionId\")) : null;\n const sessionSeed = parseSessionSeedFromQuery(query.get(\"session\"));\n if (sessionSeed === \"invalid\") {\n return error({ message: \"Invalid session seed\", code: \"invalid_input\" }, 400);\n }\n\n const [stateResult] = await this.handlerTx()\n .withServiceCalls(() => [\n services.createOAuthState({\n providerId,\n redirectUri,\n returnTo: query.get(\"returnTo\"),\n sessionId,\n link,\n session: sessionSeed,\n }),\n ])\n .execute();\n\n if (!stateResult.ok) {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n const scopes = parseScopes(query.get(\"scope\"));\n const loginHint = query.get(\"loginHint\") ?? undefined;\n const url = await provider.createAuthorizationURL({\n state: stateResult.state,\n redirectURI: redirectUri,\n scopes,\n loginHint,\n });\n\n return json({ url: url.toString() });\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/oauth/:provider/callback\",\n queryParameters: [\"code\", \"state\", \"requestSignUp\"],\n outputSchema: z.object({\n sessionId: z.string(),\n userId: z.string(),\n email: z.string(),\n role: z.enum([\"user\", \"admin\"]),\n returnTo: z.string().nullable(),\n }),\n errorCodes: [\n \"oauth_disabled\",\n \"provider_not_found\",\n \"missing_redirect_uri\",\n \"invalid_code\",\n \"invalid_state\",\n \"email_required\",\n \"signup_disabled\",\n \"signup_required\",\n \"user_banned\",\n ],\n handler: async function ({ query, pathParams }, { json, error }) {\n if (!oauthConfig) {\n return error({ message: \"OAuth is not configured\", code: \"oauth_disabled\" }, 400);\n }\n\n const providerId = pathParams.provider;\n const provider = oauthConfig.providers[providerId];\n if (!provider) {\n return error({ message: \"Unknown provider\", code: \"provider_not_found\" }, 404);\n }\n\n const code = query.get(\"code\");\n const state = query.get(\"state\");\n if (!code) {\n return error({ message: \"Missing code\", code: \"invalid_code\" }, 400);\n }\n if (!state) {\n return error({ message: \"Missing state\", code: \"invalid_state\" }, 400);\n }\n\n const redirectUri = resolveRedirectUri(provider, oauthConfig.defaultRedirectUri);\n if (!redirectUri) {\n return error({ message: \"Missing redirect URI\", code: \"missing_redirect_uri\" }, 400);\n }\n\n const tokens = await provider.validateAuthorizationCode({\n code,\n redirectURI: redirectUri,\n });\n if (!tokens) {\n return error({ message: \"Invalid code\", code: \"invalid_code\" }, 401);\n }\n\n const userInfo = await provider.getUserInfo(tokens);\n if (!userInfo) {\n return error({ message: \"Unable to load profile\", code: \"invalid_code\" }, 401);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.handleOAuthCallback({\n providerId,\n state,\n tokens,\n userInfo: userInfo.user,\n rawProfile: userInfo.data as Record<string, unknown>,\n provider,\n requestSignUp: query.get(\"requestSignUp\") === \"true\",\n }),\n ])\n .execute();\n\n if (!result.ok) {\n const status =\n result.code === \"invalid_state\"\n ? 400\n : result.code === \"email_required\"\n ? 400\n : result.code === \"signup_disabled\"\n ? 403\n : result.code === \"signup_required\"\n ? 403\n : result.code === \"user_banned\"\n ? 403\n : 400;\n return error({ message: \"OAuth failed\", code: result.code }, status);\n }\n\n const setCookieHeader = buildSetCookieHeader(result.sessionId, config.cookieOptions);\n\n if (result.returnTo) {\n return new Response(null, {\n status: 302,\n headers: {\n \"Set-Cookie\": setCookieHeader,\n Location: result.returnTo,\n },\n });\n }\n\n return json(\n {\n sessionId: result.sessionId,\n userId: result.userId,\n email: result.email,\n role: result.role,\n returnTo: result.returnTo,\n },\n {\n headers: {\n \"Set-Cookie\": setCookieHeader,\n },\n },\n );\n },\n }),\n ];\n },\n);\n","/**\n * Cookie utilities for session management\n */\n\nexport const COOKIE_NAME = \"sessionid\";\nconst MAX_AGE = 2592000; // 30 days in seconds\n\nexport interface CookieOptions {\n httpOnly?: boolean;\n secure?: boolean;\n sameSite?: \"Strict\" | \"Lax\" | \"None\";\n maxAge?: number;\n path?: string;\n}\n\n/**\n * Parse cookies from a Cookie header string\n */\nexport function parseCookies(cookieHeader: string | null): Record<string, string> {\n if (!cookieHeader) {\n return {};\n }\n\n const cookies: Record<string, string> = {};\n const pairs = cookieHeader.split(\";\");\n\n for (const pair of pairs) {\n const [key, ...valueParts] = pair.split(\"=\");\n const trimmedKey = key?.trim();\n const value = valueParts.join(\"=\").trim();\n\n if (trimmedKey) {\n cookies[trimmedKey] = decodeURIComponent(value);\n }\n }\n\n return cookies;\n}\n\n/**\n * Build a Set-Cookie header string with security attributes\n */\nexport function buildSetCookieHeader(value: string, options: CookieOptions = {}): string {\n const {\n httpOnly = true,\n secure = true,\n sameSite = \"Strict\",\n maxAge = MAX_AGE,\n path = \"/\",\n } = options;\n const effectiveSecure = sameSite === \"None\" ? true : secure;\n\n const parts = [\n `${COOKIE_NAME}=${encodeURIComponent(value)}`,\n `Max-Age=${maxAge}`,\n `Path=${path}`,\n ];\n\n if (httpOnly) {\n parts.push(\"HttpOnly\");\n }\n\n if (effectiveSecure) {\n parts.push(\"Secure\");\n }\n\n if (sameSite) {\n parts.push(`SameSite=${sameSite}`);\n }\n\n return parts.join(\"; \");\n}\n\n/**\n * Build a Set-Cookie header to clear the session cookie\n */\nexport function buildClearCookieHeader(options: CookieOptions = {}): string {\n return buildSetCookieHeader(\"\", { ...options, maxAge: 0 });\n}\n\n/**\n * Extract session ID from headers, checking cookies first, then query/body\n */\nexport function extractSessionId(\n headers: Headers,\n queryParam?: string | null,\n bodySessionId?: string,\n): string | null {\n // First, try to get from cookies\n const cookieHeader = headers.get(\"Cookie\");\n const cookies = parseCookies(cookieHeader);\n const sessionIdFromCookie = cookies[COOKIE_NAME];\n\n if (sessionIdFromCookie) {\n return sessionIdFromCookie;\n }\n\n // Fall back to query parameter\n if (queryParam) {\n return queryParam;\n }\n\n // Fall back to body\n if (bodySessionId) {\n return bodySessionId;\n }\n\n return null;\n}\n","import { z } from \"zod\";\n\nexport const organizationSchema = z.object({\n id: z.string(),\n name: z.string(),\n slug: z.string(),\n logoUrl: z.string().nullable(),\n metadata: z.record(z.string(), z.unknown()).nullable(),\n createdBy: z.string(),\n createdAt: z.string(),\n updatedAt: z.string(),\n deletedAt: z.string().nullable(),\n});\n\nexport const memberSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n userId: z.string(),\n roles: z.array(z.string()),\n createdAt: z.string(),\n updatedAt: z.string(),\n});\n\nexport const invitationSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n email: z.string(),\n roles: z.array(z.string()),\n status: z.enum([\"pending\", \"accepted\", \"rejected\", \"canceled\", \"expired\"]),\n token: z.string(),\n inviterId: z.string(),\n expiresAt: z.string(),\n createdAt: z.string(),\n respondedAt: z.string().nullable(),\n});\n\nexport const invitationSummarySchema = invitationSchema.omit({ token: true });\n","import type { OrganizationInvitation, OrganizationMember } from \"./types\";\n\ntype OrganizationLike = {\n id: string;\n name: string;\n slug: string;\n logoUrl?: string | null;\n metadata?: Record<string, unknown> | null | unknown;\n createdBy: string;\n createdAt: Date;\n updatedAt: Date;\n deletedAt?: Date | null;\n};\n\ntype SerializableOrganization = {\n id: string;\n name: string;\n slug: string;\n logoUrl: string | null;\n metadata: Record<string, unknown> | null;\n createdBy: string;\n createdAt: string;\n updatedAt: string;\n deletedAt: string | null;\n};\n\ntype SerializableMember = {\n id: string;\n organizationId: string;\n userId: string;\n roles: string[];\n createdAt: string;\n updatedAt: string;\n};\n\ntype SerializableInvitation = {\n id: string;\n organizationId: string;\n email: string;\n roles: string[];\n status: OrganizationInvitation<string>[\"status\"];\n token: string;\n inviterId: string;\n expiresAt: string;\n createdAt: string;\n respondedAt: string | null;\n};\n\ntype SerializableInvitationSummary = Omit<SerializableInvitation, \"token\">;\n\nconst normalizeMetadata = (value: unknown): Record<string, unknown> | null => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return null;\n }\n return value as Record<string, unknown>;\n};\n\nexport function serializeOrganization(organization: OrganizationLike): SerializableOrganization {\n return {\n id: organization.id,\n name: organization.name,\n slug: organization.slug,\n logoUrl: organization.logoUrl ?? null,\n metadata: normalizeMetadata(organization.metadata),\n createdBy: organization.createdBy,\n createdAt: organization.createdAt.toISOString(),\n updatedAt: organization.updatedAt.toISOString(),\n deletedAt: organization.deletedAt ? organization.deletedAt.toISOString() : null,\n };\n}\n\nexport function serializeMember<TRole extends string>(\n member: OrganizationMember<TRole>,\n): SerializableMember {\n return {\n id: member.id,\n organizationId: member.organizationId,\n userId: member.userId,\n roles: member.roles as string[],\n createdAt: member.createdAt.toISOString(),\n updatedAt: member.updatedAt.toISOString(),\n };\n}\n\nexport function serializeInvitation<TRole extends string>(\n invitation: OrganizationInvitation<TRole>,\n): SerializableInvitation {\n return {\n id: invitation.id,\n organizationId: invitation.organizationId,\n email: invitation.email,\n roles: invitation.roles as string[],\n status: invitation.status,\n token: invitation.token,\n inviterId: invitation.inviterId,\n expiresAt: invitation.expiresAt.toISOString(),\n createdAt: invitation.createdAt.toISOString(),\n respondedAt: invitation.respondedAt ? invitation.respondedAt.toISOString() : null,\n };\n}\n\nexport function serializeInvitationSummary<TRole extends string>(\n invitation: OrganizationInvitation<TRole>,\n): SerializableInvitationSummary {\n const { token: _token, ...rest } = serializeInvitation(invitation);\n return rest;\n}\n","import { type Cursor, decodeCursor } from \"@fragno-dev/db/cursor\";\nimport { z } from \"zod\";\n\nimport { defineRoute, defineRoutes } from \"@fragno-dev/core\";\n\nimport type { authFragmentDefinition } from \"..\";\nimport { extractSessionId } from \"../utils/cookie\";\nimport { invitationSchema, memberSchema, organizationSchema } from \"./schemas\";\nimport { serializeInvitation, serializeMember, serializeOrganization } from \"./serializers\";\n\nconst createOrganizationInputSchema = z.object({\n name: z.string().min(1).max(120),\n slug: z.string().min(1),\n logoUrl: z.string().nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n});\n\nconst updateOrganizationInputSchema = z\n .object({\n name: z.string().min(1).max(120).optional(),\n slug: z.string().min(1).optional(),\n logoUrl: z.string().nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n })\n .refine((value) => Object.keys(value).length > 0, {\n message: \"At least one field must be provided\",\n });\n\nconst pageQuerySchema = z.object({\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n});\n\nconst parseCursor = (cursorParam: string | null): Cursor | undefined => {\n if (!cursorParam) {\n return undefined;\n }\n try {\n return decodeCursor(cursorParam);\n } catch {\n return undefined;\n }\n};\n\nexport const organizationRoutesFactory = defineRoutes<typeof authFragmentDefinition>().create(\n ({ config, services }) => {\n const organizationsEnabled = config.organizations !== false;\n const defineOrganizationRoute = ((route: Parameters<typeof defineRoute>[0]) =>\n defineRoute({\n ...route,\n errorCodes: route.errorCodes\n ? Array.from(new Set([...route.errorCodes, \"feature_disabled\"]))\n : [\"feature_disabled\"],\n handler: async function (input, helpers) {\n if (!organizationsEnabled) {\n return helpers.error(\n { message: \"Organizations are disabled\", code: \"feature_disabled\" },\n 403,\n );\n }\n return (route.handler as typeof route.handler).call(this, input, helpers);\n },\n })) as typeof defineRoute;\n\n return [\n defineOrganizationRoute({\n method: \"POST\",\n path: \"/organizations\",\n inputSchema: createOrganizationInputSchema,\n outputSchema: z.object({\n organization: organizationSchema,\n member: memberSchema,\n }),\n errorCodes: [\n \"invalid_input\",\n \"organization_slug_taken\",\n \"permission_denied\",\n \"limit_reached\",\n \"session_invalid\",\n ],\n handler: async function ({ input, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n let body: z.infer<typeof createOrganizationInputSchema> | null = null;\n let inputError: unknown = null;\n try {\n body = await input.valid();\n } catch (err) {\n inputError = err;\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.createOrganizationWithSession({\n sessionId,\n input: body,\n inputError,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"input_invalid\") {\n if (inputError) {\n throw inputError;\n }\n return error({ message: \"Invalid input\", code: \"invalid_input\" }, 400);\n }\n\n if (result.code === \"organization_slug_taken\") {\n return error(\n { message: \"Organization slug taken\", code: \"organization_slug_taken\" },\n 400,\n );\n }\n\n if (result.code === \"invalid_slug\") {\n return error({ message: \"Invalid input\", code: \"invalid_input\" }, 400);\n }\n\n if (result.code === \"limit_reached\") {\n return error({ message: \"Limit reached\", code: \"limit_reached\" }, 400);\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({\n organization: serializeOrganization(result.organization),\n member: serializeMember(result.member),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"GET\",\n path: \"/organizations\",\n queryParameters: [\"pageSize\", \"cursor\", \"sessionId\"],\n outputSchema: z.object({\n organizations: z.array(\n z.object({\n organization: organizationSchema,\n member: memberSchema,\n }),\n ),\n cursor: z.string().optional(),\n hasNextPage: z.boolean(),\n }),\n errorCodes: [\"invalid_input\", \"session_invalid\"],\n handler: async function ({ query, headers }, { json, error }) {\n const parsed = pageQuerySchema.safeParse(Object.fromEntries(query.entries()));\n if (!parsed.success) {\n return error({ message: \"Invalid query parameters\", code: \"invalid_input\" }, 400);\n }\n\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const rawCursor = parseCursor(query.get(\"cursor\"));\n const cursor =\n rawCursor && (rawCursor.indexName === \"_primary\" || rawCursor.indexName === \"primary\")\n ? rawCursor\n : undefined;\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.getOrganizationsForSession({\n sessionId,\n pageSize: parsed.data.pageSize,\n cursor,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return json({\n organizations: result.organizations.map((entry) => ({\n organization: serializeOrganization(entry.organization),\n member: serializeMember(entry.member),\n })),\n cursor: result.cursor,\n hasNextPage: result.hasNextPage,\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"GET\",\n path: \"/organizations/active\",\n queryParameters: [\"sessionId\"],\n outputSchema: z\n .object({\n organization: organizationSchema,\n member: memberSchema,\n })\n .nullable(),\n errorCodes: [\"session_invalid\"],\n handler: async function ({ headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.getActiveOrganizationForSession({\n sessionId,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (!result.data) {\n return json(null);\n }\n\n return json({\n organization: serializeOrganization(result.data.organization),\n member: serializeMember(result.data.member),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"POST\",\n path: \"/organizations/active\",\n queryParameters: [\"sessionId\"],\n inputSchema: z.object({\n organizationId: z.string(),\n }),\n outputSchema: z.object({\n organization: organizationSchema,\n member: memberSchema,\n }),\n errorCodes: [\"organization_not_found\", \"membership_not_found\", \"session_invalid\"],\n handler: async function ({ input, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const body = await input.valid();\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.setActiveOrganizationForSession({\n sessionId,\n organizationId: body.organizationId,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n if (result.code === \"membership_not_found\") {\n return error({ message: \"Membership not found\", code: \"membership_not_found\" }, 404);\n }\n\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return json({\n organization: serializeOrganization(result.organization),\n member: serializeMember(result.member),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"GET\",\n path: \"/organizations/invitations\",\n queryParameters: [\"sessionId\"],\n outputSchema: z.object({\n invitations: z.array(\n z.object({\n invitation: invitationSchema,\n organization: organizationSchema,\n }),\n ),\n }),\n errorCodes: [\"session_invalid\"],\n handler: async function ({ headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [services.listInvitationsForSession({ sessionId })])\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return json({\n invitations: result.invitations.map((entry) => ({\n invitation: serializeInvitation(entry.invitation),\n organization: serializeOrganization(entry.organization),\n })),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"PATCH\",\n path: \"/organizations/invitations/:invitationId\",\n queryParameters: [\"sessionId\"],\n inputSchema: z.object({\n action: z.enum([\"accept\", \"reject\", \"cancel\"]),\n token: z.string().optional(),\n }),\n outputSchema: z.object({\n invitation: invitationSchema,\n }),\n errorCodes: [\n \"invitation_not_found\",\n \"invitation_expired\",\n \"permission_denied\",\n \"invalid_token\",\n \"limit_reached\",\n \"session_invalid\",\n ],\n handler: async function ({ input, pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const body = await input.valid();\n\n if ((body.action === \"accept\" || body.action === \"reject\") && !body.token) {\n return error({ message: \"Invalid token\", code: \"invalid_token\" }, 400);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.respondToInvitationWithSession({\n sessionId,\n invitationId: pathParams.invitationId,\n action: body.action,\n token: body.token,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"invalid_token\") {\n return error({ message: \"Invalid token\", code: \"invalid_token\" }, 400);\n }\n\n if (result.code === \"invitation_expired\") {\n return error({ message: \"Invitation expired\", code: \"invitation_expired\" }, 400);\n }\n\n if (result.code === \"limit_reached\") {\n return error({ message: \"Limit reached\", code: \"limit_reached\" }, 400);\n }\n\n if (result.code === \"permission_denied\") {\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return error({ message: \"Invitation not found\", code: \"invitation_not_found\" }, 404);\n }\n\n return json({\n invitation: serializeInvitation(result.invitation),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"GET\",\n path: \"/organizations/:organizationId\",\n queryParameters: [\"sessionId\"],\n outputSchema: z.object({\n organization: organizationSchema,\n member: memberSchema,\n }),\n errorCodes: [\"organization_not_found\", \"permission_denied\", \"session_invalid\"],\n handler: async function ({ pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.getOrganizationForSession({\n sessionId,\n organizationId: pathParams.organizationId,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n if (result.code === \"permission_denied\") {\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return json({\n organization: serializeOrganization(result.organization),\n member: serializeMember(result.member),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"PATCH\",\n path: \"/organizations/:organizationId\",\n queryParameters: [\"sessionId\"],\n inputSchema: updateOrganizationInputSchema,\n outputSchema: z.object({\n organization: organizationSchema,\n }),\n errorCodes: [\n \"invalid_input\",\n \"organization_not_found\",\n \"organization_slug_taken\",\n \"permission_denied\",\n \"session_invalid\",\n ],\n handler: async function ({ input, pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const body = await input.valid();\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.updateOrganizationWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n patch: body,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n if (result.code === \"organization_slug_taken\") {\n return error(\n { message: \"Organization slug taken\", code: \"organization_slug_taken\" },\n 400,\n );\n }\n\n if (result.code === \"permission_denied\") {\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return error({ message: \"Invalid input\", code: \"invalid_input\" }, 400);\n }\n\n return json({\n organization: serializeOrganization(result.organization),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"DELETE\",\n path: \"/organizations/:organizationId\",\n queryParameters: [\"sessionId\"],\n outputSchema: z.object({\n success: z.boolean(),\n }),\n errorCodes: [\"organization_not_found\", \"permission_denied\", \"session_invalid\"],\n handler: async function ({ pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.deleteOrganizationWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({ success: true });\n },\n }),\n\n defineOrganizationRoute({\n method: \"GET\",\n path: \"/organizations/:organizationId/members\",\n queryParameters: [\"pageSize\", \"cursor\", \"sessionId\"],\n outputSchema: z.object({\n members: z.array(memberSchema),\n cursor: z.string().optional(),\n hasNextPage: z.boolean(),\n }),\n errorCodes: [\n \"invalid_input\",\n \"organization_not_found\",\n \"permission_denied\",\n \"session_invalid\",\n ],\n handler: async function ({ pathParams, query, headers }, { json, error }) {\n const parsed = pageQuerySchema.safeParse(Object.fromEntries(query.entries()));\n if (!parsed.success) {\n return error({ message: \"Invalid query parameters\", code: \"invalid_input\" }, 400);\n }\n\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n const cursor = parseCursor(query.get(\"cursor\"));\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.listOrganizationMembersWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n pageSize: parsed.data.pageSize,\n cursor,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({\n members: result.members.map((member) => serializeMember(member)),\n cursor: result.cursor,\n hasNextPage: result.hasNextPage,\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"POST\",\n path: \"/organizations/:organizationId/members\",\n queryParameters: [\"sessionId\"],\n inputSchema: z.object({\n userId: z.string(),\n roles: z.array(z.string()).optional(),\n }),\n outputSchema: z.object({\n member: memberSchema,\n }),\n errorCodes: [\n \"organization_not_found\",\n \"permission_denied\",\n \"member_already_exists\",\n \"limit_reached\",\n \"session_invalid\",\n ],\n handler: async function ({ input, pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n const body = await input.valid();\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.createOrganizationMemberWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n userId: body.userId,\n roles: body.roles,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n if (result.code === \"member_already_exists\") {\n return error(\n { message: \"Member already exists\", code: \"member_already_exists\" },\n 400,\n );\n }\n\n if (result.code === \"limit_reached\") {\n return error({ message: \"Limit reached\", code: \"limit_reached\" }, 400);\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({\n member: serializeMember(result.member),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"PATCH\",\n path: \"/organizations/:organizationId/members/:memberId\",\n queryParameters: [\"sessionId\"],\n inputSchema: z.object({\n roles: z.array(z.string()).min(1),\n }),\n outputSchema: z.object({\n member: memberSchema,\n }),\n errorCodes: [\"member_not_found\", \"permission_denied\", \"last_owner\", \"session_invalid\"],\n handler: async function ({ input, pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n const body = await input.valid();\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.updateOrganizationMemberRolesWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n memberId: pathParams.memberId,\n roles: body.roles,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"member_not_found\") {\n return error({ message: \"Member not found\", code: \"member_not_found\" }, 404);\n }\n\n if (result.code === \"last_owner\") {\n return error({ message: \"Last owner\", code: \"last_owner\" }, 400);\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({\n member: serializeMember(result.member),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"DELETE\",\n path: \"/organizations/:organizationId/members/:memberId\",\n queryParameters: [\"sessionId\"],\n outputSchema: z.object({\n success: z.boolean(),\n }),\n errorCodes: [\"member_not_found\", \"permission_denied\", \"last_owner\", \"session_invalid\"],\n handler: async function ({ pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.deleteOrganizationMemberWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n memberId: pathParams.memberId,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"member_not_found\") {\n return error({ message: \"Member not found\", code: \"member_not_found\" }, 404);\n }\n\n if (result.code === \"last_owner\") {\n return error({ message: \"Last owner\", code: \"last_owner\" }, 400);\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({ success: true });\n },\n }),\n\n defineOrganizationRoute({\n method: \"GET\",\n path: \"/organizations/:organizationId/invitations\",\n queryParameters: [\"sessionId\"],\n outputSchema: z.object({\n invitations: z.array(invitationSchema),\n }),\n errorCodes: [\"organization_not_found\", \"permission_denied\", \"session_invalid\"],\n handler: async function ({ pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.listOrganizationInvitationsWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({\n invitations: result.invitations.map(serializeInvitation),\n });\n },\n }),\n\n defineOrganizationRoute({\n method: \"POST\",\n path: \"/organizations/:organizationId/invitations\",\n queryParameters: [\"sessionId\"],\n inputSchema: z.object({\n email: z.email(),\n roles: z.array(z.string()).optional(),\n }),\n outputSchema: z.object({\n invitation: invitationSchema,\n }),\n errorCodes: [\n \"organization_not_found\",\n \"permission_denied\",\n \"limit_reached\",\n \"session_invalid\",\n ],\n handler: async function ({ input, pathParams, headers, query }, { json, error }) {\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const body = await input.valid();\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [\n services.createOrganizationInvitationWithSession({\n sessionId,\n organizationId: pathParams.organizationId,\n email: body.email,\n roles: body.roles,\n }),\n ])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"session_invalid\") {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n if (result.code === \"organization_not_found\") {\n return error(\n { message: \"Organization not found\", code: \"organization_not_found\" },\n 404,\n );\n }\n\n if (result.code === \"limit_reached\") {\n return error({ message: \"Limit reached\", code: \"limit_reached\" }, 400);\n }\n\n return error({ message: \"Permission denied\", code: \"permission_denied\" }, 403);\n }\n\n return json({\n invitation: serializeInvitation(result.invitation),\n });\n },\n }),\n ];\n },\n);\n","import { column, idColumn, referenceColumn, schema } from \"@fragno-dev/db/schema\";\n\nexport const authSchema = schema(\"auth\", (s) => {\n return s\n .addTable(\"user\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"email\", column(\"string\"))\n .addColumn(\"passwordHash\", column(\"string\"))\n .addColumn(\"role\", column(\"string\").defaultTo(\"user\"))\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .createIndex(\"idx_user_email\", [\"email\"])\n .createIndex(\"idx_user_id\", [\"id\"], { unique: true });\n })\n .addTable(\"session\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"userId\", referenceColumn())\n .addColumn(\"expiresAt\", column(\"timestamp\"))\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .createIndex(\"idx_session_user\", [\"userId\"]);\n })\n .alterTable(\"user\", (t) => {\n return t\n .addColumn(\"bannedAt\", column(\"timestamp\").nullable())\n .createIndex(\"idx_user_createdAt\", [\"createdAt\"]);\n })\n .alterTable(\"session\", (t) => {\n return t.addColumn(\"activeOrganizationId\", referenceColumn().nullable());\n })\n .addTable(\"organization\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"name\", column(\"string\"))\n .addColumn(\"slug\", column(\"string\"))\n .addColumn(\"logoUrl\", column(\"string\").nullable())\n .addColumn(\"metadata\", column(\"json\").nullable())\n .addColumn(\"createdBy\", referenceColumn())\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\n \"updatedAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\"deletedAt\", column(\"timestamp\").nullable())\n .createIndex(\"idx_organization_slug\", [\"slug\"], { unique: true })\n .createIndex(\"idx_organization_createdBy\", [\"createdBy\"]);\n })\n .addTable(\"organizationMember\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"organizationId\", referenceColumn())\n .addColumn(\"userId\", referenceColumn())\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\n \"updatedAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .createIndex(\"idx_org_member_org_user\", [\"organizationId\", \"userId\"], {\n unique: true,\n })\n .createIndex(\"idx_org_member_user\", [\"userId\"])\n .createIndex(\"idx_org_member_org\", [\"organizationId\"]);\n })\n .addTable(\"organizationMemberRole\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"memberId\", referenceColumn())\n .addColumn(\"role\", column(\"string\"))\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .createIndex(\"idx_org_member_role_member_role\", [\"memberId\", \"role\"], {\n unique: true,\n })\n .createIndex(\"idx_org_member_role_member\", [\"memberId\"])\n .createIndex(\"idx_org_member_role_role\", [\"role\"]);\n })\n .addTable(\"organizationInvitation\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"organizationId\", referenceColumn())\n .addColumn(\"email\", column(\"string\"))\n .addColumn(\"roles\", column(\"json\"))\n .addColumn(\"status\", column(\"string\"))\n .addColumn(\"token\", column(\"string\"))\n .addColumn(\"inviterId\", referenceColumn())\n .addColumn(\"expiresAt\", column(\"timestamp\"))\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\"respondedAt\", column(\"timestamp\").nullable())\n .createIndex(\"idx_org_invitation_token\", [\"token\"], { unique: true })\n .createIndex(\"idx_org_invitation_org_status\", [\"organizationId\", \"status\"])\n .createIndex(\"idx_org_invitation_email\", [\"email\"])\n .createIndex(\"idx_org_invitation_email_status\", [\"email\", \"status\"]);\n })\n .addReference(\"sessionOwner\", {\n from: {\n table: \"session\",\n column: \"userId\",\n },\n to: {\n table: \"user\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"sessionActiveOrganization\", {\n from: {\n table: \"session\",\n column: \"activeOrganizationId\",\n },\n to: {\n table: \"organization\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"organizationCreator\", {\n from: {\n table: \"organization\",\n column: \"createdBy\",\n },\n to: {\n table: \"user\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"organizationMemberOrganization\", {\n from: {\n table: \"organizationMember\",\n column: \"organizationId\",\n },\n to: {\n table: \"organization\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"organizationMembers\", {\n from: {\n table: \"organization\",\n column: \"id\",\n },\n to: {\n table: \"organizationMember\",\n column: \"organizationId\",\n },\n type: \"many\",\n foreignKey: false,\n })\n .addReference(\"organizationMemberUser\", {\n from: {\n table: \"organizationMember\",\n column: \"userId\",\n },\n to: {\n table: \"user\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"organizationMemberRoleMember\", {\n from: {\n table: \"organizationMemberRole\",\n column: \"memberId\",\n },\n to: {\n table: \"organizationMember\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"organizationInvitationOrganization\", {\n from: {\n table: \"organizationInvitation\",\n column: \"organizationId\",\n },\n to: {\n table: \"organization\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"organizationInvitationInviter\", {\n from: {\n table: \"organizationInvitation\",\n column: \"inviterId\",\n },\n to: {\n table: \"user\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addTable(\"oauthAccount\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"userId\", referenceColumn())\n .addColumn(\"provider\", column(\"string\"))\n .addColumn(\"providerAccountId\", column(\"string\"))\n .addColumn(\"email\", column(\"string\").nullable())\n .addColumn(\"emailVerified\", column(\"bool\").defaultTo(false))\n .addColumn(\"image\", column(\"string\").nullable())\n .addColumn(\"accessToken\", column(\"string\").nullable())\n .addColumn(\"refreshToken\", column(\"string\").nullable())\n .addColumn(\"idToken\", column(\"string\").nullable())\n .addColumn(\"tokenType\", column(\"string\").nullable())\n .addColumn(\"tokenExpiresAt\", column(\"timestamp\").nullable())\n .addColumn(\"scopes\", column(\"json\").nullable())\n .addColumn(\"rawProfile\", column(\"json\").nullable())\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\n \"updatedAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .createIndex(\"idx_oauth_account_provider_account\", [\"provider\", \"providerAccountId\"], {\n unique: true,\n })\n .createIndex(\"idx_oauth_account_user\", [\"userId\"])\n .createIndex(\"idx_oauth_account_provider\", [\"provider\"]);\n })\n .addTable(\"oauthState\", (t) => {\n return t\n .addColumn(\"id\", idColumn())\n .addColumn(\"provider\", column(\"string\"))\n .addColumn(\"state\", column(\"string\"))\n .addColumn(\"codeVerifier\", column(\"string\").nullable())\n .addColumn(\"redirectUri\", column(\"string\").nullable())\n .addColumn(\"returnTo\", column(\"string\").nullable())\n .addColumn(\"linkUserId\", referenceColumn().nullable())\n .addColumn(\n \"createdAt\",\n column(\"timestamp\").defaultTo((b) => b.now()),\n )\n .addColumn(\"expiresAt\", column(\"timestamp\"))\n .createIndex(\"idx_oauth_state_state\", [\"state\"], { unique: true })\n .createIndex(\"idx_oauth_state_provider\", [\"provider\"])\n .createIndex(\"idx_oauth_state_expiresAt\", [\"expiresAt\"]);\n })\n .addReference(\"oauthAccountUser\", {\n from: {\n table: \"oauthAccount\",\n column: \"userId\",\n },\n to: {\n table: \"user\",\n column: \"id\",\n },\n type: \"one\",\n })\n .addReference(\"oauthStateLinkUser\", {\n from: {\n table: \"oauthState\",\n column: \"linkUserId\",\n },\n to: {\n table: \"user\",\n column: \"id\",\n },\n type: \"one\",\n })\n .alterTable(\"user\", (t) => {\n return t.alterColumn(\"passwordHash\").nullable();\n })\n .addReference(\"sessionOrganizationMembers\", {\n type: \"many\",\n from: {\n table: \"session\",\n column: \"userId\",\n },\n to: {\n table: \"organizationMember\",\n column: \"userId\",\n },\n foreignKey: false,\n })\n .addReference(\"sessionMembers\", {\n type: \"many\",\n from: {\n table: \"session\",\n column: \"userId\",\n },\n to: {\n table: \"organizationMember\",\n column: \"userId\",\n },\n foreignKey: false,\n })\n .addReference(\"organizationMemberRoles\", {\n type: \"many\",\n from: {\n table: \"organizationMember\",\n // Join-only relations coerce `id` to internal ID.\n column: \"id\",\n },\n to: {\n table: \"organizationMemberRole\",\n column: \"memberId\",\n },\n foreignKey: false,\n })\n .addReference(\"roles\", {\n type: \"many\",\n from: {\n table: \"organizationMember\",\n // Join-only relations coerce `id` to internal ID.\n column: \"id\",\n },\n to: {\n table: \"organizationMemberRole\",\n column: \"memberId\",\n },\n foreignKey: false,\n })\n .addReference(\"organization\", {\n type: \"one\",\n from: {\n table: \"organizationMember\",\n column: \"organizationId\",\n },\n to: {\n table: \"organization\",\n column: \"id\",\n },\n foreignKey: false,\n })\n .addReference(\"userOrganizationInvitations\", {\n type: \"many\",\n from: {\n table: \"user\",\n column: \"email\",\n },\n to: {\n table: \"organizationInvitation\",\n column: \"email\",\n },\n foreignKey: false,\n })\n .addReference(\"invitations\", {\n type: \"many\",\n from: {\n table: \"user\",\n column: \"email\",\n },\n to: {\n table: \"organizationInvitation\",\n column: \"email\",\n },\n foreignKey: false,\n })\n .addReference(\"organization\", {\n type: \"one\",\n from: {\n table: \"organizationInvitation\",\n column: \"organizationId\",\n },\n to: {\n table: \"organization\",\n column: \"id\",\n },\n foreignKey: false,\n })\n .alterTable(\"session\", (t) => {\n return t.createIndex(\"idx_session_id_expiresAt\", [\"id\", \"expiresAt\"]);\n })\n .addReference(\"userOrganizationMembers\", {\n type: \"many\",\n from: {\n table: \"user\",\n column: \"id\",\n },\n to: {\n table: \"organizationMember\",\n column: \"userId\",\n },\n foreignKey: false,\n })\n .alterTable(\"oauthState\", (t) => {\n return t.addColumn(\"sessionSeed\", column(\"json\").nullable());\n });\n});\n","import { z } from \"zod\";\n\nimport { toExternalId } from \"../organization/utils\";\n\nexport const sessionSeedSchema = z\n .object({\n activeOrganizationId: z.string().trim().min(1).optional(),\n })\n .strict();\n\nexport type SessionSeedInput = z.input<typeof sessionSeedSchema>;\nexport type SessionSeed = z.output<typeof sessionSeedSchema>;\nexport type ResolvedSessionSeed = {\n status: \"accepted\" | \"ignored\" | \"repaired\";\n requestedActiveOrganizationId: string | null;\n activeOrganizationId: string | null;\n};\n\nexport function normalizeSessionSeed(session?: SessionSeedInput | null): SessionSeed | null {\n const parsed = sessionSeedSchema.safeParse(session ?? {});\n if (!parsed.success) {\n return null;\n }\n\n return parsed.data.activeOrganizationId ? parsed.data : null;\n}\n\nexport function parseSessionSeed(value: unknown): SessionSeed | null {\n const parsed = sessionSeedSchema.safeParse(value);\n if (!parsed.success) {\n return null;\n }\n\n return parsed.data.activeOrganizationId ? parsed.data : null;\n}\n\nexport function resolveSessionSeedFromMembers<\n TMember extends {\n createdAt: Date;\n organization: {\n id: unknown;\n deletedAt: Date | null;\n } | null;\n },\n>(members: TMember[], session?: SessionSeedInput | null): ResolvedSessionSeed {\n const normalizedSession = normalizeSessionSeed(session);\n const requestedActiveOrganizationId = normalizedSession?.activeOrganizationId ?? null;\n\n if (!requestedActiveOrganizationId) {\n return {\n status: \"ignored\",\n requestedActiveOrganizationId: null,\n activeOrganizationId: null,\n };\n }\n\n const validMembers = members\n .filter((member) => member.organization && !member.organization.deletedAt)\n .sort((left, right) => left.createdAt.getTime() - right.createdAt.getTime());\n const requestedMember =\n validMembers.find(\n (member) => toExternalId(member.organization!.id) === requestedActiveOrganizationId,\n ) ?? null;\n const repairedMember = requestedMember ?? validMembers[0] ?? null;\n\n return {\n status: requestedMember ? \"accepted\" : repairedMember ? \"repaired\" : \"ignored\",\n requestedActiveOrganizationId,\n activeOrganizationId: repairedMember ? toExternalId(repairedMember.organization!.id) : null,\n };\n}\n\nexport function parseSessionSeedFromQuery(value: string | null): SessionSeed | null | \"invalid\" {\n if (value === null) {\n return null;\n }\n if (value === \"\") {\n return \"invalid\";\n }\n\n try {\n const parsed = parseSessionSeed(JSON.parse(value));\n return parsed ?? \"invalid\";\n } catch {\n return \"invalid\";\n }\n}\n\nexport function serializeSessionSeedForQuery(\n session?: SessionSeedInput | null,\n): string | undefined {\n const normalized = normalizeSessionSeed(session);\n return normalized ? JSON.stringify(normalized) : undefined;\n}\n","import type { FragnoId } from \"@fragno-dev/db/schema\";\nimport { z } from \"zod\";\n\nimport { defineRoute, defineRoutes } from \"@fragno-dev/core\";\nimport type { DatabaseServiceContext } from \"@fragno-dev/db\";\n\nimport type { Role, authFragmentDefinition } from \"..\";\nimport type { AuthHooksMap } from \"../hooks\";\nimport { invitationSummarySchema, memberSchema, organizationSchema } from \"../organization/schemas\";\nimport {\n serializeInvitationSummary,\n serializeMember,\n serializeOrganization,\n} from \"../organization/serializers\";\nimport type {\n Organization,\n OrganizationInvitation,\n OrganizationInvitationStatus,\n OrganizationMember,\n} from \"../organization/types\";\nimport { toExternalId } from \"../organization/utils\";\nimport { authSchema } from \"../schema\";\nimport { mapUserSummary } from \"../user/summary\";\nimport {\n buildClearCookieHeader,\n buildSetCookieHeader,\n extractSessionId,\n type CookieOptions,\n} from \"../utils/cookie\";\nimport { resolveSessionSeedFromMembers, type SessionSeedInput } from \"./session-seed\";\n\ntype AuthServiceContext = DatabaseServiceContext<AuthHooksMap>;\n\nconst requiredOrganizationServiceNames = [\n \"getOrganizationsForUser\",\n \"listOrganizationMemberRolesForMembers\",\n \"listOrganizationInvitationsForUser\",\n \"getActiveOrganization\",\n] as const;\n\nexport function assertOrganizationServices(\n services: Record<string, unknown>,\n): asserts services is Record<\n (typeof requiredOrganizationServiceNames)[number],\n (...args: unknown[]) => unknown\n> {\n const missing = requiredOrganizationServiceNames.filter(\n (name) => typeof services[name] !== \"function\",\n );\n if (missing.length > 0) {\n throw new Error(`Missing organization services: ${missing.join(\", \")}`);\n }\n}\n\ntype OrganizationRow = {\n id: unknown;\n name: string;\n slug: string;\n logoUrl: string | null;\n metadata: unknown;\n createdBy: unknown;\n createdAt: Date;\n updatedAt: Date;\n deletedAt: Date | null;\n};\n\ntype ActiveOrganizationRow = {\n id: unknown;\n};\n\ntype OrganizationMemberRoleRow = {\n role: string;\n};\n\ntype OrganizationMemberRow = {\n id: unknown;\n createdAt: Date;\n updatedAt: Date;\n organization?: OrganizationRow | null;\n roles?: OrganizationMemberRoleRow | OrganizationMemberRoleRow[] | null;\n};\n\ntype OrganizationInvitationRow = {\n id: unknown;\n organizationId: unknown;\n email: string;\n roles: unknown;\n status: string;\n token: string;\n inviterId: unknown;\n expiresAt: Date;\n createdAt: Date;\n respondedAt: Date | null;\n organization?: OrganizationRow | null;\n};\n\ntype SessionOwnerRow = {\n id: unknown;\n email: string;\n role: Role;\n};\n\ntype SessionMemberRow = {\n id: FragnoId;\n expiresAt: Date;\n sessionOwner?: SessionOwnerRow | null;\n sessionActiveOrganization?: ActiveOrganizationRow | null;\n sessionMembers?: OrganizationMemberRow | OrganizationMemberRow[] | null;\n};\n\ntype SessionInvitationRow = {\n id: FragnoId;\n expiresAt: Date;\n sessionActiveOrganization?: ActiveOrganizationRow | null;\n sessionOwner?:\n | (SessionOwnerRow & {\n invitations?: OrganizationInvitationRow | OrganizationInvitationRow[] | null;\n })\n | null;\n};\n\ntype SessionExpiryRow = {\n id: FragnoId;\n};\n\ntype SessionSeedMemberRow = {\n createdAt: Date;\n organizationMemberOrganization?: OrganizationRow | null;\n};\n\nconst organizationSelect = [\n \"id\",\n \"name\",\n \"slug\",\n \"logoUrl\",\n \"metadata\",\n \"createdBy\",\n \"createdAt\",\n \"updatedAt\",\n \"deletedAt\",\n] as const;\n\nconst normalizeMany = <T>(value: T | T[] | null | undefined): T[] => {\n if (!value) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst mapOrganizationRow = (organization: OrganizationRow): Organization => ({\n id: toExternalId(organization.id),\n name: organization.name,\n slug: organization.slug,\n logoUrl: organization.logoUrl ?? null,\n metadata: (organization.metadata ?? null) as Record<string, unknown> | null,\n createdBy: toExternalId(organization.createdBy),\n createdAt: organization.createdAt,\n updatedAt: organization.updatedAt,\n deletedAt: organization.deletedAt ?? null,\n});\n\nconst mapMemberRow = (\n member: OrganizationMemberRow,\n organizationId: string,\n userId: string,\n roles: string[],\n): OrganizationMember<string> => ({\n id: toExternalId(member.id),\n organizationId,\n userId,\n roles,\n createdAt: member.createdAt,\n updatedAt: member.updatedAt,\n});\n\nconst mapInvitationRow = (\n invitation: OrganizationInvitationRow,\n organizationId: string,\n): OrganizationInvitation<string> => ({\n id: toExternalId(invitation.id),\n organizationId,\n email: invitation.email,\n roles: Array.isArray(invitation.roles) ? (invitation.roles as string[]) : [],\n status: invitation.status as OrganizationInvitationStatus,\n token: invitation.token,\n inviterId: toExternalId(invitation.inviterId),\n expiresAt: invitation.expiresAt,\n createdAt: invitation.createdAt,\n respondedAt: invitation.respondedAt ?? null,\n});\n\nconst buildOrganizationsFromRows = (\n rows: SessionMemberRow[],\n): Array<{\n organization: ReturnType<typeof serializeOrganization>;\n member: ReturnType<typeof serializeMember>;\n}> => {\n const organizationsByMemberId = new Map<\n string,\n {\n organization: Organization;\n member: OrganizationMember<string>;\n roles: Set<string>;\n }\n >();\n\n for (const row of rows) {\n const sessionOwner = row.sessionOwner;\n if (!sessionOwner) {\n continue;\n }\n const userId = toExternalId(sessionOwner.id);\n const members = normalizeMany(row.sessionMembers) as OrganizationMemberRow[];\n for (const member of members) {\n const organizationRow = member.organization;\n if (!organizationRow || organizationRow.deletedAt) {\n continue;\n }\n const memberId = toExternalId(member.id);\n let entry = organizationsByMemberId.get(memberId);\n if (!entry) {\n const organization = mapOrganizationRow(organizationRow);\n entry = {\n organization,\n member: mapMemberRow(member, organization.id, userId, []),\n roles: new Set(),\n };\n organizationsByMemberId.set(memberId, entry);\n }\n\n const roles = normalizeMany(member.roles) as OrganizationMemberRoleRow[];\n for (const role of roles) {\n if (role?.role) {\n entry.roles.add(role.role);\n }\n }\n }\n }\n\n return Array.from(organizationsByMemberId.values()).map((entry) => ({\n organization: serializeOrganization(entry.organization),\n member: serializeMember({\n ...entry.member,\n roles: Array.from(entry.roles),\n }),\n }));\n};\n\nconst buildInvitationsFromRows = (\n rows: SessionInvitationRow[],\n): Array<{\n invitation: ReturnType<typeof serializeInvitationSummary>;\n organization: ReturnType<typeof serializeOrganization>;\n}> => {\n const invitations: Array<{\n invitation: ReturnType<typeof serializeInvitationSummary>;\n organization: ReturnType<typeof serializeOrganization>;\n }> = [];\n const seenInvitationIds = new Set<string>();\n\n for (const row of rows) {\n const sessionOwner = row.sessionOwner;\n if (!sessionOwner) {\n continue;\n }\n const invitationsForUser = normalizeMany(\n sessionOwner.invitations,\n ) as OrganizationInvitationRow[];\n for (const invitation of invitationsForUser) {\n if (!invitation || invitation.status !== \"pending\") {\n continue;\n }\n const organizationRow = invitation.organization;\n if (!organizationRow || organizationRow.deletedAt) {\n continue;\n }\n const invitationId = toExternalId(invitation.id);\n if (seenInvitationIds.has(invitationId)) {\n continue;\n }\n seenInvitationIds.add(invitationId);\n\n const organization = mapOrganizationRow(organizationRow);\n const mappedInvitation = mapInvitationRow(invitation, organization.id);\n invitations.push({\n invitation: serializeInvitationSummary(mappedInvitation),\n organization: serializeOrganization(organization),\n });\n }\n }\n\n return invitations;\n};\n\nexport function createSessionServices(cookieOptions?: CookieOptions) {\n const services = {\n resolveSessionSeedForUser: function (\n this: AuthServiceContext,\n userId: string,\n session?: SessionSeedInput | null,\n ) {\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.find(\"organizationMember\", (b) =>\n b\n .whereIndex(\"idx_org_member_user\", (eb) => eb(\"userId\", \"=\", userId))\n .join((j) =>\n j.organizationMemberOrganization((ob) =>\n ob.select([\"id\", \"deletedAt\", \"createdAt\"]),\n ),\n ),\n ),\n )\n .transformRetrieve(([members]) => {\n return resolveSessionSeedFromMembers(\n (members as SessionSeedMemberRow[]).map((member) => ({\n createdAt: member.createdAt,\n organization: member.organizationMemberOrganization ?? null,\n })),\n session,\n );\n })\n .mutate(({ retrieveResult }) => retrieveResult)\n .build();\n },\n /**\n * Build a Set-Cookie header value for the session id.\n */\n buildSessionCookie: function (sessionId: string): string {\n return buildSetCookieHeader(sessionId, cookieOptions);\n },\n /**\n * Create a session for a user, rejecting banned or missing users.\n *\n * When `options.activeOrganizationId` is provided, it is written into the session as-is.\n * This function does not verify that the user is a member of that organization; callers\n * must validate membership before passing the id.\n */\n createSession: function (\n this: AuthServiceContext,\n userId: string,\n options?: { activeOrganizationId?: string | null },\n ) {\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findFirst(\"user\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", userId))),\n )\n .mutate(({ uow, retrieveResult: [user] }) => {\n if (!user) {\n return { ok: false as const, code: \"user_not_found\" as const };\n }\n if (user.bannedAt) {\n return { ok: false as const, code: \"user_banned\" as const };\n }\n\n const expiresAt = uow.now().plus({ days: 30 });\n const id = uow.create(\"session\", {\n userId,\n activeOrganizationId: options?.activeOrganizationId ?? null,\n expiresAt,\n });\n const userSummary = mapUserSummary(user);\n\n uow.triggerHook(\"onSessionCreated\", {\n session: {\n id: id.valueOf(),\n user: userSummary,\n expiresAt,\n activeOrganizationId: options?.activeOrganizationId ?? null,\n },\n actor: userSummary,\n });\n\n return {\n ok: true as const,\n session: {\n id: id.valueOf(),\n userId,\n expiresAt,\n activeOrganizationId: options?.activeOrganizationId ?? null,\n },\n };\n })\n .build();\n },\n /**\n * Validate a session and return user info or null when invalid.\n */\n validateSession: function (this: AuthServiceContext, sessionId: string) {\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"session\", (b) =>\n b\n .whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId), eb(\"expiresAt\", \">\", eb.now())),\n )\n .join((j) => j.sessionOwner((b) => b.select([\"id\", \"email\", \"role\"]))),\n )\n .findFirst(\"session\", (b) =>\n b.whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId), eb(\"expiresAt\", \"<=\", eb.now())),\n ),\n ),\n )\n .mutate(({ uow, retrieveResult: [session, expiredSession] }) => {\n if (expiredSession) {\n uow.delete(\"session\", expiredSession.id, (b) => b.check());\n }\n if (!session) {\n return null;\n }\n if (!session.sessionOwner) {\n return null;\n }\n\n return {\n id: session.id.valueOf(),\n userId: session.userId as unknown as string,\n user: {\n id: session.sessionOwner.id.valueOf(),\n email: session.sessionOwner.email,\n role: session.sessionOwner.role,\n },\n };\n })\n .build();\n },\n /**\n * Invalidate a session and emit session invalidation hooks.\n */\n invalidateSession: function (this: AuthServiceContext, sessionId: string) {\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findFirst(\"session\", (b) =>\n b\n .whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", sessionId))\n .join((j) => j.sessionOwner((b) => b.select([\"id\", \"email\", \"role\", \"bannedAt\"]))),\n ),\n )\n .mutate(({ uow, retrieveResult: [session] }) => {\n if (!session) {\n return false;\n }\n\n uow.delete(\"session\", session.id, (b) => b.check());\n if (session.sessionOwner) {\n const userSummary = mapUserSummary({\n id: session.sessionOwner.id,\n email: session.sessionOwner.email,\n role: session.sessionOwner.role,\n bannedAt: session.sessionOwner.bannedAt ?? null,\n });\n uow.triggerHook(\"onSessionInvalidated\", {\n session: {\n id: session.id.valueOf(),\n user: userSummary,\n expiresAt: session.expiresAt,\n activeOrganizationId: session.activeOrganizationId\n ? String(session.activeOrganizationId)\n : null,\n },\n actor: userSummary,\n });\n }\n return true;\n })\n .build();\n },\n /**\n * Resolve a session from request headers for sign-in checks.\n */\n getSession: function (this: AuthServiceContext, headers: Headers) {\n const sessionId = extractSessionId(headers);\n\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"session\", (b) =>\n b\n .whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId ?? \"\"), eb(\"expiresAt\", \">\", eb.now())),\n )\n .join((j) => j.sessionOwner((b) => b.select([\"id\", \"email\", \"role\"]))),\n )\n .findFirst(\"session\", (b) =>\n b.whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId ?? \"\"), eb(\"expiresAt\", \"<=\", eb.now())),\n ),\n ),\n )\n .mutate(({ uow, retrieveResult: [session, expiredSession] }) => {\n if (expiredSession) {\n uow.delete(\"session\", expiredSession.id, (b) => b.check());\n }\n if (!session || !sessionId) {\n return undefined;\n }\n if (!session.sessionOwner) {\n return undefined;\n }\n\n return {\n userId: session.sessionOwner.id.valueOf(),\n email: session.sessionOwner.email,\n };\n })\n .build();\n },\n };\n return services;\n}\n\nexport const sessionRoutesFactory = defineRoutes<typeof authFragmentDefinition>().create(\n ({ services, config }) => {\n return [\n defineRoute({\n method: \"POST\",\n path: \"/sign-out\",\n inputSchema: z\n .object({\n sessionId: z.string().optional(),\n })\n .optional(),\n outputSchema: z.object({\n success: z.boolean(),\n }),\n errorCodes: [\"session_not_found\"],\n handler: async function ({ input, headers }, { json, error }) {\n const body = await input.valid();\n\n // Extract session ID from cookies first, then body\n const sessionId = extractSessionId(headers, null, body?.sessionId);\n\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_not_found\" }, 400);\n }\n\n const [success] = await this.handlerTx()\n .withServiceCalls(() => [services.invalidateSession(sessionId)])\n .execute();\n\n // Build response with clear cookie header\n const clearCookieHeader = buildClearCookieHeader(config.cookieOptions ?? {});\n\n if (!success) {\n // Still clear the cookie even if session not found in DB\n return json(\n { success: false },\n {\n headers: {\n \"Set-Cookie\": clearCookieHeader,\n },\n },\n );\n }\n\n return json(\n { success: true },\n {\n headers: {\n \"Set-Cookie\": clearCookieHeader,\n },\n },\n );\n },\n }),\n\n defineRoute({\n method: \"GET\",\n path: \"/me\",\n queryParameters: [\"sessionId\"],\n outputSchema: z.object({\n user: z.object({\n id: z.string(),\n email: z.string(),\n role: z.enum([\"user\", \"admin\"]),\n }),\n organizations: z.array(\n z.object({\n organization: organizationSchema,\n member: memberSchema,\n }),\n ),\n activeOrganization: z\n .object({\n organization: organizationSchema,\n member: memberSchema,\n })\n .nullable(),\n invitations: z.array(\n z.object({\n invitation: invitationSummarySchema,\n organization: organizationSchema,\n }),\n ),\n }),\n errorCodes: [\"session_invalid\"],\n handler: async function ({ query, headers }, { json, error }) {\n // Extract session ID from cookies first, then query params\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n if (config.organizations !== false) {\n assertOrganizationServices(services);\n }\n\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) => {\n const uow = forSchema(authSchema);\n const scheduleExpiredLookup = () => {\n uow.findFirst(\"session\", (b) =>\n b.whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId), eb(\"expiresAt\", \"<=\", eb.now())),\n ),\n );\n };\n\n if (config.organizations === false) {\n uow.find(\"session\", (b) =>\n b\n .whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId), eb(\"expiresAt\", \">\", eb.now())),\n )\n .join((jb) => jb.sessionOwner((ub) => ub.select([\"id\", \"email\", \"role\"]))),\n );\n scheduleExpiredLookup();\n return uow;\n }\n\n uow.find(\"session\", (b) =>\n b\n .whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId), eb(\"expiresAt\", \">\", eb.now())),\n )\n .join((jb) =>\n jb\n .sessionOwner((ub) => ub.select([\"id\", \"email\", \"role\"]))\n .sessionActiveOrganization((ob) => ob.select([\"id\"]))\n .sessionMembers((mb) =>\n mb.join((jb2) =>\n jb2[\"organization\"]((ob) => ob.select(organizationSelect))[\"roles\"](\n (rb) => rb.select([\"role\"]),\n ),\n ),\n ),\n ),\n );\n\n uow.find(\"session\", (b) =>\n b\n .whereIndex(\"idx_session_id_expiresAt\", (eb) =>\n eb.and(eb(\"id\", \"=\", sessionId), eb(\"expiresAt\", \">\", eb.now())),\n )\n .join((jb) =>\n jb.sessionOwner((ub) =>\n ub\n .select([\"id\", \"email\", \"role\"])\n .join((jb2) =>\n jb2[\"invitations\"]((ib) =>\n ib.join((jb3) =>\n jb3[\"organization\"]((ob) => ob.select(organizationSelect)),\n ),\n ),\n ),\n ),\n ),\n );\n\n scheduleExpiredLookup();\n return uow;\n })\n .transformRetrieve((retrieveResult) => {\n if (config.organizations === false) {\n const [sessions, expiredSession] = retrieveResult as unknown as [\n SessionMemberRow[],\n SessionExpiryRow | null,\n ];\n return {\n session: sessions[0] ?? null,\n organizations: [],\n invitations: [],\n activeOrganizationId: null,\n expiredSession,\n };\n }\n\n const [memberRows, invitationRows, expiredSession] = retrieveResult as unknown as [\n SessionMemberRow[],\n SessionInvitationRow[],\n SessionExpiryRow | null,\n ];\n const session = memberRows[0] ?? invitationRows[0] ?? null;\n const activeOrganizationId =\n session?.sessionActiveOrganization && session.sessionActiveOrganization.id\n ? toExternalId(session.sessionActiveOrganization.id)\n : null;\n\n return {\n session,\n organizations: buildOrganizationsFromRows(memberRows),\n invitations: buildInvitationsFromRows(invitationRows),\n activeOrganizationId,\n expiredSession,\n };\n })\n .mutate(({ forSchema, retrieveResult }) => {\n const { session, expiredSession } = retrieveResult;\n if (expiredSession) {\n const uow = forSchema(authSchema);\n uow.delete(\"session\", expiredSession.id, (b) => b.check());\n }\n if (!session) {\n return { invalid: true as const };\n }\n if (!session.sessionOwner) {\n return { invalid: true as const };\n }\n return { invalid: false as const };\n })\n .transform(({ retrieveResult, mutateResult }) => {\n const { session, organizations, invitations, activeOrganizationId } = retrieveResult;\n if (mutateResult.invalid || !session || !session.sessionOwner) {\n return { ok: false as const };\n }\n\n const user = session.sessionOwner;\n const userId = toExternalId(user.id);\n const activeOrganization = activeOrganizationId\n ? (organizations.find((entry) => entry.organization.id === activeOrganizationId) ??\n null)\n : null;\n\n return {\n ok: true as const,\n data: {\n user: {\n id: userId,\n email: user.email,\n role: user.role as Role,\n },\n organizations,\n activeOrganization,\n invitations,\n },\n };\n })\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return json(result.data);\n },\n }),\n ];\n },\n);\n","import { z } from \"zod\";\n\nimport { defineRoute, defineRoutes } from \"@fragno-dev/core\";\nimport type { DatabaseServiceContext } from \"@fragno-dev/db\";\n\nimport type { authFragmentDefinition } from \"..\";\nimport type { AuthHooksMap, BeforeCreateUserHook } from \"../hooks\";\nimport { authSchema } from \"../schema\";\nimport { resolveSessionSeedFromMembers, sessionSeedSchema } from \"../session/session-seed\";\nimport { buildSetCookieHeader, extractSessionId } from \"../utils/cookie\";\nimport { createAutoOrganization, type AutoCreateOrganizationOptions } from \"./auto-organization\";\nimport { hashPassword, verifyPassword } from \"./password\";\nimport { mapUserSummary } from \"./summary\";\n\ntype AuthServiceContext = DatabaseServiceContext<AuthHooksMap>;\ntype SessionSeedMemberRow = {\n createdAt: Date;\n organizationMemberOrganization?: {\n id: unknown;\n deletedAt: Date | null;\n } | null;\n};\n\nconst normalizeMany = <T>(value: T | T[] | null | undefined): T[] => {\n if (!value) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n};\n\nconst collectSessionSeedMembers = <\n TUser extends {\n userOrganizationMembers?: SessionSeedMemberRow | SessionSeedMemberRow[] | null;\n },\n>(\n rows: TUser[],\n) => {\n return rows.flatMap((user) =>\n normalizeMany(user.userOrganizationMembers).map((member) => ({\n createdAt: member.createdAt,\n organization: member.organizationMemberOrganization ?? null,\n })),\n );\n};\n\nexport function createUserServices(\n options?: AutoCreateOrganizationOptions,\n beforeCreateUser?: BeforeCreateUserHook,\n) {\n const runBeforeCreateUser = (email: string, role: \"user\" | \"admin\") => {\n beforeCreateUser?.({ email, role });\n };\n\n const createUserUnvalidated = function (\n this: AuthServiceContext,\n email: string,\n passwordHash: string,\n role: \"user\" | \"admin\" = \"user\",\n autoCreateOptions?: AutoCreateOrganizationOptions,\n ) {\n return this.serviceTx(authSchema)\n .mutate(({ uow }) => {\n runBeforeCreateUser(email, role);\n const now = new Date();\n const id = uow.create(\"user\", {\n email,\n passwordHash,\n role,\n });\n const userSummary = mapUserSummary({\n id: id.valueOf(),\n email,\n role,\n bannedAt: null,\n });\n\n const autoOrganization = createAutoOrganization(uow, {\n userId: id.valueOf(),\n email,\n now,\n options: autoCreateOptions ?? options,\n });\n\n uow.triggerHook(\"onUserCreated\", {\n user: userSummary,\n actor: null,\n });\n\n if (autoOrganization) {\n uow.triggerHook(\"onOrganizationCreated\", {\n organization: autoOrganization.organization,\n actor: userSummary,\n });\n uow.triggerHook(\"onMemberAdded\", {\n organization: autoOrganization.organization,\n member: autoOrganization.member,\n actor: userSummary,\n });\n }\n\n return {\n id: id.valueOf(),\n email,\n role,\n };\n })\n .build();\n };\n\n return {\n /**\n * Create a user without email uniqueness checks or session creation.\n */\n createUserUnvalidated,\n /**\n * Fetch a user by email with password hash metadata.\n */\n getUserByEmail: function (this: AuthServiceContext, email: string) {\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findFirst(\"user\", (b) =>\n b.whereIndex(\"idx_user_email\", (eb) => eb(\"email\", \"=\", email)),\n ),\n )\n .transformRetrieve(([user]) =>\n user\n ? {\n id: user.id.valueOf(),\n email: user.email,\n passwordHash: user.passwordHash ?? null,\n role: user.role as \"user\" | \"admin\",\n }\n : null,\n )\n .build();\n },\n /**\n * Update a user's role without session enforcement.\n */\n updateUserRole: function (this: AuthServiceContext, userId: string, role: \"user\" | \"admin\") {\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findFirst(\"user\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", userId))),\n )\n .mutate(({ uow, retrieveResult: [user] }) => {\n uow.update(\"user\", userId, (b) => b.set({ role }));\n\n if (user) {\n uow.triggerHook(\"onUserRoleUpdated\", {\n user: mapUserSummary({\n id: userId,\n email: user.email,\n role,\n bannedAt: user.bannedAt ?? null,\n }),\n actor: null,\n });\n }\n return { success: true };\n })\n .build();\n },\n /**\n * Update a user's password hash without session enforcement.\n */\n updateUserPassword: function (this: AuthServiceContext, userId: string, passwordHash: string) {\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findFirst(\"user\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", userId))),\n )\n .mutate(({ uow, retrieveResult: [user] }) => {\n uow.update(\"user\", userId, (b) => b.set({ passwordHash }));\n\n if (user) {\n uow.triggerHook(\"onUserPasswordChanged\", {\n user: mapUserSummary({\n id: userId,\n email: user.email,\n role: user.role,\n bannedAt: user.bannedAt ?? null,\n }),\n actor: null,\n });\n }\n return { success: true };\n })\n .build();\n },\n /**\n * Create a user and session for email/password sign-up.\n */\n signUpWithSession: function (\n this: AuthServiceContext,\n email: string,\n passwordHash: string,\n autoCreateOptions?: AutoCreateOrganizationOptions,\n ) {\n const expiresAt = new Date();\n expiresAt.setDate(expiresAt.getDate() + 30); // 30 days from now\n\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findFirst(\"user\", (b) =>\n b.whereIndex(\"idx_user_email\", (eb) => eb(\"email\", \"=\", email)),\n ),\n )\n .mutate(({ uow, retrieveResult: [existingUser] }) => {\n if (existingUser) {\n return { ok: false as const, code: \"email_already_exists\" as const };\n }\n\n const now = new Date();\n runBeforeCreateUser(email, \"user\");\n\n const userId = uow.create(\"user\", {\n email,\n passwordHash,\n role: \"user\",\n });\n\n const autoOrganization = createAutoOrganization(uow, {\n userId: userId.valueOf(),\n email,\n now,\n options: autoCreateOptions ?? options,\n });\n\n const sessionId = uow.create(\"session\", {\n userId,\n activeOrganizationId: autoOrganization?.organization.id ?? null,\n expiresAt,\n });\n const userSummary = mapUserSummary({\n id: userId.valueOf(),\n email,\n role: \"user\",\n bannedAt: null,\n });\n\n uow.triggerHook(\"onUserCreated\", {\n user: userSummary,\n actor: userSummary,\n });\n uow.triggerHook(\"onSessionCreated\", {\n session: {\n id: sessionId.valueOf(),\n user: userSummary,\n expiresAt,\n activeOrganizationId: autoOrganization?.organization.id ?? null,\n },\n actor: userSummary,\n });\n\n if (autoOrganization) {\n uow.triggerHook(\"onOrganizationCreated\", {\n organization: autoOrganization.organization,\n actor: userSummary,\n });\n uow.triggerHook(\"onMemberAdded\", {\n organization: autoOrganization.organization,\n member: autoOrganization.member,\n actor: userSummary,\n });\n }\n\n return {\n ok: true as const,\n sessionId: sessionId.valueOf(),\n userId: userId.valueOf(),\n email,\n role: \"user\" as const,\n };\n })\n .build();\n },\n /**\n * Update a user's role with admin session enforcement.\n */\n updateUserRoleWithSession: function (\n this: AuthServiceContext,\n sessionId: string,\n userId: string,\n role: \"user\" | \"admin\",\n ) {\n const now = new Date();\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow\n .findFirst(\"session\", (b) =>\n b\n .whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", sessionId))\n .join((j) => j.sessionOwner((b) => b.select([\"id\", \"email\", \"role\", \"bannedAt\"]))),\n )\n .findFirst(\"user\", (b) => b.whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", userId))),\n )\n .mutate(({ uow, retrieveResult: [session, user] }) => {\n if (!session || !session.sessionOwner) {\n return { ok: false as const, code: \"session_invalid\" as const };\n }\n\n if (session.expiresAt < now) {\n uow.delete(\"session\", session.id, (b) => b.check());\n return { ok: false as const, code: \"session_invalid\" as const };\n }\n\n if (session.sessionOwner.role !== \"admin\") {\n return { ok: false as const, code: \"permission_denied\" as const };\n }\n\n uow.update(\"user\", userId, (b) => b.set({ role }));\n\n if (user) {\n const actorSummary = mapUserSummary({\n id: session.sessionOwner.id,\n email: session.sessionOwner.email,\n role: session.sessionOwner.role,\n bannedAt: session.sessionOwner.bannedAt ?? null,\n });\n uow.triggerHook(\"onUserRoleUpdated\", {\n user: mapUserSummary({\n id: userId,\n email: user.email,\n role,\n bannedAt: user.bannedAt ?? null,\n }),\n actor: actorSummary,\n });\n }\n return { ok: true as const };\n })\n .build();\n },\n /**\n * Change the current session user's password.\n */\n changePasswordWithSession: function (\n this: AuthServiceContext,\n sessionId: string,\n passwordHash: string,\n ) {\n const now = new Date();\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findFirst(\"session\", (b) =>\n b\n .whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", sessionId))\n .join((j) => j.sessionOwner((b) => b.select([\"id\", \"email\", \"role\", \"bannedAt\"]))),\n ),\n )\n .mutate(({ uow, retrieveResult: [session] }) => {\n if (!session || !session.sessionOwner) {\n return { ok: false as const, code: \"session_invalid\" as const };\n }\n\n if (session.expiresAt < now) {\n uow.delete(\"session\", session.id, (b) => b.check());\n return { ok: false as const, code: \"session_invalid\" as const };\n }\n\n uow.update(\"user\", session.sessionOwner.id, (b) => b.set({ passwordHash }).check());\n const actorSummary = mapUserSummary({\n id: session.sessionOwner.id,\n email: session.sessionOwner.email,\n role: session.sessionOwner.role,\n bannedAt: session.sessionOwner.bannedAt ?? null,\n });\n uow.triggerHook(\"onUserPasswordChanged\", {\n user: actorSummary,\n actor: actorSummary,\n });\n return { ok: true as const };\n })\n .build();\n },\n };\n}\n\nexport const userActionsRoutesFactory = defineRoutes<typeof authFragmentDefinition>().create(\n ({ services, config }) => {\n const emailAndPasswordEnabled = config.emailAndPassword?.enabled !== false;\n\n return [\n defineRoute({\n method: \"PATCH\",\n path: \"/users/:userId/role\",\n inputSchema: z.object({\n role: z.enum([\"user\", \"admin\"]),\n }),\n outputSchema: z.object({\n success: z.boolean(),\n }),\n errorCodes: [\"invalid_input\", \"session_invalid\", \"permission_denied\"],\n handler: async function ({ input, pathParams, headers, query }, { json, error }) {\n const { role } = await input.valid();\n const { userId } = pathParams;\n\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [services.updateUserRoleWithSession(sessionId, userId, role)])\n .execute();\n\n if (!result.ok) {\n if (result.code === \"permission_denied\") {\n return error({ message: \"Unauthorized\", code: \"permission_denied\" }, 401);\n }\n\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return json({ success: true });\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/sign-up\",\n inputSchema: z.object({\n email: z.email(),\n password: z.string().min(8).max(100),\n }),\n outputSchema: z.object({\n sessionId: z.string(),\n userId: z.string(),\n email: z.string(),\n role: z.enum([\"user\", \"admin\"]),\n }),\n errorCodes: [\"email_already_exists\", \"invalid_input\", \"email_password_disabled\"],\n handler: async function ({ input }, { json, error }) {\n if (!emailAndPasswordEnabled) {\n return error(\n { message: \"Email/password auth is disabled\", code: \"email_password_disabled\" },\n 403,\n );\n }\n\n const { email, password } = await input.valid();\n\n const passwordHash = await hashPassword(password);\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [services.signUpWithSession(email, passwordHash)])\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Email already exists\", code: \"email_already_exists\" }, 400);\n }\n\n // Build response with Set-Cookie header\n const setCookieHeader = buildSetCookieHeader(result.sessionId, config.cookieOptions);\n\n return json(\n {\n sessionId: result.sessionId,\n userId: result.userId,\n email: result.email,\n role: result.role,\n },\n {\n headers: {\n \"Set-Cookie\": setCookieHeader,\n },\n },\n );\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/sign-in\",\n inputSchema: z.object({\n email: z.email(),\n password: z.string().min(8).max(100),\n session: sessionSeedSchema.optional(),\n }),\n outputSchema: z.object({\n sessionId: z.string(),\n userId: z.string(),\n email: z.string(),\n role: z.enum([\"user\", \"admin\"]),\n }),\n errorCodes: [\"invalid_credentials\", \"user_banned\", \"email_password_disabled\"],\n handler: async function ({ input }, { json, error }) {\n if (!emailAndPasswordEnabled) {\n return error(\n { message: \"Email/password auth is disabled\", code: \"email_password_disabled\" },\n 403,\n );\n }\n\n const { email, password, session } = await input.valid();\n let passwordCheck:\n | { ok: true }\n | { ok: false; code: \"invalid_credentials\" | \"user_banned\" }\n | null = null;\n\n const result = await this.handlerTx({\n onAfterRetrieve: async (_uow, results) => {\n const firstResult = Array.isArray(results[0]) ? results[0] : [];\n const user = (firstResult[0] ?? null) as {\n passwordHash?: string | null;\n bannedAt?: Date | null;\n } | null;\n\n if (!user?.passwordHash) {\n passwordCheck = { ok: false, code: \"invalid_credentials\" };\n return;\n }\n\n const isValid = await verifyPassword(password, user.passwordHash);\n if (!isValid) {\n passwordCheck = { ok: false, code: \"invalid_credentials\" };\n return;\n }\n\n if (user.bannedAt) {\n passwordCheck = { ok: false, code: \"user_banned\" };\n return;\n }\n\n passwordCheck = { ok: true };\n },\n })\n .retrieve(({ forSchema }) =>\n forSchema(authSchema).find(\"user\", (b) =>\n b\n .whereIndex(\"idx_user_email\", (eb) => eb(\"email\", \"=\", email))\n .join((j) =>\n j[\"userOrganizationMembers\"]((member) =>\n member\n .select([\"createdAt\"])\n .join((j) =>\n j[\"organizationMemberOrganization\"]((organization) =>\n organization.select([\"id\", \"deletedAt\"]),\n ),\n ),\n ),\n ),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [users] }) => {\n const user = users[0] ?? null;\n if (!user || !passwordCheck) {\n return { ok: false as const, code: \"invalid_credentials\" as const };\n }\n\n if (!passwordCheck.ok) {\n return { ok: false as const, code: passwordCheck.code };\n }\n\n const uow = forSchema(authSchema);\n // TODO: Use services.createSession instead of inline session creation (sign-up and\n // handleOAuthCallback also duplicate this logic)\n const expiresAt = uow.now().plus({ days: 30 });\n const resolvedSessionSeed = resolveSessionSeedFromMembers(\n collectSessionSeedMembers(users),\n session,\n );\n const activeOrganizationId = resolvedSessionSeed.activeOrganizationId;\n const sessionId = uow.create(\"session\", {\n userId: user.id,\n activeOrganizationId,\n expiresAt,\n });\n const userSummary = mapUserSummary({\n id: user.id.valueOf(),\n email: user.email,\n role: user.role,\n bannedAt: user.bannedAt ?? null,\n });\n\n uow.triggerHook(\"onSessionCreated\", {\n session: {\n id: sessionId.valueOf(),\n user: userSummary,\n expiresAt,\n activeOrganizationId,\n },\n actor: userSummary,\n });\n\n return {\n ok: true as const,\n sessionId: sessionId.valueOf(),\n user: userSummary,\n };\n })\n .execute();\n\n if (!result.ok) {\n if (result.code === \"user_banned\") {\n return error({ message: \"User is banned\", code: \"user_banned\" }, 403);\n }\n return error({ message: \"Invalid credentials\", code: \"invalid_credentials\" }, 401);\n }\n\n const sessionId = result.sessionId;\n const setCookieHeader = buildSetCookieHeader(sessionId, config.cookieOptions);\n\n return json(\n {\n sessionId,\n userId: result.user.id,\n email: result.user.email,\n role: result.user.role,\n },\n {\n headers: {\n \"Set-Cookie\": setCookieHeader,\n },\n },\n );\n },\n }),\n\n defineRoute({\n method: \"POST\",\n path: \"/change-password\",\n inputSchema: z.object({\n newPassword: z.string().min(8).max(100),\n }),\n outputSchema: z.object({\n success: z.boolean(),\n }),\n errorCodes: [\"session_invalid\"],\n handler: async function ({ input, headers, query }, { json, error }) {\n const { newPassword } = await input.valid();\n\n const sessionId = extractSessionId(headers, query.get(\"sessionId\"));\n\n if (!sessionId) {\n return error({ message: \"Session ID required\", code: \"session_invalid\" }, 400);\n }\n\n const passwordHash = await hashPassword(newPassword);\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [services.changePasswordWithSession(sessionId, passwordHash)])\n .execute();\n\n if (!result.ok) {\n return error({ message: \"Invalid session\", code: \"session_invalid\" }, 401);\n }\n\n return json({ success: true });\n },\n }),\n ];\n },\n);\n","import { type Cursor, decodeCursor } from \"@fragno-dev/db/cursor\";\nimport { z } from \"zod\";\n\nimport { defineRoute, defineRoutes } from \"@fragno-dev/core\";\nimport type { DatabaseServiceContext } from \"@fragno-dev/db\";\n\nimport type { authFragmentDefinition } from \"..\";\nimport { authSchema } from \"../schema\";\n\nexport type SortField = \"email\" | \"createdAt\";\nexport type SortOrder = \"asc\" | \"desc\";\n\nexport interface GetUsersParams {\n search?: string;\n sortBy: SortField;\n sortOrder: SortOrder;\n pageSize: number;\n cursor?: Cursor;\n}\n\nexport interface UserResult {\n id: string;\n email: string;\n role: \"user\" | \"admin\";\n createdAt: Date;\n}\n\ntype AuthServiceContext = DatabaseServiceContext<{}>;\n\nexport function createUserOverviewServices() {\n const mapUser = (user: {\n id: unknown;\n email: string;\n role: string;\n createdAt: Date;\n }): UserResult => ({\n id: String(user.id),\n email: user.email,\n role: user.role as \"user\" | \"admin\",\n createdAt: user.createdAt,\n });\n\n return {\n /**\n * List users with cursor-based pagination, optional search, and sorting.\n */\n getUsersWithCursor: function (this: AuthServiceContext, params: GetUsersParams) {\n const { search, sortBy, sortOrder, pageSize, cursor } = params;\n\n // Determine which index to use based on search and sortBy\n // When searching, only email sorting is allowed (search uses email index)\n const effectiveSortBy: SortField = search ? \"email\" : sortBy;\n const indexName = effectiveSortBy === \"email\" ? \"idx_user_email\" : \"idx_user_createdAt\";\n\n // If cursor is provided, extract its metadata to ensure consistency\n const effectiveSortOrder = cursor ? cursor.orderDirection : sortOrder;\n const effectivePageSize = cursor ? cursor.pageSize : pageSize;\n\n return this.serviceTx(authSchema)\n .retrieve((uow) =>\n uow.findWithCursor(\"user\", (b) => {\n // When searching, we must filter by email and can only use the email index\n if (search) {\n const query = b\n .whereIndex(\"idx_user_email\", (eb) => eb(\"email\", \"contains\", search))\n .orderByIndex(\"idx_user_email\", effectiveSortOrder)\n .pageSize(effectivePageSize);\n\n // Add cursor for pagination continuation\n return cursor ? query.after(cursor) : query;\n }\n\n // When not searching, use the appropriate index for sorting\n const query = b\n .whereIndex(indexName)\n .orderByIndex(indexName, effectiveSortOrder)\n .pageSize(effectivePageSize);\n\n // Add cursor for pagination continuation\n return cursor ? query.after(cursor) : query;\n }),\n )\n .transformRetrieve(([result]) => ({\n users: result.items.map(mapUser),\n cursor: result.cursor,\n hasNextPage: result.hasNextPage,\n }))\n .build();\n },\n };\n}\n\nconst sortBySchema = z.enum([\"email\", \"createdAt\"]);\nconst sortOrderSchema = z.enum([\"asc\", \"desc\"]);\n\nexport const userOverviewRoutesFactory = defineRoutes<typeof authFragmentDefinition>().create(\n ({ services }) => {\n const querySchema = z.object({\n search: z.string().optional(),\n sortBy: sortBySchema.default(\"createdAt\"),\n sortOrder: sortOrderSchema.default(\"desc\"),\n pageSize: z.coerce.number().int().min(1).max(100).default(20),\n });\n\n const parseCursor = (cursorParam: string | null): Cursor | undefined => {\n if (!cursorParam) {\n return undefined;\n }\n try {\n return decodeCursor(cursorParam);\n } catch {\n return undefined;\n }\n };\n\n return [\n defineRoute({\n method: \"GET\",\n path: \"/users\",\n queryParameters: [\"search\", \"sortBy\", \"sortOrder\", \"pageSize\", \"cursor\"],\n outputSchema: z.object({\n users: z.array(\n z.object({\n id: z.string(),\n email: z.string(),\n role: z.enum([\"user\", \"admin\"]),\n createdAt: z.string(),\n }),\n ),\n cursor: z.string().optional(),\n hasNextPage: z.boolean(),\n sortBy: sortBySchema,\n }),\n errorCodes: [\"invalid_input\"],\n handler: async function ({ query }, { json, error }) {\n const parsed = querySchema.safeParse(Object.fromEntries(query.entries()));\n if (!parsed.success) {\n return error({ message: \"Invalid query parameters\", code: \"invalid_input\" }, 400);\n }\n\n const rawSearch = parsed.data.search?.trim();\n const search = rawSearch ? rawSearch : undefined;\n const sortBy: SortField = search ? \"email\" : parsed.data.sortBy;\n const params = {\n search,\n sortBy,\n sortOrder: parsed.data.sortOrder as SortOrder,\n pageSize: parsed.data.pageSize,\n };\n const cursor = parseCursor(query.get(\"cursor\"));\n\n const [result] = await this.handlerTx()\n .withServiceCalls(() => [services.getUsersWithCursor({ ...params, cursor })])\n .execute();\n\n return json({\n users: result.users.map((user) => ({\n id: user.id,\n email: user.email,\n role: user.role,\n createdAt: user.createdAt.toISOString(),\n })),\n cursor: result.cursor?.encode(),\n hasNextPage: result.hasNextPage,\n sortBy: params.sortBy, // Return the actual sortBy used (may differ from requested)\n });\n },\n }),\n ];\n },\n);\n","import { bytesToBase64Url, randomBytes } from \"../utils/crypto\";\nimport type { AnyOAuthProvider, AuthOAuthConfig, OAuth2Tokens } from \"./types\";\n\nexport const DEFAULT_STATE_TTL_MS = 10 * 60 * 1000;\n\nexport const createOAuthState = (bytes = 32): string => {\n return bytesToBase64Url(randomBytes(bytes));\n};\n\nexport const createAuthorizationURL = (params: {\n authorizationEndpoint: string;\n clientId: string;\n redirectURI: string;\n state: string;\n scopes?: string[];\n prompt?: string;\n loginHint?: string;\n codeChallenge?: string;\n codeChallengeMethod?: \"S256\" | \"plain\";\n extraParams?: Record<string, string | undefined>;\n}): URL => {\n const url = new URL(params.authorizationEndpoint);\n url.searchParams.set(\"response_type\", \"code\");\n url.searchParams.set(\"client_id\", params.clientId);\n url.searchParams.set(\"redirect_uri\", params.redirectURI);\n url.searchParams.set(\"state\", params.state);\n\n if (params.scopes && params.scopes.length > 0) {\n url.searchParams.set(\"scope\", params.scopes.join(\" \"));\n }\n\n if (params.prompt) {\n url.searchParams.set(\"prompt\", params.prompt);\n }\n\n if (params.loginHint) {\n url.searchParams.set(\"login_hint\", params.loginHint);\n }\n\n if (params.codeChallenge) {\n url.searchParams.set(\"code_challenge\", params.codeChallenge);\n url.searchParams.set(\"code_challenge_method\", params.codeChallengeMethod ?? \"S256\");\n }\n\n if (params.extraParams) {\n for (const [key, value] of Object.entries(params.extraParams)) {\n if (typeof value === \"string\" && value.length > 0) {\n url.searchParams.set(key, value);\n }\n }\n }\n\n return url;\n};\n\nconst parseScopes = (scopeValue: unknown): string[] | undefined => {\n if (typeof scopeValue !== \"string\") {\n return undefined;\n }\n const scopes = scopeValue\n .split(/[,\\s]+/)\n .map((scope) => scope.trim())\n .filter(Boolean);\n return scopes.length > 0 ? scopes : undefined;\n};\n\nconst readNumber = (value: unknown): number | undefined => {\n if (typeof value === \"number\") {\n return Number.isFinite(value) ? value : undefined;\n }\n if (typeof value === \"string\") {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n};\n\nexport const normalizeOAuthTokens = (response: Record<string, unknown>): OAuth2Tokens => {\n const accessToken =\n typeof response[\"access_token\"] === \"string\" ? response[\"access_token\"] : undefined;\n const refreshToken =\n typeof response[\"refresh_token\"] === \"string\" ? response[\"refresh_token\"] : undefined;\n const tokenType = typeof response[\"token_type\"] === \"string\" ? response[\"token_type\"] : undefined;\n const idToken = typeof response[\"id_token\"] === \"string\" ? response[\"id_token\"] : undefined;\n\n const expiresIn = readNumber(response[\"expires_in\"]);\n const accessTokenExpiresAt = expiresIn ? new Date(Date.now() + expiresIn * 1000) : undefined;\n\n return {\n accessToken,\n refreshToken,\n tokenType,\n idToken,\n accessTokenExpiresAt,\n scopes: parseScopes(response[\"scope\"]),\n raw: response,\n };\n};\n\nexport const parseOAuthTokenResponse = async (\n response: Response,\n): Promise<\n | {\n ok: true;\n data: Record<string, unknown>;\n }\n | {\n ok: false;\n status: number;\n error: string;\n data?: unknown;\n }\n> => {\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n const status = response.status;\n\n let data: unknown;\n try {\n if (contentType.includes(\"application/json\")) {\n data = await response.json();\n } else {\n const text = await response.text();\n data = Object.fromEntries(new URLSearchParams(text));\n }\n } catch (err) {\n return {\n ok: false,\n status,\n error: err instanceof Error ? err.message : \"Invalid token response\",\n };\n }\n\n if (!response.ok) {\n const message =\n typeof (data as { error_description?: string }).error_description === \"string\"\n ? (data as { error_description?: string }).error_description!\n : typeof (data as { error?: string }).error === \"string\"\n ? (data as { error?: string }).error!\n : `Token request failed with status ${status}`;\n return {\n ok: false,\n status,\n error: message,\n data,\n };\n }\n\n if (!data || typeof data !== \"object\") {\n return {\n ok: false,\n status,\n error: \"Token response was empty\",\n };\n }\n\n return {\n ok: true,\n data: data as Record<string, unknown>,\n };\n};\n\nexport const normalizeOAuthProvider = (provider: AnyOAuthProvider): AnyOAuthProvider => {\n const providerOptions = provider.options;\n if (!providerOptions) {\n return provider;\n }\n\n const disableSignUp = provider.disableSignUp ?? providerOptions.disableSignUp;\n const disableImplicitSignUp =\n provider.disableImplicitSignUp ?? providerOptions.disableImplicitSignUp;\n\n if (\n disableSignUp === provider.disableSignUp &&\n disableImplicitSignUp === provider.disableImplicitSignUp\n ) {\n return provider;\n }\n\n return {\n ...provider,\n disableSignUp,\n disableImplicitSignUp,\n };\n};\n\nexport const normalizeOAuthConfig = (config?: AuthOAuthConfig): AuthOAuthConfig | undefined => {\n if (!config) {\n return config;\n }\n\n const entries = Object.entries(config.providers);\n let changed = false;\n const normalizedProviders: Record<string, AnyOAuthProvider> = {};\n\n for (const [key, provider] of entries) {\n const normalized = normalizeOAuthProvider(provider);\n normalizedProviders[key] = normalized;\n if (normalized !== provider) {\n changed = true;\n }\n }\n\n if (!changed) {\n return config;\n }\n\n return {\n ...config,\n providers: normalizedProviders,\n };\n};\n","import type { OAuthProvider, ProviderOptions, OAuth2Tokens } from \"../../types\";\nimport { createAuthorizationURL, normalizeOAuthTokens, parseOAuthTokenResponse } from \"../../utils\";\nimport type { GithubOAuthClient } from \"./client\";\n\nexport interface GithubProfile {\n login: string;\n id: string;\n node_id: string;\n avatar_url: string;\n gravatar_id: string;\n url: string;\n html_url: string;\n followers_url: string;\n following_url: string;\n gists_url: string;\n starred_url: string;\n subscriptions_url: string;\n organizations_url: string;\n repos_url: string;\n events_url: string;\n received_events_url: string;\n type: string;\n site_admin: boolean;\n name: string;\n company: string;\n blog: string;\n location: string;\n email: string;\n hireable: boolean;\n bio: string;\n twitter_username: string;\n public_repos: string;\n public_gists: string;\n followers: string;\n following: string;\n created_at: string;\n updated_at: string;\n private_gists: string;\n total_private_repos: string;\n owned_private_repos: string;\n disk_usage: string;\n collaborators: string;\n two_factor_authentication: boolean;\n plan: {\n name: string;\n space: string;\n private_repos: string;\n collaborators: string;\n };\n}\n\nexport type GithubEmail = {\n email: string;\n primary: boolean;\n verified: boolean;\n visibility: \"public\" | \"private\";\n};\n\nexport interface GithubOptions extends ProviderOptions<GithubProfile> {\n clientId: string;\n clientSecret: string;\n client?: GithubOAuthClient;\n}\n\nconst defaultScopes = [\"read:user\", \"user:email\"];\nconst defaultUserAgent = \"fragno-auth\";\nconst tokenEndpoint = \"https://github.com/login/oauth/access_token\";\nconst profileEndpoint = \"https://api.github.com/user\";\nconst emailsEndpoint = \"https://api.github.com/user/emails\";\n\nexport const createGithubOAuthClient = (options?: {\n fetcher?: typeof fetch;\n userAgent?: string;\n}): GithubOAuthClient => {\n const fetcher = options?.fetcher ?? fetch;\n const userAgent = options?.userAgent ?? defaultUserAgent;\n\n return {\n exchangeCode: async ({ code, redirectURI, clientId, clientSecret, codeVerifier }) => {\n const body = new URLSearchParams({\n client_id: clientId,\n client_secret: clientSecret,\n code,\n redirect_uri: redirectURI,\n });\n if (codeVerifier) {\n body.set(\"code_verifier\", codeVerifier);\n }\n\n const response = await fetcher(tokenEndpoint, {\n method: \"POST\",\n headers: {\n accept: \"application/json\",\n \"content-type\": \"application/x-www-form-urlencoded\",\n },\n body,\n });\n\n const parsed = await parseOAuthTokenResponse(response);\n if (!parsed.ok) {\n return null;\n }\n\n return normalizeOAuthTokens(parsed.data);\n },\n fetchProfile: async (accessToken: string) => {\n const response = await fetcher(profileEndpoint, {\n headers: {\n \"User-Agent\": userAgent,\n authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n return null;\n }\n\n return (await response.json()) as GithubProfile;\n },\n fetchEmails: async (accessToken: string) => {\n const response = await fetcher(emailsEndpoint, {\n headers: {\n \"User-Agent\": userAgent,\n authorization: `Bearer ${accessToken}`,\n },\n });\n\n if (!response.ok) {\n return [];\n }\n\n return (await response.json()) as GithubEmail[];\n },\n };\n};\n\nexport const github = (options: GithubOptions) => {\n const client = options.client ?? createGithubOAuthClient();\n const authorizationEndpoint =\n options.authorizationEndpoint ?? \"https://github.com/login/oauth/authorize\";\n\n return {\n id: \"github\",\n name: \"GitHub\",\n options,\n createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {\n const resolvedScopes = options.disableDefaultScope ? [] : [...defaultScopes];\n if (options.scope) {\n resolvedScopes.push(...options.scope);\n }\n if (scopes) {\n resolvedScopes.push(...scopes);\n }\n\n return createAuthorizationURL({\n authorizationEndpoint,\n clientId: options.clientId,\n redirectURI,\n state,\n scopes: resolvedScopes,\n prompt: options.prompt,\n loginHint: loginHint ?? undefined,\n extraParams: loginHint ? { login: loginHint } : undefined,\n });\n },\n validateAuthorizationCode: async ({ code, redirectURI, codeVerifier }) => {\n return client.exchangeCode({\n code,\n redirectURI: redirectURI,\n clientId: options.clientId,\n clientSecret: options.clientSecret,\n codeVerifier,\n });\n },\n refreshAccessToken: options.refreshAccessToken,\n async getUserInfo(token: OAuth2Tokens) {\n if (options.getUserInfo) {\n return options.getUserInfo(token);\n }\n\n if (!token.accessToken) {\n return null;\n }\n\n const profile = await client.fetchProfile(token.accessToken);\n if (!profile) {\n return null;\n }\n\n const emails = await client.fetchEmails(token.accessToken);\n\n if (!profile.email && emails.length > 0) {\n profile.email = (emails.find((entry) => entry.primary) ?? emails[0])?.email as string;\n }\n\n const emailVerified =\n emails.find((entry) => entry.email === profile.email)?.verified ?? false;\n\n const mapped = await options.mapProfileToUser?.(profile);\n\n return {\n user: {\n id: profile.id,\n name: profile.name || profile.login,\n email: profile.email ?? null,\n image: profile.avatar_url,\n emailVerified,\n ...mapped,\n },\n data: profile,\n };\n },\n } satisfies OAuthProvider<GithubProfile>;\n};\n","import { createClientBuilder, type FragnoPublicClientConfig } from \"@fragno-dev/core/client\";\n\nimport { defineFragment, instantiate } from \"@fragno-dev/core\";\nimport { withDatabase, type FragnoPublicConfigWithDatabase } from \"@fragno-dev/db\";\n\nimport {\n clearDefaultOrganizationId,\n createDefaultOrganizationPreferenceState,\n DEFAULT_ORGANIZATION_CHANGE_EVENT,\n DEFAULT_ORGANIZATION_STORAGE_KEY,\n findOrganizationEntry,\n getDefaultOrganizationChangeEventName,\n getDefaultOrganizationStorageKey,\n NO_ORGANIZATIONS_ERROR_MESSAGE,\n readDefaultOrganizationId,\n resolveDefaultOrganization,\n setDefaultOrganizationForMe,\n subscribeToDefaultOrganizationPreference,\n syncDefaultOrganizationPreference,\n writeDefaultOrganizationId,\n type AuthMeLike as AuthDefaultOrganizationMeLike,\n type DefaultOrganizationEntry as AuthDefaultOrganizationEntry,\n type DefaultOrganizationResolution as AuthDefaultOrganizationResolution,\n type DefaultOrganizationResolutionStatus,\n} from \"./client/default-organization\";\nimport type {\n AuthHooks,\n AuthHooksMap,\n BeforeCreateUserHook,\n InvitationExpiredHookPayload,\n SessionHookPayload,\n UserHookPayload,\n} from \"./hooks\";\nimport { createOAuthServices } from \"./oauth/oauth-services\";\nimport { oauthRoutesFactory } from \"./oauth/routes\";\nimport type { AuthOAuthConfig } from \"./oauth/types\";\nimport { createActiveOrganizationServices } from \"./organization/active-organization\";\nimport { createOrganizationInvitationServices } from \"./organization/invitation-services\";\nimport { createOrganizationMemberServices } from \"./organization/member-services\";\nimport { createOrganizationServices } from \"./organization/organization-services\";\nimport { organizationRoutesFactory } from \"./organization/routes\";\nimport type {\n DefaultOrganizationRole,\n OrganizationConfig,\n OrganizationHookPayload,\n OrganizationHooks,\n OrganizationInvitationHookPayload,\n OrganizationMemberHookPayload,\n OrganizationInvitationStatus,\n} from \"./organization/types\";\nimport { toExternalId } from \"./organization/utils\";\nimport { authSchema } from \"./schema\";\nimport { createSessionServices, sessionRoutesFactory } from \"./session/session\";\nimport { serializeSessionSeedForQuery } from \"./session/session-seed\";\nimport type { Role } from \"./types\";\nimport { createUserServices, userActionsRoutesFactory } from \"./user/user-actions\";\nimport {\n createUserOverviewServices,\n userOverviewRoutesFactory,\n type GetUsersParams,\n type UserResult,\n type SortField,\n type SortOrder,\n} from \"./user/user-overview\";\nimport type { CookieOptions } from \"./utils/cookie\";\n\nexport interface AuthConfig<TRole extends string = DefaultOrganizationRole> {\n cookieOptions?: CookieOptions;\n hooks?: AuthHooks;\n beforeCreateUser?: BeforeCreateUserHook;\n organizations?: OrganizationConfig<TRole> | false;\n emailAndPassword?: {\n enabled?: boolean;\n };\n oauth?: AuthOAuthConfig;\n}\n\nexport const authFragmentDefinition = defineFragment<AuthConfig>(\"auth\")\n .extend(withDatabase(authSchema))\n .provideHooks<AuthHooksMap>(({ defineHook, config }) => {\n const authHooks = config.hooks;\n const organizationConfig = config.organizations === false ? undefined : config.organizations;\n const organizationHooks = organizationConfig?.hooks as OrganizationHooks<string> | undefined;\n\n const mapOrganization = (organization: {\n id: unknown;\n name: string;\n slug: string;\n logoUrl: string | null;\n metadata: unknown;\n createdBy: unknown;\n organizationCreator?: { id?: unknown } | null;\n createdAt: Date;\n updatedAt: Date;\n deletedAt: Date | null;\n }) => ({\n id: toExternalId(organization.id),\n name: organization.name,\n slug: organization.slug,\n logoUrl: organization.logoUrl ?? null,\n metadata: (organization.metadata ?? null) as Record<string, unknown> | null,\n createdBy: toExternalId(organization.organizationCreator?.id ?? organization.createdBy),\n createdAt: organization.createdAt,\n updatedAt: organization.updatedAt,\n deletedAt: organization.deletedAt ?? null,\n });\n\n const mapInvitation = (invitation: {\n id: unknown;\n organizationId: unknown;\n email: string;\n roles: unknown;\n status: string;\n token: string;\n inviterId: unknown;\n expiresAt: Date;\n createdAt: Date;\n respondedAt: Date | null;\n }) => ({\n id: toExternalId(invitation.id),\n organizationId: toExternalId(invitation.organizationId),\n email: invitation.email,\n roles: Array.isArray(invitation.roles) ? (invitation.roles as string[]) : [],\n status: invitation.status as OrganizationInvitationStatus,\n token: invitation.token,\n inviterId: toExternalId(invitation.inviterId),\n expiresAt: invitation.expiresAt,\n createdAt: invitation.createdAt,\n respondedAt: invitation.respondedAt ?? null,\n });\n\n const baseHooks = {\n onUserCreated: defineHook<UserHookPayload>(async function (payload) {\n await authHooks?.onUserCreated?.(payload);\n }),\n onUserRoleUpdated: defineHook<UserHookPayload>(async function (payload) {\n await authHooks?.onUserRoleUpdated?.(payload);\n }),\n onUserPasswordChanged: defineHook<UserHookPayload>(async function (payload) {\n await authHooks?.onUserPasswordChanged?.(payload);\n }),\n onSessionCreated: defineHook<SessionHookPayload>(async function (payload) {\n await authHooks?.onSessionCreated?.(payload);\n }),\n onSessionInvalidated: defineHook<SessionHookPayload>(async function (payload) {\n await authHooks?.onSessionInvalidated?.(payload);\n }),\n };\n\n return {\n ...baseHooks,\n onOrganizationCreated: defineHook<OrganizationHookPayload>(async function (payload) {\n await organizationHooks?.onOrganizationCreated?.(payload);\n }),\n onOrganizationUpdated: defineHook<OrganizationHookPayload>(async function (payload) {\n await organizationHooks?.onOrganizationUpdated?.(payload);\n }),\n onOrganizationDeleted: defineHook<OrganizationHookPayload>(async function (payload) {\n await organizationHooks?.onOrganizationDeleted?.(payload);\n }),\n onMemberAdded: defineHook<OrganizationMemberHookPayload<string>>(async function (payload) {\n await organizationHooks?.onMemberAdded?.(payload);\n }),\n onMemberRemoved: defineHook<OrganizationMemberHookPayload<string>>(async function (payload) {\n await organizationHooks?.onMemberRemoved?.(payload);\n }),\n onMemberRolesUpdated: defineHook<OrganizationMemberHookPayload<string>>(\n async function (payload) {\n await organizationHooks?.onMemberRolesUpdated?.(payload);\n },\n ),\n onInvitationCreated: defineHook<OrganizationInvitationHookPayload<string>>(\n async function (payload) {\n await organizationHooks?.onInvitationCreated?.(payload);\n },\n ),\n onInvitationAccepted: defineHook<OrganizationInvitationHookPayload<string>>(\n async function (payload) {\n await organizationHooks?.onInvitationAccepted?.(payload);\n },\n ),\n onInvitationRejected: defineHook<OrganizationInvitationHookPayload<string>>(\n async function (payload) {\n await organizationHooks?.onInvitationRejected?.(payload);\n },\n ),\n onInvitationCanceled: defineHook<OrganizationInvitationHookPayload<string>>(\n async function (payload) {\n await organizationHooks?.onInvitationCanceled?.(payload);\n },\n ),\n onInvitationExpired: defineHook<InvitationExpiredHookPayload>(async function (payload) {\n if (!payload.invitationId) {\n return;\n }\n\n const now = new Date();\n const result = await this.handlerTx()\n .retrieve(({ forSchema }) =>\n forSchema(authSchema).findFirst(\"organizationInvitation\", (b) =>\n b\n .whereIndex(\"primary\", (eb) => eb(\"id\", \"=\", payload.invitationId))\n .join((j) =>\n j.organizationInvitationOrganization((org) =>\n org.join((j) => j.organizationCreator()),\n ),\n ),\n ),\n )\n .mutate(({ forSchema, retrieveResult: [invitation] }) => {\n if (!invitation) {\n return { shouldNotify: false as const };\n }\n\n const status = invitation.status as OrganizationInvitationStatus;\n if (status !== \"pending\") {\n return { shouldNotify: false as const };\n }\n\n if (invitation.expiresAt.getTime() > now.getTime()) {\n return { shouldNotify: false as const };\n }\n\n const uow = forSchema(authSchema);\n uow.update(\"organizationInvitation\", invitation.id, (b) =>\n b.set({ status: \"expired\", respondedAt: now }).check(),\n );\n\n if (!invitation.organizationInvitationOrganization) {\n return { shouldNotify: false as const };\n }\n\n return {\n shouldNotify: true as const,\n organization: mapOrganization(invitation.organizationInvitationOrganization),\n invitation: mapInvitation({\n id: invitation.id,\n organizationId: invitation.organizationId,\n email: invitation.email,\n roles: invitation.roles,\n status: \"expired\",\n token: invitation.token,\n inviterId: invitation.inviterId,\n expiresAt: invitation.expiresAt,\n createdAt: invitation.createdAt,\n respondedAt: now,\n }),\n };\n })\n .transform(({ mutateResult }) => mutateResult)\n .execute();\n\n if (result.shouldNotify) {\n await organizationHooks?.onInvitationExpired?.({\n organization: result.organization,\n invitation: result.invitation,\n actor: null,\n });\n }\n }),\n };\n })\n .providesBaseService(({ defineService, config }) => {\n const organizationsEnabled = config.organizations !== false;\n const organizationConfig = config.organizations === false ? undefined : config.organizations;\n\n const organizationConfigResolved = organizationConfig as OrganizationConfig<string> | undefined;\n const autoCreateOptions = organizationsEnabled\n ? {\n autoCreateOrganization:\n organizationConfig && organizationConfig.autoCreateOrganization !== false\n ? organizationConfig.autoCreateOrganization\n : undefined,\n creatorRoles: organizationConfig?.creatorRoles,\n }\n : undefined;\n\n return defineService({\n ...createUserServices(autoCreateOptions, config.beforeCreateUser),\n ...createSessionServices(config.cookieOptions),\n ...createUserOverviewServices(),\n ...createOrganizationServices({\n organizationConfig: organizationConfigResolved,\n }),\n ...createOrganizationMemberServices({\n organizationConfig: organizationConfigResolved,\n }),\n ...createOrganizationInvitationServices({\n organizationConfig: organizationConfigResolved,\n }),\n ...createActiveOrganizationServices(),\n ...createOAuthServices({\n oauth: config.oauth,\n autoCreateOptions,\n beforeCreateUser: config.beforeCreateUser,\n }),\n });\n })\n .build();\n\nexport type AuthFragment = typeof authFragmentDefinition;\n\nexport function createAuthFragment(\n config: AuthConfig = {},\n fragnoConfig: FragnoPublicConfigWithDatabase,\n) {\n const options = {\n ...fragnoConfig,\n // Preserve legacy namespace to avoid changing physical table names.\n databaseNamespace:\n fragnoConfig.databaseNamespace !== undefined\n ? fragnoConfig.databaseNamespace\n : \"simple-auth-db\",\n };\n\n return instantiate(authFragmentDefinition)\n .withConfig(config)\n .withOptions(options)\n .withRoutes([\n userActionsRoutesFactory,\n sessionRoutesFactory,\n userOverviewRoutesFactory,\n organizationRoutesFactory,\n oauthRoutesFactory,\n ])\n .build();\n}\n\nexport function createAuthFragmentClients(fragnoConfig?: FragnoPublicClientConfig) {\n // Note: Cookies are automatically sent for same-origin requests by the browser.\n // For cross-origin requests, you may need to configure CORS headers on the server.\n const config = { ...fragnoConfig };\n\n const b = createClientBuilder(\n authFragmentDefinition,\n config,\n [\n userActionsRoutesFactory,\n sessionRoutesFactory,\n userOverviewRoutesFactory,\n organizationRoutesFactory,\n oauthRoutesFactory,\n ],\n {\n type: \"options\",\n options: {\n credentials: \"include\",\n },\n },\n );\n\n const useMe = b.createHook(\"/me\");\n const useSignUp = b.createMutator(\"POST\", \"/sign-up\");\n const useSignIn = b.createMutator(\"POST\", \"/sign-in\");\n const useSignOut = b.createMutator(\"POST\", \"/sign-out\", (invalidate) => {\n invalidate(\"GET\", \"/me\", {});\n invalidate(\"GET\", \"/users\", {});\n });\n const useUsers = b.createHook(\"/users\");\n const useUpdateUserRole = b.createMutator(\"PATCH\", \"/users/:userId/role\", (invalidate) => {\n invalidate(\"GET\", \"/users\", {});\n invalidate(\"GET\", \"/me\", {});\n });\n const useChangePassword = b.createMutator(\"POST\", \"/change-password\");\n const useOrganizations = b.createHook(\"/organizations\");\n const useOrganization = b.createHook(\"/organizations/:organizationId\");\n const useCreateOrganization = b.createMutator(\"POST\", \"/organizations\", (invalidate) => {\n invalidate(\"GET\", \"/organizations\", {});\n invalidate(\"GET\", \"/organizations/active\", {});\n invalidate(\"GET\", \"/me\", {});\n });\n const useUpdateOrganization = b.createMutator(\n \"PATCH\",\n \"/organizations/:organizationId\",\n (invalidate, params) => {\n const organizationId = params.pathParams.organizationId;\n if (organizationId) {\n invalidate(\"GET\", \"/organizations/:organizationId\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations/:organizationId/members\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations/:organizationId/invitations\", {\n pathParams: { organizationId },\n });\n }\n invalidate(\"GET\", \"/organizations\", {});\n invalidate(\"GET\", \"/organizations/active\", {});\n invalidate(\"GET\", \"/me\", {});\n },\n );\n const useDeleteOrganization = b.createMutator(\n \"DELETE\",\n \"/organizations/:organizationId\",\n (invalidate, params) => {\n const organizationId = params.pathParams.organizationId;\n if (organizationId) {\n invalidate(\"GET\", \"/organizations/:organizationId\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations/:organizationId/members\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations/:organizationId/invitations\", {\n pathParams: { organizationId },\n });\n }\n invalidate(\"GET\", \"/organizations\", {});\n invalidate(\"GET\", \"/organizations/active\", {});\n invalidate(\"GET\", \"/me\", {});\n },\n );\n const useActiveOrganization = b.createHook(\"/organizations/active\");\n const useSetActiveOrganization = b.createMutator(\n \"POST\",\n \"/organizations/active\",\n (invalidate) => {\n invalidate(\"GET\", \"/organizations/active\", {});\n invalidate(\"GET\", \"/me\", {});\n },\n );\n const useOrganizationMembers = b.createHook(\"/organizations/:organizationId/members\");\n const useAddOrganizationMember = b.createMutator(\n \"POST\",\n \"/organizations/:organizationId/members\",\n (invalidate, params) => {\n const organizationId = params.pathParams.organizationId;\n if (!organizationId) {\n return;\n }\n invalidate(\"GET\", \"/organizations/:organizationId/members\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations/:organizationId\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations\", {});\n invalidate(\"GET\", \"/me\", {});\n },\n );\n const useUpdateOrganizationMemberRoles = b.createMutator(\n \"PATCH\",\n \"/organizations/:organizationId/members/:memberId\",\n (invalidate, params) => {\n const organizationId = params.pathParams.organizationId;\n if (!organizationId) {\n return;\n }\n invalidate(\"GET\", \"/organizations/:organizationId/members\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations/:organizationId\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations\", {});\n invalidate(\"GET\", \"/me\", {});\n },\n );\n const useRemoveOrganizationMember = b.createMutator(\n \"DELETE\",\n \"/organizations/:organizationId/members/:memberId\",\n (invalidate, params) => {\n const organizationId = params.pathParams.organizationId;\n if (!organizationId) {\n return;\n }\n invalidate(\"GET\", \"/organizations/:organizationId/members\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations/:organizationId\", {\n pathParams: { organizationId },\n });\n invalidate(\"GET\", \"/organizations\", {});\n invalidate(\"GET\", \"/me\", {});\n },\n );\n const useOrganizationInvitations = b.createHook(\"/organizations/:organizationId/invitations\");\n const useInviteOrganizationMember = b.createMutator(\n \"POST\",\n \"/organizations/:organizationId/invitations\",\n (invalidate, params) => {\n const organizationId = params.pathParams.organizationId;\n if (!organizationId) {\n return;\n }\n invalidate(\"GET\", \"/organizations/:organizationId/invitations\", {\n pathParams: { organizationId },\n });\n },\n );\n const useRespondOrganizationInvitation = b.createMutator(\n \"PATCH\",\n \"/organizations/invitations/:invitationId\",\n (invalidate) => {\n invalidate(\"GET\", \"/organizations/invitations\", {});\n invalidate(\"GET\", \"/organizations\", {});\n invalidate(\"GET\", \"/organizations/active\", {});\n invalidate(\"GET\", \"/me\", {});\n },\n );\n const useUserInvitations = b.createHook(\"/organizations/invitations\");\n const useOAuthAuthorize = b.createHook(\"/oauth/:provider/authorize\");\n const useOAuthCallback = b.createHook(\"/oauth/:provider/callback\");\n const readRawMe = async (params?: { sessionId?: string }) => {\n if (params?.sessionId) {\n return useMe.query({ query: { sessionId: params.sessionId } });\n }\n\n return useMe.query();\n };\n const defaultOrganizationPreference = createDefaultOrganizationPreferenceState({\n meStore: useMe.store(),\n readMe: readRawMe,\n getAccountId: (me) => me.user.id,\n });\n\n return {\n // Reactive hooks - Auth\n useSignUp,\n useSignIn,\n useSignOut,\n useMe,\n useDefaultOrganizationPreference: b.createStore(defaultOrganizationPreference.store),\n useUsers,\n useUpdateUserRole,\n useChangePassword,\n useOrganizations,\n useOrganization,\n useCreateOrganization,\n useUpdateOrganization,\n useDeleteOrganization,\n useActiveOrganization,\n useSetActiveOrganization,\n useOrganizationMembers,\n useAddOrganizationMember,\n useUpdateOrganizationMemberRoles,\n useRemoveOrganizationMember,\n useOrganizationInvitations,\n useInviteOrganizationMember,\n useRespondOrganizationInvitation,\n useUserInvitations,\n useOAuthAuthorize,\n useOAuthCallback,\n\n // Non-reactive methods\n signIn: {\n email: async ({\n email,\n password,\n session,\n rememberMe: _rememberMe,\n }: {\n email: string;\n password: string;\n session?: {\n activeOrganizationId?: string;\n };\n rememberMe?: boolean;\n }) => {\n // Note: rememberMe is accepted but not yet implemented on the backend\n return useSignIn.mutateQuery({\n body: {\n email,\n password,\n session,\n },\n });\n },\n },\n\n signUp: {\n email: async ({ email, password }: { email: string; password: string }) => {\n return useSignUp.mutateQuery({\n body: {\n email,\n password,\n },\n });\n },\n },\n\n signOut: (params?: { sessionId?: string }) => {\n return useSignOut.mutateQuery({\n body: params?.sessionId ? { sessionId: params.sessionId } : {},\n });\n },\n\n me: defaultOrganizationPreference.me,\n\n defaultOrganization: defaultOrganizationPreference.defaultOrganization,\n\n oauth: {\n getAuthorizationUrl: async (params: {\n provider: string;\n returnTo?: string;\n link?: boolean;\n sessionId?: string;\n session?: {\n activeOrganizationId?: string;\n };\n redirectUri?: string;\n scope?: string;\n loginHint?: string;\n }) => {\n return useOAuthAuthorize.query({\n path: { provider: params.provider },\n query: {\n redirectUri: params.redirectUri,\n returnTo: params.returnTo,\n link: params.link ? \"true\" : undefined,\n sessionId: params.sessionId,\n session: serializeSessionSeedForQuery(params.session),\n scope: params.scope,\n loginHint: params.loginHint,\n },\n });\n },\n callback: async (params: {\n provider: string;\n code: string;\n state: string;\n requestSignUp?: boolean;\n }) => {\n return useOAuthCallback.query({\n path: { provider: params.provider },\n query: {\n code: params.code,\n state: params.state,\n requestSignUp: params.requestSignUp ? \"true\" : undefined,\n },\n });\n },\n },\n };\n}\n\nexport type { FragnoRouteConfig } from \"@fragno-dev/core/api\";\nexport type { GetUsersParams, UserResult, SortField, SortOrder };\nexport type AuthMeData = Awaited<ReturnType<ReturnType<typeof createAuthFragmentClients>[\"me\"]>>;\nexport type {\n AuthHooks,\n BeforeCreateUserHook,\n BeforeCreateUserPayload,\n InvitationExpiredHookPayload,\n SessionHookPayload,\n UserHookPayload,\n SessionSummary,\n} from \"./hooks\";\nexport type { UserSummary } from \"./types\";\nexport type {\n AnyOAuthProvider,\n AuthOAuthConfig,\n OAuthProvider,\n OAuth2Tokens,\n OAuth2UserInfo,\n} from \"./oauth/types\";\nexport type { GithubOAuthClient } from \"./oauth/providers/github/client\";\nexport type { GithubEmail, GithubProfile } from \"./oauth/providers/github/github\";\nexport { createGithubOAuthClient, github } from \"./oauth/providers/github/github\";\nexport type {\n AuthMeResponse,\n AutoCreateOrganizationConfig,\n DefaultOrganizationRole,\n Organization,\n OrganizationConfig,\n OrganizationHookPayload,\n OrganizationHooks,\n OrganizationInvitation,\n OrganizationInvitationSummary,\n OrganizationInvitationHookPayload,\n OrganizationInvitationStatus,\n OrganizationMember,\n OrganizationMemberSummary,\n OrganizationMemberHookPayload,\n OrganizationRoleName,\n} from \"./organization/types\";\nexport type { AuthDefaultOrganizationMeLike as AuthMeLike, DefaultOrganizationResolutionStatus };\nexport type DefaultOrganizationEntry<TMe extends AuthDefaultOrganizationMeLike = AuthMeData> =\n AuthDefaultOrganizationEntry<TMe>;\nexport type DefaultOrganizationResolution<TMe extends AuthDefaultOrganizationMeLike = AuthMeData> =\n AuthDefaultOrganizationResolution<TMe>;\nexport type DefaultOrganizationPreferenceStore<\n TMe extends AuthDefaultOrganizationMeLike = AuthMeData,\n> = import(\"./client/default-organization\").DefaultOrganizationPreferenceStore<TMe>;\nexport {\n clearDefaultOrganizationId,\n DEFAULT_ORGANIZATION_CHANGE_EVENT,\n DEFAULT_ORGANIZATION_STORAGE_KEY,\n findOrganizationEntry,\n getDefaultOrganizationChangeEventName,\n getDefaultOrganizationStorageKey,\n NO_ORGANIZATIONS_ERROR_MESSAGE,\n readDefaultOrganizationId,\n resolveDefaultOrganization,\n setDefaultOrganizationForMe,\n subscribeToDefaultOrganizationPreference,\n syncDefaultOrganizationPreference,\n writeDefaultOrganizationId,\n};\n\nexport type { Role };\n"],"mappings":"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"}