@foldspace-fe/casdoor-next-auth-kit 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/billing/runtime.ts","../src/billing/casdoor-purchase.ts"],"sourcesContent":["import type {\n BillingActionPayload,\n BillingCatalogConfig,\n BillingCreditsState,\n BillingEntitlementState,\n BillingInterval,\n BillingItem,\n BillingPurchasableEntry,\n BillingPaymentCallbackContext,\n BillingPurchaseRequest,\n BillingOrderHistoryItem,\n BillingPaymentHistoryItem,\n BillingProductSnapshot,\n BillingProductState,\n BillingPurchaseStatus,\n BillingRuntimeConfig,\n BillingSubscriptionHistoryItem,\n BillingSubscriptionState,\n} from './types';\n\nfunction normalizeCasdoorProductId(id: string): { owner: string; name: string } {\n const [owner, ...rest] = id.split('/');\n const name = rest.join('/');\n\n if (!owner || !name) {\n throw new Error(`Invalid Casdoor product id: ${id}`);\n }\n\n return { owner, name };\n}\n\nexport function normalizeBillingRuntimeConfig(config?: Partial<BillingRuntimeConfig> | null): BillingRuntimeConfig {\n return {\n catalogKey: config?.catalogKey ?? 'default',\n items: config?.items ?? [],\n purchasableIds: config?.purchasableIds ?? [],\n purchasables: config?.purchasables ?? [],\n conversionRules: config?.conversionRules ?? [],\n defaults: config?.defaults ?? {},\n };\n}\n\nexport function normalizeBillingCatalogConfig(config?: Partial<BillingCatalogConfig> | null): BillingCatalogConfig {\n return {\n ...normalizeBillingRuntimeConfig(config),\n title: config?.title,\n description: config?.description,\n portalPath: config?.portalPath,\n successPath: config?.successPath,\n cancelPath: config?.cancelPath,\n };\n}\n\nexport function resolveBillingItem(items: BillingItem[] | undefined, key?: string | null): BillingItem | undefined {\n if (!key) return undefined;\n return items?.find((item) => item.key === key || item.backendRef.productId === key || item.backendRef.planId === key);\n}\n\nfunction isBillingPurchasableIdMatch(id: string, item: BillingItem | BillingPurchasableEntry): boolean {\n return id === item.key || id === item.backendRef.productId || ('planId' in item.backendRef && id === item.backendRef.planId);\n}\n\nexport function resolveBillingPurchasable(\n runtimeConfig: BillingRuntimeConfig | undefined,\n key?: string | null,\n): BillingPurchasableEntry | undefined {\n if (!runtimeConfig || !key) {\n return undefined;\n }\n\n const explicit = runtimeConfig.purchasables?.find(\n (item) => item.key === key || item.backendRef.productId === key || ('planId' in item.backendRef && item.backendRef.planId === key),\n );\n if (explicit) {\n return explicit;\n }\n\n if (runtimeConfig.purchasableIds?.length) {\n const matchingItem = resolveBillingItem(runtimeConfig.items, key);\n if (!matchingItem) {\n return undefined;\n }\n\n const allowed = runtimeConfig.purchasableIds.some((itemKey) => isBillingPurchasableIdMatch(itemKey, matchingItem));\n if (!allowed) {\n return undefined;\n }\n }\n\n const item = resolveBillingItem(runtimeConfig.items, key);\n if (!item) {\n return undefined;\n }\n\n if (item.kind === 'subscription') {\n return {\n key: item.key,\n kind: 'subscription',\n title: item.title,\n description: item.description,\n enabled: true,\n backendRef: {\n productId: item.backendRef.productId,\n planId: item.backendRef.planId,\n priceId: item.backendRef.priceId,\n },\n interval: item.interval,\n hooks: undefined,\n };\n }\n\n return {\n key: item.key,\n kind: 'product',\n title: item.title,\n description: item.description,\n enabled: true,\n backendRef: {\n productId: item.backendRef.productId,\n priceId: item.backendRef.priceId,\n },\n quantity: undefined,\n creditGrant: item.creditGrant,\n creditRedeem: item.creditRedeem,\n hooks: undefined,\n };\n}\n\nexport function buildBillingPurchaseRequest(\n payload: BillingActionPayload,\n runtimeConfig?: BillingRuntimeConfig | null,\n): BillingPurchaseRequest | null {\n const config = normalizeBillingRuntimeConfig(runtimeConfig);\n const purchasable = resolveBillingPurchasable(config, payload.key) ?? resolveBillingPurchasable(config, payload.productId);\n if (!purchasable) {\n return null;\n }\n\n let productOwner: string | undefined;\n let productName: string | undefined;\n try {\n const normalized = normalizeCasdoorProductId(purchasable.backendRef.productId);\n productOwner = normalized.owner;\n productName = normalized.name;\n } catch {\n productOwner = undefined;\n productName = undefined;\n }\n\n return {\n kind: purchasable.kind,\n key: purchasable.key,\n productId: purchasable.backendRef.productId,\n productOwner,\n productName,\n providerName: payload.providerName,\n pricingName: payload.pricingName,\n planName: payload.planName,\n userName: payload.userName,\n paymentEnv: payload.paymentEnv,\n customPrice: payload.customPrice,\n quantity: payload.quantity ?? 1,\n returnTo: payload.returnTo,\n metadata: payload.metadata,\n };\n}\n\nexport function filterBillingPurchasableItems(\n items: BillingItem[] | undefined,\n runtimeConfig?: BillingRuntimeConfig | null,\n): BillingItem[] {\n if (!runtimeConfig) {\n return items ?? [];\n }\n\n const config = normalizeBillingRuntimeConfig(runtimeConfig);\n if (!config.purchasableIds?.length && !config.purchasables?.length) {\n return items ?? [];\n }\n\n return (items ?? []).filter((item) => {\n const purchasable = resolveBillingPurchasable(config, item.key);\n return Boolean(purchasable);\n });\n}\n\nasync function readRequestBody(request: Request): Promise<unknown> {\n if (request.method === 'GET' || request.method === 'HEAD') {\n return null;\n }\n\n const rawBody = await request.clone().text();\n if (!rawBody) {\n return null;\n }\n\n const contentType = request.headers.get('content-type') ?? '';\n if (contentType.includes('application/json')) {\n try {\n return JSON.parse(rawBody);\n } catch {\n return rawBody;\n }\n }\n\n if (contentType.includes('application/x-www-form-urlencoded')) {\n return Object.fromEntries(new URLSearchParams(rawBody).entries());\n }\n\n return rawBody;\n}\n\nexport async function buildBillingPaymentCallbackContext(\n request: Request,\n phase?: 'success' | 'failure' | 'finished',\n): Promise<BillingPaymentCallbackContext> {\n const url = new URL(request.url);\n const params: Record<string, string> = {};\n\n for (const [key, value] of url.searchParams.entries()) {\n params[key] = value;\n }\n\n const paymentOwner = url.searchParams.get('paymentOwner') ?? url.searchParams.get('owner');\n const paymentName = url.searchParams.get('paymentName') ?? url.searchParams.get('name');\n const paymentId = url.searchParams.get('paymentId');\n const orderId = url.searchParams.get('orderId');\n const redirectTo = url.searchParams.get('redirect') ?? url.searchParams.get('returnTo');\n const failureSignal = url.searchParams.get('error') || url.searchParams.get('status') === 'failed';\n const status: BillingPaymentCallbackContext['status'] = failureSignal\n ? 'failure'\n : phase === 'finished'\n ? 'finished'\n : phase === 'failure'\n ? 'failure'\n : 'success';\n\n return {\n request,\n url,\n searchParams: url.searchParams,\n params,\n paymentOwner,\n paymentName,\n paymentId,\n orderId,\n redirectTo,\n status,\n body: await readRequestBody(request),\n };\n}\n\nexport function resolveBillingSubscriptionProduct(\n subscription: BillingSubscriptionState | undefined,\n runtimeConfig: BillingRuntimeConfig | undefined,\n): BillingProductSnapshot | undefined {\n if (!subscription) return undefined;\n if (subscription.product) return subscription.product;\n\n const item = resolveBillingItem(runtimeConfig?.items, subscription.planKey ?? subscription.subscriptionId);\n if (!item) return undefined;\n\n return {\n productKey: item.key,\n productId: item.backendRef.productId,\n title: item.title,\n kind: item.kind,\n planId: item.backendRef.planId,\n priceId: item.backendRef.priceId,\n interval: item.interval,\n creditGrant: item.creditGrant,\n creditRedeem: item.creditRedeem,\n metadata: item.metadata,\n };\n}\n\nexport function resolveBillingProductSnapshot(item?: BillingItem | null): BillingProductSnapshot | undefined {\n if (!item) return undefined;\n return {\n productKey: item.key,\n productId: item.backendRef.productId,\n title: item.title,\n kind: item.kind,\n planId: item.backendRef.planId,\n priceId: item.backendRef.priceId,\n interval: item.interval,\n creditGrant: item.creditGrant,\n creditRedeem: item.creditRedeem,\n metadata: item.metadata,\n };\n}\n\nexport function deriveBillingCreditsState(\n credits?: BillingCreditsState | null,\n products?: BillingProductState[] | null,\n conversionRules?: BillingRuntimeConfig['conversionRules'],\n): BillingCreditsState {\n if (credits) return credits;\n\n const fromProducts = products?.reduce((total, product) => {\n if (typeof product.creditsBalance === 'number') {\n return total + Number(product.creditsBalance);\n }\n\n if (!product.creditGrant) {\n return total;\n }\n\n const quantity = Number(product.quantity ?? 1);\n return total + Number(product.creditGrant.creditsPerUnit || 0) * quantity;\n }, 0);\n\n const fromRules = conversionRules?.reduce((total, rule) => {\n if (rule.kind !== 'grant-credits') return total;\n return total + Number(rule.creditsPerUnit || 0);\n }, 0);\n\n return {\n balance: Number(fromProducts ?? fromRules ?? 0),\n };\n}\n\nexport function deriveBillingEntitlements(\n subscription: BillingSubscriptionState | undefined,\n products: BillingProductState[] | undefined,\n credits: BillingCreditsState | undefined,\n runtimeConfig: BillingRuntimeConfig | undefined,\n): BillingEntitlementState {\n const features = new Set<string>();\n const limits: Record<string, number> = {};\n const flags: Record<string, boolean> = {};\n const creditBalance = credits?.balance ?? 0;\n\n for (const item of runtimeConfig?.items ?? []) {\n for (const feature of item.features ?? []) {\n features.add(feature);\n }\n if (item.metadata?.tier) {\n flags[item.metadata.tier] = true;\n }\n }\n\n if (subscription?.status === 'active' || subscription?.status === 'trialing') {\n flags.subscribed = true;\n }\n\n if (creditBalance > 0) {\n flags.hasCredits = true;\n limits.credits = creditBalance;\n }\n\n for (const product of products ?? []) {\n if (product.owned) {\n flags[`product:${product.productKey}`] = true;\n }\n }\n\n return {\n features: [...features],\n limits,\n flags,\n };\n}\n\nexport function normalizeBillingPurchaseStatus(\n status?: Partial<BillingPurchaseStatus> | null,\n order?: BillingOrderHistoryItem | null,\n payment?: BillingPaymentHistoryItem | null,\n): BillingPurchaseStatus {\n if (status) {\n return {\n actionKey: status.actionKey,\n orderId: status.orderId,\n paymentId: status.paymentId,\n transactionId: status.transactionId,\n status: status.status ?? 'idle',\n orderStatus: status.orderStatus,\n paymentStatus: status.paymentStatus,\n transactionStatus: status.transactionStatus,\n redirectTo: status.redirectTo,\n updatedAt: status.updatedAt,\n };\n }\n\n const orderStatus = order?.status;\n const paymentStatus = payment?.status;\n const normalizedStatus =\n paymentStatus === 'paid' || orderStatus === 'paid'\n ? 'paid'\n : paymentStatus === 'pending' || orderStatus === 'pending'\n ? 'pending'\n : paymentStatus === 'failed' || orderStatus === 'failed'\n ? 'failed'\n : paymentStatus === 'canceled' || orderStatus === 'canceled'\n ? 'canceled'\n : paymentStatus === 'refunded' || orderStatus === 'refunded'\n ? 'refunded'\n : paymentStatus === 'pending'\n ? 'requires_payment'\n : 'idle';\n\n return {\n actionKey: order?.orderId ?? payment?.paymentId,\n orderId: order?.orderId,\n paymentId: payment?.paymentId,\n transactionId: payment?.transactionId ?? order?.transactionId,\n status: normalizedStatus,\n orderStatus,\n paymentStatus,\n transactionStatus: payment?.transactionId ? 'linked' : undefined,\n updatedAt: payment?.updatedAt ?? order?.updatedAt,\n };\n}\n\nexport function resolveBillingInterval(interval?: BillingInterval | null): BillingInterval | undefined {\n return interval === 'month' || interval === 'year' ? interval : undefined;\n}\n\nexport function buildBillingActionPayload(\n payload: BillingActionPayload,\n runtimeConfig?: BillingRuntimeConfig | null,\n): BillingActionPayload {\n const config = normalizeBillingRuntimeConfig(runtimeConfig);\n const item = resolveBillingItem(config.items, payload.key) ?? resolveBillingItem(config.items, payload.productId);\n\n if (payload.kind === 'subscribe' && item) {\n return {\n ...payload,\n subscriptionConfig: payload.subscriptionConfig ?? {\n productKey: item.key,\n productId: item.backendRef.productId,\n planId: item.backendRef.planId,\n priceId: item.backendRef.priceId,\n interval: item.interval ?? config.defaults?.defaultInterval,\n quantity: payload.quantity ?? config.defaults?.defaultQuantity,\n metadata: item.metadata,\n },\n };\n }\n\n if ((payload.kind === 'purchase' || payload.kind === 'manage' || payload.kind === 'upgrade' || payload.kind === 'cancel') && item) {\n return {\n ...payload,\n productConfig: payload.productConfig ?? {\n productKey: item.key,\n productId: item.backendRef.productId,\n priceId: item.backendRef.priceId,\n quantity: payload.quantity ?? config.defaults?.defaultQuantity,\n creditGrant: item.creditGrant,\n creditRedeem: item.creditRedeem,\n metadata: item.metadata,\n },\n };\n }\n\n return payload;\n}\n","import type {\n BillingActionExecutionResult,\n BillingCasdoorBuyProductRequest,\n BillingCasdoorBuyProductResponse,\n BillingCasdoorErrorPayload,\n BillingCasdoorProductDetail,\n BillingCasdoorProviderOption,\n BillingPurchaseRequest,\n} from './types';\n\nexport interface NormalizedCasdoorProductId {\n owner: string;\n name: string;\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction extractString(value: unknown): string | undefined {\n return isNonEmptyString(value) ? value : undefined;\n}\n\nfunction parseCasdoorErrorPayload(message: string | undefined): BillingCasdoorErrorPayload | undefined {\n if (!isNonEmptyString(message)) {\n return undefined;\n }\n\n const trimmed = message.trim();\n if (!trimmed.startsWith('{')) {\n return { message: trimmed };\n }\n\n try {\n const parsed = JSON.parse(trimmed) as unknown;\n if (!isRecord(parsed)) {\n return { message: trimmed };\n }\n\n const detail = isRecord(parsed.detail)\n ? {\n ...parsed.detail,\n field: extractString(parsed.detail.field),\n value: extractString(parsed.detail.value),\n issue: extractString(parsed.detail.issue),\n location: extractString(parsed.detail.location),\n }\n : undefined;\n\n return {\n ...parsed,\n code: extractString(parsed.code),\n message: extractString(parsed.message) ?? extractString(parsed.msg) ?? extractString(detail?.issue) ?? trimmed,\n detail,\n };\n } catch {\n return { message: trimmed };\n }\n}\n\nexport function readBuyProductRedirectTo(value: unknown): string | undefined {\n if (!isRecord(value)) {\n return undefined;\n }\n\n for (const key of ['redirectTo', 'redirectUrl', 'redirect_url', 'url', 'href', 'location']) {\n const candidate = value[key];\n if (isNonEmptyString(candidate)) {\n return candidate;\n }\n }\n\n return undefined;\n}\n\nexport function normalizeCasdoorProductId(id: string): NormalizedCasdoorProductId {\n const [owner, ...rest] = id.split('/');\n const name = rest.join('/');\n\n if (!isNonEmptyString(owner) || !isNonEmptyString(name)) {\n throw new Error(`Invalid Casdoor product id: ${id}`);\n }\n\n return { owner, name };\n}\n\nfunction chooseProviderFromObjects(\n providerObjs: BillingCasdoorProviderOption[] | undefined,\n preferredProviderName?: string,\n): string | undefined {\n if (isNonEmptyString(preferredProviderName)) {\n return preferredProviderName;\n }\n\n return providerObjs?.find((provider) => isNonEmptyString(provider.name))?.name;\n}\n\nexport function chooseCasdoorProviderName(\n product: Pick<BillingCasdoorProductDetail, 'providers' | 'providerObjs'>,\n preferredProviderName?: string,\n): string {\n if (isNonEmptyString(preferredProviderName)) {\n return preferredProviderName;\n }\n\n const fromProviders = product.providers?.find(isNonEmptyString);\n if (fromProviders) {\n return fromProviders;\n }\n\n const fromProviderObjs = chooseProviderFromObjects(product.providerObjs, preferredProviderName);\n if (fromProviderObjs) {\n return fromProviderObjs;\n }\n\n throw new Error('No providerName available for Casdoor buy-product request.');\n}\n\nexport function buildCasdoorBuyProductParams(\n input: BillingCasdoorBuyProductRequest,\n): URLSearchParams {\n const params = new URLSearchParams();\n params.set('id', input.id);\n params.set('providerName', input.providerName);\n params.set('pricingName', input.pricingName ?? '');\n params.set('planName', input.planName ?? '');\n params.set('userName', input.userName ?? '');\n params.set('paymentEnv', input.paymentEnv ?? '');\n params.set('customPrice', String(input.customPrice ?? 0));\n return params;\n}\n\nexport function buildCasdoorBuyProductRequest(\n purchase: BillingPurchaseRequest,\n product: BillingCasdoorProductDetail,\n preferredProviderName?: string,\n): BillingCasdoorBuyProductRequest {\n const providerName = chooseCasdoorProviderName(product, purchase.providerName ?? preferredProviderName);\n const productId = `${product.owner}/${product.name}`;\n\n return {\n id: productId,\n providerName,\n pricingName: purchase.pricingName ?? '',\n planName: purchase.planName ?? '',\n userName: purchase.userName ?? '',\n paymentEnv: purchase.paymentEnv ?? '',\n customPrice: purchase.customPrice ?? 0,\n };\n}\n\nfunction normalizeCasdoorBuyProductStatus(status: string | undefined): 'succeeded' | 'pending' | 'failed' {\n const statusText = typeof status === 'string' ? status.toLowerCase() : '';\n if (statusText.includes('error') || statusText.includes('fail') || statusText.includes('cancel')) {\n return 'failed';\n }\n if (statusText.includes('pend') || statusText.includes('require')) {\n return 'pending';\n }\n return 'succeeded';\n}\n\nexport function normalizeCasdoorBuyProductResponse(\n response: BillingCasdoorBuyProductResponse,\n fallbackRedirectTo?: string,\n): BillingActionExecutionResult {\n const errorPayload = parseCasdoorErrorPayload(response.msg);\n const redirectTo =\n readBuyProductRedirectTo(response.data) ??\n readBuyProductRedirectTo(response.data2) ??\n readBuyProductRedirectTo(response.data3) ??\n fallbackRedirectTo;\n const status = normalizeCasdoorBuyProductStatus(response.status);\n\n if (status === 'failed') {\n return {\n status,\n redirectTo,\n message: errorPayload?.message ?? response.msg ?? 'Casdoor buy-product failed.',\n errorCode: errorPayload?.code,\n rawResult: response,\n };\n }\n\n return {\n status,\n redirectTo,\n rawResult: response,\n };\n}\n"],"mappings":"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","names":["item","normalizeCasdoorProductId"]}
@@ -78,6 +78,20 @@ var AUTH_KIT_ENV_VARIABLES = [
78
78
  local: "/login/oauth/authorize",
79
79
  production: "/login/oauth/authorize"
80
80
  },
81
+ {
82
+ key: "NEXT_PUBLIC_AUTH_LOGOUT_REDIRECT_PATH",
83
+ description: "\u6CE8\u9500\u540E\u8DF3\u8F6C\u8DEF\u5F84\uFF0C\u9ED8\u8BA4\u9996\u9875",
84
+ example: "/",
85
+ local: "/",
86
+ production: "/"
87
+ },
88
+ {
89
+ key: "NEXT_PUBLIC_BILLING_PURCHASABLE_IDS",
90
+ description: "Billing \u53EF\u8D2D\u4E70\u9879\u767D\u540D\u5355\uFF0C\u9017\u53F7\u5206\u9694",
91
+ example: "starter-month,credits-1000",
92
+ local: "starter-month,credits-1000",
93
+ production: "starter-month,credits-1000"
94
+ },
81
95
  {
82
96
  key: "NEXT_PUBLIC_CASDOOR_STATIC_ORIGIN",
83
97
  description: "Casdoor \u9759\u6001\u8D44\u6E90 origin",
@@ -315,4 +329,4 @@ export {
315
329
  AUTH_PRISMA_SCHEMA_MODELS,
316
330
  buildAuthPrismaSchemaTemplate
317
331
  };
318
- //# sourceMappingURL=chunk-CULH4UKG.js.map
332
+ //# sourceMappingURL=chunk-FW4WDHNS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/env.ts","../src/prisma/schema-template.ts"],"sourcesContent":["import type { ManagedEnvFile, ManagedEnvVariableDefinition } from '../types';\n\nexport const AUTH_KIT_ENV_FILES: ManagedEnvFile[] = ['.env', '.env.local', '.env.production', '.env.example'];\n\nexport const AUTH_KIT_ENV_VARIABLES: ManagedEnvVariableDefinition[] = [\n {\n key: 'APP_URL',\n description: '站点对外公开地址',\n example: 'https://your-domain.com',\n local: 'http://localhost:5177',\n production: 'https://your-domain.com',\n },\n {\n key: 'NEXTAUTH_URL',\n description: 'NextAuth 回调地址',\n example: 'http://localhost:5177',\n local: 'http://localhost:5177',\n production: 'https://your-domain.com',\n },\n {\n key: 'NEXTAUTH_SECRET',\n description: 'NextAuth JWT secret',\n example: 'replace-with-a-random-secret',\n local: 'replace-with-a-random-secret',\n production: 'replace-with-a-random-secret',\n },\n {\n key: 'GLOBAL_ADMIN_EMAILS',\n description: '全局管理员邮箱,逗号分隔',\n example: 'admin@example.com',\n local: 'admin@example.com',\n production: 'admin@example.com',\n },\n {\n key: 'AUTH_DEBUG',\n description: '是否开启认证调试日志',\n example: 'false',\n local: 'false',\n production: 'false',\n },\n {\n key: 'NEXT_PUBLIC_CASDOOR_SERVER_URL',\n description: 'Casdoor 服务地址',\n example: 'https://auth.example.com',\n local: 'https://auth.example.com',\n production: 'https://auth.example.com',\n },\n {\n key: 'NEXT_PUBLIC_CASDOOR_CLIENT_ID',\n description: 'Casdoor client id',\n example: 'your-casdoor-client-id',\n local: 'your-casdoor-client-id',\n production: 'your-casdoor-client-id',\n },\n {\n key: 'NEXT_PUBLIC_CASDOOR_APP_NAME',\n description: 'Casdoor app name',\n example: 'your-app-name',\n local: 'your-app-name',\n production: 'your-app-name',\n },\n {\n key: 'NEXT_PUBLIC_CASDOOR_ORGANIZATION_NAME',\n description: 'Casdoor organization name',\n example: 'your-org-name',\n local: 'your-org-name',\n production: 'your-org-name',\n },\n {\n key: 'NEXT_PUBLIC_CASDOOR_REDIRECT_PATH',\n description: 'Casdoor OAuth 回调路径',\n example: '/callback',\n local: '/callback',\n production: '/callback',\n },\n {\n key: 'NEXT_PUBLIC_CASDOOR_SIGNIN_PATH',\n description: 'Casdoor authorize 路径',\n example: '/login/oauth/authorize',\n local: '/login/oauth/authorize',\n production: '/login/oauth/authorize',\n },\n {\n key: 'NEXT_PUBLIC_AUTH_LOGOUT_REDIRECT_PATH',\n description: '注销后跳转路径,默认首页',\n example: '/',\n local: '/',\n production: '/',\n },\n {\n key: 'NEXT_PUBLIC_BILLING_PURCHASABLE_IDS',\n description: 'Billing 可购买项白名单,逗号分隔',\n example: 'starter-month,credits-1000',\n local: 'starter-month,credits-1000',\n production: 'starter-month,credits-1000',\n },\n {\n key: 'NEXT_PUBLIC_CASDOOR_STATIC_ORIGIN',\n description: 'Casdoor 静态资源 origin',\n example: 'https://casdoor-static.foldspace.cn',\n local: 'https://casdoor-static.foldspace.cn',\n production: 'https://casdoor-static.foldspace.cn',\n },\n {\n key: 'CASDOOR_CLIENT_SECRET',\n description: 'Casdoor client secret',\n example: 'your-casdoor-client-secret',\n local: 'your-casdoor-client-secret',\n production: 'your-casdoor-client-secret',\n },\n {\n key: 'BILLING_PAYMENT_SUCCESS_DEBUG',\n description: '是否打印 payment-success 调试日志',\n example: 'false',\n local: 'false',\n production: 'false',\n },\n];\n\nfunction stringifyEnvValue(value: string): string {\n if (value === '') {\n return '\"\"';\n }\n\n if (/^[A-Za-z0-9_./:-]+$/.test(value)) {\n return value;\n }\n\n return JSON.stringify(value);\n}\n\nfunction stripQuotes(value: string): string {\n const trimmed = value.trim();\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n\n return trimmed;\n}\n\nfunction parseEnvKeys(content: string): Set<string> {\n const keys = new Set<string>();\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n\n const separatorIndex = trimmed.indexOf('=');\n if (separatorIndex === -1) {\n continue;\n }\n\n const key = trimmed.slice(0, separatorIndex).trim();\n if (key) {\n keys.add(key);\n }\n }\n return keys;\n}\n\nexport function readManagedEnvValue(content: string, key: string): string | null {\n for (const line of content.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) {\n continue;\n }\n\n const separatorIndex = trimmed.indexOf('=');\n if (separatorIndex === -1) {\n continue;\n }\n\n const currentKey = trimmed.slice(0, separatorIndex).trim();\n if (currentKey !== key) {\n continue;\n }\n\n const rawValue = trimmed.slice(separatorIndex + 1).trim();\n return stripQuotes(rawValue);\n }\n\n return null;\n}\n\nexport function getManagedEnvValue(definition: ManagedEnvVariableDefinition, file: ManagedEnvFile): string {\n if (file === '.env.example') {\n return definition.example;\n }\n if (file === '.env.production') {\n return definition.production ?? definition.example;\n }\n if (file === '.env.local') {\n return definition.local ?? definition.example;\n }\n return definition.base ?? definition.local ?? definition.production ?? definition.example;\n}\n\nexport function buildManagedEnvTemplate(file: ManagedEnvFile, existingContent = ''): string {\n const existingKeys = parseEnvKeys(existingContent);\n const lines: string[] = existingContent.trimEnd() ? existingContent.trimEnd().split(/\\r?\\n/) : [];\n const missing = AUTH_KIT_ENV_VARIABLES.filter((definition) => !existingKeys.has(definition.key));\n\n if (missing.length === 0 && existingContent) {\n return existingContent;\n }\n\n if (lines.length > 0) {\n lines.push('');\n }\n\n lines.push(`# Casdoor Next Auth Kit managed values for ${file}`);\n for (const definition of missing) {\n const value = getManagedEnvValue(definition, file);\n lines.push(`# ${definition.description}`);\n lines.push(`${definition.key}=${stringifyEnvValue(value)}`);\n lines.push('');\n }\n\n while (lines.length > 0 && lines[lines.length - 1] === '') {\n lines.pop();\n }\n\n return `${lines.join('\\n')}\\n`;\n}\n\nexport function getMissingManagedEnvKeys(content: string): string[] {\n const existingKeys = parseEnvKeys(content);\n return AUTH_KIT_ENV_VARIABLES.filter((definition) => !existingKeys.has(definition.key)).map(\n (definition) => definition.key,\n );\n}\n\nexport function sanitizeExistingEnvContent(content: string): string {\n return stripQuotes(content);\n}\n","import type { PrismaSchemaFieldDefinition, PrismaSchemaModelDefinition } from '../types';\n\nexport const AUTH_PRISMA_SCHEMA_MODELS: PrismaSchemaModelDefinition[] = [\n {\n name: 'AuthUser',\n description: 'Shared authentication user record',\n fields: [\n { name: 'id', type: 'String', attributes: ['@id', '@default(cuid())'] },\n { name: 'email', type: 'String?', attributes: ['@unique'] },\n { name: 'name', type: 'String?' },\n { name: 'image', type: 'String?' },\n { name: 'isAdmin', type: 'Boolean', attributes: ['@default(false)'] },\n { name: 'tokenBalance', type: 'Int', attributes: ['@default(0)'] },\n { name: 'isVip', type: 'Boolean', attributes: ['@default(false)'] },\n { name: 'createdAt', type: 'DateTime', attributes: ['@default(now())'] },\n { name: 'updatedAt', type: 'DateTime', attributes: ['@updatedAt'] },\n ],\n blockAttributes: ['@@index([email])'],\n },\n {\n name: 'AuthMembership',\n description: 'Subscription membership snapshot',\n fields: [\n { name: 'id', type: 'String', attributes: ['@id', '@default(cuid())'] },\n { name: 'userId', type: 'String', attributes: ['@unique'] },\n { name: 'plan', type: 'String' },\n { name: 'status', type: 'String' },\n { name: 'startsAt', type: 'DateTime?' },\n { name: 'endsAt', type: 'DateTime?' },\n { name: 'createdAt', type: 'DateTime', attributes: ['@default(now())'] },\n { name: 'updatedAt', type: 'DateTime', attributes: ['@updatedAt'] },\n ],\n blockAttributes: ['@@index([userId])'],\n },\n {\n name: 'AuthOrder',\n description: 'Commerce order record',\n fields: [\n { name: 'id', type: 'String', attributes: ['@id', '@default(cuid())'] },\n { name: 'userId', type: 'String' },\n { name: 'kind', type: 'String' },\n { name: 'status', type: 'String' },\n { name: 'amount', type: 'Int' },\n { name: 'currency', type: 'String', attributes: ['@default(\"CNY\")'] },\n { name: 'payload', type: 'Json?' },\n { name: 'createdAt', type: 'DateTime', attributes: ['@default(now())'] },\n { name: 'updatedAt', type: 'DateTime', attributes: ['@updatedAt'] },\n ],\n blockAttributes: ['@@index([userId])'],\n },\n {\n name: 'AuthSubscription',\n description: 'Commerce subscription record',\n fields: [\n { name: 'id', type: 'String', attributes: ['@id', '@default(cuid())'] },\n { name: 'userId', type: 'String' },\n { name: 'productId', type: 'String' },\n { name: 'status', type: 'String' },\n { name: 'interval', type: 'String' },\n { name: 'startsAt', type: 'DateTime?' },\n { name: 'endsAt', type: 'DateTime?' },\n { name: 'createdAt', type: 'DateTime', attributes: ['@default(now())'] },\n { name: 'updatedAt', type: 'DateTime', attributes: ['@updatedAt'] },\n ],\n blockAttributes: ['@@index([userId])', '@@index([productId])'],\n },\n {\n name: 'AuthInvoice',\n description: 'Commerce invoice record',\n fields: [\n { name: 'id', type: 'String', attributes: ['@id', '@default(cuid())'] },\n { name: 'userId', type: 'String' },\n { name: 'orderId', type: 'String?' },\n { name: 'invoiceNo', type: 'String', attributes: ['@unique'] },\n { name: 'status', type: 'String' },\n { name: 'amount', type: 'Int' },\n { name: 'createdAt', type: 'DateTime', attributes: ['@default(now())'] },\n { name: 'updatedAt', type: 'DateTime', attributes: ['@updatedAt'] },\n ],\n blockAttributes: ['@@index([userId])', '@@index([orderId])'],\n },\n];\n\nfunction renderField(field: PrismaSchemaFieldDefinition): string {\n const attributes = field.attributes?.length ? ` ${field.attributes.join(' ')}` : '';\n return ` ${field.name} ${field.type}${attributes}`;\n}\n\nfunction renderModel(model: PrismaSchemaModelDefinition): string {\n const lines = [\n `/// ${model.description}`,\n `model ${model.name} {`,\n ...model.fields.map(renderField),\n ];\n\n if (model.blockAttributes?.length) {\n lines.push(...model.blockAttributes.map((attribute) => ` ${attribute}`));\n }\n\n lines.push('}');\n return lines.join('\\n');\n}\n\nexport function buildAuthPrismaSchemaTemplate(models: PrismaSchemaModelDefinition[] = AUTH_PRISMA_SCHEMA_MODELS): string {\n return [\n '// generated by @foldspace-fe/casdoor-next-auth-kit',\n '// merge these models into the host Prisma schema if you want a dedicated auth module',\n '',\n ...models.map(renderModel),\n ].join('\\n\\n');\n}\n"],"mappings":";AAEO,IAAM,qBAAuC,CAAC,QAAQ,cAAc,mBAAmB,cAAc;AAErG,IAAM,yBAAyD;AAAA,EACpE;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AAAA,EACA;AAAA,IACE,KAAK;AAAA,IACL,aAAa;AAAA,IACb,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AACF;AAEA,SAAS,kBAAkB,OAAuB;AAChD,MAAI,UAAU,IAAI;AAChB,WAAO;AAAA,EACT;AAEA,MAAI,sBAAsB,KAAK,KAAK,GAAG;AACrC,WAAO;AAAA,EACT;AAEA,SAAO,KAAK,UAAU,KAAK;AAC7B;AAEA,SAAS,YAAY,OAAuB;AAC1C,QAAM,UAAU,MAAM,KAAK;AAC3B,MACG,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,KAC/C,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GAChD;AACA,WAAO,QAAQ,MAAM,GAAG,EAAE;AAAA,EAC5B;AAEA,SAAO;AACT;AAEA,SAAS,aAAa,SAA8B;AAClD,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,QAAQ,QAAQ,MAAM,OAAO,GAAG;AACzC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,GAAG;AACvC;AAAA,IACF;AAEA,UAAM,iBAAiB,QAAQ,QAAQ,GAAG;AAC1C,QAAI,mBAAmB,IAAI;AACzB;AAAA,IACF;AAEA,UAAM,MAAM,QAAQ,MAAM,GAAG,cAAc,EAAE,KAAK;AAClD,QAAI,KAAK;AACP,WAAK,IAAI,GAAG;AAAA,IACd;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,oBAAoB,SAAiB,KAA4B;AAC/E,aAAW,QAAQ,QAAQ,MAAM,OAAO,GAAG;AACzC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,GAAG;AACvC;AAAA,IACF;AAEA,UAAM,iBAAiB,QAAQ,QAAQ,GAAG;AAC1C,QAAI,mBAAmB,IAAI;AACzB;AAAA,IACF;AAEA,UAAM,aAAa,QAAQ,MAAM,GAAG,cAAc,EAAE,KAAK;AACzD,QAAI,eAAe,KAAK;AACtB;AAAA,IACF;AAEA,UAAM,WAAW,QAAQ,MAAM,iBAAiB,CAAC,EAAE,KAAK;AACxD,WAAO,YAAY,QAAQ;AAAA,EAC7B;AAEA,SAAO;AACT;AAEO,SAAS,mBAAmB,YAA0C,MAA8B;AACzG,MAAI,SAAS,gBAAgB;AAC3B,WAAO,WAAW;AAAA,EACpB;AACA,MAAI,SAAS,mBAAmB;AAC9B,WAAO,WAAW,cAAc,WAAW;AAAA,EAC7C;AACA,MAAI,SAAS,cAAc;AACzB,WAAO,WAAW,SAAS,WAAW;AAAA,EACxC;AACA,SAAO,WAAW,QAAQ,WAAW,SAAS,WAAW,cAAc,WAAW;AACpF;AAEO,SAAS,wBAAwB,MAAsB,kBAAkB,IAAY;AAC1F,QAAM,eAAe,aAAa,eAAe;AACjD,QAAM,QAAkB,gBAAgB,QAAQ,IAAI,gBAAgB,QAAQ,EAAE,MAAM,OAAO,IAAI,CAAC;AAChG,QAAM,UAAU,uBAAuB,OAAO,CAAC,eAAe,CAAC,aAAa,IAAI,WAAW,GAAG,CAAC;AAE/F,MAAI,QAAQ,WAAW,KAAK,iBAAiB;AAC3C,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,SAAS,GAAG;AACpB,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,QAAM,KAAK,8CAA8C,IAAI,EAAE;AAC/D,aAAW,cAAc,SAAS;AAChC,UAAM,QAAQ,mBAAmB,YAAY,IAAI;AACjD,UAAM,KAAK,KAAK,WAAW,WAAW,EAAE;AACxC,UAAM,KAAK,GAAG,WAAW,GAAG,IAAI,kBAAkB,KAAK,CAAC,EAAE;AAC1D,UAAM,KAAK,EAAE;AAAA,EACf;AAEA,SAAO,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,CAAC,MAAM,IAAI;AACzD,UAAM,IAAI;AAAA,EACZ;AAEA,SAAO,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA;AAC5B;AAEO,SAAS,yBAAyB,SAA2B;AAClE,QAAM,eAAe,aAAa,OAAO;AACzC,SAAO,uBAAuB,OAAO,CAAC,eAAe,CAAC,aAAa,IAAI,WAAW,GAAG,CAAC,EAAE;AAAA,IACtF,CAAC,eAAe,WAAW;AAAA,EAC7B;AACF;AAEO,SAAS,2BAA2B,SAAyB;AAClE,SAAO,YAAY,OAAO;AAC5B;;;AC5OO,IAAM,4BAA2D;AAAA,EACtE;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,UAAU,YAAY,CAAC,OAAO,kBAAkB,EAAE;AAAA,MACtE,EAAE,MAAM,SAAS,MAAM,WAAW,YAAY,CAAC,SAAS,EAAE;AAAA,MAC1D,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,MAChC,EAAE,MAAM,SAAS,MAAM,UAAU;AAAA,MACjC,EAAE,MAAM,WAAW,MAAM,WAAW,YAAY,CAAC,iBAAiB,EAAE;AAAA,MACpE,EAAE,MAAM,gBAAgB,MAAM,OAAO,YAAY,CAAC,aAAa,EAAE;AAAA,MACjE,EAAE,MAAM,SAAS,MAAM,WAAW,YAAY,CAAC,iBAAiB,EAAE;AAAA,MAClE,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,iBAAiB,EAAE;AAAA,MACvE,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,YAAY,EAAE;AAAA,IACpE;AAAA,IACA,iBAAiB,CAAC,kBAAkB;AAAA,EACtC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,UAAU,YAAY,CAAC,OAAO,kBAAkB,EAAE;AAAA,MACtE,EAAE,MAAM,UAAU,MAAM,UAAU,YAAY,CAAC,SAAS,EAAE;AAAA,MAC1D,EAAE,MAAM,QAAQ,MAAM,SAAS;AAAA,MAC/B,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MACjC,EAAE,MAAM,YAAY,MAAM,YAAY;AAAA,MACtC,EAAE,MAAM,UAAU,MAAM,YAAY;AAAA,MACpC,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,iBAAiB,EAAE;AAAA,MACvE,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,YAAY,EAAE;AAAA,IACpE;AAAA,IACA,iBAAiB,CAAC,mBAAmB;AAAA,EACvC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,UAAU,YAAY,CAAC,OAAO,kBAAkB,EAAE;AAAA,MACtE,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MACjC,EAAE,MAAM,QAAQ,MAAM,SAAS;AAAA,MAC/B,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MACjC,EAAE,MAAM,UAAU,MAAM,MAAM;AAAA,MAC9B,EAAE,MAAM,YAAY,MAAM,UAAU,YAAY,CAAC,iBAAiB,EAAE;AAAA,MACpE,EAAE,MAAM,WAAW,MAAM,QAAQ;AAAA,MACjC,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,iBAAiB,EAAE;AAAA,MACvE,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,YAAY,EAAE;AAAA,IACpE;AAAA,IACA,iBAAiB,CAAC,mBAAmB;AAAA,EACvC;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,UAAU,YAAY,CAAC,OAAO,kBAAkB,EAAE;AAAA,MACtE,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MACjC,EAAE,MAAM,aAAa,MAAM,SAAS;AAAA,MACpC,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MACjC,EAAE,MAAM,YAAY,MAAM,SAAS;AAAA,MACnC,EAAE,MAAM,YAAY,MAAM,YAAY;AAAA,MACtC,EAAE,MAAM,UAAU,MAAM,YAAY;AAAA,MACpC,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,iBAAiB,EAAE;AAAA,MACvE,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,YAAY,EAAE;AAAA,IACpE;AAAA,IACA,iBAAiB,CAAC,qBAAqB,sBAAsB;AAAA,EAC/D;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,MACN,EAAE,MAAM,MAAM,MAAM,UAAU,YAAY,CAAC,OAAO,kBAAkB,EAAE;AAAA,MACtE,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MACjC,EAAE,MAAM,WAAW,MAAM,UAAU;AAAA,MACnC,EAAE,MAAM,aAAa,MAAM,UAAU,YAAY,CAAC,SAAS,EAAE;AAAA,MAC7D,EAAE,MAAM,UAAU,MAAM,SAAS;AAAA,MACjC,EAAE,MAAM,UAAU,MAAM,MAAM;AAAA,MAC9B,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,iBAAiB,EAAE;AAAA,MACvE,EAAE,MAAM,aAAa,MAAM,YAAY,YAAY,CAAC,YAAY,EAAE;AAAA,IACpE;AAAA,IACA,iBAAiB,CAAC,qBAAqB,oBAAoB;AAAA,EAC7D;AACF;AAEA,SAAS,YAAY,OAA4C;AAC/D,QAAM,aAAa,MAAM,YAAY,SAAS,IAAI,MAAM,WAAW,KAAK,GAAG,CAAC,KAAK;AACjF,SAAO,KAAK,MAAM,IAAI,IAAI,MAAM,IAAI,GAAG,UAAU;AACnD;AAEA,SAAS,YAAY,OAA4C;AAC/D,QAAM,QAAQ;AAAA,IACZ,OAAO,MAAM,WAAW;AAAA,IACxB,SAAS,MAAM,IAAI;AAAA,IACnB,GAAG,MAAM,OAAO,IAAI,WAAW;AAAA,EACjC;AAEA,MAAI,MAAM,iBAAiB,QAAQ;AACjC,UAAM,KAAK,GAAG,MAAM,gBAAgB,IAAI,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;AAAA,EAC1E;AAEA,QAAM,KAAK,GAAG;AACd,SAAO,MAAM,KAAK,IAAI;AACxB;AAEO,SAAS,8BAA8B,SAAwC,2BAAmC;AACvH,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,OAAO,IAAI,WAAW;AAAA,EAC3B,EAAE,KAAK,MAAM;AACf;","names":[]}
@@ -8,8 +8,7 @@ import {
8
8
  encodeSessionToken,
9
9
  isGlobalAdminEmail,
10
10
  isSecureRequest,
11
- normalizeAuthKitConfig,
12
- pkceCookiePrefix
11
+ normalizeAuthKitConfig
13
12
  } from "./chunk-MWXY4JSL.js";
14
13
 
15
14
  // src/next/login.ts
@@ -35,44 +34,49 @@ function getCookieNamesFromHeader(cookieHeader) {
35
34
  }
36
35
  return cookieHeader.split(";").map((part) => part.trim()).filter(Boolean).map((part) => part.split("=")[0]?.trim()).filter((name) => Boolean(name));
37
36
  }
37
+ function getPathCandidates(pathname) {
38
+ const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
39
+ const segments = normalized.split("/").filter(Boolean);
40
+ const paths = /* @__PURE__ */ new Set(["/"]);
41
+ let current = "";
42
+ for (const segment of segments) {
43
+ current += `/${segment}`;
44
+ paths.add(current);
45
+ }
46
+ return [...paths];
47
+ }
48
+ function resolveLogoutTargetUrl(request, config) {
49
+ const origin = request.cookies.get("auth_origin")?.value ?? config.appUrl ?? new URL(request.url).origin;
50
+ const logoutRedirectPath = config.logoutRedirectPath ?? "/";
51
+ return new URL(logoutRedirectPath, origin);
52
+ }
53
+ function clearCookieEverywhere(response, cookieName, secure, pathCandidates) {
54
+ for (const path of pathCandidates) {
55
+ response.cookies.set(cookieName, "", {
56
+ path,
57
+ httpOnly: true,
58
+ sameSite: "lax",
59
+ secure,
60
+ maxAge: 0
61
+ });
62
+ }
63
+ }
38
64
  function createLogoutHandler(config) {
39
65
  return async function GET(request) {
40
- const origin = request.cookies.get("auth_origin")?.value ?? config.appUrl ?? new URL(request.url).origin;
41
66
  const secure = config.cookie?.secure === "auto" ? isSecureRequest(request, config.appUrl) : Boolean(config.cookie?.secure);
42
- const response = NextResponse.redirect(new URL("/", origin));
67
+ const targetUrl = resolveLogoutTargetUrl(request, config);
68
+ const response = NextResponse.redirect(targetUrl, 307);
69
+ response.headers.set("Clear-Site-Data", '"cookies"');
43
70
  const cookieNames = getCookieNamesFromHeader(request.headers.get("cookie"));
44
- const sessionCookiePrefixes = [
45
- "next-auth.session-token",
46
- "__Secure-next-auth.session-token",
47
- "authjs.session-token",
48
- "__Secure-authjs.session-token"
49
- ];
71
+ const pathCandidates = getPathCandidates(request.nextUrl.pathname);
50
72
  for (const cookieName of cookieNames) {
51
- if (sessionCookiePrefixes.some((prefix) => cookieName === prefix || cookieName.startsWith(`${prefix}.`))) {
52
- response.cookies.set(cookieName, "", {
53
- path: "/",
54
- httpOnly: true,
55
- sameSite: "lax",
56
- secure,
57
- maxAge: 0
58
- });
59
- }
73
+ clearCookieEverywhere(response, cookieName, secure, pathCandidates);
60
74
  }
61
- response.cookies.delete("oauth_state");
62
- response.cookies.delete("auth_origin");
75
+ clearCookieEverywhere(response, "oauth_state", secure, pathCandidates);
76
+ clearCookieEverywhere(response, "auth_origin", secure, pathCandidates);
77
+ clearCookieEverywhere(response, "auth_redirect", secure, pathCandidates);
63
78
  clearAuthRedirectCookie(response, secure);
64
79
  clearPublicOriginCookie(response, secure);
65
- for (const cookieName of cookieNames) {
66
- if (cookieName.startsWith(`${pkceCookiePrefix}.`)) {
67
- response.cookies.set(cookieName, "", {
68
- path: "/",
69
- httpOnly: true,
70
- sameSite: "lax",
71
- secure,
72
- maxAge: 0
73
- });
74
- }
75
- }
76
80
  return response;
77
81
  };
78
82
  }
@@ -189,4 +193,4 @@ export {
189
193
  createNextAuthOptions,
190
194
  createNextAuthRouteHandler
191
195
  };
192
- //# sourceMappingURL=chunk-QYGC4WNG.js.map
196
+ //# sourceMappingURL=chunk-GLK4IW22.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/next/login.ts","../src/next/signup.ts","../src/next/authorize.ts","../src/next/logout.ts","../src/next/options.ts"],"sourcesContent":["import type { NextRequest } from 'next/server';\nimport type { AuthKitConfig } from '../types';\nimport { createLoginEntryResponse } from '../casdoor/entry';\n\nexport function createLoginRouteHandler(config: AuthKitConfig) {\n return async (request: NextRequest) => createLoginEntryResponse(request, config);\n}\n","import type { NextRequest } from 'next/server';\nimport type { AuthKitConfig } from '../types';\nimport { createSignupEntryResponse } from '../casdoor/entry';\n\nexport function createSignupRouteHandler(config: AuthKitConfig) {\n return async (request: NextRequest) => createSignupEntryResponse(request, config);\n}\n","import type { NextRequest } from 'next/server';\nimport type { AuthKitConfig } from '../types';\nimport { createAuthorizeEntryResponse } from '../casdoor/entry';\n\nexport function createAuthorizeRouteHandler(config: AuthKitConfig) {\n return async (request: NextRequest) => createAuthorizeEntryResponse(request, config);\n}\n","import { NextResponse, type NextRequest } from 'next/server';\nimport type { AuthKitConfig } from '../types';\nimport { isSecureRequest } from '../core/request-security';\nimport { clearAuthRedirectCookie } from '../core/auth-redirect';\nimport { clearPublicOriginCookie } from '../core/public-origin';\n\nfunction getCookieNamesFromHeader(cookieHeader: string | null): string[] {\n if (!cookieHeader) {\n return [];\n }\n\n return cookieHeader\n .split(';')\n .map((part) => part.trim())\n .filter(Boolean)\n .map((part) => part.split('=')[0]?.trim())\n .filter((name): name is string => Boolean(name));\n}\n\nfunction getPathCandidates(pathname: string): string[] {\n const normalized = pathname.startsWith('/') ? pathname : `/${pathname}`;\n const segments = normalized.split('/').filter(Boolean);\n const paths = new Set<string>(['/']);\n\n let current = '';\n for (const segment of segments) {\n current += `/${segment}`;\n paths.add(current);\n }\n\n return [...paths];\n}\n\nfunction resolveLogoutTargetUrl(request: NextRequest, config: AuthKitConfig): URL {\n const origin = request.cookies.get('auth_origin')?.value ?? config.appUrl ?? new URL(request.url).origin;\n const logoutRedirectPath = config.logoutRedirectPath ?? '/';\n return new URL(logoutRedirectPath, origin);\n}\n\nfunction clearCookieEverywhere(\n response: NextResponse,\n cookieName: string,\n secure: boolean,\n pathCandidates: string[],\n) {\n for (const path of pathCandidates) {\n response.cookies.set(cookieName, '', {\n path,\n httpOnly: true,\n sameSite: 'lax',\n secure,\n maxAge: 0,\n });\n }\n}\n\nexport function createLogoutHandler(config: AuthKitConfig) {\n return async function GET(request: NextRequest) {\n const secure = config.cookie?.secure === 'auto' ? isSecureRequest(request, config.appUrl) : Boolean(config.cookie?.secure);\n // 307 keeps same-path targets behaving like a reload instead of a cache-friendly rewrite.\n const targetUrl = resolveLogoutTargetUrl(request, config);\n const response = NextResponse.redirect(targetUrl, 307);\n response.headers.set('Clear-Site-Data', '\"cookies\"');\n const cookieNames = getCookieNamesFromHeader(request.headers.get('cookie'));\n const pathCandidates = getPathCandidates(request.nextUrl.pathname);\n\n for (const cookieName of cookieNames) {\n clearCookieEverywhere(response, cookieName, secure, pathCandidates);\n }\n clearCookieEverywhere(response, 'oauth_state', secure, pathCandidates);\n clearCookieEverywhere(response, 'auth_origin', secure, pathCandidates);\n clearCookieEverywhere(response, 'auth_redirect', secure, pathCandidates);\n clearAuthRedirectCookie(response, secure);\n clearPublicOriginCookie(response, secure);\n\n return response;\n };\n}\n","import NextAuth from 'next-auth';\nimport type { NextAuthOptions, Session } from 'next-auth';\nimport type { JWT } from 'next-auth/jwt';\nimport type { AuthBusinessAdapter, AuthKitConfig, AuthPersistenceAdapter, AuthUser } from '../types';\nimport { normalizeAuthKitConfig } from '../core/config';\nimport { decodeSessionToken, encodeSessionToken } from '../core/session-token';\nimport { isGlobalAdminEmail } from '../core/admin';\n\nexport interface NextAuthRouteOptions {\n config: AuthKitConfig;\n adapter?: AuthBusinessAdapter;\n persistence?: AuthPersistenceAdapter;\n providers?: NextAuthOptions['providers'];\n}\n\nexport interface AuthTokenPayload extends JWT {\n id?: string;\n name?: string;\n email?: string;\n picture?: string | null;\n userId?: string;\n accessToken?: string;\n expiresAt?: number;\n tokenBalance?: number;\n isVip?: boolean;\n isAdmin?: boolean;\n}\n\nexport interface AuthSessionUser {\n id?: string;\n isAdmin?: boolean;\n tokenBalance?: number;\n isVip?: boolean;\n}\n\nexport interface AuthSession extends Session {\n accessToken?: string;\n expiresAt?: number;\n user?: AuthSessionUser & NonNullable<Session['user']>;\n}\n\nfunction resolveAuthUserFromToken(token: AuthTokenPayload, adapter?: AuthBusinessAdapter): AuthUser {\n const email = typeof token.email === 'string' ? token.email : null;\n return {\n id: token.userId || token.sub || token.id || email || 'casdoor-user',\n name: typeof token.name === 'string' ? token.name : null,\n email,\n image: typeof token.picture === 'string' ? token.picture : null,\n isAdmin: Boolean(token.isAdmin) || Boolean(adapter?.isAdminEmail?.(email)) || isGlobalAdminEmail(email),\n tokenBalance: Number(token.tokenBalance ?? 2580),\n isVip: Boolean(token.isVip ?? true),\n };\n}\n\nexport function createNextAuthOptions(options: NextAuthRouteOptions): NextAuthOptions {\n const normalized = normalizeAuthKitConfig(options.config);\n\n return {\n providers: options.providers ?? [],\n session: {\n strategy: 'jwt',\n },\n jwt: {\n encode: encodeSessionToken,\n decode: decodeSessionToken,\n },\n pages: {\n signIn: '/login',\n error: '/callback/error',\n },\n callbacks: {\n async jwt({ token, account, profile }) {\n const typedToken = token as AuthTokenPayload;\n\n if (account) {\n typedToken.accessToken = account.access_token;\n typedToken.expiresAt = account.expires_at ? account.expires_at * 1000 : undefined;\n }\n\n if (profile && typeof profile === 'object') {\n const typedProfile = profile as Partial<AuthUser> & {\n sub?: string;\n id?: string;\n picture?: string;\n };\n\n typedToken.userId = typedProfile.id || typedProfile.sub || typedToken.userId;\n typedToken.name = typedProfile.name || typedToken.name;\n typedToken.email = typedProfile.email || typedToken.email;\n typedToken.picture = typedProfile.image || typedProfile.picture || typedToken.picture;\n typedToken.isAdmin = Boolean(typedProfile.isAdmin ?? typedToken.isAdmin);\n typedToken.tokenBalance = typedProfile.tokenBalance ?? typedToken.tokenBalance ?? 2580;\n typedToken.isVip = typedProfile.isVip ?? typedToken.isVip ?? true;\n }\n\n return typedToken;\n },\n async session({ session, token }) {\n const typedSession = session as AuthSession;\n const typedToken = token as AuthTokenPayload;\n const tokenUserId = typedToken.userId || typedToken.sub || typedToken.id || '';\n const tokenEmail = typeof typedToken.email === 'string' ? typedToken.email : null;\n const persistedUser = options.persistence?.findAuthUser\n ? await options.persistence.findAuthUser({ id: tokenUserId || undefined, email: tokenEmail })\n : null;\n const resolvedUser = persistedUser ?? resolveAuthUserFromToken(typedToken, options.adapter);\n\n if (typedSession.user) {\n typedSession.user.id = resolvedUser.id;\n typedSession.user.isAdmin = resolvedUser.isAdmin;\n typedSession.user.tokenBalance = resolvedUser.tokenBalance;\n typedSession.user.isVip = resolvedUser.isVip;\n }\n\n typedSession.accessToken = typedToken.accessToken;\n typedSession.expiresAt = typedToken.expiresAt;\n typedSession.user = {\n ...(typedSession.user || {}),\n name: typedSession.user?.name || resolvedUser.name,\n email: typedSession.user?.email || resolvedUser.email,\n image: typedSession.user?.image || resolvedUser.image,\n id: resolvedUser.id,\n isAdmin: resolvedUser.isAdmin,\n tokenBalance: resolvedUser.tokenBalance,\n isVip: resolvedUser.isVip,\n };\n\n return typedSession;\n },\n },\n events: {\n async signOut({ token }) {\n const typedToken = token as AuthTokenPayload | null;\n if (!typedToken?.accessToken || !normalized.appUrl) {\n return;\n }\n\n try {\n await fetch(new URL('/api/casdoor/logout', normalized.appUrl).toString(), {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${typedToken.accessToken}`,\n },\n });\n } catch {\n // ignored\n }\n },\n },\n secret: normalized.nextauthSecret,\n };\n}\n\nexport function createNextAuthRouteHandler(options: NextAuthRouteOptions) {\n const handler = NextAuth(createNextAuthOptions(options));\n return {\n GET: handler,\n POST: handler,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AAIO,SAAS,wBAAwB,QAAuB;AAC7D,SAAO,OAAO,YAAyB,yBAAyB,SAAS,MAAM;AACjF;;;ACFO,SAAS,yBAAyB,QAAuB;AAC9D,SAAO,OAAO,YAAyB,0BAA0B,SAAS,MAAM;AAClF;;;ACFO,SAAS,4BAA4B,QAAuB;AACjE,SAAO,OAAO,YAAyB,6BAA6B,SAAS,MAAM;AACrF;;;ACNA,SAAS,oBAAsC;AAM/C,SAAS,yBAAyB,cAAuC;AACvE,MAAI,CAAC,cAAc;AACjB,WAAO,CAAC;AAAA,EACV;AAEA,SAAO,aACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,OAAO,OAAO,EACd,IAAI,CAAC,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,CAAC,EACxC,OAAO,CAAC,SAAyB,QAAQ,IAAI,CAAC;AACnD;AAEA,SAAS,kBAAkB,UAA4B;AACrD,QAAM,aAAa,SAAS,WAAW,GAAG,IAAI,WAAW,IAAI,QAAQ;AACrE,QAAM,WAAW,WAAW,MAAM,GAAG,EAAE,OAAO,OAAO;AACrD,QAAM,QAAQ,oBAAI,IAAY,CAAC,GAAG,CAAC;AAEnC,MAAI,UAAU;AACd,aAAW,WAAW,UAAU;AAC9B,eAAW,IAAI,OAAO;AACtB,UAAM,IAAI,OAAO;AAAA,EACnB;AAEA,SAAO,CAAC,GAAG,KAAK;AAClB;AAEA,SAAS,uBAAuB,SAAsB,QAA4B;AAChF,QAAM,SAAS,QAAQ,QAAQ,IAAI,aAAa,GAAG,SAAS,OAAO,UAAU,IAAI,IAAI,QAAQ,GAAG,EAAE;AAClG,QAAM,qBAAqB,OAAO,sBAAsB;AACxD,SAAO,IAAI,IAAI,oBAAoB,MAAM;AAC3C;AAEA,SAAS,sBACP,UACA,YACA,QACA,gBACA;AACA,aAAW,QAAQ,gBAAgB;AACjC,aAAS,QAAQ,IAAI,YAAY,IAAI;AAAA,MACnC;AAAA,MACA,UAAU;AAAA,MACV,UAAU;AAAA,MACV;AAAA,MACA,QAAQ;AAAA,IACV,CAAC;AAAA,EACH;AACF;AAEO,SAAS,oBAAoB,QAAuB;AACzD,SAAO,eAAe,IAAI,SAAsB;AAC9C,UAAM,SAAS,OAAO,QAAQ,WAAW,SAAS,gBAAgB,SAAS,OAAO,MAAM,IAAI,QAAQ,OAAO,QAAQ,MAAM;AAEzH,UAAM,YAAY,uBAAuB,SAAS,MAAM;AACxD,UAAM,WAAW,aAAa,SAAS,WAAW,GAAG;AACrD,aAAS,QAAQ,IAAI,mBAAmB,WAAW;AACnD,UAAM,cAAc,yBAAyB,QAAQ,QAAQ,IAAI,QAAQ,CAAC;AAC1E,UAAM,iBAAiB,kBAAkB,QAAQ,QAAQ,QAAQ;AAEjE,eAAW,cAAc,aAAa;AACpC,4BAAsB,UAAU,YAAY,QAAQ,cAAc;AAAA,IACpE;AACA,0BAAsB,UAAU,eAAe,QAAQ,cAAc;AACrE,0BAAsB,UAAU,eAAe,QAAQ,cAAc;AACrE,0BAAsB,UAAU,iBAAiB,QAAQ,cAAc;AACvE,4BAAwB,UAAU,MAAM;AACxC,4BAAwB,UAAU,MAAM;AAExC,WAAO;AAAA,EACT;AACF;;;AC7EA,OAAO,cAAc;AAyCrB,SAAS,yBAAyB,OAAyB,SAAyC;AAClG,QAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAC9D,SAAO;AAAA,IACL,IAAI,MAAM,UAAU,MAAM,OAAO,MAAM,MAAM,SAAS;AAAA,IACtD,MAAM,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAAA,IACpD;AAAA,IACA,OAAO,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AAAA,IAC3D,SAAS,QAAQ,MAAM,OAAO,KAAK,QAAQ,SAAS,eAAe,KAAK,CAAC,KAAK,mBAAmB,KAAK;AAAA,IACtG,cAAc,OAAO,MAAM,gBAAgB,IAAI;AAAA,IAC/C,OAAO,QAAQ,MAAM,SAAS,IAAI;AAAA,EACpC;AACF;AAEO,SAAS,sBAAsB,SAAgD;AACpF,QAAM,aAAa,uBAAuB,QAAQ,MAAM;AAExD,SAAO;AAAA,IACL,WAAW,QAAQ,aAAa,CAAC;AAAA,IACjC,SAAS;AAAA,MACP,UAAU;AAAA,IACZ;AAAA,IACA,KAAK;AAAA,MACH,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,IACA,OAAO;AAAA,MACL,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,IACA,WAAW;AAAA,MACT,MAAM,IAAI,EAAE,OAAO,SAAS,QAAQ,GAAG;AACrC,cAAM,aAAa;AAEnB,YAAI,SAAS;AACX,qBAAW,cAAc,QAAQ;AACjC,qBAAW,YAAY,QAAQ,aAAa,QAAQ,aAAa,MAAO;AAAA,QAC1E;AAEA,YAAI,WAAW,OAAO,YAAY,UAAU;AAC1C,gBAAM,eAAe;AAMrB,qBAAW,SAAS,aAAa,MAAM,aAAa,OAAO,WAAW;AACtE,qBAAW,OAAO,aAAa,QAAQ,WAAW;AAClD,qBAAW,QAAQ,aAAa,SAAS,WAAW;AACpD,qBAAW,UAAU,aAAa,SAAS,aAAa,WAAW,WAAW;AAC9E,qBAAW,UAAU,QAAQ,aAAa,WAAW,WAAW,OAAO;AACvE,qBAAW,eAAe,aAAa,gBAAgB,WAAW,gBAAgB;AAClF,qBAAW,QAAQ,aAAa,SAAS,WAAW,SAAS;AAAA,QAC/D;AAEA,eAAO;AAAA,MACT;AAAA,MACA,MAAM,QAAQ,EAAE,SAAS,MAAM,GAAG;AAChC,cAAM,eAAe;AACrB,cAAM,aAAa;AACnB,cAAM,cAAc,WAAW,UAAU,WAAW,OAAO,WAAW,MAAM;AAC5E,cAAM,aAAa,OAAO,WAAW,UAAU,WAAW,WAAW,QAAQ;AAC7E,cAAM,gBAAgB,QAAQ,aAAa,eACvC,MAAM,QAAQ,YAAY,aAAa,EAAE,IAAI,eAAe,QAAW,OAAO,WAAW,CAAC,IAC1F;AACJ,cAAM,eAAe,iBAAiB,yBAAyB,YAAY,QAAQ,OAAO;AAE1F,YAAI,aAAa,MAAM;AACrB,uBAAa,KAAK,KAAK,aAAa;AACpC,uBAAa,KAAK,UAAU,aAAa;AACzC,uBAAa,KAAK,eAAe,aAAa;AAC9C,uBAAa,KAAK,QAAQ,aAAa;AAAA,QACzC;AAEA,qBAAa,cAAc,WAAW;AACtC,qBAAa,YAAY,WAAW;AACpC,qBAAa,OAAO;AAAA,UAClB,GAAI,aAAa,QAAQ,CAAC;AAAA,UAC1B,MAAM,aAAa,MAAM,QAAQ,aAAa;AAAA,UAC9C,OAAO,aAAa,MAAM,SAAS,aAAa;AAAA,UAChD,OAAO,aAAa,MAAM,SAAS,aAAa;AAAA,UAChD,IAAI,aAAa;AAAA,UACjB,SAAS,aAAa;AAAA,UACtB,cAAc,aAAa;AAAA,UAC3B,OAAO,aAAa;AAAA,QACtB;AAEA,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,MAAM,QAAQ,EAAE,MAAM,GAAG;AACvB,cAAM,aAAa;AACnB,YAAI,CAAC,YAAY,eAAe,CAAC,WAAW,QAAQ;AAClD;AAAA,QACF;AAEA,YAAI;AACF,gBAAM,MAAM,IAAI,IAAI,uBAAuB,WAAW,MAAM,EAAE,SAAS,GAAG;AAAA,YACxE,QAAQ;AAAA,YACR,SAAS;AAAA,cACP,eAAe,UAAU,WAAW,WAAW;AAAA,YACjD;AAAA,UACF,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ,WAAW;AAAA,EACrB;AACF;AAEO,SAAS,2BAA2B,SAA+B;AACxE,QAAM,UAAU,SAAS,sBAAsB,OAAO,CAAC;AACvD,SAAO;AAAA,IACL,KAAK;AAAA,IACL,MAAM;AAAA,EACR;AACF;","names":[]}
@@ -1,3 +1,7 @@
1
+ import {
2
+ buildBillingPaymentCallbackContext
3
+ } from "./chunk-46V73LSW.js";
4
+
1
5
  // src/billing/payment-route.ts
2
6
  import { NextResponse } from "next/server";
3
7
 
@@ -42,44 +46,6 @@ function isDebugEnabled() {
42
46
  }
43
47
  return ["1", "true", "yes", "on"].includes(value.toLowerCase());
44
48
  }
