{"version":3,"sources":["../src/auth/pkce.ts","../src/auth/oauth-client.ts"],"sourcesContent":["const CHARSET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~\"\n\n/**\n * Generate a cryptographically random code verifier for PKCE.\n * Returns a 43-character URL-safe string (the minimum length per RFC 7636).\n * Uses globalThis.crypto for cross-runtime compatibility (Node 18+, Deno, Bun, edge).\n */\nexport function generateCodeVerifier(): string {\n  const bytes = new Uint8Array(43)\n  globalThis.crypto.getRandomValues(bytes)\n  let result = \"\"\n  for (const byte of bytes) {\n    result += CHARSET[byte % CHARSET.length]\n  }\n  return result\n}\n\n/**\n * Compute an S256 code challenge from a code verifier.\n * SHA-256 hash → base64url encoded (no padding).\n * Uses globalThis.crypto.subtle for cross-runtime compatibility.\n */\nexport async function generateCodeChallenge(verifier: string): Promise<string> {\n  const encoder = new TextEncoder()\n  const data = encoder.encode(verifier)\n  const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", data)\n  const bytes = new Uint8Array(digest)\n  let binary = \"\"\n  for (const byte of bytes) {\n    binary += String.fromCharCode(byte)\n  }\n  return btoa(binary).replace(/\\+/g, \"-\").replace(/\\//g, \"_\").replace(/=+$/, \"\")\n}\n","import { ContentstackHttpClient } from \"../http/client.js\"\nimport {\n  ContentstackAuthError,\n  ContentstackConfigError,\n  ContentstackError,\n} from \"../http/errors.js\"\nimport type { ContentstackRegion } from \"../regions/index.js\"\nimport { resolveEndpoints } from \"../regions/index.js\"\nimport { generateCodeChallenge, generateCodeVerifier } from \"./pkce.js\"\nimport type { AuthHttpOptions, ContentstackUser, OAuthConfig, OAuthTokens } from \"./types.js\"\n\ninterface AuthorizationUrlOptions {\n  state?: string\n  usePKCE?: boolean\n}\n\ninterface AuthorizationUrlResult {\n  url: string\n  state: string\n  codeVerifier?: string\n}\n\ninterface ExchangeCodeOptions {\n  codeVerifier?: string\n  httpOptions?: AuthHttpOptions\n}\n\nfunction validateConfig(config: OAuthConfig): void {\n  if (!config.appId) {\n    throw new ContentstackConfigError(\n      \"appId is required for OAuth. This is your Contentstack app's UID, not the client ID.\",\n    )\n  }\n  if (config.appId === config.clientId) {\n    throw new ContentstackConfigError(\n      \"appId and clientId must be different. appId is your Contentstack app UID; clientId is the OAuth client identifier.\",\n    )\n  }\n}\n\n/**\n * Build a Contentstack OAuth authorization URL.\n *\n * @example\n * ```ts\n * const { url, state, codeVerifier } = await buildAuthorizationUrl({\n *   region: \"us\",\n *   appId: \"app-uid\",\n *   clientId: \"client-id\",\n *   clientSecret: \"secret\",\n *   scopes: [\"user:read\"],\n *   redirectUri: \"http://localhost:3000/api/auth/callback/contentstack\",\n * }, { usePKCE: true })\n * ```\n */\nexport async function buildAuthorizationUrl(\n  config: OAuthConfig,\n  options?: AuthorizationUrlOptions,\n): Promise<AuthorizationUrlResult> {\n  validateConfig(config)\n\n  const endpoints = resolveEndpoints(config.region)\n  const authorizationUrl = `${endpoints.app}/apps/${config.appId}/authorize`\n\n  const state = options?.state ?? generateCodeVerifier()\n\n  const params = new URLSearchParams({\n    response_type: \"code\",\n    client_id: config.clientId,\n    redirect_uri: config.redirectUri,\n    scope: config.scopes.join(\" \"),\n    state,\n  })\n\n  let codeVerifier: string | undefined\n  if (options?.usePKCE) {\n    codeVerifier = generateCodeVerifier()\n    const codeChallenge = await generateCodeChallenge(codeVerifier)\n    params.set(\"code_challenge\", codeChallenge)\n    params.set(\"code_challenge_method\", \"S256\")\n  }\n\n  return {\n    url: `${authorizationUrl}?${params.toString()}`,\n    state,\n    codeVerifier,\n  }\n}\n\nfunction mapTokenResponse(data: Record<string, unknown>): OAuthTokens {\n  return {\n    accessToken: data.access_token as string,\n    refreshToken: (data.refresh_token as string | undefined) ?? \"\",\n    expiresIn: data.expires_in as number,\n    tokenType: data.token_type as string,\n  }\n}\n\nasync function makeTokenRequest(\n  appBaseUrl: string,\n  body: URLSearchParams,\n  errorMessage: string,\n  httpOptions?: AuthHttpOptions,\n): Promise<OAuthTokens> {\n  const client = new ContentstackHttpClient({ ...httpOptions, baseUrl: appBaseUrl })\n  try {\n    const { data } = await client.postForm<Record<string, unknown>>(\"/apps-api/token\", body)\n    return mapTokenResponse(data)\n  } catch (err) {\n    if (err instanceof ContentstackError) {\n      throw new ContentstackAuthError(err.message || errorMessage, {\n        status: err.status,\n        requestPath: \"/apps-api/token\",\n        cause: err,\n      })\n    }\n    throw new ContentstackAuthError(errorMessage, {\n      requestPath: \"/apps-api/token\",\n      cause: err instanceof Error ? err : undefined,\n    })\n  }\n}\n\n/**\n * Exchange an authorization code for OAuth tokens.\n */\nexport async function exchangeCode(\n  config: OAuthConfig,\n  code: string,\n  options?: ExchangeCodeOptions,\n): Promise<OAuthTokens> {\n  const endpoints = resolveEndpoints(config.region)\n\n  const body = new URLSearchParams({\n    grant_type: \"authorization_code\",\n    code,\n    redirect_uri: config.redirectUri,\n    client_id: config.clientId,\n    client_secret: config.clientSecret,\n  })\n\n  if (options?.codeVerifier) {\n    body.set(\"code_verifier\", options.codeVerifier)\n  }\n\n  return makeTokenRequest(\n    endpoints.app,\n    body,\n    \"Failed to exchange authorization code\",\n    options?.httpOptions,\n  )\n}\n\n/**\n * Refresh an expired access token using a refresh token.\n */\nexport async function refreshToken(\n  config: OAuthConfig,\n  token: string,\n  options?: { httpOptions?: AuthHttpOptions },\n): Promise<OAuthTokens> {\n  const endpoints = resolveEndpoints(config.region)\n\n  const body = new URLSearchParams({\n    grant_type: \"refresh_token\",\n    refresh_token: token,\n    client_id: config.clientId,\n    client_secret: config.clientSecret,\n  })\n\n  return makeTokenRequest(endpoints.app, body, \"Failed to refresh token\", options?.httpOptions)\n}\n\nexport interface AppTokenCredentials {\n  clientId: string\n  clientSecret: string\n}\n\n/**\n * Obtain an app token (client credentials grant) for machine-to-machine integrations.\n * Requires the app's `app_token_config` to be enabled with the needed scopes.\n */\nexport async function exchangeAppToken(\n  region: ContentstackRegion,\n  credentials: AppTokenCredentials,\n  options?: { httpOptions?: AuthHttpOptions },\n): Promise<OAuthTokens> {\n  const endpoints = resolveEndpoints(region)\n\n  const body = new URLSearchParams({\n    grant_type: \"client_credentials\",\n    client_id: credentials.clientId,\n    client_secret: credentials.clientSecret,\n  })\n\n  return makeTokenRequest(endpoints.app, body, \"Failed to obtain app token\", options?.httpOptions)\n}\n\nfunction mapUser(user: Record<string, unknown>): ContentstackUser {\n  return {\n    uid: user.uid as string,\n    email: user.email as string,\n    firstName: (user.first_name as string) ?? undefined,\n    lastName: (user.last_name as string) ?? undefined,\n    username: (user.username as string) ?? undefined,\n    profileImage: (user.profile_image as string) ?? undefined,\n  }\n}\n\n/**\n * Fetch the authenticated user's profile from Contentstack.\n * Unwraps the nested `user` key and maps snake_case → camelCase.\n */\nexport async function getUser(\n  region: ContentstackRegion,\n  accessToken: string,\n  options?: { httpOptions?: AuthHttpOptions },\n): Promise<ContentstackUser> {\n  const endpoints = resolveEndpoints(region)\n  const client = new ContentstackHttpClient({\n    ...options?.httpOptions,\n    baseUrl: `${endpoints.cma}/v3`,\n    headers: { Authorization: `Bearer ${accessToken}` },\n  })\n\n  try {\n    const { data } = await client.get<{ user: Record<string, unknown> }>(\"/user\")\n    return mapUser(data.user)\n  } catch (err) {\n    if (err instanceof ContentstackError) {\n      throw new ContentstackAuthError(err.message || \"Failed to fetch user profile\", {\n        status: err.status,\n        requestPath: \"/v3/user\",\n        cause: err,\n      })\n    }\n    throw new ContentstackAuthError(\"Failed to fetch user profile\", {\n      requestPath: \"/v3/user\",\n      cause: err instanceof Error ? err : undefined,\n    })\n  }\n}\n\n/**\n * Create an Auth.js v5 provider config object for Contentstack.\n *\n * No Auth.js dependency is required in this package — the returned object\n * conforms to the Auth.js OAuthConfig shape and can be passed directly to\n * `next-auth` or `@auth/core`.\n *\n * @example\n * ```ts\n * // app/api/auth/[...nextauth]/route.ts\n * import NextAuth from \"next-auth\"\n * import { createAuthProvider } from \"@timbenniks/contentstack-platform-sdk/auth\"\n *\n * export const { handlers, signIn, signOut, auth } = NextAuth({\n *   providers: [createAuthProvider({ region: \"us\", appId: \"...\", ... })],\n * })\n * ```\n */\nexport function createAuthProvider(config: OAuthConfig): Record<string, unknown> {\n  validateConfig(config)\n\n  const endpoints = resolveEndpoints(config.region)\n  const userClient = new ContentstackHttpClient({ baseUrl: `${endpoints.cma}/v3` })\n\n  return {\n    id: \"contentstack\",\n    name: \"Contentstack\",\n    type: \"oauth\",\n    checks: [\"state\"],\n    authorization: {\n      url: `${endpoints.app}/apps/${config.appId}/authorize`,\n      params: {\n        response_type: \"code\",\n        scope: config.scopes.join(\" \"),\n      },\n    },\n    token: `${endpoints.app}/apps-api/token`,\n    userinfo: {\n      url: `${endpoints.cma}/v3/user`,\n      async request({ tokens }: { tokens: { access_token: string } }) {\n        const authedClient = userClient.withHeaders({\n          Authorization: `Bearer ${tokens.access_token}`,\n        })\n        const { data } = await authedClient.get<Record<string, unknown>>(\"/user\")\n        return data\n      },\n    },\n    profile(profile: { user: Record<string, unknown> }) {\n      const user = profile.user\n      return {\n        id: user.uid as string,\n        name:\n          [user.first_name, user.last_name].filter(Boolean).join(\" \") || (user.username as string),\n        email: user.email as string,\n        image: (user.profile_image as string) ?? null,\n      }\n    },\n    clientId: config.clientId,\n    clientSecret: config.clientSecret,\n  }\n}\n\n/**\n * Create Auth.js v5 callbacks for token persistence and automatic refresh.\n *\n * The `jwt` callback persists OAuth tokens on initial sign-in and attempts\n * to refresh expired tokens (with a 60-second safety window).\n *\n * The `session` callback exposes the access token and any refresh errors\n * on the session object.\n *\n * @example\n * ```ts\n * import NextAuth from \"next-auth\"\n * import { createAuthProvider, contentstackAuthCallbacks } from \"@timbenniks/contentstack-platform-sdk/auth\"\n *\n * export const { handlers, auth } = NextAuth({\n *   providers: [createAuthProvider({ ... })],\n *   callbacks: contentstackAuthCallbacks({ region: \"us\", ... }),\n * })\n * ```\n */\nexport function contentstackAuthCallbacks(config: OAuthConfig) {\n  return {\n    async jwt({\n      token,\n      account,\n    }: { token: Record<string, unknown>; account?: Record<string, unknown> | null }) {\n      // Initial sign-in: persist tokens from the OAuth account\n      if (account) {\n        token.accessToken = account.access_token\n        token.refreshToken = account.refresh_token\n        token.accessTokenExpiresAt = Date.now() + ((account.expires_in as number) ?? 3600) * 1000\n        return token\n      }\n\n      // Subsequent calls: check if token needs refresh (60s safety window)\n      const expiresAt = token.accessTokenExpiresAt as number | undefined\n      if (expiresAt && Date.now() < expiresAt - 60_000) {\n        return token\n      }\n\n      // Token is expired or about to expire — attempt refresh\n      const currentRefreshToken = token.refreshToken as string | undefined\n      if (!currentRefreshToken) {\n        token.error = \"RefreshAccessTokenError\"\n        return token\n      }\n\n      try {\n        const tokens = await refreshToken(config, currentRefreshToken)\n        token.accessToken = tokens.accessToken\n        token.refreshToken = tokens.refreshToken\n        token.accessTokenExpiresAt = Date.now() + tokens.expiresIn * 1000\n        token.error = undefined\n      } catch {\n        token.error = \"RefreshAccessTokenError\"\n      }\n\n      return token\n    },\n    async session({\n      session,\n      token,\n    }: { session: Record<string, unknown>; token: Record<string, unknown> }) {\n      session.accessToken = token.accessToken\n      if (token.error) {\n        session.error = token.error\n      }\n      return session\n    },\n  }\n}\n"],"mappings":"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","names":[]}