UNPKG

@teamsparta/cross-platform-logger

Version:

```typescript import * as CPL from "@teamsparta/cross-platform-logger";

99 lines (93 loc) 4.74 kB
import { NextRequest, NextFetchEvent, NextResponse } from 'next/server'; declare const UTM_KEYS: readonly ["utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]; type UtmKey = (typeof UTM_KEYS)[number]; type UtmRecord = Partial<Record<UtmKey, string>>; type ConsumerMiddleware = (req: NextRequest, event?: NextFetchEvent) => NextResponse | void | undefined | null | Promise<NextResponse | void | undefined | null>; /** * utm-collector 백엔드로 보내는 페이로드. * * Lambda(`utm-collector`)의 입력 스키마와 정확히 매칭된다. * 스키마가 바뀌면 양쪽을 함께 갱신해야 한다. */ type UtmCapturePayload = { userId?: string; anonId: string; utm: UtmRecord; url: string; referrer?: string; capturedAt: string; }; type WithUtmCaptureOptions = { /** * 백엔드 인증 토큰 (필수). * * 컨슈머가 자신의 시크릿 관리 방식대로 주입한다 — `process.env.XXX`, * secret manager 등. SDK는 토큰을 어디서 가져오는지 알지 못한다. * * 클라이언트 번들에 절대 노출되어선 안 된다 — server-only env 또는 server-only * 시크릿으로 관리할 것 (`NEXT_PUBLIC_` 접두사 금지). */ token: string; /** * 인증된 user_id 추출. 미인증 요청은 anonId만 사용. * 동기 또는 비동기 모두 지원. */ getUserId?: (req: NextRequest) => string | undefined | Promise<string | undefined>; /** 쿠키 도메인. default '.spartaclub.kr' */ cookieDomain?: string; /** anon id 쿠키 이름. default 'sparta_anon_id' */ anonCookieName?: string; /** anon id 쿠키 만료 (초). default 180일 */ anonCookieMaxAge?: number; }; /** * 미들웨어를 감싸서 UTM 캡처를 추가하는 HOF. * * 컨슈머의 미들웨어 결과(NextResponse / redirect / rewrite)를 그대로 보존하면서 * anon 쿠키 set과 백엔드 영속화만 얹는다. * * - 컨슈머 미들웨어가 throw하면 그대로 throw (의도된 흐름 보장). * - UTM 캡처 단계 에러는 절대 throw하지 않음 — stderr 로그만 남기고 응답은 정상 반환. * * 컨슈머가 NextResponse를 반환하지 않으면 (void/null) `NextResponse.next()`로 fallback. * 기존 미들웨어가 없는 경우 `() => NextResponse.next()`를 넘기면 된다. * * 백엔드 호출은 `event.waitUntil`로 백그라운드에서 실행되므로 응답 TTFB에 영향이 없다. * `event`가 주입되지 않은 환경(테스트 등)에서는 await fallback으로 동작한다. * anon 쿠키 set은 첫 await 이전에 동기로 res에 박히므로, 백그라운드 실행이어도 * 응답에 함께 실려나간다. * * 백엔드 endpoint는 SDK 내부에 hardcode되어 있다 — 컨슈머는 Lambda의 존재를 모른다. * 인증 토큰은 `opts.token`으로 주입한다 — 컨슈머가 자신의 시크릿 관리 방식대로 * (`process.env.XXX`, secret manager 등) 결정한다. * * 토큰은 server-only로 관리할 것 — 클라이언트 번들에 노출되어선 안 된다. * Edge/Node 어느 런타임에서도 동작한다 — fetch + Web Crypto만 쓰므로 Node 전용 API 의존 없음. */ declare function withUtmCapture(middleware: ConsumerMiddleware, opts: WithUtmCaptureOptions): (req: NextRequest, event?: NextFetchEvent) => Promise<NextResponse>; type WithUtmCookieOptions = { /** 쿠키 도메인. default '.spartaclub.kr' */ cookieDomain?: string; /** * utm 쿠키 이름. * default 'utm_last' (브라우저 SDK의 setUTMCookies와 호환). */ utmCookieName?: string; /** utm 쿠키 만료 (초). default 7일 */ utmCookieMaxAge?: number; }; /** * 미들웨어를 감싸 UTM 쿠키 SSR 발급을 추가하는 HOF. * * query string에 utm이 있을 때 1st-party 쿠키로 발급한다. * 백엔드 영속화나 식별자 발급은 하지 않는다. * * 기존 미들웨어가 없는 경우 `() => NextResponse.next()`를 넘기면 된다. * * 브라우저 측 `setUTMCookies`도 동일한 `utm_last` 쿠키를 발급한다. * SSR 응답에서 1차 발급(이 함수) → hydration 후 클라 SDK가 동일 키로 재발급. * 두 발급 경로 모두 raw JSON value를 사용해 정합성을 유지한다 — 백엔드가 * 어느 쪽 발급의 쿠키를 받든 cookie-parser → JSON.parse로 동일하게 처리된다. */ declare function withUtmCookie(middleware: ConsumerMiddleware, opts?: WithUtmCookieOptions): (req: NextRequest, event?: NextFetchEvent) => Promise<NextResponse>; export { type UtmCapturePayload, type UtmRecord, type WithUtmCaptureOptions, type WithUtmCookieOptions, withUtmCapture, withUtmCookie };