45
- async function readRequestBody(request) {
46
- if (request.method === "GET" || request.method === "HEAD") {
47
- return null;
48
- }
49
- const rawBody = await request.clone().text();
50
- if (!rawBody) {
51
- return null;
52
- }
53
- const contentType = request.headers.get("content-type") ?? "";
54
- if (contentType.includes("application/json")) {
55
- try {
56
- return JSON.parse(rawBody);
57
- } catch {
58
- return rawBody;
59
- }
60
- }
61
- if (contentType.includes("application/x-www-form-urlencoded")) {
62
- return Object.fromEntries(new URLSearchParams(rawBody).entries());
63
- }
64
- return rawBody;
65
- }
66
- async function buildContext(request) {
67
- const url = new URL(request.url);
68
- const params = {};
69
- for (const [key, value] of url.searchParams.entries()) {
70
- params[key] = value;
71
- }
72
- return {
73
- request,
74
- url,
75
- searchParams: url.searchParams,
76
- params,
77
- paymentId: url.searchParams.get("paymentId"),
78
- orderId: url.searchParams.get("orderId"),
79
- redirectTo: url.searchParams.get("redirect") ?? url.searchParams.get("returnTo"),
80
- body: await readRequestBody(request)
81
- };
82
- }
83
49
  function resolveRedirectTarget(result, context, fallbackRedirect) {
84
50
  if (typeof result === "string") {
85
51
  return sanitizeRedirectPath(result, fallbackRedirect);
@@ -96,6 +62,8 @@ function logMissingPaymentHandler(context, fallbackRedirect, missingHandlerFile,
96
62
  console.warn(
97
63
  `[casdoor-next-auth-kit] default billing handler at ${missingHandlerFile} has no business logic. Edit this file to handle ${routePath} with order/payment enrichment before redirecting. Falling back to ${fallbackRedirect}.`,
98
64
  {
65
+ paymentOwner: context.paymentOwner,
66
+ paymentName: context.paymentName,
99
67
  paymentId: context.paymentId,
100
68
  orderId: context.orderId,
101
69
  params: context.params
@@ -105,7 +73,7 @@ function logMissingPaymentHandler(context, fallbackRedirect, missingHandlerFile,
105
73
  async function createBillingPaymentRouteResponse(request, options) {
106
74
  const origin = resolvePublicOrigin(request, options.appUrl);
107
75
  const fallbackRedirect = options.fallbackRedirect ?? "/";
108
- const context = await buildContext(request);
76
+ const context = await buildBillingPaymentCallbackContext(request, options.phase);
109
77
  if (isDebugEnabled()) {
110
78
  console.info(`[casdoor-next-auth-kit] ${options.routePath} request`, {
111
79
  method: request.method,
@@ -116,7 +84,8 @@ async function createBillingPaymentRouteResponse(request, options) {
116
84
  }
117
85
  try {
118
86
  if (options.handler) {
119
- const result = await options.handler(context);
87
+ const handler = options.handler;
88
+ const result = options.phase === "finished" ? await handler(context) : await handler(context);
120
89
  if (result instanceof Response) {
121
90
  return result;
122
91
  }
@@ -138,7 +107,8 @@ async function createBillingPaymentSuccessResponse(request, options = {}) {
138
107
  ...options,
139
108
  routePath: "/auth/payment/success",
140
109
  missingHandlerFile: "lib/billing/payment-success.ts",
141
- fallbackRedirect: options.fallbackRedirect ?? "/auth/payment/finished"
110
+ fallbackRedirect: options.fallbackRedirect ?? "/auth/payment/finished",
111
+ phase: options.phase ?? "success"
142
112
  });
143
113
  }
144
114
  function createBillingPaymentSuccessRouteHandler(options = {}) {
@@ -153,7 +123,8 @@ async function createBillingPaymentFinishedResponse(request, options = {}) {
153
123
  ...options,
154
124
  routePath: "/auth/payment/finished",
155
125
  missingHandlerFile: "lib/billing/payment-finished.ts",
156
- fallbackRedirect: options.fallbackRedirect ?? "/"
126
+ fallbackRedirect: options.fallbackRedirect ?? "/",
127
+ phase: options.phase ?? "finished"
157
128
  });
158
129
  }
159
130
  function createBillingPaymentFinishedRouteHandler(options = {}) {
@@ -168,4 +139,4 @@ export {
168
139
  createBillingPaymentFinishedResponse,
169
140
  createBillingPaymentFinishedRouteHandler
170
141
  };
171
- //# sourceMappingURL=chunk-5ISF7ZAG.js.map
142
+ //# sourceMappingURL=chunk-ZCHLJYLN.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/billing/payment-route.ts","../src/core/origin.ts","../src/billing/payment-success.ts","../src/billing/payment-finished.ts"],"sourcesContent":["import { NextResponse } from 'next/server';\n\nimport { resolvePublicOrigin } from '../core/origin';\nimport { buildBillingPaymentCallbackContext } from './runtime';\nimport type {\n BillingPaymentRouteBaseOptions,\n BillingPaymentFinishedRouteOptions,\n BillingPaymentFinishedContext,\n BillingPaymentFinishedHandler,\n BillingPaymentSuccessContext,\n BillingPaymentSuccessHandlerResult,\n BillingPaymentSuccessRouteOptions,\n} from './types';\n\nexport interface BillingPaymentRouteOptions extends BillingPaymentRouteBaseOptions {\n routePath: string;\n missingHandlerFile: string;\n handler?: BillingPaymentSuccessRouteOptions['handler'] | BillingPaymentFinishedRouteOptions['handler'];\n phase?: 'success' | 'failure' | 'finished';\n}\n\nfunction sanitizeRedirectPath(value: string | null | undefined, fallback: string): string {\n if (!value || !value.startsWith('/') || value.startsWith('//')) {\n return fallback;\n }\n\n return value;\n}\n\nfunction isDebugEnabled(): boolean {\n const value = process.env.BILLING_PAYMENT_SUCCESS_DEBUG;\n if (!value) {\n return false;\n }\n\n return ['1', 'true', 'yes', 'on'].includes(value.toLowerCase());\n}\n\nfunction resolveRedirectTarget(\n result: BillingPaymentSuccessHandlerResult | undefined,\n context: BillingPaymentSuccessContext,\n fallbackRedirect: string,\n): string {\n if (typeof result === 'string') {\n return sanitizeRedirectPath(result, fallbackRedirect);\n }\n\n if (result && typeof result === 'object' && 'redirectTo' in result) {\n return sanitizeRedirectPath(result.redirectTo ?? null, fallbackRedirect);\n }\n\n return sanitizeRedirectPath(context.redirectTo, fallbackRedirect);\n}\n\nfunction resolveFallbackTarget(fallbackRedirect: string): string {\n return sanitizeRedirectPath(fallbackRedirect, '/');\n}\n\nfunction logMissingPaymentHandler(\n context: BillingPaymentSuccessContext,\n fallbackRedirect: string,\n missingHandlerFile: string,\n routePath: string,\n): void {\n console.warn(\n `[casdoor-next-auth-kit] default billing handler at ${missingHandlerFile} has no business logic. ` +\n `Edit this file to handle ${routePath} with order/payment enrichment before redirecting. ` +\n `Falling back to ${fallbackRedirect}.`,\n {\n paymentOwner: context.paymentOwner,\n paymentName: context.paymentName,\n paymentId: context.paymentId,\n orderId: context.orderId,\n params: context.params,\n },\n );\n}\n\nexport async function createBillingPaymentRouteResponse(\n request: Request,\n options: BillingPaymentRouteOptions,\n) {\n const origin = resolvePublicOrigin(request, options.appUrl);\n const fallbackRedirect = options.fallbackRedirect ?? '/';\n const context = await buildBillingPaymentCallbackContext(request, options.phase);\n\n if (isDebugEnabled()) {\n console.info(`[casdoor-next-auth-kit] ${options.routePath} request`, {\n method: request.method,\n path: context.url.pathname,\n query: context.params,\n body: context.body,\n });\n }\n\n try {\n if (options.handler) {\n const handler = options.handler;\n const result =\n options.phase === 'finished'\n ? await (handler as BillingPaymentFinishedHandler)(context as BillingPaymentFinishedContext)\n : await (handler as NonNullable<BillingPaymentSuccessRouteOptions['handler']>)(context);\n if (result instanceof Response) {\n return result;\n }\n\n const target = resolveRedirectTarget(result, context, fallbackRedirect);\n return NextResponse.redirect(new URL(target, origin), 307);\n }\n\n logMissingPaymentHandler(context, fallbackRedirect, options.missingHandlerFile, options.routePath);\n const target = resolveFallbackTarget(fallbackRedirect);\n return NextResponse.redirect(new URL(target, origin), 307);\n } catch (error) {\n console.error(`[casdoor-next-auth-kit] ${options.routePath} handler failed:`, error);\n return new NextResponse('Billing payment handler failed', { status: 500 });\n }\n}\n","export function normalizeOrigin(value: string | null | undefined): string | null {\n if (!value) return null;\n try {\n return new URL(value).origin;\n } catch {\n return null;\n }\n}\n\nexport function getRequestOrigin(request: Request, appUrl?: string): string {\n const configured = normalizeOrigin(appUrl);\n if (configured) return configured;\n\n const referer = normalizeOrigin(request.headers.get('referer'));\n if (referer) return referer;\n\n const origin = normalizeOrigin(request.headers.get('origin'));\n if (origin) return origin;\n\n const forwardedProto = request.headers.get('x-forwarded-proto')?.split(',')[0]?.trim();\n const forwardedHost = request.headers.get('x-forwarded-host')?.split(',')[0]?.trim();\n if (forwardedProto && forwardedHost) {\n return forwardedProto + '://' + forwardedHost;\n }\n\n return new URL(request.url).origin;\n}\n\nexport function resolvePublicOrigin(request: Request, appUrl?: string): string {\n return getRequestOrigin(request, appUrl);\n}\n","import type { BillingPaymentSuccessHandler, BillingPaymentSuccessRouteOptions } from './types';\nimport { createBillingPaymentRouteResponse } from './payment-route';\n\nexport async function createBillingPaymentSuccessResponse(\n request: Request,\n options: BillingPaymentSuccessRouteOptions = {},\n) {\n return createBillingPaymentRouteResponse(request, {\n ...options,\n routePath: '/auth/payment/success',\n missingHandlerFile: 'lib/billing/payment-success.ts',\n fallbackRedirect: options.fallbackRedirect ?? '/auth/payment/finished',\n phase: options.phase ?? 'success',\n });\n}\n\nexport function createBillingPaymentSuccessRouteHandler(options: BillingPaymentSuccessRouteOptions = {}) {\n return async function GET(request: Request) {\n return createBillingPaymentSuccessResponse(request, options);\n };\n}\n\nexport type { BillingPaymentSuccessHandler };\n","import type { BillingPaymentFinishedHandler, BillingPaymentFinishedRouteOptions } from './types';\nimport { createBillingPaymentRouteResponse } from './payment-route';\n\nexport async function createBillingPaymentFinishedResponse(\n request: Request,\n options: BillingPaymentFinishedRouteOptions = {},\n) {\n return createBillingPaymentRouteResponse(request, {\n ...options,\n routePath: '/auth/payment/finished',\n missingHandlerFile: 'lib/billing/payment-finished.ts',\n fallbackRedirect: options.fallbackRedirect ?? '/',\n phase: options.phase ?? 'finished',\n });\n}\n\nexport function createBillingPaymentFinishedRouteHandler(options: BillingPaymentFinishedRouteOptions = {}) {\n return async function GET(request: Request) {\n return createBillingPaymentFinishedResponse(request, options);\n };\n}\n\nexport type { BillingPaymentFinishedHandler };\n"],"mappings":"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","names":["target"]}
package/dist/cli.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  buildAuthPrismaSchemaTemplate,
5
5
  buildManagedEnvTemplate,
6
6
  getMissingManagedEnvKeys
7
- } from "./chunk-CULH4UKG.js";
7
+ } from "./chunk-FW4WDHNS.js";
8
8
 
9
9
  // package.json
10
10
  var package_default = {
@@ -14,7 +14,7 @@ var package_default = {
14
14
  type: "module",
15
15
  repository: {
16
16
  type: "git",
17
- url: "https://github.com/foldspace-stack/casdoor-next-auth-kit"
17
+ url: "git+https://github.com/foldspace-stack/casdoor-next-auth-kit.git"
18
18
  },
19
19
  homepage: "https://github.com/foldspace-stack/casdoor-next-auth-kit#readme",
20
20
  bugs: {
@@ -54,7 +54,8 @@ var package_default = {
54
54
  files: ["dist", "README.md"],
55
55
  scripts: {
56
56
  build: "tsup && node ./scripts/copy-skill.mjs",
57
- test: "pnpm build && node --test --experimental-strip-types ./scripts/verify-casdoor-proxy.mjs",
57
+ test: "pnpm build && node --test --experimental-strip-types ./scripts/verify-casdoor-proxy.mjs ./test/*.test.ts",
58
+ lint: "tsc -p tsconfig.json --noEmit",
58
59
  typecheck: "tsc -p tsconfig.json --noEmit",
59
60
  dev: "tsup --watch"
60
61
  },
@@ -180,18 +181,96 @@ export default async function CallbackErrorPage({
180
181
  const params = await searchParams;
181
182
 
182
183
  return (
183
- <main style={{ background: '#fff', borderRadius: 24, padding: 28, boxShadow: '0 18px 40px rgba(15, 23, 42, 0.08)' }}>
184
- <h2 style={{ marginTop: 0 }}>{params.title ?? 'Callback Error'}</h2>
185
- <p>{params.message ?? 'Unknown callback failure.'}</p>
186
- {params.details ? <pre style={{ whiteSpace: 'pre-wrap' }}>{params.details}</pre> : null}
184
+ <main
185
+ style={{
186
+ minHeight: '100dvh',
187
+ display: 'flex',
188
+ alignItems: 'center',
189
+ justifyContent: 'center',
190
+ padding: '20px 16px',
191
+ background:
192
+ 'radial-gradient(circle at top, rgba(99, 102, 241, 0.12) 0, rgba(99, 102, 241, 0) 38%), linear-gradient(180deg, #f8fafc 0%, #eef2ff 100%)',
193
+ }}
194
+ >
195
+ <section
196
+ style={{
197
+ width: 'min(100%, 400px)',
198
+ borderRadius: 28,
199
+ padding: '24px 20px',
200
+ boxSizing: 'border-box',
201
+ background: 'rgba(255, 255, 255, 0.96)',
202
+ border: '1px solid rgba(148, 163, 184, 0.2)',
203
+ boxShadow: '0 22px 52px rgba(15, 23, 42, 0.12)',
204
+ textAlign: 'center',
205
+ backdropFilter: 'blur(10px)',
206
+ }}
207
+ >
208
+ <div
209
+ style={{
210
+ width: 52,
211
+ height: 52,
212
+ margin: '0 auto 14px',
213
+ display: 'grid',
214
+ placeItems: 'center',
215
+ borderRadius: 18,
216
+ background: 'linear-gradient(135deg, rgba(239, 68, 68, 0.15), rgba(249, 115, 22, 0.1))',
217
+ color: '#b91c1c',
218
+ fontSize: 28,
219
+ lineHeight: 1,
220
+ }}
221
+ aria-hidden="true"
222
+ >
223
+ !
224
+ </div>
225
+ <div
226
+ style={{
227
+ display: 'inline-flex',
228
+ alignItems: 'center',
229
+ justifyContent: 'center',
230
+ marginBottom: 12,
231
+ padding: '6px 12px',
232
+ borderRadius: 9999,
233
+ background: 'rgba(254, 226, 226, 0.9)',
234
+ color: '#b91c1c',
235
+ fontSize: 13,
236
+ fontWeight: 600,
237
+ letterSpacing: '0.04em',
238
+ }}
239
+ >
240
+ \u8BA4\u8BC1\u5931\u8D25
241
+ </div>
242
+ <h2 style={{ margin: 0, fontSize: 24, lineHeight: 1.2, color: '#0f172a' }}>{params.title ?? 'Callback Error'}</h2>
243
+ <p style={{ margin: '12px 0 0', color: '#334155', lineHeight: 1.6 }}>{params.message ?? 'Unknown callback failure.'}</p>
244
+ {params.details ? (
245
+ <pre
246
+ style={{
247
+ margin: '14px 0 0',
248
+ maxHeight: 140,
249
+ overflow: 'auto',
250
+ padding: 14,
251
+ borderRadius: 18,
252
+ textAlign: 'left',
253
+ whiteSpace: 'pre-wrap',
254
+ wordBreak: 'break-word',
255
+ background: '#f8fafc',
256
+ color: '#0f172a',
257
+ border: '1px solid rgba(148, 163, 184, 0.18)',
258
+ fontSize: 13,
259
+ lineHeight: 1.6,
260
+ }}
261
+ >
262
+ {params.details}
263
+ </pre>
264
+ ) : null}
187
265
  ${customBegin}
188
- <div style={{ display: 'flex', flexWrap: 'wrap', gap: 12, marginTop: 24 }}>
266
+ <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginTop: 20 }}>
189
267
  <ClearDomainCookiesButton />
190
- <a href="/" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', minHeight: 44, padding: '0 16px', borderRadius: 9999, border: '1px solid rgba(148, 163, 184, 0.35)', color: '#0f172a', textDecoration: 'none', background: 'rgba(248, 250, 252, 0.9)' }}>\u8FD4\u56DE\u9996\u9875</a>
191
- <a href="/auth/login" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', minHeight: 44, padding: '0 16px', borderRadius: 9999, border: '1px solid rgba(148, 163, 184, 0.35)', color: '#0f172a', textDecoration: 'none', background: 'rgba(248, 250, 252, 0.9)' }}>\u91CD\u65B0\u767B\u5F55</a>
192
- <a href="/auth/signup" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center', minHeight: 44, padding: '0 16px', borderRadius: 9999, border: '1px solid rgba(148, 163, 184, 0.35)', color: '#0f172a', textDecoration: 'none', background: 'rgba(248, 250, 252, 0.9)' }}>\u53BB\u6CE8\u518C</a>
193
- </div>
268
+ <a href="/" style={{ display: 'inline-flex', width: '100%', alignItems: 'center', justifyContent: 'center', minHeight: 44, padding: '0 16px', boxSizing: 'border-box', borderRadius: 9999, border: '1px solid rgba(148, 163, 184, 0.35)', color: '#0f172a', textDecoration: 'none', background: 'rgba(248, 250, 252, 0.9)' }}>\u8FD4\u56DE\u9996\u9875</a>
269
+ <a href="/auth/login" style={{ display: 'inline-flex', width: '100%', alignItems: 'center', justifyContent: 'center', minHeight: 44, padding: '0 16px', boxSizing: 'border-box', borderRadius: 9999, border: '1px solid rgba(148, 163, 184, 0.35)', color: '#0f172a', textDecoration: 'none', background: 'rgba(248, 250, 252, 0.9)' }}>\u91CD\u65B0\u767B\u5F55</a>
270
+ <a href="/auth/signup" style={{ display: 'inline-flex', width: '100%', alignItems: 'center', justifyContent: 'center', minHeight: 44, padding: '0 16px', boxSizing: 'border-box', borderRadius: 9999, border: '1px solid rgba(148, 163, 184, 0.35)', color: '#0f172a', textDecoration: 'none', background: 'rgba(248, 250, 252, 0.9)' }}>\u53BB\u6CE8\u518C</a>
271
+ </div>
194
272
  ${customEnd}
273
+ </section>
195
274
  </main>
196
275
  );
197
276
  }
@@ -313,10 +392,12 @@ export function ClearDomainCookiesButton() {
313
392
  disabled={cleared}
314
393
  style={{
315
394
  display: 'inline-flex',
395
+ width: '100%',
316
396
  alignItems: 'center',
317
397
  justifyContent: 'center',
318
398
  minHeight: 44,
319
399
  padding: '0 16px',
400
+ boxSizing: 'border-box',
320
401
  borderRadius: 9999,
321
402
  border: '1px solid rgba(148, 163, 184, 0.35)',
322
403
  color: '#0f172a',
@@ -353,6 +434,7 @@ export function createAuthKitConfig(): AuthKitConfig {
353
434
  return {
354
435
  appUrl: process.env.APP_URL || '',
355
436
  nextauthSecret: process.env.NEXTAUTH_SECRET || 'dev-nextauth-secret',
437
+ logoutRedirectPath: process.env.NEXT_PUBLIC_AUTH_LOGOUT_REDIRECT_PATH || '/',
356
438
  casdoor: {
357
439
  serverUrl: process.env.NEXT_PUBLIC_CASDOOR_SERVER_URL || process.env.CASDOOR_SERVER_URL || '',
358
440
  clientId: process.env.NEXT_PUBLIC_CASDOOR_CLIENT_ID || process.env.CASDOOR_CLIENT_ID || '',
@@ -432,6 +514,7 @@ export const GET = createBillingPaymentSuccessRouteHandler({
432
514
  appUrl: authKitConfig.appUrl,
433
515
  fallbackRedirect: '/auth/payment/finished',
434
516
  handler: paymentSuccessHandler,
517
+ phase: 'success',
435
518
  });
436
519
  `;
437
520
  }
@@ -446,6 +529,7 @@ export const GET = createBillingPaymentFinishedRouteHandler({
446
529
  appUrl: authKitConfig.appUrl,
447
530
  fallbackRedirect: '/',
448
531
  handler: paymentFinishedHandler,
532
+ phase: 'finished',
449
533
  });
450
534
  `;
451
535
  }
@@ -453,7 +537,13 @@ function billingPaymentSuccessHandlerTemplate() {
453
537
  return `import type { BillingPaymentSuccessHandler } from '@foldspace-fe/casdoor-next-auth-kit/billing';
454
538
 
455
539
  ${customBegin}
456
- const paymentSuccessHandlerImpl: BillingPaymentSuccessHandler = async () => {
540
+ const paymentSuccessHandlerImpl: BillingPaymentSuccessHandler = async (context) => {
541
+ console.info('[casdoor-next-auth-kit] payment success callback received', {
542
+ paymentId: context.paymentId,
543
+ orderId: context.orderId,
544
+ status: context.status,
545
+ redirectTo: context.redirectTo,
546
+ });
457
547
  return;
458
548
  };
459
549
  ${customEnd}
@@ -465,7 +555,13 @@ function billingPaymentFinishedHandlerTemplate() {
465
555
  return `import type { BillingPaymentFinishedHandler } from '@foldspace-fe/casdoor-next-auth-kit/billing';
466
556
 
467
557
  ${customBegin}
468
- const paymentFinishedHandlerImpl: BillingPaymentFinishedHandler = async () => {
558
+ const paymentFinishedHandlerImpl: BillingPaymentFinishedHandler = async (context) => {
559
+ console.info('[casdoor-next-auth-kit] payment finished callback received', {
560
+ paymentId: context.paymentId,
561
+ orderId: context.orderId,
562
+ status: context.status,
563
+ redirectTo: context.redirectTo,
564
+ });
469
565
  return;
470
566
  };
471
567
  ${customEnd}