@geekapps/auth-nextjs 0.3.10 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.d.ts +25 -1
- package/dist/client.js +34 -0
- package/dist/client.js.map +1 -1
- package/dist/middleware.js.map +1 -1
- package/package.json +1 -1
package/dist/client.d.ts
CHANGED
|
@@ -74,6 +74,22 @@ type OrganizationMember = {
|
|
|
74
74
|
user: User;
|
|
75
75
|
roleAssignments?: RoleAssignment[];
|
|
76
76
|
};
|
|
77
|
+
type OrganizationInvite = {
|
|
78
|
+
id: string;
|
|
79
|
+
organizationId: string;
|
|
80
|
+
email: string;
|
|
81
|
+
roleId?: string | null;
|
|
82
|
+
status: "pending" | "accepted" | "expired" | "revoked";
|
|
83
|
+
expiresAt: string | Date;
|
|
84
|
+
createdAt?: string | Date;
|
|
85
|
+
};
|
|
86
|
+
type MemberInviteInput = {
|
|
87
|
+
email: string;
|
|
88
|
+
roleId?: string;
|
|
89
|
+
};
|
|
90
|
+
type UpdateMemberRoleInput = {
|
|
91
|
+
roleId: string;
|
|
92
|
+
};
|
|
77
93
|
type OrganizationOwnedApplication = {
|
|
78
94
|
id: string;
|
|
79
95
|
name: string;
|
|
@@ -320,6 +336,12 @@ type GeekappsAuthContextValue = {
|
|
|
320
336
|
organizationId?: string | null;
|
|
321
337
|
}) => Promise<UserSession[]>;
|
|
322
338
|
revokeUserSession: (sessionId: string) => Promise<AuthResult<null>>;
|
|
339
|
+
listMembers: (organizationId: string) => Promise<OrganizationMember[]>;
|
|
340
|
+
updateMemberRole: (organizationId: string, memberId: string, input: UpdateMemberRoleInput) => Promise<AuthResult<OrganizationMember>>;
|
|
341
|
+
removeMember: (organizationId: string, memberId: string) => Promise<AuthResult<null>>;
|
|
342
|
+
inviteMember: (organizationId: string, input: MemberInviteInput) => Promise<AuthResult<OrganizationInvite>>;
|
|
343
|
+
listInvites: (organizationId: string) => Promise<OrganizationInvite[]>;
|
|
344
|
+
revokeInvite: (organizationId: string, inviteId: string) => Promise<AuthResult<null>>;
|
|
323
345
|
};
|
|
324
346
|
type UseOrgResult = Pick<GeekappsAuthContextValue, "organizations" | "currentOrg" | "currentOrgId" | "isLoadingOrganizations" | "refreshOrganizations" | "setCurrentOrg" | "createOrganization" | "updateOrganization" | "deleteOrganization" | "hasPermission">;
|
|
325
347
|
type UseAccountsResult = Pick<GeekappsAuthContextValue, "accounts" | "addAccount" | "isLoadingAccounts" | "refreshAccounts" | "switchAccount">;
|
|
@@ -327,6 +349,7 @@ type UseUsersResult = Pick<GeekappsAuthContextValue, "listUsers" | "getUser" | "
|
|
|
327
349
|
type UseRolesResult = Pick<GeekappsAuthContextValue, "listRoles" | "getRole" | "createRole" | "updateRole" | "deleteRole">;
|
|
328
350
|
type UsePermissionsResult = Pick<GeekappsAuthContextValue, "listPermissions" | "createPermission" | "updatePermission" | "deletePermission">;
|
|
329
351
|
type UseSessionsResult = Pick<GeekappsAuthContextValue, "listUserSessions" | "revokeUserSession">;
|
|
352
|
+
type UseMembersResult = Pick<GeekappsAuthContextValue, "listMembers" | "updateMemberRole" | "removeMember" | "inviteMember" | "listInvites" | "revokeInvite">;
|
|
330
353
|
declare function GeekappsAuthProvider({ children, basePath, initialUser, initialOrganizations, initialCurrentOrgId, }: GeekappsAuthProviderProps): ReactElement;
|
|
331
354
|
declare function useAuth(): GeekappsAuthContextValue;
|
|
332
355
|
declare function useOrg(): UseOrgResult;
|
|
@@ -335,6 +358,7 @@ declare function useUsers(): UseUsersResult;
|
|
|
335
358
|
declare function useRoles(): UseRolesResult;
|
|
336
359
|
declare function usePermissions(): UsePermissionsResult;
|
|
337
360
|
declare function useSessions(): UseSessionsResult;
|
|
361
|
+
declare function useMembers(): UseMembersResult;
|
|
338
362
|
type ServiceAccount = {
|
|
339
363
|
id: string;
|
|
340
364
|
membershipId: string;
|
|
@@ -379,4 +403,4 @@ type UseServiceAccountResult = {
|
|
|
379
403
|
};
|
|
380
404
|
declare function useServiceAccount(): UseServiceAccountResult;
|
|
381
405
|
|
|
382
|
-
export { type AuthResult, type CallbackUrlOptions, type ConnectedAccount, type CreateServiceAccountInput, type GeekappsAuthContextValue, GeekappsAuthProvider, type GeekappsAuthProviderProps, type LoginResponse, type OAuthClientType, type Organization, type OrganizationInput, type OrganizationMember, type OrganizationOwnedApplication, type OrganizationStatus, type OrganizationUpdateInput, type Permission, type PermissionCheckOptions, type PermissionInput, type PermissionUpdateInput, type RegisterResponse, type Role, type RoleAssignment, type RoleInput, type RolePermission, type RoleUpdateInput, type ServiceAccount, type ServiceAccountWithSecret, type SessionApplication, type SignInInput, type SignInOptions, type UseAccountsResult, type UseOrgResult, type UsePermissionsResult, type UseRolesResult, type UseServiceAccountResult, type UseSessionsResult, type UseUsersResult, type User, type UserInput, type UserSession, type UserStatus, loginWithPassword, registerWithPassword, requestPasswordlessLink, startGoogleLogin, useAccounts, useAuth, useOrg, usePermissions, useRoles, useServiceAccount, useSessions, useUsers };
|
|
406
|
+
export { type AuthResult, type CallbackUrlOptions, type ConnectedAccount, type CreateServiceAccountInput, type GeekappsAuthContextValue, GeekappsAuthProvider, type GeekappsAuthProviderProps, type LoginResponse, type MemberInviteInput, type OAuthClientType, type Organization, type OrganizationInput, type OrganizationInvite, type OrganizationMember, type OrganizationOwnedApplication, type OrganizationStatus, type OrganizationUpdateInput, type Permission, type PermissionCheckOptions, type PermissionInput, type PermissionUpdateInput, type RegisterResponse, type Role, type RoleAssignment, type RoleInput, type RolePermission, type RoleUpdateInput, type ServiceAccount, type ServiceAccountWithSecret, type SessionApplication, type SignInInput, type SignInOptions, type UpdateMemberRoleInput, type UseAccountsResult, type UseMembersResult, type UseOrgResult, type UsePermissionsResult, type UseRolesResult, type UseServiceAccountResult, type UseSessionsResult, type UseUsersResult, type User, type UserInput, type UserSession, type UserStatus, loginWithPassword, registerWithPassword, requestPasswordlessLink, startGoogleLogin, useAccounts, useAuth, useMembers, useOrg, usePermissions, useRoles, useServiceAccount, useSessions, useUsers };
|
package/dist/client.js
CHANGED
|
@@ -394,6 +394,28 @@ function GeekappsAuthProvider({
|
|
|
394
394
|
revokeUserSession: (sessionId) => toAuthResult(async () => {
|
|
395
395
|
await request(`/sessions/${sessionId}`, { method: "DELETE" });
|
|
396
396
|
return null;
|
|
397
|
+
}),
|
|
398
|
+
listMembers: (organizationId) => request(`/organizations/${organizationId}/members`),
|
|
399
|
+
updateMemberRole: (organizationId, memberId, input) => toAuthResult(
|
|
400
|
+
() => request(`/organizations/${organizationId}/members/${memberId}`, {
|
|
401
|
+
method: "PATCH",
|
|
402
|
+
body: input
|
|
403
|
+
})
|
|
404
|
+
),
|
|
405
|
+
removeMember: (organizationId, memberId) => toAuthResult(async () => {
|
|
406
|
+
await request(`/organizations/${organizationId}/members/${memberId}`, { method: "DELETE" });
|
|
407
|
+
return null;
|
|
408
|
+
}),
|
|
409
|
+
inviteMember: (organizationId, input) => toAuthResult(
|
|
410
|
+
() => request(`/organizations/${organizationId}/invites`, {
|
|
411
|
+
method: "POST",
|
|
412
|
+
body: input
|
|
413
|
+
})
|
|
414
|
+
),
|
|
415
|
+
listInvites: (organizationId) => request(`/organizations/${organizationId}/invites`),
|
|
416
|
+
revokeInvite: (organizationId, inviteId) => toAuthResult(async () => {
|
|
417
|
+
await request(`/organizations/${organizationId}/invites/${inviteId}`, { method: "DELETE" });
|
|
418
|
+
return null;
|
|
397
419
|
})
|
|
398
420
|
}),
|
|
399
421
|
[
|
|
@@ -487,6 +509,17 @@ function useSessions() {
|
|
|
487
509
|
revokeUserSession: context.revokeUserSession
|
|
488
510
|
};
|
|
489
511
|
}
|
|
512
|
+
function useMembers() {
|
|
513
|
+
const context = useAuth();
|
|
514
|
+
return {
|
|
515
|
+
listMembers: context.listMembers,
|
|
516
|
+
updateMemberRole: context.updateMemberRole,
|
|
517
|
+
removeMember: context.removeMember,
|
|
518
|
+
inviteMember: context.inviteMember,
|
|
519
|
+
listInvites: context.listInvites,
|
|
520
|
+
revokeInvite: context.revokeInvite
|
|
521
|
+
};
|
|
522
|
+
}
|
|
490
523
|
function useServiceAccount() {
|
|
491
524
|
const { request } = useAuth();
|
|
492
525
|
const listServiceAccounts = useCallback(
|
|
@@ -542,6 +575,7 @@ export {
|
|
|
542
575
|
startGoogleLogin,
|
|
543
576
|
useAccounts,
|
|
544
577
|
useAuth,
|
|
578
|
+
useMembers,
|
|
545
579
|
useOrg,
|
|
546
580
|
usePermissions,
|
|
547
581
|
useRoles,
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n type MouseEvent,\n type ReactElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\n\nexport type UserStatus = \"active\" | \"inactive\" | \"suspended\";\nexport type OrganizationStatus = \"active\" | \"inactive\" | \"suspended\";\nexport type OAuthClientType = \"public\" | \"confidential\";\n\nexport type AuthResult<T = unknown> =\n | { success: true; data: T }\n | { success: false; error: string; status?: number };\n\nexport type User = {\n id: string;\n email: string;\n name: string | null;\n phone: string | null;\n imageUrl: string | null;\n status?: UserStatus;\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type ConnectedAccount = {\n id: string;\n sessionId?: string;\n isActive: boolean;\n user: User;\n};\n\nexport type Permission = {\n id: string;\n applicationId?: string | null;\n key: string;\n name: string;\n description: string | null;\n category: string | null;\n isSystem: boolean;\n isActive: boolean;\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type RolePermission = {\n permissionDefinition: Permission;\n};\n\nexport type Role = {\n id: string;\n applicationId?: string | null;\n /** Present only on custom roles */\n organizationId?: string | null;\n /** \"system\" | \"custom\" */\n type?: string;\n key: string;\n name: string;\n description: string | null;\n isSystem?: boolean;\n isDefault?: boolean;\n isActive: boolean;\n permissions: RolePermission[];\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type RoleAssignment = {\n id: string;\n roleDefinitionId?: string | null;\n customRoleId?: string | null;\n roleDefinition?: Role | null;\n customRole?: Role | null;\n};\n\nexport type OrganizationMember = {\n id: string;\n organizationId?: string;\n userId?: string;\n createdAt?: string | Date;\n user: User;\n roleAssignments?: RoleAssignment[];\n};\n\nexport type OrganizationOwnedApplication = {\n id: string;\n name: string;\n description: string | null;\n imageUrl: string | null;\n type?: OAuthClientType;\n organizationId: string;\n isFirstParty: boolean;\n ssoEnabled: boolean;\n status?: \"active\" | \"inactive\" | \"suspended\";\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type Organization = {\n id: string;\n name: string;\n description: string | null;\n slug: string;\n domain: string | null;\n imageUrl: string | null;\n faviconUrl: string | null;\n status: OrganizationStatus;\n members?: OrganizationMember[];\n ownedApplications?: OrganizationOwnedApplication[];\n applicationLinks?: Array<{\n id: string;\n status: OrganizationStatus;\n createdAt?: string | Date;\n application: OrganizationOwnedApplication;\n }>;\n createdAt: string | Date;\n updatedAt: string | Date;\n};\n\nexport type SessionApplication = {\n id: string;\n createdAt: string | Date;\n expiresAt: string | Date;\n application: {\n id: string;\n name: string;\n organizationId: string;\n };\n};\n\nexport type UserSession = {\n id: string;\n userId: string;\n organizationId: string | null;\n deviceAgent: string | null;\n deviceId: string | null;\n deviceName: string | null;\n ip: string | null;\n authState?: unknown;\n authTime?: string | Date;\n expiresAt: string | Date;\n createdAt: string | Date;\n updatedAt: string | Date;\n user?: User;\n applicationSessions?: SessionApplication[];\n};\n\nexport type UserInput = {\n name?: string | null;\n email?: string;\n phone?: string | null;\n imageUrl?: string | null;\n password?: string;\n organizationId?: string | null;\n status?: UserStatus;\n};\n\nexport type OrganizationInput = {\n name: string;\n description?: string | null;\n slug: string;\n domain?: string | null;\n imageUrl?: string | null;\n faviconUrl?: string | null;\n};\n\nexport type OrganizationUpdateInput = Partial<OrganizationInput> & {\n status?: OrganizationStatus;\n};\n\nexport type RoleInput = {\n organizationId: string;\n applicationId?: string | null;\n key: string;\n name: string;\n description?: string | null;\n permissionDefinitionIds?: string[];\n};\n\nexport type RoleUpdateInput = {\n name?: string;\n description?: string | null;\n isActive?: boolean;\n permissionDefinitionIds?: string[];\n};\n\nexport type PermissionInput = {\n applicationId?: string | null;\n key: string;\n name: string;\n description?: string | null;\n category?: string | null;\n};\n\nexport type PermissionUpdateInput = {\n name?: string;\n description?: string | null;\n category?: string | null;\n isActive?: boolean;\n};\n\nexport type SignInOptions = {\n redirectTo?: string;\n authorizationFlowId?: string;\n /** When false, forces the IDP to show the login screen even if a session exists. Defaults to true (silent). */\n silentLogin?: boolean;\n};\n\nexport type SignInInput = SignInOptions | MouseEvent<HTMLElement>;\n\nexport type CallbackUrlOptions = SignInOptions & {\n callbackUrl?: string;\n};\n\nexport type PermissionCheckOptions = {\n permission: string;\n organizationId?: string | null;\n applicationId?: string | null;\n resourceId?: string | null;\n};\n\nexport type LoginResponse = {\n user: User;\n redirectTo?: string | null;\n};\n\nexport type RegisterResponse = User;\n\nexport type GeekappsAuthProviderProps = {\n children: ReactNode;\n basePath?: string;\n initialUser?: User | null;\n initialOrganizations?: Organization[];\n initialCurrentOrgId?: string | null;\n};\n\ntype RequestOptions = {\n body?: unknown;\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n};\n\nfunction normalizeBasePath(basePath: string) {\n return basePath.endsWith(\"/\") ? basePath.slice(0, -1) : basePath;\n}\n\nfunction buildUrl(basePath: string, path: string) {\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${normalizeBasePath(basePath)}${normalizedPath}`;\n}\n\nasync function parseError(response: Response) {\n const data = await response.json().catch(() => null);\n return (\n data?.error_description ??\n data?.error ??\n data?.message ??\n `Request failed with status ${response.status}`\n );\n}\n\nfunction redirectTo(path: string) {\n window.location.assign(path);\n}\n\nfunction isMouseEvent(value: unknown): value is MouseEvent<HTMLElement> {\n return Boolean(value && typeof value === \"object\" && \"preventDefault\" in value);\n}\n\nfunction normalizeSignInOptions(input?: SignInInput): SignInOptions | undefined {\n if (!input) return undefined;\n if (isMouseEvent(input)) {\n input.preventDefault();\n return undefined;\n }\n return input;\n}\n\n\ntype ClientActionOptions = {\n basePath?: string;\n};\n\nasync function clientRequest<T>(\n path: string,\n options: RequestOptions = {},\n basePath = \"/api/auth\",\n): Promise<T> {\n const response = await fetch(buildUrl(basePath, path), {\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n credentials: \"include\",\n headers:\n options.body === undefined\n ? undefined\n : {\n \"content-type\": \"application/json\",\n },\n method: options.method ?? \"GET\",\n });\n\n if (!response.ok) {\n throw new Error(await parseError(response));\n }\n\n if (response.status === 204) {\n return null as T;\n }\n\n return (await response.json()) as T;\n}\n\nasync function toStandaloneAuthResult<T>(\n fn: () => Promise<T>,\n): Promise<AuthResult<T>> {\n try {\n return {\n success: true,\n data: await fn(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Auth request failed\",\n };\n }\n}\n\nexport async function loginWithPassword(\n params: {\n identifier?: string;\n email?: string;\n phone?: string;\n password: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n },\n options?: ClientActionOptions,\n): Promise<AuthResult<LoginResponse>> {\n return toStandaloneAuthResult(async () => {\n const data = await clientRequest<LoginResponse>(\n \"/login/password\",\n {\n body: params,\n method: \"POST\",\n },\n options?.basePath,\n );\n\n if (params.redirectTo ?? data.redirectTo) {\n redirectTo(params.redirectTo ?? data.redirectTo!);\n }\n\n return data;\n });\n}\n\nexport async function registerWithPassword(\n params: {\n name: string;\n email: string;\n phone?: string;\n imageUrl?: string;\n address?: Record<string, unknown>;\n password: string;\n redirectTo?: string;\n },\n options?: ClientActionOptions,\n): Promise<AuthResult<RegisterResponse>> {\n return toStandaloneAuthResult(async () => {\n const data = await clientRequest<RegisterResponse>(\n \"/register/password\",\n {\n body: params,\n method: \"POST\",\n },\n options?.basePath,\n );\n\n if (params.redirectTo) {\n redirectTo(params.redirectTo);\n }\n\n return data;\n });\n}\n\nexport function startGoogleLogin(\n params?: CallbackUrlOptions,\n options?: ClientActionOptions,\n) {\n const basePath = options?.basePath ?? \"/api/auth\";\n const url = new URL(buildUrl(basePath, \"/login/google\"), window.location.origin);\n\n if (params?.callbackUrl) {\n url.searchParams.set(\"callbackUrl\", params.callbackUrl);\n }\n\n if (params?.redirectTo) {\n url.searchParams.set(\"redirectTo\", params.redirectTo);\n }\n\n if (params?.authorizationFlowId) {\n url.searchParams.set(\"flow_id\", params.authorizationFlowId);\n }\n\n redirectTo(url.toString());\n}\n\nexport async function requestPasswordlessLink(\n params: {\n email: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n callbackUrl?: string;\n },\n options?: ClientActionOptions,\n): Promise<AuthResult> {\n return toStandaloneAuthResult(() =>\n clientRequest(\n \"/passwordless/link\",\n {\n body: params,\n method: \"POST\",\n },\n options?.basePath,\n ),\n );\n}\n\nexport type GeekappsAuthContextValue = {\n basePath: string;\n user: User | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n accounts: ConnectedAccount[];\n isLoadingAccounts: boolean;\n organizations: Organization[];\n currentOrg: Organization | null;\n currentOrgId: string | null;\n isLoadingOrganizations: boolean;\n\n request: <T>(path: string, options?: RequestOptions) => Promise<T>;\n\n signIn: (options?: SignInInput) => Promise<void>;\n signUp: (options?: SignInInput) => Promise<void>;\n addAccount: (options?: SignInInput) => Promise<void>;\n signOut: () => Promise<void>;\n signOutAll: () => Promise<void>;\n refreshUser: () => Promise<void>;\n refreshAccounts: () => Promise<void>;\n switchAccount: (sessionId: string, options?: SignInOptions) => Promise<void>;\n\n loginWithPassword: (params: {\n identifier?: string;\n email?: string;\n phone?: string;\n password: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n }) => Promise<AuthResult<LoginResponse>>;\n registerWithPassword: (params: {\n name: string;\n email: string;\n phone?: string;\n imageUrl?: string;\n address?: Record<string, unknown>;\n password: string;\n redirectTo?: string;\n }) => Promise<AuthResult<RegisterResponse>>;\n startGoogleLogin: (params?: CallbackUrlOptions) => void;\n requestPasswordlessLink: (params: {\n email: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n callbackUrl?: string;\n }) => Promise<AuthResult>;\n\n refreshOrganizations: () => Promise<void>;\n setCurrentOrg: (organizationId: string | null) => Promise<void>;\n createOrganization: (input: OrganizationInput) => Promise<AuthResult<Organization>>;\n updateOrganization: (id: string, input: OrganizationUpdateInput) => Promise<AuthResult<Organization>>;\n deleteOrganization: (id: string) => Promise<AuthResult<null>>;\n hasPermission: (options: PermissionCheckOptions) => Promise<boolean>;\n\n listUsers: (params?: { organizationId?: string | null }) => Promise<User[]>;\n getUser: (id: string) => Promise<User>;\n createUser: (input: UserInput) => Promise<AuthResult<User>>;\n updateUser: (id: string, input: UserInput) => Promise<AuthResult<User>>;\n deleteUser: (id: string) => Promise<AuthResult<null>>;\n\n listRoles: (params?: { organizationId?: string; applicationId?: string; type?: \"system\" | \"custom\" | \"all\" }) => Promise<{ systemRoles: Role[]; customRoles: Role[] }>;\n getRole: (id: string, type: \"system\" | \"custom\") => Promise<Role>;\n createRole: (input: RoleInput) => Promise<AuthResult<Role>>;\n updateRole: (id: string, input: RoleUpdateInput) => Promise<AuthResult<Role>>;\n deleteRole: (id: string) => Promise<AuthResult<null>>;\n\n listPermissions: (params?: { applicationId?: string; roleId?: string | null }) => Promise<Permission[]>;\n createPermission: (input: PermissionInput) => Promise<AuthResult<Permission>>;\n updatePermission: (id: string, input: PermissionUpdateInput) => Promise<AuthResult<Permission>>;\n deletePermission: (id: string) => Promise<AuthResult<null>>;\n\n listUserSessions: (params?: { userId?: string; organizationId?: string | null }) => Promise<UserSession[]>;\n revokeUserSession: (sessionId: string) => Promise<AuthResult<null>>;\n};\n\nexport type UseOrgResult = Pick<\n GeekappsAuthContextValue,\n | \"organizations\"\n | \"currentOrg\"\n | \"currentOrgId\"\n | \"isLoadingOrganizations\"\n | \"refreshOrganizations\"\n | \"setCurrentOrg\"\n | \"createOrganization\"\n | \"updateOrganization\"\n | \"deleteOrganization\"\n | \"hasPermission\"\n>;\n\nexport type UseAccountsResult = Pick<\n GeekappsAuthContextValue,\n \"accounts\" | \"addAccount\" | \"isLoadingAccounts\" | \"refreshAccounts\" | \"switchAccount\"\n>;\n\nexport type UseUsersResult = Pick<\n GeekappsAuthContextValue,\n \"listUsers\" | \"getUser\" | \"createUser\" | \"updateUser\" | \"deleteUser\"\n>;\n\nexport type UseRolesResult = Pick<\n GeekappsAuthContextValue,\n \"listRoles\" | \"getRole\" | \"createRole\" | \"updateRole\" | \"deleteRole\"\n>;\n\nexport type UsePermissionsResult = Pick<\n GeekappsAuthContextValue,\n \"listPermissions\" | \"createPermission\" | \"updatePermission\" | \"deletePermission\"\n>;\n\nexport type UseSessionsResult = Pick<\n GeekappsAuthContextValue,\n \"listUserSessions\" | \"revokeUserSession\"\n>;\n\nconst GeekappsAuthContext = createContext<GeekappsAuthContextValue | null>(null);\n\nexport function GeekappsAuthProvider({\n children,\n basePath = \"/api/auth\",\n initialUser = null,\n initialOrganizations = [],\n initialCurrentOrgId = null,\n}: GeekappsAuthProviderProps): ReactElement {\n const [user, setUser] = useState<User | null>(initialUser);\n const [isLoading, setIsLoading] = useState(true);\n const [accounts, setAccounts] = useState<ConnectedAccount[]>([]);\n const [isLoadingAccounts, setIsLoadingAccounts] = useState(true);\n const [organizations, setOrganizations] = useState<Organization[]>(initialOrganizations);\n const [currentOrgId, setCurrentOrgId] = useState<string | null>(initialCurrentOrgId);\n const [isLoadingOrganizations, setIsLoadingOrganizations] = useState(true);\n\n const request = useCallback(\n async <T,>(path: string, options: RequestOptions = {}) => {\n const response = await fetch(buildUrl(basePath, path), {\n method: options.method ?? \"GET\",\n credentials: \"include\",\n headers:\n options.body === undefined\n ? undefined\n : {\n \"content-type\": \"application/json\",\n },\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n });\n\n if (!response.ok) {\n throw new Error(await parseError(response));\n }\n\n if (response.status === 204) {\n return null as T;\n }\n\n return (await response.json()) as T;\n },\n [basePath],\n );\n\n const refreshUser = useCallback(async () => {\n setIsLoading(true);\n try {\n const { user: u } = await request<{ user: User | null }>(\"/me\");\n setUser(u);\n } catch {\n setUser(null);\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n const refreshAccounts = useCallback(async () => {\n setIsLoadingAccounts(true);\n try {\n const { accounts: a } = await request<{ accounts: ConnectedAccount[] }>(\n \"/accounts\",\n );\n setAccounts(a);\n } catch {\n setAccounts([]);\n } finally {\n setIsLoadingAccounts(false);\n }\n }, []);\n\n const refreshOrganizations = useCallback(async () => {\n setIsLoadingOrganizations(true);\n try {\n const { organizations: orgs, currentOrgId: nextCurrentOrgId } =\n await request<{\n organizations: Organization[];\n currentOrgId?: string | null;\n }>(\"/organizations\");\n setOrganizations(orgs);\n setCurrentOrgId((current) => {\n if (nextCurrentOrgId !== undefined) return nextCurrentOrgId ?? null;\n if (current && orgs.some((org) => org.id === current)) return current;\n return orgs[0]?.id ?? null;\n });\n } catch {\n setOrganizations([]);\n setCurrentOrgId(null);\n } finally {\n setIsLoadingOrganizations(false);\n }\n }, []);\n\n useEffect(() => {\n void refreshUser();\n void refreshAccounts();\n void refreshOrganizations();\n }, [refreshAccounts, refreshOrganizations, refreshUser]);\n\n const currentOrg = useMemo(\n () => organizations.find((organization) => organization.id === currentOrgId) ?? null,\n [currentOrgId, organizations],\n );\n\n const setCurrentOrg = useCallback(\n async (organizationId: string | null) => {\n await request(\"/organizations/active\", {\n method: \"POST\",\n body: { organizationId },\n });\n setCurrentOrgId(organizationId);\n },\n [request],\n );\n\n const signIn = useCallback(\n async (input?: SignInInput) => {\n const options = normalizeSignInOptions(input);\n const url = new URL(buildUrl(basePath, \"/sign-in\"), window.location.origin);\n if (options?.redirectTo) url.searchParams.set(\"redirectTo\", options.redirectTo);\n if (options?.authorizationFlowId) url.searchParams.set(\"flow_id\", options.authorizationFlowId);\n if (options?.silentLogin === false) url.searchParams.set(\"silentLogin\", \"false\");\n redirectTo(url.toString());\n },\n [basePath],\n );\n\n const signUp = useCallback(\n async (input?: SignInInput) => {\n const options = normalizeSignInOptions(input);\n const url = new URL(buildUrl(basePath, \"/sign-up\"), window.location.origin);\n if (options?.redirectTo) url.searchParams.set(\"redirectTo\", options.redirectTo);\n if (options?.authorizationFlowId) url.searchParams.set(\"flow_id\", options.authorizationFlowId);\n if (options?.silentLogin === false) url.searchParams.set(\"silentLogin\", \"false\");\n redirectTo(url.toString());\n },\n [basePath],\n );\n\n const addAccount = useCallback(\n async (input?: SignInInput) => {\n const options = normalizeSignInOptions(input);\n const url = new URL(buildUrl(basePath, \"/add-account\"), window.location.origin);\n if (options?.redirectTo) url.searchParams.set(\"redirectTo\", options.redirectTo);\n redirectTo(url.toString());\n },\n [basePath],\n );\n\n const signOut = useCallback(async () => {\n await request(\"/sign-out\", { method: \"POST\" });\n setUser(null);\n await refreshAccounts();\n }, [refreshAccounts, request]);\n\n const signOutAll = useCallback(async () => {\n await request(\"/sign-out-all\", { method: \"POST\" });\n setUser(null);\n setAccounts([]);\n }, [request]);\n\n const switchAccount = useCallback(\n async (sessionId: string, options?: SignInOptions) => {\n await request(\"/accounts/switch\", {\n method: \"POST\",\n body: { sessionId },\n });\n await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);\n if (options?.redirectTo) redirectTo(options.redirectTo);\n },\n [refreshAccounts, refreshOrganizations, refreshUser, request],\n );\n\n async function toAuthResult<T>(fn: () => Promise<T>): Promise<AuthResult<T>> {\n try {\n return { success: true, data: await fn() };\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : \"Unexpected error\" };\n }\n }\n\n const value = useMemo<GeekappsAuthContextValue>(\n () => ({\n basePath,\n user,\n isAuthenticated: !isLoading && user !== null,\n isLoading,\n accounts,\n isLoadingAccounts,\n organizations,\n currentOrg,\n currentOrgId,\n isLoadingOrganizations,\n request,\n signIn,\n signUp,\n addAccount,\n signOut,\n signOutAll,\n refreshUser,\n refreshAccounts,\n switchAccount,\n loginWithPassword: (params) =>\n toAuthResult(async () => {\n const data = await request<LoginResponse>(\"/login/password\", { method: \"POST\", body: params });\n await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);\n if (params.redirectTo ?? data.redirectTo) redirectTo(params.redirectTo ?? data.redirectTo!);\n return data;\n }),\n registerWithPassword: (params) =>\n toAuthResult(async () => {\n const data = await request<RegisterResponse>(\"/register/password\", { method: \"POST\", body: params });\n await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);\n if (params.redirectTo) redirectTo(params.redirectTo);\n return data;\n }),\n startGoogleLogin: (params) => {\n const url = new URL(buildUrl(basePath, \"/login/google\"), window.location.origin);\n if (params?.callbackUrl) url.searchParams.set(\"callbackUrl\", params.callbackUrl);\n if (params?.redirectTo) url.searchParams.set(\"redirectTo\", params.redirectTo);\n if (params?.authorizationFlowId) url.searchParams.set(\"flow_id\", params.authorizationFlowId);\n redirectTo(url.toString());\n },\n requestPasswordlessLink: (params) =>\n toAuthResult(() => request(\"/passwordless/link\", { method: \"POST\", body: params })),\n refreshOrganizations,\n setCurrentOrg,\n createOrganization: (input) =>\n toAuthResult(async () => {\n const organization = await request<Organization>(\"/organizations\", { method: \"POST\", body: input });\n await refreshOrganizations();\n setCurrentOrgId(organization.id);\n return organization;\n }),\n updateOrganization: (id, input) =>\n toAuthResult(async () => {\n const organization = await request<Organization>(`/organizations/${id}`, { method: \"PATCH\", body: input });\n await refreshOrganizations();\n return organization;\n }),\n deleteOrganization: (id) =>\n toAuthResult(async () => {\n await request<null>(`/organizations/${id}`, { method: \"DELETE\" });\n await refreshOrganizations();\n return null;\n }),\n hasPermission: async (options) => {\n try {\n const data = await request<{ allowed: boolean }>(\"/permissions/check\", {\n method: \"POST\",\n body: options,\n });\n return data.allowed;\n } catch {\n return false;\n }\n },\n listUsers: (params) => {\n const query = new URLSearchParams();\n if (params?.organizationId) query.set(\"organizationId\", params.organizationId);\n return request<User[]>(`/users${query.size ? `?${query.toString()}` : \"\"}`);\n },\n getUser: (id) => request<User>(`/users/${id}`),\n createUser: (input) => toAuthResult(() => request<User>(\"/users\", { method: \"POST\", body: input })),\n updateUser: (id, input) => toAuthResult(() => request<User>(`/users/${id}`, { method: \"PATCH\", body: input })),\n deleteUser: (id) =>\n toAuthResult(async () => {\n await request<null>(`/users/${id}`, { method: \"DELETE\" });\n return null;\n }),\n listRoles: (params) => {\n const query = new URLSearchParams();\n if (params?.organizationId) query.set(\"organizationId\", params.organizationId);\n if (params?.applicationId) query.set(\"applicationId\", params.applicationId);\n if (params?.type) query.set(\"type\", params.type);\n return request<{ systemRoles: Role[]; customRoles: Role[] }>(`/roles${query.size ? `?${query.toString()}` : \"\"}`);\n },\n getRole: (id, type) => request<Role>(type === \"custom\" ? `/roles/custom/${id}` : `/roles/definitions/${id}`),\n createRole: (input) => toAuthResult(() => request<Role>(\"/roles\", { method: \"POST\", body: input })),\n updateRole: (id, input) => toAuthResult(() => request<Role>(`/roles/custom/${id}`, { method: \"PATCH\", body: input })),\n deleteRole: (id) =>\n toAuthResult(async () => {\n await request<null>(`/roles/custom/${id}`, { method: \"DELETE\" });\n return null;\n }),\n listPermissions: (params) => {\n const query = new URLSearchParams();\n if (params?.applicationId) query.set(\"applicationId\", params.applicationId);\n if (params?.roleId) query.set(\"roleId\", params.roleId);\n return request<Permission[]>(`/permissions${query.size ? `?${query.toString()}` : \"\"}`);\n },\n createPermission: (input) =>\n toAuthResult(() => request<Permission>(\"/permissions\", { method: \"POST\", body: input })),\n updatePermission: (id, input) =>\n toAuthResult(() => request<Permission>(`/permissions/${id}`, { method: \"PATCH\", body: input })),\n deletePermission: (id) =>\n toAuthResult(async () => {\n await request<null>(`/permissions/${id}`, { method: \"DELETE\" });\n return null;\n }),\n listUserSessions: (params) => {\n const query = new URLSearchParams();\n if (params?.userId) query.set(\"userId\", params.userId);\n if (params?.organizationId) query.set(\"organizationId\", params.organizationId);\n return request<UserSession[]>(`/sessions${query.size ? `?${query.toString()}` : \"\"}`);\n },\n revokeUserSession: (sessionId) =>\n toAuthResult(async () => {\n await request<null>(`/sessions/${sessionId}`, { method: \"DELETE\" });\n return null;\n }),\n }),\n [\n accounts,\n addAccount,\n basePath,\n currentOrg,\n currentOrgId,\n isLoading,\n isLoadingAccounts,\n isLoadingOrganizations,\n organizations,\n refreshAccounts,\n refreshOrganizations,\n refreshUser,\n request,\n setCurrentOrg,\n signIn,\n signOut,\n signOutAll,\n signUp,\n switchAccount,\n user,\n ],\n );\n\n return <GeekappsAuthContext.Provider value={value}>{children}</GeekappsAuthContext.Provider>;\n}\n\nexport function useAuth(): GeekappsAuthContextValue {\n const context = useContext(GeekappsAuthContext);\n if (!context) throw new Error(\"useAuth must be used inside GeekappsAuthProvider\");\n return context;\n}\n\nexport function useOrg(): UseOrgResult {\n const context = useAuth();\n return {\n organizations: context.organizations,\n currentOrg: context.currentOrg,\n currentOrgId: context.currentOrgId,\n isLoadingOrganizations: context.isLoadingOrganizations,\n refreshOrganizations: context.refreshOrganizations,\n setCurrentOrg: context.setCurrentOrg,\n createOrganization: context.createOrganization,\n updateOrganization: context.updateOrganization,\n deleteOrganization: context.deleteOrganization,\n hasPermission: context.hasPermission,\n };\n}\n\nexport function useAccounts(): UseAccountsResult {\n const context = useAuth();\n return {\n accounts: context.accounts,\n addAccount: context.addAccount,\n isLoadingAccounts: context.isLoadingAccounts,\n refreshAccounts: context.refreshAccounts,\n switchAccount: context.switchAccount,\n };\n}\n\nexport function useUsers(): UseUsersResult {\n const context = useAuth();\n return {\n listUsers: context.listUsers,\n getUser: context.getUser,\n createUser: context.createUser,\n updateUser: context.updateUser,\n deleteUser: context.deleteUser,\n };\n}\n\nexport function useRoles(): UseRolesResult {\n const context = useAuth();\n return {\n listRoles: context.listRoles,\n getRole: context.getRole,\n createRole: context.createRole,\n updateRole: context.updateRole,\n deleteRole: context.deleteRole,\n };\n}\n\nexport function usePermissions(): UsePermissionsResult {\n const context = useAuth();\n return {\n listPermissions: context.listPermissions,\n createPermission: context.createPermission,\n updatePermission: context.updatePermission,\n deletePermission: context.deletePermission,\n };\n}\n\nexport function useSessions(): UseSessionsResult {\n const context = useAuth();\n return {\n listUserSessions: context.listUserSessions,\n revokeUserSession: context.revokeUserSession,\n };\n}\n\n// ── Service Accounts ─────────────────────────────────────────────────────────\n\nexport type ServiceAccount = {\n id: string;\n membershipId: string;\n organizationId: string;\n applicationId: string | null;\n name: string;\n status: \"active\" | \"inactive\" | \"suspended\";\n serviceId: string | null;\n roleAssignment: { role: { id: string; key: string; name: string } } | null;\n createdAt: string;\n updatedAt: string;\n};\n\nexport type ServiceAccountWithSecret = ServiceAccount & { serviceSecret: string };\n\nexport type CreateServiceAccountInput = {\n organizationId: string;\n applicationId?: string;\n name: string;\n description?: string;\n roleId?: string;\n};\n\nexport type UseServiceAccountResult = {\n listServiceAccounts: (params: { organizationId: string; applicationId?: string }) => Promise<ServiceAccount[]>;\n createServiceAccount: (input: CreateServiceAccountInput) => Promise<ServiceAccountWithSecret>;\n updateServiceAccountRole: (id: string, roleId: string | null) => Promise<void>;\n revokeServiceAccount: (id: string) => Promise<void>;\n rotateServiceAccountSecret: (id: string) => Promise<{ serviceId: string; serviceSecret: string }>;\n deleteServiceAccount: (id: string) => Promise<void>;\n};\n\nexport function useServiceAccount(): UseServiceAccountResult {\n const { request } = useAuth();\n\n const listServiceAccounts = useCallback(\n (params: { organizationId: string; applicationId?: string }) => {\n const query = new URLSearchParams({ organizationId: params.organizationId });\n if (params.applicationId) query.set(\"applicationId\", params.applicationId);\n return request<ServiceAccount[]>(`/service-accounts?${query.toString()}`);\n },\n [request],\n );\n\n const createServiceAccount = useCallback(\n (input: CreateServiceAccountInput) =>\n request<ServiceAccountWithSecret>(\"/service-accounts\", { method: \"POST\", body: input }),\n [request],\n );\n\n const updateServiceAccountRole = useCallback(\n async (id: string, roleId: string | null) => {\n await request<void>(`/service-accounts/${id}`, { method: \"PATCH\", body: { roleId } });\n },\n [request],\n );\n\n const revokeServiceAccount = useCallback(\n async (id: string) => {\n await request<void>(`/service-accounts/${id}/revoke`, { method: \"POST\" });\n },\n [request],\n );\n\n const rotateServiceAccountSecret = useCallback(\n (id: string) =>\n request<{ serviceId: string; serviceSecret: string }>(`/service-accounts/${id}/rotate-secret`, {\n method: \"POST\",\n }),\n [request],\n );\n\n const deleteServiceAccount = useCallback(\n async (id: string) => {\n await request<null>(`/service-accounts/${id}`, { method: \"DELETE\" });\n },\n [request],\n );\n\n return {\n listServiceAccounts,\n createServiceAccount,\n updateServiceAccountRole,\n revokeServiceAccount,\n rotateServiceAccountSecret,\n deleteServiceAccount,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/client.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n createContext,\n type MouseEvent,\n type ReactElement,\n type ReactNode,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\n\nexport type UserStatus = \"active\" | \"inactive\" | \"suspended\";\nexport type OrganizationStatus = \"active\" | \"inactive\" | \"suspended\";\nexport type OAuthClientType = \"public\" | \"confidential\";\n\nexport type AuthResult<T = unknown> =\n | { success: true; data: T }\n | { success: false; error: string; status?: number };\n\nexport type User = {\n id: string;\n email: string;\n name: string | null;\n phone: string | null;\n imageUrl: string | null;\n status?: UserStatus;\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type ConnectedAccount = {\n id: string;\n sessionId?: string;\n isActive: boolean;\n user: User;\n};\n\nexport type Permission = {\n id: string;\n applicationId?: string | null;\n key: string;\n name: string;\n description: string | null;\n category: string | null;\n isSystem: boolean;\n isActive: boolean;\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type RolePermission = {\n permissionDefinition: Permission;\n};\n\nexport type Role = {\n id: string;\n applicationId?: string | null;\n /** Present only on custom roles */\n organizationId?: string | null;\n /** \"system\" | \"custom\" */\n type?: string;\n key: string;\n name: string;\n description: string | null;\n isSystem?: boolean;\n isDefault?: boolean;\n isActive: boolean;\n permissions: RolePermission[];\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type RoleAssignment = {\n id: string;\n roleDefinitionId?: string | null;\n customRoleId?: string | null;\n roleDefinition?: Role | null;\n customRole?: Role | null;\n};\n\nexport type OrganizationMember = {\n id: string;\n organizationId?: string;\n userId?: string;\n createdAt?: string | Date;\n user: User;\n roleAssignments?: RoleAssignment[];\n};\n\nexport type OrganizationInvite = {\n id: string;\n organizationId: string;\n email: string;\n roleId?: string | null;\n status: \"pending\" | \"accepted\" | \"expired\" | \"revoked\";\n expiresAt: string | Date;\n createdAt?: string | Date;\n};\n\nexport type MemberInviteInput = {\n email: string;\n roleId?: string;\n};\n\nexport type UpdateMemberRoleInput = {\n roleId: string;\n};\n\nexport type OrganizationOwnedApplication = {\n id: string;\n name: string;\n description: string | null;\n imageUrl: string | null;\n type?: OAuthClientType;\n organizationId: string;\n isFirstParty: boolean;\n ssoEnabled: boolean;\n status?: \"active\" | \"inactive\" | \"suspended\";\n createdAt?: string | Date;\n updatedAt?: string | Date;\n};\n\nexport type Organization = {\n id: string;\n name: string;\n description: string | null;\n slug: string;\n domain: string | null;\n imageUrl: string | null;\n faviconUrl: string | null;\n status: OrganizationStatus;\n members?: OrganizationMember[];\n ownedApplications?: OrganizationOwnedApplication[];\n applicationLinks?: Array<{\n id: string;\n status: OrganizationStatus;\n createdAt?: string | Date;\n application: OrganizationOwnedApplication;\n }>;\n createdAt: string | Date;\n updatedAt: string | Date;\n};\n\nexport type SessionApplication = {\n id: string;\n createdAt: string | Date;\n expiresAt: string | Date;\n application: {\n id: string;\n name: string;\n organizationId: string;\n };\n};\n\nexport type UserSession = {\n id: string;\n userId: string;\n organizationId: string | null;\n deviceAgent: string | null;\n deviceId: string | null;\n deviceName: string | null;\n ip: string | null;\n authState?: unknown;\n authTime?: string | Date;\n expiresAt: string | Date;\n createdAt: string | Date;\n updatedAt: string | Date;\n user?: User;\n applicationSessions?: SessionApplication[];\n};\n\nexport type UserInput = {\n name?: string | null;\n email?: string;\n phone?: string | null;\n imageUrl?: string | null;\n password?: string;\n organizationId?: string | null;\n status?: UserStatus;\n};\n\nexport type OrganizationInput = {\n name: string;\n description?: string | null;\n slug: string;\n domain?: string | null;\n imageUrl?: string | null;\n faviconUrl?: string | null;\n};\n\nexport type OrganizationUpdateInput = Partial<OrganizationInput> & {\n status?: OrganizationStatus;\n};\n\nexport type RoleInput = {\n organizationId: string;\n applicationId?: string | null;\n key: string;\n name: string;\n description?: string | null;\n permissionDefinitionIds?: string[];\n};\n\nexport type RoleUpdateInput = {\n name?: string;\n description?: string | null;\n isActive?: boolean;\n permissionDefinitionIds?: string[];\n};\n\nexport type PermissionInput = {\n applicationId?: string | null;\n key: string;\n name: string;\n description?: string | null;\n category?: string | null;\n};\n\nexport type PermissionUpdateInput = {\n name?: string;\n description?: string | null;\n category?: string | null;\n isActive?: boolean;\n};\n\nexport type SignInOptions = {\n redirectTo?: string;\n authorizationFlowId?: string;\n /** When false, forces the IDP to show the login screen even if a session exists. Defaults to true (silent). */\n silentLogin?: boolean;\n};\n\nexport type SignInInput = SignInOptions | MouseEvent<HTMLElement>;\n\nexport type CallbackUrlOptions = SignInOptions & {\n callbackUrl?: string;\n};\n\nexport type PermissionCheckOptions = {\n permission: string;\n organizationId?: string | null;\n applicationId?: string | null;\n resourceId?: string | null;\n};\n\nexport type LoginResponse = {\n user: User;\n redirectTo?: string | null;\n};\n\nexport type RegisterResponse = User;\n\nexport type GeekappsAuthProviderProps = {\n children: ReactNode;\n basePath?: string;\n initialUser?: User | null;\n initialOrganizations?: Organization[];\n initialCurrentOrgId?: string | null;\n};\n\ntype RequestOptions = {\n body?: unknown;\n method?: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n};\n\nfunction normalizeBasePath(basePath: string) {\n return basePath.endsWith(\"/\") ? basePath.slice(0, -1) : basePath;\n}\n\nfunction buildUrl(basePath: string, path: string) {\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n return `${normalizeBasePath(basePath)}${normalizedPath}`;\n}\n\nasync function parseError(response: Response) {\n const data = await response.json().catch(() => null);\n return (\n data?.error_description ??\n data?.error ??\n data?.message ??\n `Request failed with status ${response.status}`\n );\n}\n\nfunction redirectTo(path: string) {\n window.location.assign(path);\n}\n\nfunction isMouseEvent(value: unknown): value is MouseEvent<HTMLElement> {\n return Boolean(value && typeof value === \"object\" && \"preventDefault\" in value);\n}\n\nfunction normalizeSignInOptions(input?: SignInInput): SignInOptions | undefined {\n if (!input) return undefined;\n if (isMouseEvent(input)) {\n input.preventDefault();\n return undefined;\n }\n return input;\n}\n\n\ntype ClientActionOptions = {\n basePath?: string;\n};\n\nasync function clientRequest<T>(\n path: string,\n options: RequestOptions = {},\n basePath = \"/api/auth\",\n): Promise<T> {\n const response = await fetch(buildUrl(basePath, path), {\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n credentials: \"include\",\n headers:\n options.body === undefined\n ? undefined\n : {\n \"content-type\": \"application/json\",\n },\n method: options.method ?? \"GET\",\n });\n\n if (!response.ok) {\n throw new Error(await parseError(response));\n }\n\n if (response.status === 204) {\n return null as T;\n }\n\n return (await response.json()) as T;\n}\n\nasync function toStandaloneAuthResult<T>(\n fn: () => Promise<T>,\n): Promise<AuthResult<T>> {\n try {\n return {\n success: true,\n data: await fn(),\n };\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Auth request failed\",\n };\n }\n}\n\nexport async function loginWithPassword(\n params: {\n identifier?: string;\n email?: string;\n phone?: string;\n password: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n },\n options?: ClientActionOptions,\n): Promise<AuthResult<LoginResponse>> {\n return toStandaloneAuthResult(async () => {\n const data = await clientRequest<LoginResponse>(\n \"/login/password\",\n {\n body: params,\n method: \"POST\",\n },\n options?.basePath,\n );\n\n if (params.redirectTo ?? data.redirectTo) {\n redirectTo(params.redirectTo ?? data.redirectTo!);\n }\n\n return data;\n });\n}\n\nexport async function registerWithPassword(\n params: {\n name: string;\n email: string;\n phone?: string;\n imageUrl?: string;\n address?: Record<string, unknown>;\n password: string;\n redirectTo?: string;\n },\n options?: ClientActionOptions,\n): Promise<AuthResult<RegisterResponse>> {\n return toStandaloneAuthResult(async () => {\n const data = await clientRequest<RegisterResponse>(\n \"/register/password\",\n {\n body: params,\n method: \"POST\",\n },\n options?.basePath,\n );\n\n if (params.redirectTo) {\n redirectTo(params.redirectTo);\n }\n\n return data;\n });\n}\n\nexport function startGoogleLogin(\n params?: CallbackUrlOptions,\n options?: ClientActionOptions,\n) {\n const basePath = options?.basePath ?? \"/api/auth\";\n const url = new URL(buildUrl(basePath, \"/login/google\"), window.location.origin);\n\n if (params?.callbackUrl) {\n url.searchParams.set(\"callbackUrl\", params.callbackUrl);\n }\n\n if (params?.redirectTo) {\n url.searchParams.set(\"redirectTo\", params.redirectTo);\n }\n\n if (params?.authorizationFlowId) {\n url.searchParams.set(\"flow_id\", params.authorizationFlowId);\n }\n\n redirectTo(url.toString());\n}\n\nexport async function requestPasswordlessLink(\n params: {\n email: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n callbackUrl?: string;\n },\n options?: ClientActionOptions,\n): Promise<AuthResult> {\n return toStandaloneAuthResult(() =>\n clientRequest(\n \"/passwordless/link\",\n {\n body: params,\n method: \"POST\",\n },\n options?.basePath,\n ),\n );\n}\n\nexport type GeekappsAuthContextValue = {\n basePath: string;\n user: User | null;\n isAuthenticated: boolean;\n isLoading: boolean;\n accounts: ConnectedAccount[];\n isLoadingAccounts: boolean;\n organizations: Organization[];\n currentOrg: Organization | null;\n currentOrgId: string | null;\n isLoadingOrganizations: boolean;\n\n request: <T>(path: string, options?: RequestOptions) => Promise<T>;\n\n signIn: (options?: SignInInput) => Promise<void>;\n signUp: (options?: SignInInput) => Promise<void>;\n addAccount: (options?: SignInInput) => Promise<void>;\n signOut: () => Promise<void>;\n signOutAll: () => Promise<void>;\n refreshUser: () => Promise<void>;\n refreshAccounts: () => Promise<void>;\n switchAccount: (sessionId: string, options?: SignInOptions) => Promise<void>;\n\n loginWithPassword: (params: {\n identifier?: string;\n email?: string;\n phone?: string;\n password: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n }) => Promise<AuthResult<LoginResponse>>;\n registerWithPassword: (params: {\n name: string;\n email: string;\n phone?: string;\n imageUrl?: string;\n address?: Record<string, unknown>;\n password: string;\n redirectTo?: string;\n }) => Promise<AuthResult<RegisterResponse>>;\n startGoogleLogin: (params?: CallbackUrlOptions) => void;\n requestPasswordlessLink: (params: {\n email: string;\n authorizationFlowId?: string;\n redirectTo?: string;\n callbackUrl?: string;\n }) => Promise<AuthResult>;\n\n refreshOrganizations: () => Promise<void>;\n setCurrentOrg: (organizationId: string | null) => Promise<void>;\n createOrganization: (input: OrganizationInput) => Promise<AuthResult<Organization>>;\n updateOrganization: (id: string, input: OrganizationUpdateInput) => Promise<AuthResult<Organization>>;\n deleteOrganization: (id: string) => Promise<AuthResult<null>>;\n hasPermission: (options: PermissionCheckOptions) => Promise<boolean>;\n\n listUsers: (params?: { organizationId?: string | null }) => Promise<User[]>;\n getUser: (id: string) => Promise<User>;\n createUser: (input: UserInput) => Promise<AuthResult<User>>;\n updateUser: (id: string, input: UserInput) => Promise<AuthResult<User>>;\n deleteUser: (id: string) => Promise<AuthResult<null>>;\n\n listRoles: (params?: { organizationId?: string; applicationId?: string; type?: \"system\" | \"custom\" | \"all\" }) => Promise<{ systemRoles: Role[]; customRoles: Role[] }>;\n getRole: (id: string, type: \"system\" | \"custom\") => Promise<Role>;\n createRole: (input: RoleInput) => Promise<AuthResult<Role>>;\n updateRole: (id: string, input: RoleUpdateInput) => Promise<AuthResult<Role>>;\n deleteRole: (id: string) => Promise<AuthResult<null>>;\n\n listPermissions: (params?: { applicationId?: string; roleId?: string | null }) => Promise<Permission[]>;\n createPermission: (input: PermissionInput) => Promise<AuthResult<Permission>>;\n updatePermission: (id: string, input: PermissionUpdateInput) => Promise<AuthResult<Permission>>;\n deletePermission: (id: string) => Promise<AuthResult<null>>;\n\n listUserSessions: (params?: { userId?: string; organizationId?: string | null }) => Promise<UserSession[]>;\n revokeUserSession: (sessionId: string) => Promise<AuthResult<null>>;\n\n listMembers: (organizationId: string) => Promise<OrganizationMember[]>;\n updateMemberRole: (\n organizationId: string,\n memberId: string,\n input: UpdateMemberRoleInput,\n ) => Promise<AuthResult<OrganizationMember>>;\n removeMember: (organizationId: string, memberId: string) => Promise<AuthResult<null>>;\n inviteMember: (organizationId: string, input: MemberInviteInput) => Promise<AuthResult<OrganizationInvite>>;\n listInvites: (organizationId: string) => Promise<OrganizationInvite[]>;\n revokeInvite: (organizationId: string, inviteId: string) => Promise<AuthResult<null>>;\n};\n\nexport type UseOrgResult = Pick<\n GeekappsAuthContextValue,\n | \"organizations\"\n | \"currentOrg\"\n | \"currentOrgId\"\n | \"isLoadingOrganizations\"\n | \"refreshOrganizations\"\n | \"setCurrentOrg\"\n | \"createOrganization\"\n | \"updateOrganization\"\n | \"deleteOrganization\"\n | \"hasPermission\"\n>;\n\nexport type UseAccountsResult = Pick<\n GeekappsAuthContextValue,\n \"accounts\" | \"addAccount\" | \"isLoadingAccounts\" | \"refreshAccounts\" | \"switchAccount\"\n>;\n\nexport type UseUsersResult = Pick<\n GeekappsAuthContextValue,\n \"listUsers\" | \"getUser\" | \"createUser\" | \"updateUser\" | \"deleteUser\"\n>;\n\nexport type UseRolesResult = Pick<\n GeekappsAuthContextValue,\n \"listRoles\" | \"getRole\" | \"createRole\" | \"updateRole\" | \"deleteRole\"\n>;\n\nexport type UsePermissionsResult = Pick<\n GeekappsAuthContextValue,\n \"listPermissions\" | \"createPermission\" | \"updatePermission\" | \"deletePermission\"\n>;\n\nexport type UseSessionsResult = Pick<\n GeekappsAuthContextValue,\n \"listUserSessions\" | \"revokeUserSession\"\n>;\n\nexport type UseMembersResult = Pick<\n GeekappsAuthContextValue,\n | \"listMembers\"\n | \"updateMemberRole\"\n | \"removeMember\"\n | \"inviteMember\"\n | \"listInvites\"\n | \"revokeInvite\"\n>;\n\nconst GeekappsAuthContext = createContext<GeekappsAuthContextValue | null>(null);\n\nexport function GeekappsAuthProvider({\n children,\n basePath = \"/api/auth\",\n initialUser = null,\n initialOrganizations = [],\n initialCurrentOrgId = null,\n}: GeekappsAuthProviderProps): ReactElement {\n const [user, setUser] = useState<User | null>(initialUser);\n const [isLoading, setIsLoading] = useState(true);\n const [accounts, setAccounts] = useState<ConnectedAccount[]>([]);\n const [isLoadingAccounts, setIsLoadingAccounts] = useState(true);\n const [organizations, setOrganizations] = useState<Organization[]>(initialOrganizations);\n const [currentOrgId, setCurrentOrgId] = useState<string | null>(initialCurrentOrgId);\n const [isLoadingOrganizations, setIsLoadingOrganizations] = useState(true);\n\n const request = useCallback(\n async <T,>(path: string, options: RequestOptions = {}) => {\n const response = await fetch(buildUrl(basePath, path), {\n method: options.method ?? \"GET\",\n credentials: \"include\",\n headers:\n options.body === undefined\n ? undefined\n : {\n \"content-type\": \"application/json\",\n },\n body: options.body === undefined ? undefined : JSON.stringify(options.body),\n });\n\n if (!response.ok) {\n throw new Error(await parseError(response));\n }\n\n if (response.status === 204) {\n return null as T;\n }\n\n return (await response.json()) as T;\n },\n [basePath],\n );\n\n const refreshUser = useCallback(async () => {\n setIsLoading(true);\n try {\n const { user: u } = await request<{ user: User | null }>(\"/me\");\n setUser(u);\n } catch {\n setUser(null);\n } finally {\n setIsLoading(false);\n }\n }, []);\n\n const refreshAccounts = useCallback(async () => {\n setIsLoadingAccounts(true);\n try {\n const { accounts: a } = await request<{ accounts: ConnectedAccount[] }>(\n \"/accounts\",\n );\n setAccounts(a);\n } catch {\n setAccounts([]);\n } finally {\n setIsLoadingAccounts(false);\n }\n }, []);\n\n const refreshOrganizations = useCallback(async () => {\n setIsLoadingOrganizations(true);\n try {\n const { organizations: orgs, currentOrgId: nextCurrentOrgId } =\n await request<{\n organizations: Organization[];\n currentOrgId?: string | null;\n }>(\"/organizations\");\n setOrganizations(orgs);\n setCurrentOrgId((current) => {\n if (nextCurrentOrgId !== undefined) return nextCurrentOrgId ?? null;\n if (current && orgs.some((org) => org.id === current)) return current;\n return orgs[0]?.id ?? null;\n });\n } catch {\n setOrganizations([]);\n setCurrentOrgId(null);\n } finally {\n setIsLoadingOrganizations(false);\n }\n }, []);\n\n useEffect(() => {\n void refreshUser();\n void refreshAccounts();\n void refreshOrganizations();\n }, [refreshAccounts, refreshOrganizations, refreshUser]);\n\n const currentOrg = useMemo(\n () => organizations.find((organization) => organization.id === currentOrgId) ?? null,\n [currentOrgId, organizations],\n );\n\n const setCurrentOrg = useCallback(\n async (organizationId: string | null) => {\n await request(\"/organizations/active\", {\n method: \"POST\",\n body: { organizationId },\n });\n setCurrentOrgId(organizationId);\n },\n [request],\n );\n\n const signIn = useCallback(\n async (input?: SignInInput) => {\n const options = normalizeSignInOptions(input);\n const url = new URL(buildUrl(basePath, \"/sign-in\"), window.location.origin);\n if (options?.redirectTo) url.searchParams.set(\"redirectTo\", options.redirectTo);\n if (options?.authorizationFlowId) url.searchParams.set(\"flow_id\", options.authorizationFlowId);\n if (options?.silentLogin === false) url.searchParams.set(\"silentLogin\", \"false\");\n redirectTo(url.toString());\n },\n [basePath],\n );\n\n const signUp = useCallback(\n async (input?: SignInInput) => {\n const options = normalizeSignInOptions(input);\n const url = new URL(buildUrl(basePath, \"/sign-up\"), window.location.origin);\n if (options?.redirectTo) url.searchParams.set(\"redirectTo\", options.redirectTo);\n if (options?.authorizationFlowId) url.searchParams.set(\"flow_id\", options.authorizationFlowId);\n if (options?.silentLogin === false) url.searchParams.set(\"silentLogin\", \"false\");\n redirectTo(url.toString());\n },\n [basePath],\n );\n\n const addAccount = useCallback(\n async (input?: SignInInput) => {\n const options = normalizeSignInOptions(input);\n const url = new URL(buildUrl(basePath, \"/add-account\"), window.location.origin);\n if (options?.redirectTo) url.searchParams.set(\"redirectTo\", options.redirectTo);\n redirectTo(url.toString());\n },\n [basePath],\n );\n\n const signOut = useCallback(async () => {\n await request(\"/sign-out\", { method: \"POST\" });\n setUser(null);\n await refreshAccounts();\n }, [refreshAccounts, request]);\n\n const signOutAll = useCallback(async () => {\n await request(\"/sign-out-all\", { method: \"POST\" });\n setUser(null);\n setAccounts([]);\n }, [request]);\n\n const switchAccount = useCallback(\n async (sessionId: string, options?: SignInOptions) => {\n await request(\"/accounts/switch\", {\n method: \"POST\",\n body: { sessionId },\n });\n await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);\n if (options?.redirectTo) redirectTo(options.redirectTo);\n },\n [refreshAccounts, refreshOrganizations, refreshUser, request],\n );\n\n async function toAuthResult<T>(fn: () => Promise<T>): Promise<AuthResult<T>> {\n try {\n return { success: true, data: await fn() };\n } catch (error) {\n return { success: false, error: error instanceof Error ? error.message : \"Unexpected error\" };\n }\n }\n\n const value = useMemo<GeekappsAuthContextValue>(\n () => ({\n basePath,\n user,\n isAuthenticated: !isLoading && user !== null,\n isLoading,\n accounts,\n isLoadingAccounts,\n organizations,\n currentOrg,\n currentOrgId,\n isLoadingOrganizations,\n request,\n signIn,\n signUp,\n addAccount,\n signOut,\n signOutAll,\n refreshUser,\n refreshAccounts,\n switchAccount,\n loginWithPassword: (params) =>\n toAuthResult(async () => {\n const data = await request<LoginResponse>(\"/login/password\", { method: \"POST\", body: params });\n await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);\n if (params.redirectTo ?? data.redirectTo) redirectTo(params.redirectTo ?? data.redirectTo!);\n return data;\n }),\n registerWithPassword: (params) =>\n toAuthResult(async () => {\n const data = await request<RegisterResponse>(\"/register/password\", { method: \"POST\", body: params });\n await Promise.all([refreshUser(), refreshAccounts(), refreshOrganizations()]);\n if (params.redirectTo) redirectTo(params.redirectTo);\n return data;\n }),\n startGoogleLogin: (params) => {\n const url = new URL(buildUrl(basePath, \"/login/google\"), window.location.origin);\n if (params?.callbackUrl) url.searchParams.set(\"callbackUrl\", params.callbackUrl);\n if (params?.redirectTo) url.searchParams.set(\"redirectTo\", params.redirectTo);\n if (params?.authorizationFlowId) url.searchParams.set(\"flow_id\", params.authorizationFlowId);\n redirectTo(url.toString());\n },\n requestPasswordlessLink: (params) =>\n toAuthResult(() => request(\"/passwordless/link\", { method: \"POST\", body: params })),\n refreshOrganizations,\n setCurrentOrg,\n createOrganization: (input) =>\n toAuthResult(async () => {\n const organization = await request<Organization>(\"/organizations\", { method: \"POST\", body: input });\n await refreshOrganizations();\n setCurrentOrgId(organization.id);\n return organization;\n }),\n updateOrganization: (id, input) =>\n toAuthResult(async () => {\n const organization = await request<Organization>(`/organizations/${id}`, { method: \"PATCH\", body: input });\n await refreshOrganizations();\n return organization;\n }),\n deleteOrganization: (id) =>\n toAuthResult(async () => {\n await request<null>(`/organizations/${id}`, { method: \"DELETE\" });\n await refreshOrganizations();\n return null;\n }),\n hasPermission: async (options) => {\n try {\n const data = await request<{ allowed: boolean }>(\"/permissions/check\", {\n method: \"POST\",\n body: options,\n });\n return data.allowed;\n } catch {\n return false;\n }\n },\n listUsers: (params) => {\n const query = new URLSearchParams();\n if (params?.organizationId) query.set(\"organizationId\", params.organizationId);\n return request<User[]>(`/users${query.size ? `?${query.toString()}` : \"\"}`);\n },\n getUser: (id) => request<User>(`/users/${id}`),\n createUser: (input) => toAuthResult(() => request<User>(\"/users\", { method: \"POST\", body: input })),\n updateUser: (id, input) => toAuthResult(() => request<User>(`/users/${id}`, { method: \"PATCH\", body: input })),\n deleteUser: (id) =>\n toAuthResult(async () => {\n await request<null>(`/users/${id}`, { method: \"DELETE\" });\n return null;\n }),\n listRoles: (params) => {\n const query = new URLSearchParams();\n if (params?.organizationId) query.set(\"organizationId\", params.organizationId);\n if (params?.applicationId) query.set(\"applicationId\", params.applicationId);\n if (params?.type) query.set(\"type\", params.type);\n return request<{ systemRoles: Role[]; customRoles: Role[] }>(`/roles${query.size ? `?${query.toString()}` : \"\"}`);\n },\n getRole: (id, type) => request<Role>(type === \"custom\" ? `/roles/custom/${id}` : `/roles/definitions/${id}`),\n createRole: (input) => toAuthResult(() => request<Role>(\"/roles\", { method: \"POST\", body: input })),\n updateRole: (id, input) => toAuthResult(() => request<Role>(`/roles/custom/${id}`, { method: \"PATCH\", body: input })),\n deleteRole: (id) =>\n toAuthResult(async () => {\n await request<null>(`/roles/custom/${id}`, { method: \"DELETE\" });\n return null;\n }),\n listPermissions: (params) => {\n const query = new URLSearchParams();\n if (params?.applicationId) query.set(\"applicationId\", params.applicationId);\n if (params?.roleId) query.set(\"roleId\", params.roleId);\n return request<Permission[]>(`/permissions${query.size ? `?${query.toString()}` : \"\"}`);\n },\n createPermission: (input) =>\n toAuthResult(() => request<Permission>(\"/permissions\", { method: \"POST\", body: input })),\n updatePermission: (id, input) =>\n toAuthResult(() => request<Permission>(`/permissions/${id}`, { method: \"PATCH\", body: input })),\n deletePermission: (id) =>\n toAuthResult(async () => {\n await request<null>(`/permissions/${id}`, { method: \"DELETE\" });\n return null;\n }),\n listUserSessions: (params) => {\n const query = new URLSearchParams();\n if (params?.userId) query.set(\"userId\", params.userId);\n if (params?.organizationId) query.set(\"organizationId\", params.organizationId);\n return request<UserSession[]>(`/sessions${query.size ? `?${query.toString()}` : \"\"}`);\n },\n revokeUserSession: (sessionId) =>\n toAuthResult(async () => {\n await request<null>(`/sessions/${sessionId}`, { method: \"DELETE\" });\n return null;\n }),\n listMembers: (organizationId) =>\n request<OrganizationMember[]>(`/organizations/${organizationId}/members`),\n updateMemberRole: (organizationId, memberId, input) =>\n toAuthResult(() =>\n request<OrganizationMember>(`/organizations/${organizationId}/members/${memberId}`, {\n method: \"PATCH\",\n body: input,\n }),\n ),\n removeMember: (organizationId, memberId) =>\n toAuthResult(async () => {\n await request<null>(`/organizations/${organizationId}/members/${memberId}`, { method: \"DELETE\" });\n return null;\n }),\n inviteMember: (organizationId, input) =>\n toAuthResult(() =>\n request<OrganizationInvite>(`/organizations/${organizationId}/invites`, {\n method: \"POST\",\n body: input,\n }),\n ),\n listInvites: (organizationId) =>\n request<OrganizationInvite[]>(`/organizations/${organizationId}/invites`),\n revokeInvite: (organizationId, inviteId) =>\n toAuthResult(async () => {\n await request<null>(`/organizations/${organizationId}/invites/${inviteId}`, { method: \"DELETE\" });\n return null;\n }),\n }),\n [\n accounts,\n addAccount,\n basePath,\n currentOrg,\n currentOrgId,\n isLoading,\n isLoadingAccounts,\n isLoadingOrganizations,\n organizations,\n refreshAccounts,\n refreshOrganizations,\n refreshUser,\n request,\n setCurrentOrg,\n signIn,\n signOut,\n signOutAll,\n signUp,\n switchAccount,\n user,\n ],\n );\n\n return <GeekappsAuthContext.Provider value={value}>{children}</GeekappsAuthContext.Provider>;\n}\n\nexport function useAuth(): GeekappsAuthContextValue {\n const context = useContext(GeekappsAuthContext);\n if (!context) throw new Error(\"useAuth must be used inside GeekappsAuthProvider\");\n return context;\n}\n\nexport function useOrg(): UseOrgResult {\n const context = useAuth();\n return {\n organizations: context.organizations,\n currentOrg: context.currentOrg,\n currentOrgId: context.currentOrgId,\n isLoadingOrganizations: context.isLoadingOrganizations,\n refreshOrganizations: context.refreshOrganizations,\n setCurrentOrg: context.setCurrentOrg,\n createOrganization: context.createOrganization,\n updateOrganization: context.updateOrganization,\n deleteOrganization: context.deleteOrganization,\n hasPermission: context.hasPermission,\n };\n}\n\nexport function useAccounts(): UseAccountsResult {\n const context = useAuth();\n return {\n accounts: context.accounts,\n addAccount: context.addAccount,\n isLoadingAccounts: context.isLoadingAccounts,\n refreshAccounts: context.refreshAccounts,\n switchAccount: context.switchAccount,\n };\n}\n\nexport function useUsers(): UseUsersResult {\n const context = useAuth();\n return {\n listUsers: context.listUsers,\n getUser: context.getUser,\n createUser: context.createUser,\n updateUser: context.updateUser,\n deleteUser: context.deleteUser,\n };\n}\n\nexport function useRoles(): UseRolesResult {\n const context = useAuth();\n return {\n listRoles: context.listRoles,\n getRole: context.getRole,\n createRole: context.createRole,\n updateRole: context.updateRole,\n deleteRole: context.deleteRole,\n };\n}\n\nexport function usePermissions(): UsePermissionsResult {\n const context = useAuth();\n return {\n listPermissions: context.listPermissions,\n createPermission: context.createPermission,\n updatePermission: context.updatePermission,\n deletePermission: context.deletePermission,\n };\n}\n\nexport function useSessions(): UseSessionsResult {\n const context = useAuth();\n return {\n listUserSessions: context.listUserSessions,\n revokeUserSession: context.revokeUserSession,\n };\n}\n\nexport function useMembers(): UseMembersResult {\n const context = useAuth();\n return {\n listMembers: context.listMembers,\n updateMemberRole: context.updateMemberRole,\n removeMember: context.removeMember,\n inviteMember: context.inviteMember,\n listInvites: context.listInvites,\n revokeInvite: context.revokeInvite,\n };\n}\n\n// ── Service Accounts ─────────────────────────────────────────────────────────\n\nexport type ServiceAccount = {\n id: string;\n membershipId: string;\n organizationId: string;\n applicationId: string | null;\n name: string;\n status: \"active\" | \"inactive\" | \"suspended\";\n serviceId: string | null;\n roleAssignment: { role: { id: string; key: string; name: string } } | null;\n createdAt: string;\n updatedAt: string;\n};\n\nexport type ServiceAccountWithSecret = ServiceAccount & { serviceSecret: string };\n\nexport type CreateServiceAccountInput = {\n organizationId: string;\n applicationId?: string;\n name: string;\n description?: string;\n roleId?: string;\n};\n\nexport type UseServiceAccountResult = {\n listServiceAccounts: (params: { organizationId: string; applicationId?: string }) => Promise<ServiceAccount[]>;\n createServiceAccount: (input: CreateServiceAccountInput) => Promise<ServiceAccountWithSecret>;\n updateServiceAccountRole: (id: string, roleId: string | null) => Promise<void>;\n revokeServiceAccount: (id: string) => Promise<void>;\n rotateServiceAccountSecret: (id: string) => Promise<{ serviceId: string; serviceSecret: string }>;\n deleteServiceAccount: (id: string) => Promise<void>;\n};\n\nexport function useServiceAccount(): UseServiceAccountResult {\n const { request } = useAuth();\n\n const listServiceAccounts = useCallback(\n (params: { organizationId: string; applicationId?: string }) => {\n const query = new URLSearchParams({ organizationId: params.organizationId });\n if (params.applicationId) query.set(\"applicationId\", params.applicationId);\n return request<ServiceAccount[]>(`/service-accounts?${query.toString()}`);\n },\n [request],\n );\n\n const createServiceAccount = useCallback(\n (input: CreateServiceAccountInput) =>\n request<ServiceAccountWithSecret>(\"/service-accounts\", { method: \"POST\", body: input }),\n [request],\n );\n\n const updateServiceAccountRole = useCallback(\n async (id: string, roleId: string | null) => {\n await request<void>(`/service-accounts/${id}`, { method: \"PATCH\", body: { roleId } });\n },\n [request],\n );\n\n const revokeServiceAccount = useCallback(\n async (id: string) => {\n await request<void>(`/service-accounts/${id}/revoke`, { method: \"POST\" });\n },\n [request],\n );\n\n const rotateServiceAccountSecret = useCallback(\n (id: string) =>\n request<{ serviceId: string; serviceSecret: string }>(`/service-accounts/${id}/rotate-secret`, {\n method: \"POST\",\n }),\n [request],\n );\n\n const deleteServiceAccount = useCallback(\n async (id: string) => {\n await request<null>(`/service-accounts/${id}`, { method: \"DELETE\" });\n },\n [request],\n );\n\n return {\n listServiceAccounts,\n createServiceAccount,\n updateServiceAccountRole,\n revokeServiceAccount,\n rotateServiceAccountSecret,\n deleteServiceAccount,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/middleware.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse, type NextRequest } from \"next/server\";\r\nimport { createRemoteJWKSet, jwtVerify } from \"jose\";\r\n\r\nexport type AuthMiddlewareConfig = {\r\n issuer?: string;\r\n basePath?: string;\r\n /**\r\n * @deprecated cookiePrefix is now auto-derived from GEEKAPPS_AUTH_CLIENT_ID.\r\n * This field is kept for backwards compatibility but is ignored.\r\n */\r\n cookiePrefix?: string;\r\n secureCookies?: boolean;\r\n /** Base URL of this app (e.g. \"https://meuapp.com\"). Overrides the GEEKAPPS_APP_URL env var. */\r\n appUrl?: string;\r\n /**\r\n * When true, unauthenticated requests are redirected to sign-in.\r\n * Defaults to false — the app controls its own auth-gating.\r\n */\r\n forceLoginOnUnauthenticated?: boolean;\r\n};\r\n\r\ntype TokenLikeResponse = {\r\n access_token?: string;\r\n accessToken?: string;\r\n refresh_token?: string;\r\n refreshToken?: string;\r\n id_token?: string;\r\n idToken?: string;\r\n};\r\n\r\nfunction env(name: string) {\r\n const value = process.env[name];\r\n return value && value.trim().length > 0 ? value : undefined;\r\n}\r\n\r\nfunction normalizeBaseUrl(url: string) {\r\n return url.replace(/\\/$/, \"\");\r\n}\r\n\r\nfunction normalizeBasePath(path = \"/api/auth\") {\r\n if (!path.startsWith(\"/\")) return `/${path}`;\r\n return path.replace(/\\/$/, \"\");\r\n}\r\n\r\nfunction resolveIssuer(input: AuthMiddlewareConfig) {\r\n return normalizeBaseUrl(\r\n input.issuer ??\r\n env(\"GEEKAPPS_AUTH_ISSUER\") ??\r\n env(\"GEEKAPPS_AUTH_API_URL\") ??\r\n \"http://localhost:3020\",\r\n );\r\n}\r\n\r\nfunction hashClientId(clientId: string): string {\r\n let h = 5381;\r\n for (let i = 0; i < clientId.length; i++) {\r\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\r\n h = h >>> 0;\r\n }\r\n return h.toString(16).padStart(8, \"0\");\r\n}\r\n\r\nfunction deriveCookiePrefix(clientId: string | undefined): string {\r\n if (!clientId) return \"gk\";\r\n return `gk_${hashClientId(clientId)}`;\r\n}\r\n\r\n\r\nconst MAX_REFRESH_ATTEMPTS = 3;\r\n\r\nfunction decodeJwtExp(token: string): number | null {\r\n try {\r\n const parts = token.split(\".\");\r\n if (parts.length !== 3) return null;\r\n const payload = parts[1]!;\r\n const padded = payload + \"=\".repeat((4 - (payload.length % 4)) % 4);\r\n const decoded = JSON.parse(atob(padded)) as { exp?: number };\r\n return typeof decoded.exp === \"number\" ? decoded.exp : null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\nfunction resolveAppOrigin(request: NextRequest, appUrl?: string): string {\r\n const configured =\r\n appUrl ??\r\n env(\"GEEKAPPS_APP_URL\");\r\n if (configured) return configured.replace(/\\/$/, \"\");\r\n\r\n throw new Error(\r\n \"Cannot determine app origin for redirect. Set GEEKAPPS_APP_URL.\",\r\n );\r\n}\r\n\r\nconst _jwksCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\r\n\r\nfunction getRemoteJWKS(issuer: string) {\r\n if (!_jwksCache.has(issuer)) {\r\n _jwksCache.set(issuer, createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`)));\r\n }\r\n return _jwksCache.get(issuer)!;\r\n}\r\n\r\ntype VerifyResult = \"valid\" | \"invalid\" | \"network_error\";\r\n\r\nasync function verifyAccessToken(token: string, issuer: string): Promise<VerifyResult> {\r\n try {\r\n await jwtVerify(token, getRemoteJWKS(issuer), { algorithms: [\"RS256\"], issuer });\r\n return \"valid\";\r\n } catch (err) {\r\n // TypeError is thrown by fetch when the JWKS endpoint is unreachable.\r\n if (err instanceof TypeError) return \"network_error\";\r\n // ERR_JWKS_* means the JWKS endpoint returned something unexpected\r\n // (e.g. no matching key yet after a key rotation, or a fetch-level error\r\n // wrapped by jose). Treat as transient so we don't destroy the session.\r\n const code = (err as { code?: string }).code ?? \"\";\r\n if (code.startsWith(\"ERR_JWKS\")) return \"network_error\";\r\n // Everything else (ERR_JWS_SIGNATURE_VERIFICATION_FAILED, ERR_JWT_EXPIRED,\r\n // ERR_JWT_CLAIM_VALIDATION_FAILED, …) means the token is genuinely invalid.\r\n return \"invalid\";\r\n }\r\n}\r\n\r\nexport function createAuthMiddleware(input: AuthMiddlewareConfig = {}) {\r\n const issuer = resolveIssuer(input);\r\n const basePath = normalizeBasePath(input.basePath);\r\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\");\r\n const prefix = deriveCookiePrefix(clientId);\r\n\r\n const activeCookie = `${prefix}_active`;\r\n const countCookie = `${prefix}_count`;\r\n const tokenPubCookie = `${prefix}_tp`; // legacy — cleared on next refresh\r\n const slotAt = (n: number) => `${prefix}_at${n}`;\r\n const slotRt = (n: number) => `${prefix}_rt${n}`;\r\n\r\n // RSC/prefetch requests are cross-origin fetches — a 302 redirect triggers CORS.\r\n // Return a redirect response that Next.js understands instead.\r\n function redirectResponse(request: NextRequest, url: URL): NextResponse {\r\n const isRsc =\r\n request.headers.has(\"rsc\") ||\r\n request.headers.has(\"next-router-prefetch\") ||\r\n request.nextUrl.searchParams.has(\"_rsc\");\r\n if (isRsc) {\r\n return new NextResponse(null, {\r\n status: 302,\r\n headers: {\r\n location: url.toString(),\r\n \"x-action-redirect\": url.toString(),\r\n vary: \"RSC, Next-Router-State-Tree, Next-Router-Prefetch\",\r\n },\r\n }) as NextResponse;\r\n }\r\n return NextResponse.redirect(url);\r\n }\r\n\r\n return async function authMiddleware(request: NextRequest): Promise<NextResponse> {\r\n // Always allow the SDK's own routes through — never redirect /api/auth/* to sign-in.\r\n if (request.nextUrl.pathname.startsWith(basePath + \"/\") || request.nextUrl.pathname === basePath) {\r\n return NextResponse.next();\r\n }\r\n\r\n const countRaw = request.cookies.get(countCookie)?.value;\r\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\r\n\r\n const activeRaw = request.cookies.get(activeCookie)?.value;\r\n let activeIdx = activeRaw ? Number.parseInt(activeRaw, 10) : 1;\r\n if (Number.isNaN(activeIdx) || activeIdx < 1 || activeIdx > count) {\r\n activeIdx = count > 0 ? 1 : 0;\r\n }\r\n\r\n // Fallback: if count cookie is missing/zero but slot 1 tokens exist, use slot 1.\r\n // This handles the case where the count/active control cookies expired before the token cookies.\r\n if (activeIdx === 0) {\r\n const fallbackAt = request.cookies.get(slotAt(1))?.value;\r\n const fallbackRt = request.cookies.get(slotRt(1))?.value;\r\n if (fallbackAt || fallbackRt) activeIdx = 1;\r\n }\r\n\r\n const accessToken = activeIdx > 0 ? (request.cookies.get(slotAt(activeIdx))?.value ?? null) : null;\r\n const refreshToken = activeIdx > 0 ? (request.cookies.get(slotRt(activeIdx))?.value ?? null) : null;\r\n\r\n const origin = resolveAppOrigin(request, input.appUrl);\r\n const signInUrl = new URL(`${origin}${basePath}/sign-in`);\r\n const redirectTo = request.nextUrl.pathname + request.nextUrl.search;\r\n if (redirectTo && redirectTo !== \"/\") {\r\n signInUrl.searchParams.set(\"redirectTo\", redirectTo);\r\n }\r\n\r\n if (!accessToken && !refreshToken) {\r\n if (input.forceLoginOnUnauthenticated) return redirectResponse(request, signInUrl);\r\n return NextResponse.next();\r\n }\r\n\r\n // Fast-path: check exp before hitting JWKS (avoids network on every request)\r\n const exp = accessToken ? decodeJwtExp(accessToken) : null;\r\n const nowSec = Math.floor(Date.now() / 1000);\r\n const expiredOrMissing = !exp || exp - nowSec < 60;\r\n\r\n if (!expiredOrMissing) {\r\n // Verify signature against app-api JWKS\r\n const verifyResult = await verifyAccessToken(accessToken!, issuer);\r\n if (verifyResult === \"valid\") return NextResponse.next();\r\n // If JWKS endpoint is unreachable, fail-open to avoid destroying the session.\r\n if (verifyResult === \"network_error\") return NextResponse.next();\r\n // \"invalid\" — fall through to refresh attempt below.\r\n }\r\n\r\n if (!refreshToken) {\r\n if (input.forceLoginOnUnauthenticated) return redirectResponse(request, signInUrl);\r\n return NextResponse.next();\r\n }\r\n\r\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\") ?? \"\";\r\n const basicAuth = btoa(`${clientId ?? \"\"}:${clientSecret}`);\r\n\r\n let newAccessToken: string | null = null;\r\n let newRefreshToken: string | null = null;\r\n\r\n for (let attempt = 1; attempt <= MAX_REFRESH_ATTEMPTS; attempt++) {\r\n try {\r\n const refreshResponse = await fetch(`${issuer}/auth/token`, {\r\n method: \"POST\",\r\n headers: {\r\n \"content-type\": \"application/x-www-form-urlencoded\",\r\n authorization: `Basic ${basicAuth}`,\r\n },\r\n body: new URLSearchParams({\r\n grant_type: \"refresh_token\",\r\n refresh_token: refreshToken,\r\n }),\r\n cache: \"no-store\",\r\n });\r\n\r\n if (!refreshResponse.ok) break;\r\n\r\n const data = (await refreshResponse.json()) as TokenLikeResponse;\r\n newAccessToken = data.accessToken ?? data.access_token ?? null;\r\n newRefreshToken = data.refreshToken ?? data.refresh_token ?? null;\r\n if (newAccessToken) break;\r\n } catch {\r\n if (attempt === MAX_REFRESH_ATTEMPTS) break;\r\n }\r\n }\r\n\r\n if (!newAccessToken) {\r\n // Refresh failed — clear the active slot and optionally redirect to sign-in\r\n const response = input.forceLoginOnUnauthenticated\r\n ? redirectResponse(request, signInUrl)\r\n : NextResponse.next();\r\n const clearOpts = {\r\n httpOnly: true,\r\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\r\n sameSite: \"lax\" as const,\r\n path: \"/\",\r\n maxAge: 0,\r\n };\r\n response.cookies.set(slotAt(activeIdx), \"\", clearOpts);\r\n response.cookies.set(slotRt(activeIdx), \"\", clearOpts);\r\n response.cookies.set(`${prefix}_m${activeIdx}`, \"\", clearOpts);\r\n response.cookies.set(tokenPubCookie, \"\", { ...clearOpts, httpOnly: false });\r\n response.cookies.set(activeCookie, \"0\", clearOpts);\r\n return response;\r\n }\r\n\r\n const cookieOptions = {\r\n httpOnly: true,\r\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\r\n sameSite: \"lax\" as const,\r\n path: \"/\",\r\n maxAge: 60 * 60 * 24 * 30,\r\n };\r\n\r\n // Forward new token via request header so server actions in the same\r\n // request can read it — response cookies are not visible within the same request.\r\n const requestHeaders = new Headers(request.headers);\r\n requestHeaders.set(\"authorization\", `Bearer ${newAccessToken}`);\r\n\r\n const response = NextResponse.next({ request: { headers: requestHeaders } });\r\n response.cookies.set(slotAt(activeIdx), newAccessToken, cookieOptions);\r\n if (newRefreshToken) response.cookies.set(slotRt(activeIdx), newRefreshToken, cookieOptions);\r\n // Clear legacy _tp cookie to reduce header size\r\n if (request.cookies.get(tokenPubCookie)?.value) {\r\n response.cookies.set(tokenPubCookie, \"\", { httpOnly: false, maxAge: 0, path: \"/\" });\r\n }\r\n\r\n return response;\r\n };\r\n}\r\n"],"mappings":"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","names":["response"]}
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts"],"sourcesContent":["import { NextResponse, type NextRequest } from \"next/server\";\nimport { createRemoteJWKSet, jwtVerify } from \"jose\";\n\nexport type AuthMiddlewareConfig = {\n issuer?: string;\n basePath?: string;\n /**\n * @deprecated cookiePrefix is now auto-derived from GEEKAPPS_AUTH_CLIENT_ID.\n * This field is kept for backwards compatibility but is ignored.\n */\n cookiePrefix?: string;\n secureCookies?: boolean;\n /** Base URL of this app (e.g. \"https://meuapp.com\"). Overrides the GEEKAPPS_APP_URL env var. */\n appUrl?: string;\n /**\n * When true, unauthenticated requests are redirected to sign-in.\n * Defaults to false — the app controls its own auth-gating.\n */\n forceLoginOnUnauthenticated?: boolean;\n};\n\ntype TokenLikeResponse = {\n access_token?: string;\n accessToken?: string;\n refresh_token?: string;\n refreshToken?: string;\n id_token?: string;\n idToken?: string;\n};\n\nfunction env(name: string) {\n const value = process.env[name];\n return value && value.trim().length > 0 ? value : undefined;\n}\n\nfunction normalizeBaseUrl(url: string) {\n return url.replace(/\\/$/, \"\");\n}\n\nfunction normalizeBasePath(path = \"/api/auth\") {\n if (!path.startsWith(\"/\")) return `/${path}`;\n return path.replace(/\\/$/, \"\");\n}\n\nfunction resolveIssuer(input: AuthMiddlewareConfig) {\n return normalizeBaseUrl(\n input.issuer ??\n env(\"GEEKAPPS_AUTH_ISSUER\") ??\n env(\"GEEKAPPS_AUTH_API_URL\") ??\n \"http://localhost:3020\",\n );\n}\n\nfunction hashClientId(clientId: string): string {\n let h = 5381;\n for (let i = 0; i < clientId.length; i++) {\n h = ((h << 5) + h) ^ (clientId.charCodeAt(i) & 0xff);\n h = h >>> 0;\n }\n return h.toString(16).padStart(8, \"0\");\n}\n\nfunction deriveCookiePrefix(clientId: string | undefined): string {\n if (!clientId) return \"gk\";\n return `gk_${hashClientId(clientId)}`;\n}\n\n\nconst MAX_REFRESH_ATTEMPTS = 3;\n\nfunction decodeJwtExp(token: string): number | null {\n try {\n const parts = token.split(\".\");\n if (parts.length !== 3) return null;\n const payload = parts[1]!;\n const padded = payload + \"=\".repeat((4 - (payload.length % 4)) % 4);\n const decoded = JSON.parse(atob(padded)) as { exp?: number };\n return typeof decoded.exp === \"number\" ? decoded.exp : null;\n } catch {\n return null;\n }\n}\n\nfunction resolveAppOrigin(request: NextRequest, appUrl?: string): string {\n const configured =\n appUrl ??\n env(\"GEEKAPPS_APP_URL\");\n if (configured) return configured.replace(/\\/$/, \"\");\n\n throw new Error(\n \"Cannot determine app origin for redirect. Set GEEKAPPS_APP_URL.\",\n );\n}\n\nconst _jwksCache = new Map<string, ReturnType<typeof createRemoteJWKSet>>();\n\nfunction getRemoteJWKS(issuer: string) {\n if (!_jwksCache.has(issuer)) {\n _jwksCache.set(issuer, createRemoteJWKSet(new URL(`${issuer}/.well-known/jwks.json`)));\n }\n return _jwksCache.get(issuer)!;\n}\n\ntype VerifyResult = \"valid\" | \"invalid\" | \"network_error\";\n\nasync function verifyAccessToken(token: string, issuer: string): Promise<VerifyResult> {\n try {\n await jwtVerify(token, getRemoteJWKS(issuer), { algorithms: [\"RS256\"], issuer });\n return \"valid\";\n } catch (err) {\n // TypeError is thrown by fetch when the JWKS endpoint is unreachable.\n if (err instanceof TypeError) return \"network_error\";\n // ERR_JWKS_* means the JWKS endpoint returned something unexpected\n // (e.g. no matching key yet after a key rotation, or a fetch-level error\n // wrapped by jose). Treat as transient so we don't destroy the session.\n const code = (err as { code?: string }).code ?? \"\";\n if (code.startsWith(\"ERR_JWKS\")) return \"network_error\";\n // Everything else (ERR_JWS_SIGNATURE_VERIFICATION_FAILED, ERR_JWT_EXPIRED,\n // ERR_JWT_CLAIM_VALIDATION_FAILED, …) means the token is genuinely invalid.\n return \"invalid\";\n }\n}\n\nexport function createAuthMiddleware(input: AuthMiddlewareConfig = {}) {\n const issuer = resolveIssuer(input);\n const basePath = normalizeBasePath(input.basePath);\n const clientId = env(\"GEEKAPPS_AUTH_CLIENT_ID\");\n const prefix = deriveCookiePrefix(clientId);\n\n const activeCookie = `${prefix}_active`;\n const countCookie = `${prefix}_count`;\n const tokenPubCookie = `${prefix}_tp`; // legacy — cleared on next refresh\n const slotAt = (n: number) => `${prefix}_at${n}`;\n const slotRt = (n: number) => `${prefix}_rt${n}`;\n\n // RSC/prefetch requests are cross-origin fetches — a 302 redirect triggers CORS.\n // Return a redirect response that Next.js understands instead.\n function redirectResponse(request: NextRequest, url: URL): NextResponse {\n const isRsc =\n request.headers.has(\"rsc\") ||\n request.headers.has(\"next-router-prefetch\") ||\n request.nextUrl.searchParams.has(\"_rsc\");\n if (isRsc) {\n return new NextResponse(null, {\n status: 302,\n headers: {\n location: url.toString(),\n \"x-action-redirect\": url.toString(),\n vary: \"RSC, Next-Router-State-Tree, Next-Router-Prefetch\",\n },\n }) as NextResponse;\n }\n return NextResponse.redirect(url);\n }\n\n return async function authMiddleware(request: NextRequest): Promise<NextResponse> {\n // Always allow the SDK's own routes through — never redirect /api/auth/* to sign-in.\n if (request.nextUrl.pathname.startsWith(basePath + \"/\") || request.nextUrl.pathname === basePath) {\n return NextResponse.next();\n }\n\n const countRaw = request.cookies.get(countCookie)?.value;\n const count = countRaw ? Number.parseInt(countRaw, 10) : 0;\n\n const activeRaw = request.cookies.get(activeCookie)?.value;\n let activeIdx = activeRaw ? Number.parseInt(activeRaw, 10) : 1;\n if (Number.isNaN(activeIdx) || activeIdx < 1 || activeIdx > count) {\n activeIdx = count > 0 ? 1 : 0;\n }\n\n // Fallback: if count cookie is missing/zero but slot 1 tokens exist, use slot 1.\n // This handles the case where the count/active control cookies expired before the token cookies.\n if (activeIdx === 0) {\n const fallbackAt = request.cookies.get(slotAt(1))?.value;\n const fallbackRt = request.cookies.get(slotRt(1))?.value;\n if (fallbackAt || fallbackRt) activeIdx = 1;\n }\n\n const accessToken = activeIdx > 0 ? (request.cookies.get(slotAt(activeIdx))?.value ?? null) : null;\n const refreshToken = activeIdx > 0 ? (request.cookies.get(slotRt(activeIdx))?.value ?? null) : null;\n\n const origin = resolveAppOrigin(request, input.appUrl);\n const signInUrl = new URL(`${origin}${basePath}/sign-in`);\n const redirectTo = request.nextUrl.pathname + request.nextUrl.search;\n if (redirectTo && redirectTo !== \"/\") {\n signInUrl.searchParams.set(\"redirectTo\", redirectTo);\n }\n\n if (!accessToken && !refreshToken) {\n if (input.forceLoginOnUnauthenticated) return redirectResponse(request, signInUrl);\n return NextResponse.next();\n }\n\n // Fast-path: check exp before hitting JWKS (avoids network on every request)\n const exp = accessToken ? decodeJwtExp(accessToken) : null;\n const nowSec = Math.floor(Date.now() / 1000);\n const expiredOrMissing = !exp || exp - nowSec < 60;\n\n if (!expiredOrMissing) {\n // Verify signature against app-api JWKS\n const verifyResult = await verifyAccessToken(accessToken!, issuer);\n if (verifyResult === \"valid\") return NextResponse.next();\n // If JWKS endpoint is unreachable, fail-open to avoid destroying the session.\n if (verifyResult === \"network_error\") return NextResponse.next();\n // \"invalid\" — fall through to refresh attempt below.\n }\n\n if (!refreshToken) {\n if (input.forceLoginOnUnauthenticated) return redirectResponse(request, signInUrl);\n return NextResponse.next();\n }\n\n const clientSecret = env(\"GEEKAPPS_AUTH_CLIENT_SECRET\") ?? \"\";\n const basicAuth = btoa(`${clientId ?? \"\"}:${clientSecret}`);\n\n let newAccessToken: string | null = null;\n let newRefreshToken: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_REFRESH_ATTEMPTS; attempt++) {\n try {\n const refreshResponse = await fetch(`${issuer}/auth/token`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/x-www-form-urlencoded\",\n authorization: `Basic ${basicAuth}`,\n },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n }),\n cache: \"no-store\",\n });\n\n if (!refreshResponse.ok) break;\n\n const data = (await refreshResponse.json()) as TokenLikeResponse;\n newAccessToken = data.accessToken ?? data.access_token ?? null;\n newRefreshToken = data.refreshToken ?? data.refresh_token ?? null;\n if (newAccessToken) break;\n } catch {\n if (attempt === MAX_REFRESH_ATTEMPTS) break;\n }\n }\n\n if (!newAccessToken) {\n // Refresh failed — clear the active slot and optionally redirect to sign-in\n const response = input.forceLoginOnUnauthenticated\n ? redirectResponse(request, signInUrl)\n : NextResponse.next();\n const clearOpts = {\n httpOnly: true,\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 0,\n };\n response.cookies.set(slotAt(activeIdx), \"\", clearOpts);\n response.cookies.set(slotRt(activeIdx), \"\", clearOpts);\n response.cookies.set(`${prefix}_m${activeIdx}`, \"\", clearOpts);\n response.cookies.set(tokenPubCookie, \"\", { ...clearOpts, httpOnly: false });\n response.cookies.set(activeCookie, \"0\", clearOpts);\n return response;\n }\n\n const cookieOptions = {\n httpOnly: true,\n secure: input.secureCookies ?? process.env.NODE_ENV === \"production\",\n sameSite: \"lax\" as const,\n path: \"/\",\n maxAge: 60 * 60 * 24 * 30,\n };\n\n // Forward new token via request header so server actions in the same\n // request can read it — response cookies are not visible within the same request.\n const requestHeaders = new Headers(request.headers);\n requestHeaders.set(\"authorization\", `Bearer ${newAccessToken}`);\n\n const response = NextResponse.next({ request: { headers: requestHeaders } });\n response.cookies.set(slotAt(activeIdx), newAccessToken, cookieOptions);\n if (newRefreshToken) response.cookies.set(slotRt(activeIdx), newRefreshToken, cookieOptions);\n // Clear legacy _tp cookie to reduce header size\n if (request.cookies.get(tokenPubCookie)?.value) {\n response.cookies.set(tokenPubCookie, \"\", { httpOnly: false, maxAge: 0, path: \"/\" });\n }\n\n return response;\n };\n}\n"],"mappings":"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","names":["response"]}
|