@ahnseungchan/webviewkit 2.1.0 → 2.2.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/README.md +10 -6
- package/dist/index.d.mts +32 -5
- package/dist/index.d.ts +32 -5
- package/dist/index.js +456 -112
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +433 -85
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/bridge/detect-host.ts","../src/bridge/errors.ts","../src/bridge/pending-responses.ts","../src/bridge/protocol.ts","../src/bridge/transport.ts","../src/bridge/url-policy.ts","../src/bridge/client.ts","../src/bridge/stack-router-bridge.ts","../src/bridge/host.ts","../src/bridge/WebViewBridgeProvider.tsx","../src/type.ts","../src/history.ts","../src/stack-dev/stack-dev-roadmap.tsx","../src/stack-router/_components/back-router.tsx","../src/stack-router/stack-router-provider.tsx","../src/stack-router/_components/header.tsx","../src/stack-router/_components/stack-page.tsx","../src/stack-router/activity-context.tsx","../src/stack-router/stack-reducer.ts","../src/stack-router/use-prefers-reduced-motion.ts","../src/stack-router/use-stack-bridge-sync.ts","../src/stack-router/use-stack-navigation.ts","../src/stack-router/match-path.ts"],"sourcesContent":["export * from \"./bridge\";\nexport {\n BACK_TIMEOUT_MS,\n BRIDGE_TIMEOUT_MS,\n STACK_TRANSITION_MS,\n} from \"./constants\";\nexport { history } from \"./history\";\nexport { StackDevRoadmap } from \"./stack-dev/stack-dev-roadmap\";\nexport { default as BackRouter } from \"./stack-router/_components/back-router\";\nexport { default as StackHeader } from \"./stack-router/_components/header\";\nexport {\n type ActivityContextValue,\n useActivity,\n useParams,\n} from \"./stack-router/activity-context\";\nexport { findActivity, matchPath, parseQuery } from \"./stack-router/match-path\";\nexport type { StackEntry } from \"./stack-router/stack-reducer\";\nexport {\n type StackRouterContextValue,\n default as StackRouterProvider,\n useStackRouter,\n} from \"./stack-router/stack-router-provider\";\nexport type { StackBridgeSyncOptions } from \"./stack-router/use-stack-bridge-sync\";\nexport type {\n Activity,\n DirectionType,\n HistoryListener,\n HistoryState,\n RestoreStackPolicy,\n StackRouterProviderProps,\n StackTransitionType,\n VisiblePage,\n} from \"./type\";\nexport { Direction, HistoryAction } from \"./type\";\n","/**\n * push/back 전환 기본 시간 (ms). iOS 네비게이션 전환 체감에 맞춘 값.\n * `StackRouterProvider` `duration` 으로 조정\n */\nexport const STACK_TRANSITION_MS = 500;\n\n/** 전환 종료 안전 타이머 여유 (animationend 누락 대비) */\nexport const TRANSITION_END_GRACE_MS = 50;\n\n/** `history.back()` 이 popstate 를 기다리는 최대 시간 */\nexport const BACK_TIMEOUT_MS = 1000;\n\n/** 브릿지 요청 응답 기본 타임아웃 */\nexport const BRIDGE_TIMEOUT_MS = 5000;\n\n/** 네이티브 브릿지 주입 대기 기본 시간 */\nexport const BRIDGE_HOST_WAIT_MS = 3000;\n\n/** 네이티브 브릿지 주입 재확인 간격 */\nexport const BRIDGE_HOST_POLL_MS = 100;\n","import { BRIDGE_HOST_POLL_MS, BRIDGE_HOST_WAIT_MS } from \"../constants\";\nimport type { BridgeHostKind } from \"./protocol\";\n\n/** flutter_inappwebview 가 JS 브릿지를 붙인 뒤 window 에 dispatch 하는 이벤트 */\nexport const FLUTTER_READY_EVENT = \"flutterInAppWebViewPlatformReady\";\n\nexport function detectBridgeHost(): BridgeHostKind {\n if (typeof window === \"undefined\") return \"unknown\";\n\n if (window.ReactNativeWebView?.postMessage) {\n return \"react-native\";\n }\n\n if (window.flutter_inappwebview?.callHandler) {\n return \"flutter\";\n }\n\n return \"browser\";\n}\n\nexport function isNativeBridgeHost(host: BridgeHostKind): boolean {\n return host === \"react-native\" || host === \"flutter\";\n}\n\nexport interface WaitForBridgeHostOptions {\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * 네이티브 브릿지가 늦게 주입되는 경우(Flutter platformReady 이전)를 기다린다.\n * 즉시 감지되면 바로, 아니면 ready 이벤트·폴링으로 재감지. 타임아웃·abort 시 현재 판정값.\n */\nexport function waitForBridgeHost({\n timeoutMs = BRIDGE_HOST_WAIT_MS,\n signal,\n}: WaitForBridgeHostOptions = {}): Promise<BridgeHostKind> {\n const host = detectBridgeHost();\n if (isNativeBridgeHost(host) || host === \"unknown\") {\n return Promise.resolve(host);\n }\n\n return new Promise<BridgeHostKind>((resolve) => {\n const finish = () => {\n clearInterval(poll);\n clearTimeout(timer);\n window.removeEventListener(FLUTTER_READY_EVENT, check);\n signal?.removeEventListener(\"abort\", finish);\n resolve(detectBridgeHost());\n };\n const check = () => {\n if (isNativeBridgeHost(detectBridgeHost())) finish();\n };\n const poll = setInterval(check, BRIDGE_HOST_POLL_MS);\n const timer = setTimeout(finish, timeoutMs);\n window.addEventListener(FLUTTER_READY_EVENT, check);\n signal?.addEventListener(\"abort\", finish);\n });\n}\n","export const BRIDGE_ERROR_CODES = {\n TIMEOUT: \"TIMEOUT\",\n BRIDGE_UNAVAILABLE: \"BRIDGE_UNAVAILABLE\",\n INVALID_PAYLOAD: \"INVALID_PAYLOAD\",\n URL_NOT_ALLOWED: \"URL_NOT_ALLOWED\",\n UNKNOWN_METHOD: \"UNKNOWN_METHOD\",\n HANDLER_ERROR: \"HANDLER_ERROR\",\n} as const;\n\nexport type BridgeErrorCode =\n (typeof BRIDGE_ERROR_CODES)[keyof typeof BRIDGE_ERROR_CODES];\n\nexport class BridgeError extends Error {\n readonly code: BridgeErrorCode | string;\n\n constructor(\n code: BridgeErrorCode | string,\n message: string,\n cause?: unknown\n ) {\n super(message);\n // ES5 타깃에서 Error 상속 시 instanceof 가 깨지는 것 방지\n Object.setPrototypeOf(this, new.target.prototype);\n this.name = \"BridgeError\";\n this.code = code;\n if (cause !== undefined) {\n (this as { cause?: unknown }).cause = cause;\n }\n }\n\n toBody() {\n return { code: this.code, message: this.message };\n }\n}\n\nexport function toBridgeError(\n error: unknown,\n fallbackCode: BridgeErrorCode\n): BridgeError {\n if (error instanceof BridgeError) return error;\n const message = error instanceof Error ? error.message : String(error);\n return new BridgeError(fallbackCode, message, error);\n}\n","import { BRIDGE_ERROR_CODES, BridgeError } from \"./errors\";\nimport type { BridgeEnvelope } from \"./protocol\";\n\ninterface PendingRequest {\n resolve: (response: BridgeEnvelope) => void;\n reject: (error: BridgeError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst pending = new Map<string, PendingRequest>();\n\n/** `bridge.response`(`replyTo === requestId`) 를 timeoutMs 동안 기다린다 */\nexport function waitForResponse(\n requestId: string,\n timeoutMs: number\n): Promise<BridgeEnvelope> {\n return new Promise<BridgeEnvelope>((resolve, reject) => {\n const timer = setTimeout(() => {\n pending.delete(requestId);\n reject(\n new BridgeError(\n BRIDGE_ERROR_CODES.TIMEOUT,\n `No response for ${requestId} within ${timeoutMs}ms`\n )\n );\n }, timeoutMs);\n pending.set(requestId, { resolve, reject, timer });\n });\n}\n\n/** 응답 envelope 이면 대기 중인 요청을 settle 하고 true */\nexport function settleResponse(envelope: BridgeEnvelope): boolean {\n if (!envelope.replyTo) return false;\n const request = pending.get(envelope.replyTo);\n if (!request) return false;\n clearTimeout(request.timer);\n pending.delete(envelope.replyTo);\n if (envelope.error) {\n request.reject(\n new BridgeError(envelope.error.code, envelope.error.message)\n );\n } else {\n request.resolve(envelope);\n }\n return true;\n}\n\n/** 전송 실패 등으로 대기를 취소 */\nexport function cancelResponse(requestId: string): void {\n const request = pending.get(requestId);\n if (!request) return;\n clearTimeout(request.timer);\n pending.delete(requestId);\n}\n","import type { BridgeErrorCode } from \"./errors\";\n\n/** WebViewKit native bridge protocol (v1) */\nexport const BRIDGE_PROTOCOL_VERSION = 1 as const;\nexport const BRIDGE_NAMESPACE = \"webviewkit\" as const;\n\nexport type BridgeHostKind = \"react-native\" | \"flutter\" | \"browser\" | \"unknown\";\n\n/** Stack navigation — maps to common `stackPush` / `stackPop` WebView handlers */\nexport const STACK_BRIDGE_METHODS = {\n PUSH: \"stack.push\",\n REPLACE: \"stack.replace\",\n POP: \"stack.pop\",\n RESET: \"stack.reset\",\n /** web → native: 웹 스택 깊이 변경 알림 */\n CHANGED: \"stack.changed\",\n} as const;\n\nexport type StackBridgeMethod =\n (typeof STACK_BRIDGE_METHODS)[keyof typeof STACK_BRIDGE_METHODS];\n\n/** native → web: 하드웨어 back. 응답 payload `{ handled }` */\nexport const BACK_REQUEST_METHOD = \"back.request\" as const;\n\n/** 요청에 대한 응답 envelope method (`replyTo` 필수) */\nexport const BRIDGE_RESPONSE_METHOD = \"bridge.response\" as const;\n\nexport type StackMeta = Record<string, unknown> | null;\n\nexport type StackPushPayload = { url: string; meta?: StackMeta };\nexport type StackReplacePayload = StackPushPayload;\nexport type StackResetPayload = { url: string; meta?: StackMeta };\nexport type StackChangedPayload = { depth: number; path: string };\nexport type BackRequestResult = { handled: boolean };\n\nexport type BridgeErrorBody = {\n code: BridgeErrorCode | string;\n message: string;\n};\n\nexport type BridgeEnvelope<TPayload = unknown> = {\n v: typeof BRIDGE_PROTOCOL_VERSION;\n ns: typeof BRIDGE_NAMESPACE;\n id: string;\n method: string;\n payload?: TPayload;\n error?: BridgeErrorBody;\n /** 응답일 때 원 요청 id */\n replyTo?: string;\n};\n\nexport function createBridgeId(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n return `wv-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nexport function createBridgeEnvelope<TPayload>(\n method: string,\n payload?: TPayload,\n id?: string\n): BridgeEnvelope<TPayload> {\n return {\n v: BRIDGE_PROTOCOL_VERSION,\n ns: BRIDGE_NAMESPACE,\n id: id ?? createBridgeId(),\n method,\n ...(payload !== undefined ? { payload } : {}),\n };\n}\n\nexport function createBridgeResponse<TPayload>(\n request: Pick<BridgeEnvelope, \"id\">,\n result: { payload?: TPayload; error?: BridgeErrorBody }\n): BridgeEnvelope<TPayload> {\n return {\n ...createBridgeEnvelope(BRIDGE_RESPONSE_METHOD, result.payload),\n replyTo: request.id,\n ...(result.error ? { error: result.error } : {}),\n };\n}\n\nexport function isBridgeEnvelope(value: unknown): value is BridgeEnvelope {\n if (!value || typeof value !== \"object\") return false;\n const o = value as BridgeEnvelope;\n return (\n o.v === BRIDGE_PROTOCOL_VERSION &&\n o.ns === BRIDGE_NAMESPACE &&\n typeof o.id === \"string\" &&\n typeof o.method === \"string\"\n );\n}\n\nexport function parseBridgeMessage(\n raw: string | unknown\n): BridgeEnvelope | null {\n try {\n const parsed = typeof raw === \"string\" ? (JSON.parse(raw) as unknown) : raw;\n return isBridgeEnvelope(parsed) ? parsed : null;\n } catch {\n // 프로토콜 밖 메시지(다른 라이브러리의 postMessage 등)는 무시한다\n return null;\n }\n}\n\nexport function serializeBridgeMessage(msg: BridgeEnvelope): string {\n return JSON.stringify(msg);\n}\n\n/** Flutter InAppWebView legacy handler names */\nexport const FLUTTER_LEGACY_STACK_HANDLERS = {\n push: \"stackPush\",\n replace: \"stackReplace\",\n pop: \"stackPop\",\n reset: \"stackReset\",\n} as const;\n\n/** Unified handler name when native listens on one channel */\nexport const FLUTTER_UNIFIED_HANDLER = \"webviewkitBridge\";\n\n/** React Native receives messages via this global handler name suggestion */\nexport const RN_BRIDGE_HANDLER = \"webviewkitBridge\";\n","import { detectBridgeHost } from \"./detect-host\";\nimport { BRIDGE_ERROR_CODES, toBridgeError } from \"./errors\";\nimport type { BridgeEnvelope, BridgeHostKind } from \"./protocol\";\nimport {\n FLUTTER_LEGACY_STACK_HANDLERS,\n FLUTTER_UNIFIED_HANDLER,\n serializeBridgeMessage,\n STACK_BRIDGE_METHODS,\n} from \"./protocol\";\n\nexport type BridgeTransportOptions = {\n /** Flutter: use stackPush/stackPop handlers (default true) */\n flutterLegacyHandlers?: boolean;\n};\n\nexport interface BridgeTransport {\n readonly host: BridgeHostKind;\n /** Flutter 는 callHandler 반환값, RN·browser 는 undefined */\n send(envelope: BridgeEnvelope): Promise<unknown>;\n}\n\nconst LEGACY_HANDLER_BY_METHOD: Record<string, string> = {\n [STACK_BRIDGE_METHODS.PUSH]: FLUTTER_LEGACY_STACK_HANDLERS.push,\n [STACK_BRIDGE_METHODS.REPLACE]: FLUTTER_LEGACY_STACK_HANDLERS.replace,\n [STACK_BRIDGE_METHODS.POP]: FLUTTER_LEGACY_STACK_HANDLERS.pop,\n [STACK_BRIDGE_METHODS.RESET]: FLUTTER_LEGACY_STACK_HANDLERS.reset,\n};\n\nfunction unavailable(host: BridgeHostKind): never {\n throw new Error(`${host} bridge is not available`);\n}\n\nfunction createReactNativeTransport(): BridgeTransport {\n return {\n host: \"react-native\",\n async send(envelope) {\n try {\n const bridge = window.ReactNativeWebView ?? unavailable(\"react-native\");\n bridge.postMessage(serializeBridgeMessage(envelope));\n return undefined;\n } catch (error) {\n throw toBridgeError(error, BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE);\n }\n },\n };\n}\n\nfunction createFlutterTransport(\n options: BridgeTransportOptions\n): BridgeTransport {\n const useLegacy = options.flutterLegacyHandlers !== false;\n\n return {\n host: \"flutter\",\n async send(envelope) {\n const bridge = window.flutter_inappwebview;\n if (!bridge?.callHandler) {\n throw toBridgeError(\n new Error(\"flutter bridge is not available\"),\n BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE\n );\n }\n const call = bridge.callHandler.bind(bridge);\n const handler = useLegacy\n ? LEGACY_HANDLER_BY_METHOD[envelope.method]\n : null;\n if (!handler) {\n return call(FLUTTER_UNIFIED_HANDLER, serializeBridgeMessage(envelope));\n }\n if (envelope.method === STACK_BRIDGE_METHODS.POP) {\n return call(handler);\n }\n const payload = envelope.payload as\n | { url?: string; meta?: unknown }\n | undefined;\n return call(handler, payload?.url ?? \"\", payload?.meta ?? null);\n },\n };\n}\n\nconst browserTransport: BridgeTransport = {\n host: \"browser\",\n async send() {\n // no native host — web-only\n return undefined;\n },\n};\n\nexport function createBridgeTransport(\n host: BridgeHostKind = detectBridgeHost(),\n options: BridgeTransportOptions = {}\n): BridgeTransport {\n if (host === \"react-native\") return createReactNativeTransport();\n if (host === \"flutter\") return createFlutterTransport(options);\n return browserTransport;\n}\n","import { BRIDGE_ERROR_CODES, BridgeError } from \"./errors\";\n\nexport type AllowUrl = (url: string) => boolean;\n\n/**\n * 기본 정책: 같은 앱 안의 경로만 허용.\n * - `/a/b?x=1` 같은 상대 경로 (`//host` 프로토콜 상대 URL 제외)\n * - 현재 origin 과 같은 절대 http(s) URL\n * `javascript:`, `data:`, 외부 도메인은 거부한다.\n */\nexport function isSafeStackUrl(url: string): boolean {\n if (url.startsWith(\"/\"))\n return !url.startsWith(\"//\") && !url.startsWith(\"/\\\\\");\n if (typeof window === \"undefined\") return false;\n try {\n const parsed = new URL(url);\n return (\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n parsed.origin === window.location.origin\n );\n } catch {\n return false;\n }\n}\n\n/** 같은 origin 절대 URL → 경로로 정규화. 그 밖(상대 경로·커스텀 스킴)은 그대로 */\nexport function toStackPath(url: string): string {\n if (url.startsWith(\"/\") || typeof window === \"undefined\") return url;\n try {\n const parsed = new URL(url);\n if (parsed.origin !== window.location.origin) return url;\n return parsed.pathname + parsed.search + parsed.hash;\n } catch {\n return url;\n }\n}\n\n/** payload 에서 url 을 꺼내 형식·정책 검증 후 경로로 반환. 실패 시 BridgeError */\nexport function assertStackUrl(\n payload: unknown,\n allowUrl: AllowUrl = isSafeStackUrl\n): string {\n const url = (payload as { url?: unknown } | undefined)?.url;\n if (typeof url !== \"string\" || url.trim().length === 0) {\n throw new BridgeError(\n BRIDGE_ERROR_CODES.INVALID_PAYLOAD,\n \"payload.url must be a non-empty string\"\n );\n }\n if (!allowUrl(url)) {\n throw new BridgeError(\n BRIDGE_ERROR_CODES.URL_NOT_ALLOWED,\n `url is not allowed: ${url}`\n );\n }\n return toStackPath(url);\n}\n","import { BRIDGE_TIMEOUT_MS } from \"../constants\";\nimport { detectBridgeHost } from \"./detect-host\";\nimport { BRIDGE_ERROR_CODES, BridgeError } from \"./errors\";\nimport { cancelResponse, waitForResponse } from \"./pending-responses\";\nimport {\n type BridgeEnvelope,\n createBridgeEnvelope,\n STACK_BRIDGE_METHODS,\n type StackChangedPayload,\n type StackMeta,\n type StackPushPayload,\n type StackResetPayload,\n} from \"./protocol\";\nimport type { BridgeTransport } from \"./transport\";\nimport {\n type BridgeTransportOptions,\n createBridgeTransport,\n} from \"./transport\";\nimport { type AllowUrl, assertStackUrl } from \"./url-policy\";\n\nexport type WebViewBridgeClientOptions = BridgeTransportOptions & {\n transport?: BridgeTransport;\n /** outbound stack URL 검증 (기본 isSafeStackUrl) */\n allowUrl?: AllowUrl;\n /** 요청 기본 타임아웃 ms */\n timeoutMs?: number;\n};\n\nexport interface BridgeRequestOptions {\n timeoutMs?: number;\n /**\n * RN: 네이티브가 `bridge.response`(replyTo) 로 회신할 때까지 기다린다.\n * 기본 false — 전송 즉시 resolve (1.x 네이티브 호환).\n */\n expectResponse?: boolean;\n}\n\nexport interface BridgeResult<TResult = unknown> {\n /** 전송한 요청 envelope */\n envelope: BridgeEnvelope;\n /** Flutter callHandler 반환값 또는 RN 응답 payload */\n result?: TResult;\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n method: string\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () =>\n reject(\n new BridgeError(\n BRIDGE_ERROR_CODES.TIMEOUT,\n `${method} timed out after ${timeoutMs}ms`\n )\n ),\n timeoutMs\n );\n });\n return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));\n}\n\nexport class WebViewBridgeClient {\n readonly host: ReturnType<typeof detectBridgeHost>;\n private readonly transport: BridgeTransport;\n private readonly allowUrl?: AllowUrl;\n private readonly timeoutMs: number;\n\n constructor(options: WebViewBridgeClientOptions = {}) {\n this.host = options.transport?.host ?? detectBridgeHost();\n this.transport =\n options.transport ?? createBridgeTransport(this.host, options);\n this.allowUrl = options.allowUrl;\n this.timeoutMs = options.timeoutMs ?? BRIDGE_TIMEOUT_MS;\n }\n\n /** 응답을 기다리지 않는 단방향 전송 */\n async send(envelope: BridgeEnvelope): Promise<unknown> {\n return this.transport.send(envelope);\n }\n\n async request<TPayload = unknown, TResult = unknown>(\n method: string,\n payload?: TPayload,\n options: BridgeRequestOptions = {}\n ): Promise<BridgeResult<TResult>> {\n const envelope = createBridgeEnvelope(method, payload);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const waitsForReply =\n options.expectResponse === true && this.host === \"react-native\";\n const reply = waitsForReply\n ? waitForResponse(envelope.id, timeoutMs)\n : null;\n\n try {\n const sent = await withTimeout(this.send(envelope), timeoutMs, method);\n if (!reply) return { envelope, result: sent as TResult };\n const response = await reply;\n return { envelope, result: response.payload as TResult };\n } catch (error) {\n cancelResponse(envelope.id);\n throw error;\n }\n }\n\n private async stackRequest(\n method: string,\n url: string,\n meta: StackMeta,\n options?: BridgeRequestOptions\n ) {\n const path = assertStackUrl({ url }, this.allowUrl);\n return this.request<StackPushPayload>(method, { url: path, meta }, options);\n }\n\n stackPush(\n url: string,\n meta: StackMeta = null,\n options?: BridgeRequestOptions\n ) {\n return this.stackRequest(STACK_BRIDGE_METHODS.PUSH, url, meta, options);\n }\n\n stackReplace(\n url: string,\n meta: StackMeta = null,\n options?: BridgeRequestOptions\n ) {\n return this.stackRequest(STACK_BRIDGE_METHODS.REPLACE, url, meta, options);\n }\n\n stackPop(options?: BridgeRequestOptions) {\n return this.request(STACK_BRIDGE_METHODS.POP, undefined, options);\n }\n\n async stackReset(\n url: string,\n meta: StackMeta = null,\n options?: BridgeRequestOptions\n ) {\n const path = assertStackUrl({ url }, this.allowUrl);\n return this.request<StackResetPayload>(\n STACK_BRIDGE_METHODS.RESET,\n { url: path, meta },\n options\n );\n }\n\n /** web → native 웹 스택 변경 알림 (응답 없음) */\n notifyStackChanged(payload: StackChangedPayload): Promise<unknown> {\n return this.send(\n createBridgeEnvelope(STACK_BRIDGE_METHODS.CHANGED, payload)\n );\n }\n}\n\nexport function createWebViewBridgeClient(\n options?: WebViewBridgeClientOptions\n): WebViewBridgeClient {\n return new WebViewBridgeClient(options);\n}\n","import type { BridgeRequestOptions, BridgeResult } from \"./client\";\nimport { createWebViewBridgeClient } from \"./client\";\nimport { detectBridgeHost, isNativeBridgeHost } from \"./detect-host\";\nimport type { StackMeta } from \"./protocol\";\nimport type { BridgeTransportOptions } from \"./transport\";\nimport type { AllowUrl } from \"./url-policy\";\n\nexport type StackRouterBridge = {\n push: (\n url: string,\n meta?: StackMeta,\n options?: BridgeRequestOptions\n ) => Promise<BridgeResult>;\n replace: (\n url: string,\n meta?: StackMeta,\n options?: BridgeRequestOptions\n ) => Promise<BridgeResult>;\n pop: (options?: BridgeRequestOptions) => Promise<BridgeResult>;\n reset: (\n url: string,\n meta?: StackMeta,\n options?: BridgeRequestOptions\n ) => Promise<BridgeResult>;\n};\n\nexport type CreateStackRouterBridgeOptions = BridgeTransportOptions & {\n allowUrl?: AllowUrl;\n timeoutMs?: number;\n};\n\nlet cachedBridge: StackRouterBridge | null = null;\n\n/**\n * Web → native stack navigation (Flutter `callHandler` / RN `postMessage`).\n * Returns null in browser-only environments.\n */\nexport function createStackRouterBridge(\n options?: CreateStackRouterBridgeOptions\n): StackRouterBridge | null {\n const host = detectBridgeHost();\n if (!isNativeBridgeHost(host)) return null;\n\n const client = createWebViewBridgeClient(options);\n\n return {\n push: (url, meta, requestOptions) =>\n client.stackPush(url, meta ?? null, requestOptions),\n replace: (url, meta, requestOptions) =>\n client.stackReplace(url, meta ?? null, requestOptions),\n pop: (requestOptions) => client.stackPop(requestOptions),\n reset: (url, meta, requestOptions) =>\n client.stackReset(url, meta ?? null, requestOptions),\n };\n}\n\n/** `window.stackRouterBridge` → 모듈 캐시 → 새로 생성 후 캐시 */\nexport function getStackRouterBridge(): StackRouterBridge | null {\n if (typeof window === \"undefined\") return null;\n if (window.stackRouterBridge) return window.stackRouterBridge;\n if (!cachedBridge) cachedBridge = createStackRouterBridge();\n return cachedBridge;\n}\n\nexport function installStackRouterBridge(\n options?: CreateStackRouterBridgeOptions\n): StackRouterBridge | null {\n if (typeof window === \"undefined\") return null;\n const bridge = createStackRouterBridge(options);\n if (bridge) {\n window.stackRouterBridge = bridge;\n }\n return bridge;\n}\n\n/** 테스트·호스트 전환용 캐시 초기화 */\nexport function resetStackRouterBridgeCache(): void {\n cachedBridge = null;\n}\n","import { detectBridgeHost, isNativeBridgeHost } from \"./detect-host\";\nimport { BRIDGE_ERROR_CODES, BridgeError, toBridgeError } from \"./errors\";\nimport { settleResponse } from \"./pending-responses\";\nimport {\n BACK_REQUEST_METHOD,\n BRIDGE_RESPONSE_METHOD,\n type BridgeEnvelope,\n createBridgeEnvelope,\n createBridgeResponse,\n parseBridgeMessage,\n STACK_BRIDGE_METHODS,\n type StackMeta,\n} from \"./protocol\";\nimport {\n createStackRouterBridge,\n type StackRouterBridge,\n} from \"./stack-router-bridge\";\nimport {\n type BridgeTransportOptions,\n createBridgeTransport,\n} from \"./transport\";\nimport { type AllowUrl, assertStackUrl } from \"./url-policy\";\n\ntype HandlerResult = boolean | Promise<boolean>;\n\nexport type StackRouterHostHandlers = {\n push: (url: string, meta?: StackMeta) => HandlerResult;\n replace: (url: string, meta?: StackMeta) => HandlerResult;\n pop: () => HandlerResult;\n reset: (url: string, meta?: StackMeta) => HandlerResult;\n};\n\nexport type InstallBridgeHostOptions = {\n /** Native → web stack navigation */\n stack?: StackRouterHostHandlers;\n /** Custom method handlers keyed by envelope `method` */\n handlers?: Record<\n string,\n (payload: unknown, envelope: BridgeEnvelope) => HandlerResult\n >;\n /** native → web `back.request` (하드웨어 back). true = 웹에서 처리함 */\n onBackRequest?: () => HandlerResult;\n /** Called for every valid envelope before routing */\n onMessage?: (envelope: BridgeEnvelope) => void;\n /** 검증 실패·핸들러 예외 (throw 대신 여기로 전달) */\n onError?: (error: BridgeError, envelope?: BridgeEnvelope) => void;\n /** inbound stack URL 검증 (기본 isSafeStackUrl) */\n allowUrl?: AllowUrl;\n /** 모든 inbound 요청에 `bridge.response` 회신 (back.request 는 항상 회신) */\n replyToNative?: boolean;\n /** 회신용 transport 옵션 */\n transport?: BridgeTransportOptions;\n /**\n * `window.stackRouterBridge` 설치 (web → native).\n * true 면 `createStackRouterBridge()` 로 생성한다.\n */\n exposeStackRouterBridge?: StackRouterBridge | boolean;\n /** Register `window.stackPush` / `stackPop` for Flutter native→web (default true when `stack`) */\n legacyInboundHandlers?: boolean;\n};\n\nconst STACK_URL_METHODS = {\n [STACK_BRIDGE_METHODS.PUSH]: \"push\",\n [STACK_BRIDGE_METHODS.REPLACE]: \"replace\",\n [STACK_BRIDGE_METHODS.RESET]: \"reset\",\n} as const;\n\nasync function route(\n envelope: BridgeEnvelope,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n const custom = options.handlers?.[envelope.method];\n if (custom) return Boolean(await custom(envelope.payload, envelope));\n\n if (envelope.method === BACK_REQUEST_METHOD) {\n return Boolean(await options.onBackRequest?.());\n }\n\n const stack = options.stack;\n const urlMethod =\n STACK_URL_METHODS[envelope.method as keyof typeof STACK_URL_METHODS];\n if (stack && urlMethod) {\n const url = assertStackUrl(envelope.payload, options.allowUrl);\n const meta = (envelope.payload as { meta?: StackMeta }).meta ?? null;\n return Boolean(await stack[urlMethod](url, meta));\n }\n if (stack && envelope.method === STACK_BRIDGE_METHODS.POP) {\n return Boolean(await stack.pop());\n }\n\n throw new BridgeError(\n BRIDGE_ERROR_CODES.UNKNOWN_METHOD,\n `No handler for ${envelope.method}`\n );\n}\n\nasync function reply(\n request: BridgeEnvelope,\n result: { handled: boolean; error?: BridgeError },\n options: InstallBridgeHostOptions\n) {\n const host = detectBridgeHost();\n if (!isNativeBridgeHost(host)) return;\n const response = createBridgeResponse(request, {\n payload: { handled: result.handled },\n error: result.error?.toBody(),\n });\n try {\n await createBridgeTransport(host, options.transport).send(response);\n } catch (error) {\n options.onError?.(\n toBridgeError(error, BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE),\n response\n );\n }\n}\n\nasync function dispatchEnvelope(\n envelope: BridgeEnvelope,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n if (envelope.method === BRIDGE_RESPONSE_METHOD) {\n return settleResponse(envelope);\n }\n\n options.onMessage?.(envelope);\n\n let handled = false;\n let failure: BridgeError | undefined;\n try {\n handled = await route(envelope, options);\n } catch (error) {\n failure = toBridgeError(error, BRIDGE_ERROR_CODES.HANDLER_ERROR);\n options.onError?.(failure, envelope);\n }\n\n if (options.replyToNative || envelope.method === BACK_REQUEST_METHOD) {\n await reply(envelope, { handled, error: failure }, options);\n }\n return handled;\n}\n\n/** inbound 메시지 처리. 절대 reject 하지 않는다 (실패는 false + onError) */\nexport function handleBridgeMessage(\n raw: string | unknown,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n const envelope = parseBridgeMessage(raw);\n if (!envelope) return Promise.resolve(false);\n return dispatchEnvelope(envelope, options);\n}\n\nexport type BridgeHostCleanup = () => void;\n\nconst isDev = () =>\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\ntype GlobalKey =\n | \"webviewkitBridge\"\n | \"stackPush\"\n | \"stackReplace\"\n | \"stackPop\"\n | \"stackReset\"\n | \"stackRouterBridge\";\n\nfunction legacyCall(\n method: string,\n payload: unknown,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n return dispatchEnvelope(createBridgeEnvelope(method, payload), {\n ...options,\n replyToNative: false,\n });\n}\n\nexport function installBridgeHost(\n options: InstallBridgeHostOptions\n): BridgeHostCleanup {\n if (typeof window === \"undefined\") {\n return () => undefined;\n }\n\n const installed: Partial<Record<GlobalKey, unknown>> = {};\n const target = window as unknown as Record<GlobalKey, unknown>;\n const install = (key: GlobalKey, value: unknown) => {\n if (isDev() && target[key] !== undefined) {\n console.warn(`[webviewkit] window.${key} is being overwritten`);\n }\n target[key] = value;\n installed[key] = value;\n };\n\n install(\"webviewkitBridge\", {\n postMessage: (raw: string | unknown) => {\n void handleBridgeMessage(raw, options);\n },\n });\n\n if (options.legacyInboundHandlers !== false && options.stack) {\n install(\"stackPush\", (url: string, meta?: StackMeta) =>\n legacyCall(STACK_BRIDGE_METHODS.PUSH, { url, meta }, options)\n );\n install(\"stackReplace\", (url: string, meta?: StackMeta) =>\n legacyCall(STACK_BRIDGE_METHODS.REPLACE, { url, meta }, options)\n );\n install(\"stackPop\", () =>\n legacyCall(STACK_BRIDGE_METHODS.POP, undefined, options)\n );\n install(\"stackReset\", (url: string, meta?: StackMeta) =>\n legacyCall(STACK_BRIDGE_METHODS.RESET, { url, meta }, options)\n );\n }\n\n const outbound =\n options.exposeStackRouterBridge === true\n ? createStackRouterBridge(options.transport)\n : options.exposeStackRouterBridge || null;\n if (outbound) install(\"stackRouterBridge\", outbound);\n\n return () => {\n // 다른 설치가 덮어쓴 전역은 건드리지 않는다\n (Object.keys(installed) as GlobalKey[]).forEach((key) => {\n if (target[key] === installed[key]) delete target[key];\n });\n };\n}\n\n/** Emit a protocol envelope from web (e.g. for tests or custom native listeners) */\nexport function emitBridgeEnvelope(\n method: string,\n payload?: unknown\n): BridgeEnvelope {\n return createBridgeEnvelope(method, payload);\n}\n","import React, { type ReactNode, useEffect, useRef } from \"react\";\nimport { waitForBridgeHost } from \"./detect-host\";\nimport {\n installBridgeHost,\n type InstallBridgeHostOptions,\n type StackRouterHostHandlers,\n} from \"./host\";\nimport {\n createStackRouterBridge,\n type CreateStackRouterBridgeOptions,\n} from \"./stack-router-bridge\";\n\nexport type WebViewBridgeProviderProps = {\n children?: ReactNode;\n /** Native → web stack handlers (e.g. Next.js `router.push`) */\n stack?: StackRouterHostHandlers;\n transport?: CreateStackRouterBridgeOptions;\n /** Install `window.stackRouterBridge` for web → native */\n enableOutboundBridge?: boolean;\n hostOptions?: Omit<\n InstallBridgeHostOptions,\n \"stack\" | \"exposeStackRouterBridge\" | \"legacyInboundHandlers\"\n >;\n};\n\n/**\n * Mount once near the app root (Next.js `layout`, SPA `App`).\n * Wires protocol ingress + optional legacy window stack handlers.\n * `stack`·`hostOptions` 는 최신 값을 ref 로 읽으므로 인라인 객체여도 재설치하지 않는다.\n */\nexport function WebViewBridgeProvider({\n children = null,\n stack,\n transport,\n enableOutboundBridge = true,\n hostOptions,\n}: WebViewBridgeProviderProps) {\n const latest = useRef({ stack, transport, hostOptions });\n latest.current = { stack, transport, hostOptions };\n const hasStack = Boolean(stack);\n\n useEffect(() => {\n const call =\n <K extends keyof StackRouterHostHandlers>(key: K) =>\n (...args: Parameters<StackRouterHostHandlers[K]>) => {\n const handler = latest.current.stack?.[key] as\n | ((\n ...a: Parameters<StackRouterHostHandlers[K]>\n ) => boolean | Promise<boolean>)\n | undefined;\n return handler ? handler(...args) : false;\n };\n\n const options = latest.current.hostOptions;\n const cleanups: (() => void)[] = [];\n cleanups.push(\n installBridgeHost({\n ...options,\n onMessage: (envelope) =>\n latest.current.hostOptions?.onMessage?.(envelope),\n onError: (error, envelope) =>\n latest.current.hostOptions?.onError?.(error, envelope),\n onBackRequest: () =>\n latest.current.hostOptions?.onBackRequest?.() ?? false,\n stack: hasStack\n ? {\n push: call(\"push\"),\n replace: call(\"replace\"),\n pop: call(\"pop\"),\n reset: call(\"reset\"),\n }\n : undefined,\n legacyInboundHandlers: hasStack,\n })\n );\n\n // Flutter 는 platformReady 이후에 브릿지가 붙을 수 있다 → 감지 후 outbound 설치\n const abort = new AbortController();\n if (enableOutboundBridge) {\n void waitForBridgeHost({ signal: abort.signal }).then(() => {\n if (abort.signal.aborted) return;\n const outbound = createStackRouterBridge(latest.current.transport);\n if (!outbound) return;\n window.stackRouterBridge = outbound;\n cleanups.push(() => {\n if (window.stackRouterBridge === outbound)\n delete window.stackRouterBridge;\n });\n });\n }\n\n return () => {\n abort.abort();\n cleanups.forEach((cleanup) => cleanup());\n };\n }, [enableOutboundBridge, hasStack]);\n\n return <>{children}</>;\n}\n","import type React from \"react\";\nimport type { StackBridgeSyncOptions } from \"./stack-router/use-stack-bridge-sync\";\n\nexport interface Activity {\n /** 정적 경로 또는 동적 세그먼트 패턴 (`/detail/:id`) */\n path: string;\n element: React.ReactNode;\n}\n\nexport type StackTransitionType = \"slide\" | \"fade\" | \"none\";\n\nexport type RestoreStackPolicy = \"with-root\" | \"top-only\";\n\nexport interface StackRouterProviderProps {\n initialActivity: Activity;\n Activities?: Activity[];\n maxWidth?: string;\n /** true면 상단에 `StackHeader` 렌더 */\n isShowHeader?: boolean;\n /** 개발 시 스택 로드맵 오버레이 (기본: NODE_ENV === \"development\") */\n enableDevTools?: boolean;\n transition?: StackTransitionType;\n /** 전환 시간 ms (기본 STACK_TRANSITION_MS) */\n duration?: number;\n /** 새로고침·딥링크 진입 시 스택 복원 정책 (기본 \"with-root\") */\n restoreStack?: RestoreStackPolicy;\n /** env(safe-area-inset-*) padding 적용 */\n safeArea?: boolean;\n /** 루트에서 back 했을 때 (앱 종료·WebView 닫기 위임) */\n onBackAtRoot?: () => void;\n /** 등록되지 않은 경로로 이동하려 할 때 */\n onNotFound?: (path: string) => void;\n /** 네이티브 브릿지 연동 */\n bridge?: boolean | StackBridgeSyncOptions;\n}\n\nexport interface VisiblePage {\n path: string;\n element: React.ReactNode;\n}\n\nexport enum Direction {\n FORWARD = \"forward\",\n BACKWARD = \"backward\",\n}\n\nexport type DirectionType = Direction.FORWARD | Direction.BACKWARD;\n\nexport enum HistoryAction {\n PUSH = \"PUSH\",\n POP = \"POP\",\n REPLACE = \"REPLACE\",\n}\n\nexport interface HistoryState {\n /** pathname + search */\n path: string;\n data?: unknown;\n action?: HistoryAction;\n /** 스택 엔트리 고유 key */\n key?: string;\n /** 스택 내 위치 (0 = root) */\n index?: number;\n}\n\nexport type HistoryListener = (state: HistoryState) => void;\n","import { BACK_TIMEOUT_MS } from \"./constants\";\nimport { HistoryAction, HistoryListener, HistoryState } from \"./type\";\n\ntype HistoryEntryState = Omit<HistoryState, \"path\" | \"action\">;\n\nconst isBrowser = () => typeof window !== \"undefined\";\n\nconst listeners = new Set<HistoryListener>();\n\nconst currentPath = () => window.location.pathname + window.location.search;\n\nconst onPopState = (event: PopStateEvent) => {\n const state: HistoryState = {\n path: currentPath(),\n ...((event.state as HistoryState | null) ?? {}),\n action: HistoryAction.POP,\n };\n listeners.forEach((listener) => listener(state));\n};\n\n/**\n * `window.history` 래퍼.\n * - 리스너는 브라우저 popstate(뒤로·앞으로·`go`)에서만 호출된다.\n * - push/replace 는 동기 실행이며 리스너를 호출하지 않는다 (호출자가 상태를 직접 갱신).\n * - popstate 구독은 첫 리스너 등록 시점에 건다 (import 부작용 없음).\n */\nexport const history = {\n push: (path: string, state: HistoryEntryState = {}) => {\n if (!isBrowser()) return;\n window.history.pushState(\n { ...state, path, action: HistoryAction.PUSH },\n \"\",\n path\n );\n },\n\n replace: (path: string, state: HistoryEntryState = {}) => {\n if (!isBrowser()) return;\n window.history.replaceState(\n { ...state, path, action: HistoryAction.REPLACE },\n \"\",\n path\n );\n },\n\n /** `history.go(delta)` 후 popstate 가 오면 true, BACK_TIMEOUT_MS 안에 오지 않으면 false */\n travel: (delta: number): Promise<boolean> => {\n if (!isBrowser()) return Promise.resolve(false);\n return new Promise<boolean>((resolve) => {\n const finish = (popped: boolean) => {\n window.clearTimeout(timer);\n window.removeEventListener(\"popstate\", onPop);\n resolve(popped);\n };\n const onPop = () => finish(true);\n const timer = window.setTimeout(() => finish(false), BACK_TIMEOUT_MS);\n window.addEventListener(\"popstate\", onPop);\n window.history.go(delta);\n });\n },\n\n back: (): Promise<boolean> => history.travel(-1),\n\n forward: () => {\n if (!isBrowser()) return;\n window.history.forward();\n },\n\n go: (delta: number) => {\n if (!isBrowser()) return;\n window.history.go(delta);\n },\n\n getCurrentState: (): HistoryState => {\n if (!isBrowser()) return { path: \"/\" };\n const state = window.history.state as HistoryState | null;\n return state?.path ? state : { path: currentPath() };\n },\n\n addListener: (listener: HistoryListener) => {\n if (!isBrowser()) return () => false;\n if (listeners.size === 0) {\n window.addEventListener(\"popstate\", onPopState);\n }\n listeners.add(listener);\n return () => {\n const removed = listeners.delete(listener);\n if (listeners.size === 0) {\n window.removeEventListener(\"popstate\", onPopState);\n }\n return removed;\n };\n },\n};\n","import React from \"react\";\n\nexport interface StackDevRoadmapProps {\n /** 스택에 쌓인 페이지 경로 (아래 → 위 순) */\n pages: { path: string }[];\n currentPath: string;\n /** false면 렌더하지 않음 */\n visible?: boolean;\n}\n\n/**\n * 개발 환경에서 스택 깊이·경로를 눈으로 확인하는 로드맵 오버레이.\n * StackRouterProvider `enableDevTools` 와 함께 사용합니다.\n */\nexport function StackDevRoadmap({\n pages,\n currentPath,\n visible = true,\n}: StackDevRoadmapProps) {\n if (!visible || pages.length === 0) return null;\n\n const depth = pages.length;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label={`WebViewKit stack depth ${depth}`}\n style={{\n position: \"fixed\",\n bottom: 12,\n right: 12,\n zIndex: 2147483646,\n minWidth: 200,\n maxWidth: 320,\n padding: \"10px 12px\",\n borderRadius: 10,\n background: \"rgba(7, 11, 18, 0.92)\",\n border: \"1px solid rgba(0, 232, 184, 0.35)\",\n color: \"#e8eef4\",\n fontFamily:\n 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", monospace',\n fontSize: 11,\n lineHeight: 1.45,\n boxShadow: \"0 8px 24px rgba(0,0,0,0.35)\",\n pointerEvents: \"none\",\n }}\n >\n <div style={{ display: \"flex\", justifyContent: \"space-between\", gap: 8 }}>\n <span style={{ color: \"#00e8b8\", fontWeight: 700 }}>WebViewKit</span>\n <span style={{ color: \"#94a3b8\" }}>stack × {depth}</span>\n </div>\n\n {/* 점 → 선 로드맵 */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 0,\n marginTop: 10,\n padding: \"4px 0\",\n }}\n >\n {pages.map((page, index) => {\n const isCurrent = page.path === currentPath;\n const isLast = index === pages.length - 1;\n return (\n <React.Fragment key={`${page.path}-${index}`}>\n {index > 0 && (\n <span\n style={{\n width: 14,\n height: 2,\n background: isLast\n ? \"linear-gradient(90deg,#334155,#00e8b8)\"\n : \"#334155\",\n flexShrink: 0,\n }}\n />\n )}\n <span\n title={page.path}\n style={{\n width: isCurrent ? 12 : 8,\n height: isCurrent ? 12 : 8,\n borderRadius: \"50%\",\n flexShrink: 0,\n background: isCurrent ? \"#00e8b8\" : \"#475569\",\n boxShadow: isCurrent\n ? \"0 0 10px rgba(0,232,184,0.85)\"\n : \"none\",\n transition: \"all 0.2s ease\",\n }}\n />\n </React.Fragment>\n );\n })}\n </div>\n\n <ol style={{ margin: \"8px 0 0\", paddingLeft: 18, color: \"#cbd5e1\" }}>\n {pages.map((page, index) => {\n const isCurrent = index === pages.length - 1;\n return (\n <li\n key={`${page.path}-${index}`}\n style={{\n fontWeight: isCurrent ? 600 : 400,\n color: isCurrent ? \"#00e8b8\" : \"#94a3b8\",\n }}\n >\n {page.path}\n {isCurrent ? \" ← top\" : \"\"}\n </li>\n );\n })}\n </ol>\n </div>\n );\n}\n","import styled from \"@emotion/styled\";\nimport React from \"react\";\nimport { useStackRouter } from \"../stack-router-provider\";\n\ninterface BackRouterProps {\n /** 스크린리더 라벨 */\n label?: string;\n}\n\nconst BackRouter = ({ label = \"뒤로 가기\" }: BackRouterProps) => {\n const { back } = useStackRouter();\n return (\n <BackButton type=\"button\" aria-label={label} onClick={() => back()}>\n <BackIcon />\n </BackButton>\n );\n};\n\nexport default BackRouter;\n\n/**\n styles\n */\n\nconst BackButton = styled.button`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border: none;\n background: none;\n cursor: pointer;\n padding: 8px;\n border-radius: 50%;\n transition: all 0.2s;\n color: var(--wvk-back-color, #000000);\n\n &:hover {\n color: var(--wvk-back-hover-color, #666666);\n }\n\n &:active {\n color: var(--wvk-back-active-color, #999999);\n }\n`;\n\nconst BackIcon = () => (\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 20L4 12L12 4\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n","import styled from \"@emotion/styled\";\nimport React, { createContext, useContext, useMemo } from \"react\";\nimport { STACK_TRANSITION_MS } from \"../constants\";\nimport { StackDevRoadmap } from \"../stack-dev/stack-dev-roadmap\";\nimport type {\n Activity,\n HistoryState,\n StackRouterProviderProps,\n VisiblePage,\n} from \"../type\";\nimport StackHeader from \"./_components/header\";\nimport StackPage from \"./_components/stack-page\";\nimport { ActivityContext } from \"./activity-context\";\nimport { getRenderedPages, type StackEntry } from \"./stack-reducer\";\nimport { usePrefersReducedMotion } from \"./use-prefers-reduced-motion\";\nimport { useStackBridgeSync } from \"./use-stack-bridge-sync\";\nimport { useStackNavigation } from \"./use-stack-navigation\";\n\nexport interface StackRouterContextValue {\n currentPath: string;\n /** top 엔트리의 history state */\n currentState: HistoryState;\n depth: number;\n canGoBack: boolean;\n isTransitioning: boolean;\n entries: StackEntry[];\n /** 1.x 호환 */\n visiblePages: VisiblePage[];\n Activities: Activity[];\n initialActivity: Activity;\n push: (path: string, data?: unknown) => boolean;\n replace: (path: string, data?: unknown) => boolean;\n reset: (path: string, data?: unknown) => boolean;\n back: () => boolean;\n pop: (count?: number) => boolean;\n popTo: (path: string) => boolean;\n /** @deprecated 스택과 동기화되지 않는다. 브라우저 forward 는 popstate 로 처리된다 */\n forward: () => void;\n}\n\nconst StackRouterContext = createContext<StackRouterContextValue | null>(null);\n\nexport const useStackRouter = () => {\n const context = useContext(StackRouterContext);\n if (!context) {\n throw new Error(\"useStackRouter must be used within a StackRouterProvider\");\n }\n return context;\n};\n\nconst isDevEnv = () =>\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"development\";\n\nconst StackRouterProvider = ({\n initialActivity,\n Activities = [],\n maxWidth = \"600px\",\n isShowHeader = false,\n enableDevTools,\n transition = \"slide\",\n duration = STACK_TRANSITION_MS,\n restoreStack = \"with-root\",\n safeArea = false,\n onBackAtRoot,\n onNotFound,\n bridge,\n}: StackRouterProviderProps) => {\n const reducedMotion = usePrefersReducedMotion();\n const effectiveDuration =\n transition === \"none\" || reducedMotion ? 0 : duration;\n\n const navigation = useStackNavigation({\n initialActivity,\n activities: Activities,\n duration: effectiveDuration,\n restoreStack,\n onBackAtRoot,\n onNotFound,\n });\n const { state, endTransition } = navigation;\n\n const elementFor = (pattern: string) =>\n Activities.find((activity) => activity.path === pattern)?.element ??\n (initialActivity.path === pattern ? initialActivity.element : null);\n\n const top = state.entries[state.entries.length - 1];\n\n const value = useMemo<StackRouterContextValue>(\n () => ({\n currentPath: top.path,\n currentState: {\n path: top.path,\n data: top.data,\n key: top.key,\n index: state.entries.length - 1,\n },\n depth: state.entries.length,\n canGoBack: state.entries.length > 1,\n isTransitioning: state.transition !== null,\n entries: state.entries,\n visiblePages: state.entries.map((entry) => ({\n path: entry.path,\n element: elementFor(entry.pattern),\n })),\n Activities,\n initialActivity,\n push: navigation.push,\n replace: navigation.replace,\n reset: navigation.reset,\n back: navigation.back,\n pop: navigation.pop,\n popTo: navigation.popTo,\n forward: () => window.history.forward(),\n }),\n [state, Activities, initialActivity, navigation]\n );\n\n useStackBridgeSync(bridge, value, onBackAtRoot);\n\n const direction = state.transition?.type ?? \"push\";\n const pages = getRenderedPages(state);\n const showDevTools = enableDevTools ?? isDevEnv();\n\n return (\n <StackRouterContext.Provider value={value}>\n <LayoutContainer safeArea={safeArea}>\n <Layout maxWidth={maxWidth} data-testid=\"layout\">\n {isShowHeader && <StackHeader />}\n <PageContainer>\n {pages.map(({ entry, pageState, isTop }, index) => (\n <ActivityContext.Provider\n key={entry.key}\n value={{\n key: entry.key,\n path: entry.path,\n pattern: entry.pattern,\n params: entry.params,\n query: entry.query,\n data: entry.data,\n index,\n isTop,\n }}\n >\n <StackPage\n pageState={pageState}\n direction={direction}\n transitionType={transition}\n duration={effectiveDuration}\n zIndex={index}\n isTop={isTop}\n onAnimationEnd={\n pageState === \"enter\" ? endTransition : undefined\n }\n >\n {elementFor(entry.pattern)}\n </StackPage>\n </ActivityContext.Provider>\n ))}\n </PageContainer>\n </Layout>\n </LayoutContainer>\n <StackDevRoadmap\n visible={showDevTools}\n pages={state.entries.map((entry) => ({ path: entry.path }))}\n currentPath={top.path}\n />\n </StackRouterContext.Provider>\n );\n};\n\nexport default StackRouterProvider;\nexport { StackRouterProvider };\n\n/**styles */\nconst LayoutContainer = styled.div<{ safeArea: boolean }>`\n width: 100%;\n height: 100vh;\n height: 100dvh;\n display: flex;\n justify-content: center;\n background: var(--wvk-page-bg, #ffffff);\n box-sizing: border-box;\n ${({ safeArea }) =>\n safeArea\n ? `padding: env(safe-area-inset-top) env(safe-area-inset-right)\n env(safe-area-inset-bottom) env(safe-area-inset-left);`\n : \"\"}\n`;\n\nconst Layout = styled.div<{ maxWidth: string }>`\n width: 100%;\n max-width: ${({ maxWidth }) => maxWidth};\n height: 100%;\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: hidden;\n`;\n\nconst PageContainer = styled.div`\n position: relative;\n flex: 1;\n width: 100%;\n overflow: hidden;\n`;\n","import styled from \"@emotion/styled\";\nimport React from \"react\";\nimport { useStackRouter } from \"../stack-router-provider\";\nimport BackRouter from \"./back-router\";\n\ninterface StackHeaderProps {\n /** 기본: 현재 path */\n title?: React.ReactNode;\n}\n\nconst Header = ({ title }: StackHeaderProps) => {\n const { currentPath, canGoBack } = useStackRouter();\n\n return (\n <StyledHeader>\n {canGoBack && <BackRouter />}\n <StyledTitle>{title ?? currentPath}</StyledTitle>\n </StyledHeader>\n );\n};\n\n/**\n styles\n */\n\nconst StyledHeader = styled.header`\n width: 100%;\n height: 64px;\n flex-shrink: 0;\n box-sizing: border-box;\n background-color: var(--wvk-header-bg, #ffffff);\n border-bottom: 1px solid var(--wvk-header-border, #e5e7eb);\n display: flex;\n align-items: center;\n padding: 0 1rem;\n`;\n\nconst StyledTitle = styled.h1`\n margin: 0;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--wvk-header-color, #111827);\n`;\n\nexport default Header;\n","import { css, keyframes } from \"@emotion/react\";\nimport styled from \"@emotion/styled\";\nimport React, { useLayoutEffect, useRef } from \"react\";\nimport type { StackTransitionType } from \"../../type\";\nimport type { PageState } from \"../stack-reducer\";\n\ntype Direction = \"push\" | \"pop\";\n\n/**\n * iOS UINavigationController 전환을 따른다.\n * - 위 페이지: 화면 오른쪽 끝 ↔ 0, 왼쪽 가장자리 그림자\n * - 아래 페이지: 0 ↔ -30% 패럴랙스, 투명도 대신 검은 dim 레이어\n * - 곡선: 빠르게 출발해 천천히 멈추는 iOS 기본 감속 곡선\n */\nconst IOS_EASING = \"cubic-bezier(0.32, 0.72, 0, 1)\";\nconst FADE_EASING = \"ease\";\nconst PARALLAX_OFFSET = \"-30%\";\n\nconst coverIn = keyframes`\n from { transform: translate3d(100%, 0, 0); }\n to { transform: translate3d(0, 0, 0); }\n`;\nconst coverOut = keyframes`\n from { transform: translate3d(0, 0, 0); }\n to { transform: translate3d(100%, 0, 0); }\n`;\nconst parallaxOut = keyframes`\n from { transform: translate3d(0, 0, 0); }\n to { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }\n`;\nconst parallaxIn = keyframes`\n from { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }\n to { transform: translate3d(0, 0, 0); }\n`;\nconst dimIn = keyframes`\n from { opacity: 0; }\n to { opacity: 1; }\n`;\nconst dimOut = keyframes`\n from { opacity: 1; }\n to { opacity: 0; }\n`;\nconst fadeIn = keyframes`\n from { opacity: 0; }\n to { opacity: 1; }\n`;\nconst fadeOut = keyframes`\n from { opacity: 1; }\n to { opacity: 0; }\n`;\n\ntype Layer = \"upper\" | \"lower\";\n\n/** push 의 enter·pop 의 exit 는 위에서 움직이는 페이지, 나머지는 아래 페이지 */\nconst layerOf = (direction: Direction, pageState: \"enter\" | \"exit\"): Layer =>\n (direction === \"push\") === (pageState === \"enter\") ? \"upper\" : \"lower\";\n\nfunction slideStyles(\n direction: Direction,\n pageState: \"enter\" | \"exit\",\n duration: number\n) {\n const timing = `${duration}ms ${IOS_EASING} forwards`;\n if (layerOf(direction, pageState) === \"upper\") {\n return css`\n animation: ${direction === \"push\" ? coverIn : coverOut} ${timing};\n box-shadow: var(--wvk-edge-shadow, -6px 0 24px rgba(0, 0, 0, 0.12));\n `;\n }\n return css`\n animation: ${direction === \"push\" ? parallaxOut : parallaxIn} ${timing};\n &::after {\n content: \"\";\n /* transform 중인 페이지 기준 fixed = 스크롤과 무관하게 페이지 전체를 덮음 */\n position: fixed;\n inset: 0;\n pointer-events: none;\n background: var(--wvk-dim-color, rgba(0, 0, 0, 0.12));\n animation: ${direction === \"push\" ? dimIn : dimOut} ${timing};\n }\n `;\n}\n\ninterface PageWrapperProps {\n pageState: PageState;\n direction: Direction;\n transitionType: StackTransitionType;\n duration: number;\n zIndex: number;\n}\n\nconst PageWrapper = styled.div<PageWrapperProps>`\n position: absolute;\n inset: 0;\n overflow: auto;\n -webkit-overflow-scrolling: touch;\n background: var(--wvk-page-bg, #ffffff);\n z-index: ${({ zIndex }) => zIndex};\n visibility: ${({ pageState }) =>\n pageState === \"covered\" ? \"hidden\" : \"visible\"};\n ${({ pageState, direction, transitionType, duration }) => {\n if (pageState !== \"enter\" && pageState !== \"exit\") return \"\";\n if (transitionType === \"none\" || duration === 0) return \"\";\n if (transitionType === \"fade\") {\n return css`\n will-change: opacity;\n animation: ${pageState === \"enter\" ? fadeIn : fadeOut} ${duration}ms\n ${FADE_EASING} forwards;\n `;\n }\n return css`\n will-change: transform;\n ${slideStyles(direction, pageState, duration)}\n `;\n }}\n`;\n\ninterface StackPageProps extends PageWrapperProps {\n isTop: boolean;\n onAnimationEnd?: () => void;\n children: React.ReactNode;\n}\n\n/** 스택 한 장. top 이 아니면 inert·aria-hidden (스크린리더·포커스 차단) */\nexport default function StackPage({\n isTop,\n onAnimationEnd,\n children,\n ...wrapperProps\n}: StackPageProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n // ponytail: React 18/19 의 inert prop 처리가 달라 DOM 속성을 직접 토글\n ref.current?.toggleAttribute(\"inert\", !isTop);\n }, [isTop]);\n\n return (\n <PageWrapper\n ref={ref}\n {...wrapperProps}\n data-state={wrapperProps.pageState}\n aria-hidden={isTop ? undefined : true}\n onAnimationEnd={(event) => {\n // dim(::after) 애니메이션 종료는 무시하고 페이지 자체 전환만 본다\n if (event.target === event.currentTarget && !event.pseudoElement) {\n onAnimationEnd?.();\n }\n }}\n >\n {children}\n </PageWrapper>\n );\n}\n","import { createContext, useContext } from \"react\";\n\nexport interface ActivityContextValue {\n key: string;\n path: string;\n pattern: string;\n params: Record<string, string>;\n query: Record<string, string>;\n data?: unknown;\n /** 스택 내 위치 (0 = root) */\n index: number;\n isTop: boolean;\n}\n\nexport const ActivityContext = createContext<ActivityContextValue | null>(null);\n\n/** 현재 페이지(Activity) 자신의 path·params·query·data */\nexport function useActivity(): ActivityContextValue {\n const context = useContext(ActivityContext);\n if (!context) {\n throw new Error(\n \"useActivity must be used inside a StackRouterProvider page\"\n );\n }\n return context;\n}\n\n/** `/detail/:id` → `{ id }` */\nexport function useParams<\n TParams extends Record<string, string> = Record<string, string>,\n>(): TParams {\n return useActivity().params as TParams;\n}\n","export interface StackEntry {\n key: string;\n /** 실제 URL (pathname + search) */\n path: string;\n /** 매칭된 Activity path 패턴 */\n pattern: string;\n params: Record<string, string>;\n query: Record<string, string>;\n data?: unknown;\n}\n\nexport type StackTransition =\n | { type: \"push\"; enterKey: string; exitKey: string }\n | { type: \"pop\"; enterKey: string; exitKeys: string[] }\n | null;\n\nexport interface StackState {\n entries: StackEntry[];\n /** pop 애니메이션 중인 엔트리. END_TRANSITION 에서 제거 */\n leaving: StackEntry[];\n transition: StackTransition;\n}\n\nexport type StackAction =\n | { type: \"PUSH\"; entry: StackEntry; animate: boolean }\n | { type: \"REPLACE\"; entry: StackEntry }\n | { type: \"POP_TO\"; index: number; animate: boolean }\n | { type: \"RESET\"; entry: StackEntry }\n | { type: \"RESTORE\"; entries: StackEntry[] }\n | { type: \"END_TRANSITION\" };\n\nconst topOf = (entries: StackEntry[]) => entries[entries.length - 1];\n\nexport function createStackState(entry: StackEntry): StackState {\n return { entries: [entry], leaving: [], transition: null };\n}\n\nexport function stackReducer(\n state: StackState,\n action: StackAction\n): StackState {\n switch (action.type) {\n case \"PUSH\": {\n const previousTop = topOf(state.entries);\n return {\n entries: [...state.entries, action.entry],\n leaving: [],\n transition: action.animate\n ? {\n type: \"push\",\n enterKey: action.entry.key,\n exitKey: previousTop.key,\n }\n : null,\n };\n }\n case \"REPLACE\":\n return {\n ...state,\n entries: [...state.entries.slice(0, -1), action.entry],\n };\n case \"POP_TO\": {\n const index = Math.max(0, action.index);\n if (index >= state.entries.length - 1) return state;\n const entries = state.entries.slice(0, index + 1);\n const leaving = state.entries.slice(index + 1);\n if (!action.animate) {\n return { entries, leaving: [], transition: null };\n }\n return {\n entries,\n leaving,\n transition: {\n type: \"pop\",\n enterKey: topOf(entries).key,\n exitKeys: leaving.map((entry) => entry.key),\n },\n };\n }\n case \"RESET\":\n return createStackState(action.entry);\n case \"RESTORE\":\n return { entries: action.entries, leaving: [], transition: null };\n case \"END_TRANSITION\":\n if (!state.transition && state.leaving.length === 0) return state;\n return { ...state, leaving: [], transition: null };\n default:\n return state;\n }\n}\n\nexport type PageState = \"enter\" | \"exit\" | \"idle\" | \"covered\";\n\n/** 렌더 순서(아래 → 위)와 각 페이지의 data-state */\nexport function getRenderedPages(\n state: StackState\n): { entry: StackEntry; pageState: PageState; isTop: boolean }[] {\n const { entries, leaving, transition } = state;\n const top = topOf(entries);\n return [...entries, ...leaving].map((entry) => {\n const isTop = entry.key === top.key;\n let pageState: PageState = isTop ? \"idle\" : \"covered\";\n if (transition?.type === \"push\") {\n if (entry.key === transition.enterKey) pageState = \"enter\";\n if (entry.key === transition.exitKey) pageState = \"exit\";\n }\n if (transition?.type === \"pop\") {\n if (entry.key === transition.enterKey) pageState = \"enter\";\n if (transition.exitKeys.includes(entry.key)) pageState = \"exit\";\n }\n return { entry, pageState, isTop };\n });\n}\n","import { useEffect, useState } from \"react\";\n\nconst QUERY = \"(prefers-reduced-motion: reduce)\";\n\nconst getMediaQuery = () =>\n typeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n ? window.matchMedia(QUERY)\n : null;\n\n/** OS \"동작 줄이기\" 설정 */\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(\n () => getMediaQuery()?.matches ?? false\n );\n\n useEffect(() => {\n const mediaQuery = getMediaQuery();\n if (!mediaQuery) return;\n const onChange = () => setReduced(mediaQuery.matches);\n mediaQuery.addEventListener?.(\"change\", onChange);\n return () => mediaQuery.removeEventListener?.(\"change\", onChange);\n }, []);\n\n return reduced;\n}\n","import { useEffect, useRef } from \"react\";\nimport { createWebViewBridgeClient } from \"../bridge/client\";\nimport { detectBridgeHost, isNativeBridgeHost } from \"../bridge/detect-host\";\nimport type { BridgeError } from \"../bridge/errors\";\nimport { installBridgeHost } from \"../bridge/host\";\nimport type { BridgeEnvelope } from \"../bridge/protocol\";\nimport type { AllowUrl } from \"../bridge/url-policy\";\n\nexport interface StackBridgeSyncOptions {\n allowUrl?: AllowUrl;\n onError?: (error: BridgeError, envelope?: BridgeEnvelope) => void;\n /** 웹 스택 변경 시 `stack.changed` 전송 (기본 true) */\n emitStackChanged?: boolean;\n}\n\ninterface StackRouterLike {\n depth: number;\n currentPath: string;\n canGoBack: boolean;\n push: (path: string) => boolean;\n replace: (path: string) => boolean;\n reset: (path: string) => boolean;\n back: () => boolean;\n}\n\n/**\n * StackRouterProvider ↔ 네이티브 브릿지 연결.\n * - native `stack.*` → 라우터 push/replace/reset/back\n * - native `back.request` → canGoBack 이면 back, 아니면 onBackAtRoot. `{ handled }` 회신\n * - web 스택 변경 → `stack.changed { depth, path }`\n */\nexport function useStackBridgeSync(\n bridge: boolean | StackBridgeSyncOptions | undefined,\n router: StackRouterLike,\n onBackAtRoot?: () => void\n): void {\n const enabled = Boolean(bridge);\n const options = typeof bridge === \"object\" ? bridge : {};\n const latest = useRef({ router, options, onBackAtRoot });\n latest.current = { router, options, onBackAtRoot };\n\n useEffect(() => {\n if (!enabled) return;\n return installBridgeHost({\n allowUrl: latest.current.options.allowUrl,\n onError: (error, envelope) =>\n latest.current.options.onError?.(error, envelope),\n stack: {\n push: (url) => latest.current.router.push(url),\n replace: (url) => latest.current.router.replace(url),\n reset: (url) => latest.current.router.reset(url),\n pop: () => latest.current.router.back(),\n },\n onBackRequest: () => {\n const current = latest.current;\n if (current.router.canGoBack) return current.router.back();\n current.onBackAtRoot?.();\n return false;\n },\n });\n }, [enabled]);\n\n const { depth, currentPath } = router;\n const emit = enabled && options.emitStackChanged !== false;\n useEffect(() => {\n if (!emit || !isNativeBridgeHost(detectBridgeHost())) return;\n createWebViewBridgeClient()\n .notifyStackChanged({ depth, path: currentPath })\n .catch((error: BridgeError) => latest.current.options.onError?.(error));\n }, [emit, depth, currentPath]);\n}\n","import { useCallback, useEffect, useReducer, useRef } from \"react\";\nimport { createBridgeId } from \"../bridge/protocol\";\nimport { TRANSITION_END_GRACE_MS } from \"../constants\";\nimport { history } from \"../history\";\nimport type { Activity, HistoryState, RestoreStackPolicy } from \"../type\";\nimport { findActivity, type PathMatch } from \"./match-path\";\nimport {\n createStackState,\n type StackEntry,\n stackReducer,\n type StackState,\n} from \"./stack-reducer\";\n\nexport interface StackNavigationOptions {\n initialActivity: Activity;\n activities: Activity[];\n /** 0 이면 애니메이션 없이 즉시 전환 */\n duration: number;\n restoreStack: RestoreStackPolicy;\n onBackAtRoot?: () => void;\n onNotFound?: (path: string) => void;\n}\n\nexport interface StackNavigation {\n state: StackState;\n push: (path: string, data?: unknown) => boolean;\n replace: (path: string, data?: unknown) => boolean;\n reset: (path: string, data?: unknown) => boolean;\n back: () => boolean;\n pop: (count?: number) => boolean;\n popTo: (path: string) => boolean;\n endTransition: () => void;\n}\n\nconst isDev = () =>\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\nfunction createEntry(\n hit: { activity: Activity; match: PathMatch },\n path: string,\n data?: unknown,\n key: string = createBridgeId()\n): StackEntry {\n return {\n key,\n path,\n pattern: hit.activity.path,\n params: hit.match.params,\n query: hit.match.query,\n data,\n };\n}\n\nconst currentUrl = () => window.location.pathname + window.location.search;\n\n/** 스택 상태 + 내비게이션. 모든 브라우저 이동(back/forward)은 popstate 한 경로로 처리 */\nexport function useStackNavigation(\n options: StackNavigationOptions\n): StackNavigation {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const [state, dispatch] = useReducer(stackReducer, undefined, () => {\n const { initialActivity } = options;\n return createStackState(\n createEntry(\n { activity: initialActivity, match: { params: {}, query: {} } },\n initialActivity.path\n )\n );\n });\n const stateRef = useRef(state);\n stateRef.current = state;\n\n // 전환 중 입력 잠금 (같은 tick 연타까지 막기 위해 ref)\n const busyRef = useRef(false);\n\n const resolve = useCallback((path: string) => {\n const { activities, initialActivity } = optionsRef.current;\n return findActivity([...activities, initialActivity], path);\n }, []);\n\n const resolveOrNotify = useCallback(\n (path: string) => {\n const hit = resolve(path);\n if (!hit) {\n if (isDev()) {\n console.warn(`[webviewkit] No activity matches \"${path}\"`);\n }\n optionsRef.current.onNotFound?.(path);\n }\n return hit;\n },\n [resolve]\n );\n\n const animate = () => optionsRef.current.duration > 0;\n\n const push = useCallback(\n (path: string, data?: unknown) => {\n if (busyRef.current) return false;\n const hit = resolveOrNotify(path);\n if (!hit) return false;\n const entry = createEntry(hit, path, data);\n busyRef.current = true;\n history.push(path, {\n key: entry.key,\n index: stateRef.current.entries.length,\n data,\n });\n dispatch({ type: \"PUSH\", entry, animate: animate() });\n return true;\n },\n [resolveOrNotify]\n );\n\n const replace = useCallback(\n (path: string, data?: unknown) => {\n if (busyRef.current) return false;\n const hit = resolveOrNotify(path);\n if (!hit) return false;\n const entry = createEntry(hit, path, data);\n history.replace(path, {\n key: entry.key,\n index: stateRef.current.entries.length - 1,\n data,\n });\n dispatch({ type: \"REPLACE\", entry });\n return true;\n },\n [resolveOrNotify]\n );\n\n const reset = useCallback(\n (path: string, data?: unknown) => {\n if (busyRef.current) return false;\n const hit = resolveOrNotify(path);\n if (!hit) return false;\n const entry = createEntry(hit, path, data);\n history.replace(path, { key: entry.key, index: 0, data });\n dispatch({ type: \"RESET\", entry });\n return true;\n },\n [resolveOrNotify]\n );\n\n const pop = useCallback((count: number = 1) => {\n if (busyRef.current) return false;\n const { entries } = stateRef.current;\n if (entries.length <= 1) {\n optionsRef.current.onBackAtRoot?.();\n return false;\n }\n const delta = Math.min(Math.max(1, count), entries.length - 1);\n const targetIndex = entries.length - 1 - delta;\n busyRef.current = true;\n // push 와 같이 클릭 tick 에서 바로 전환을 시작한다. popstate 를 기다리면\n // 브라우저가 history traversal 동안 프레임을 늦춰 애니메이션이 시작되지 않는다.\n // 뒤따르는 popstate 는 key 가 이미 top 이라 onPop 에서 no-op 이 된다.\n dispatch({ type: \"POP_TO\", index: targetIndex, animate: animate() });\n void history.travel(-delta);\n return true;\n }, []);\n\n const back = useCallback(() => pop(1), [pop]);\n\n const popTo = useCallback(\n (path: string) => {\n const { entries } = stateRef.current;\n for (let i = entries.length - 2; i >= 0; i -= 1) {\n if (entries[i].path === path || entries[i].pattern === path) {\n return pop(entries.length - 1 - i);\n }\n }\n return false;\n },\n [pop]\n );\n\n const endTransition = useCallback(() => {\n dispatch({ type: \"END_TRANSITION\" });\n }, []);\n\n // popstate (브라우저·하드웨어 back, forward, history.go)\n useEffect(() => {\n const onPop = (historyState: HistoryState) => {\n const { entries } = stateRef.current;\n const index = historyState.key\n ? entries.findIndex((entry) => entry.key === historyState.key)\n : -1;\n if (index !== -1) {\n if (index < entries.length - 1) {\n busyRef.current = true;\n dispatch({ type: \"POP_TO\", index, animate: animate() });\n }\n return;\n }\n const hit = resolveOrNotify(historyState.path);\n if (!hit) {\n busyRef.current = false;\n return;\n }\n const entry = createEntry(\n hit,\n historyState.path,\n historyState.data,\n historyState.key\n );\n if (\n typeof historyState.index === \"number\" &&\n historyState.index === entries.length\n ) {\n busyRef.current = true;\n dispatch({ type: \"PUSH\", entry, animate: animate() });\n return;\n }\n dispatch({ type: \"RESET\", entry });\n };\n const removeListener = history.addListener(onPop);\n return () => {\n removeListener();\n };\n }, [resolveOrNotify]);\n\n // 새로고침·딥링크 복원 (마운트 1회, StrictMode 재실행 방지)\n const restoredRef = useRef(false);\n useEffect(() => {\n if (restoredRef.current) return;\n restoredRef.current = true;\n\n const root = stateRef.current.entries[0];\n const url = currentUrl();\n const hit = url === root.path ? null : resolve(url);\n if (!hit || hit.activity === optionsRef.current.initialActivity) {\n history.replace(root.path, { key: root.key, index: 0 });\n return;\n }\n\n const savedData = (history.getCurrentState() as HistoryState).data;\n const top = createEntry(hit, url, savedData);\n if (optionsRef.current.restoreStack === \"top-only\") {\n history.replace(url, { key: top.key, index: 0, data: savedData });\n dispatch({ type: \"RESTORE\", entries: [top] });\n return;\n }\n history.replace(root.path, { key: root.key, index: 0 });\n history.push(url, { key: top.key, index: 1, data: savedData });\n dispatch({ type: \"RESTORE\", entries: [root, top] });\n }, [resolve]);\n\n // 전환 종료 안전 타이머 (animationend 누락·jsdom 대비)\n useEffect(() => {\n if (!state.transition) {\n busyRef.current = false;\n return;\n }\n const timer = setTimeout(\n endTransition,\n optionsRef.current.duration + TRANSITION_END_GRACE_MS\n );\n return () => clearTimeout(timer);\n }, [state, endTransition]);\n\n return { state, push, replace, reset, back, pop, popTo, endTransition };\n}\n","import type { Activity } from \"../type\";\n\nexport interface PathMatch {\n params: Record<string, string>;\n query: Record<string, string>;\n}\n\nconst splitSegments = (pathname: string) =>\n pathname.split(\"/\").filter((segment) => segment.length > 0);\n\nconst safeDecode = (value: string) => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nexport function parseQuery(search: string): Record<string, string> {\n const query: Record<string, string> = {};\n new URLSearchParams(search).forEach((value, key) => {\n query[key] = value;\n });\n return query;\n}\n\n/**\n * `pattern`(`/detail/:id`)과 `url`(`/detail/3?tab=a#x`)을 비교한다.\n * 끝의 `/`와 `#hash`는 무시한다. 불일치면 null.\n */\nexport function matchPath(pattern: string, url: string): PathMatch | null {\n const [withoutHash] = url.split(\"#\");\n const queryIndex = withoutHash.indexOf(\"?\");\n const pathname =\n queryIndex === -1 ? withoutHash : withoutHash.slice(0, queryIndex);\n const search = queryIndex === -1 ? \"\" : withoutHash.slice(queryIndex);\n\n const patternSegments = splitSegments(pattern);\n const pathSegments = splitSegments(pathname);\n if (patternSegments.length !== pathSegments.length) return null;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < patternSegments.length; i += 1) {\n const expected = patternSegments[i];\n const actual = pathSegments[i];\n if (expected.startsWith(\":\")) {\n params[expected.slice(1)] = safeDecode(actual);\n } else if (expected !== actual) {\n return null;\n }\n }\n\n return { params, query: parseQuery(search) };\n}\n\n/** 등록 순서대로 첫 매칭 Activity */\nexport function findActivity(\n activities: Activity[],\n url: string\n): { activity: Activity; match: PathMatch } | null {\n for (const activity of activities) {\n const match = matchPath(activity.path, url);\n if (match) return { activity, match };\n }\n return null;\n}\n"],"mappings":"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","names":["reply","Direction","HistoryAction","import_react","import_jsx_runtime","currentPath","React","import_styled","import_styled","import_react","import_jsx_runtime","currentPath","styled","import_react","import_styled","import_jsx_runtime","styled","import_react","import_react","_a","import_react","currentPath","import_react","isDev","entry","import_jsx_runtime","_a","_b","styled","import_jsx_runtime","styled"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/bridge/detect-host.ts","../src/bridge/errors.ts","../src/bridge/pending-responses.ts","../src/bridge/protocol.ts","../src/bridge/transport.ts","../src/bridge/url-policy.ts","../src/bridge/client.ts","../src/bridge/stack-router-bridge.ts","../src/bridge/host.ts","../src/bridge/WebViewBridgeProvider.tsx","../src/type.ts","../src/history.ts","../src/stack-dev/stack-dev-roadmap.tsx","../src/stack-router/_components/back-router.tsx","../src/stack-router/stack-router-provider.tsx","../src/stack-router/_components/header.tsx","../src/stack-router/activity-context.tsx","../src/stack-router/_components/stack-page.tsx","../src/stack-router/stack-reducer.ts","../src/stack-router/use-prefers-reduced-motion.ts","../src/stack-router/use-stack-bridge-sync.ts","../src/stack-router/use-stack-navigation.ts","../src/stack-router/match-path.ts"],"sourcesContent":["export * from \"./bridge\";\nexport {\n BACK_TIMEOUT_MS,\n BRIDGE_TIMEOUT_MS,\n KEEP_ALIVE_LIMIT,\n STACK_TRANSITION_MS,\n} from \"./constants\";\nexport { history } from \"./history\";\nexport { StackDevRoadmap } from \"./stack-dev/stack-dev-roadmap\";\nexport { default as BackRouter } from \"./stack-router/_components/back-router\";\nexport { default as StackHeader } from \"./stack-router/_components/header\";\nexport {\n type ActivityContextValue,\n useActivity,\n useOnRevive,\n useParams,\n} from \"./stack-router/activity-context\";\nexport { findActivity, matchPath, parseQuery } from \"./stack-router/match-path\";\nexport type { StackEntry } from \"./stack-router/stack-reducer\";\nexport {\n type StackRouterContextValue,\n default as StackRouterProvider,\n useStackRouter,\n} from \"./stack-router/stack-router-provider\";\nexport type { StackBridgeSyncOptions } from \"./stack-router/use-stack-bridge-sync\";\nexport type {\n Activity,\n DirectionType,\n HistoryListener,\n HistoryState,\n RestoreStackPolicy,\n StackRouterProviderProps,\n StackTransitionType,\n VisiblePage,\n} from \"./type\";\nexport { Direction, HistoryAction } from \"./type\";\n","/**\n * push/back 전환 기본 시간 (ms). iOS 네비게이션 전환 체감에 맞춘 값.\n * `StackRouterProvider` `duration` 으로 조정\n */\nexport const STACK_TRANSITION_MS = 500;\n\n/** 전환 종료 안전 타이머 여유 (animationend 누락 대비) */\nexport const TRANSITION_END_GRACE_MS = 50;\n\n/** `history.back()` 이 popstate 를 기다리는 최대 시간 */\nexport const BACK_TIMEOUT_MS = 1000;\n\n/** 브릿지 요청 응답 기본 타임아웃 */\nexport const BRIDGE_TIMEOUT_MS = 5000;\n\n/** 네이티브 브릿지 주입 대기 기본 시간 */\nexport const BRIDGE_HOST_WAIT_MS = 3000;\n\n/** 네이티브 브릿지 주입 재확인 간격 */\nexport const BRIDGE_HOST_POLL_MS = 100;\n\n/** keepAlive 페이지 기본 최대 보관 수 (스택 안 keepAlive 포함) */\nexport const KEEP_ALIVE_LIMIT = 5;\n\n/** 마운트된 페이지가 이 수를 넘으면 개발 모드에서 한 번 경고 */\nexport const DEV_MOUNTED_PAGES_WARN = 15;\n","import { BRIDGE_HOST_POLL_MS, BRIDGE_HOST_WAIT_MS } from \"../constants\";\nimport type { BridgeHostKind } from \"./protocol\";\n\n/** flutter_inappwebview 가 JS 브릿지를 붙인 뒤 window 에 dispatch 하는 이벤트 */\nexport const FLUTTER_READY_EVENT = \"flutterInAppWebViewPlatformReady\";\n\nexport function detectBridgeHost(): BridgeHostKind {\n if (typeof window === \"undefined\") return \"unknown\";\n\n if (window.ReactNativeWebView?.postMessage) {\n return \"react-native\";\n }\n\n if (window.flutter_inappwebview?.callHandler) {\n return \"flutter\";\n }\n\n return \"browser\";\n}\n\nexport function isNativeBridgeHost(host: BridgeHostKind): boolean {\n return host === \"react-native\" || host === \"flutter\";\n}\n\nexport interface WaitForBridgeHostOptions {\n timeoutMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * 네이티브 브릿지가 늦게 주입되는 경우(Flutter platformReady 이전)를 기다린다.\n * 즉시 감지되면 바로, 아니면 ready 이벤트·폴링으로 재감지. 타임아웃·abort 시 현재 판정값.\n */\nexport function waitForBridgeHost({\n timeoutMs = BRIDGE_HOST_WAIT_MS,\n signal,\n}: WaitForBridgeHostOptions = {}): Promise<BridgeHostKind> {\n const host = detectBridgeHost();\n if (isNativeBridgeHost(host) || host === \"unknown\") {\n return Promise.resolve(host);\n }\n\n return new Promise<BridgeHostKind>((resolve) => {\n const finish = () => {\n clearInterval(poll);\n clearTimeout(timer);\n window.removeEventListener(FLUTTER_READY_EVENT, check);\n signal?.removeEventListener(\"abort\", finish);\n resolve(detectBridgeHost());\n };\n const check = () => {\n if (isNativeBridgeHost(detectBridgeHost())) finish();\n };\n const poll = setInterval(check, BRIDGE_HOST_POLL_MS);\n const timer = setTimeout(finish, timeoutMs);\n window.addEventListener(FLUTTER_READY_EVENT, check);\n signal?.addEventListener(\"abort\", finish);\n });\n}\n","export const BRIDGE_ERROR_CODES = {\n TIMEOUT: \"TIMEOUT\",\n BRIDGE_UNAVAILABLE: \"BRIDGE_UNAVAILABLE\",\n INVALID_PAYLOAD: \"INVALID_PAYLOAD\",\n URL_NOT_ALLOWED: \"URL_NOT_ALLOWED\",\n UNKNOWN_METHOD: \"UNKNOWN_METHOD\",\n HANDLER_ERROR: \"HANDLER_ERROR\",\n} as const;\n\nexport type BridgeErrorCode =\n (typeof BRIDGE_ERROR_CODES)[keyof typeof BRIDGE_ERROR_CODES];\n\nexport class BridgeError extends Error {\n readonly code: BridgeErrorCode | string;\n\n constructor(\n code: BridgeErrorCode | string,\n message: string,\n cause?: unknown\n ) {\n super(message);\n // ES5 타깃에서 Error 상속 시 instanceof 가 깨지는 것 방지\n Object.setPrototypeOf(this, new.target.prototype);\n this.name = \"BridgeError\";\n this.code = code;\n if (cause !== undefined) {\n (this as { cause?: unknown }).cause = cause;\n }\n }\n\n toBody() {\n return { code: this.code, message: this.message };\n }\n}\n\nexport function toBridgeError(\n error: unknown,\n fallbackCode: BridgeErrorCode\n): BridgeError {\n if (error instanceof BridgeError) return error;\n const message = error instanceof Error ? error.message : String(error);\n return new BridgeError(fallbackCode, message, error);\n}\n","import { BRIDGE_ERROR_CODES, BridgeError } from \"./errors\";\nimport type { BridgeEnvelope } from \"./protocol\";\n\ninterface PendingRequest {\n resolve: (response: BridgeEnvelope) => void;\n reject: (error: BridgeError) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\nconst pending = new Map<string, PendingRequest>();\n\n/** `bridge.response`(`replyTo === requestId`) 를 timeoutMs 동안 기다린다 */\nexport function waitForResponse(\n requestId: string,\n timeoutMs: number\n): Promise<BridgeEnvelope> {\n return new Promise<BridgeEnvelope>((resolve, reject) => {\n const timer = setTimeout(() => {\n pending.delete(requestId);\n reject(\n new BridgeError(\n BRIDGE_ERROR_CODES.TIMEOUT,\n `No response for ${requestId} within ${timeoutMs}ms`\n )\n );\n }, timeoutMs);\n pending.set(requestId, { resolve, reject, timer });\n });\n}\n\n/** 응답 envelope 이면 대기 중인 요청을 settle 하고 true */\nexport function settleResponse(envelope: BridgeEnvelope): boolean {\n if (!envelope.replyTo) return false;\n const request = pending.get(envelope.replyTo);\n if (!request) return false;\n clearTimeout(request.timer);\n pending.delete(envelope.replyTo);\n if (envelope.error) {\n request.reject(\n new BridgeError(envelope.error.code, envelope.error.message)\n );\n } else {\n request.resolve(envelope);\n }\n return true;\n}\n\n/** 전송 실패 등으로 대기를 취소 */\nexport function cancelResponse(requestId: string): void {\n const request = pending.get(requestId);\n if (!request) return;\n clearTimeout(request.timer);\n pending.delete(requestId);\n}\n","import type { BridgeErrorCode } from \"./errors\";\n\n/** WebViewKit native bridge protocol (v1) */\nexport const BRIDGE_PROTOCOL_VERSION = 1 as const;\nexport const BRIDGE_NAMESPACE = \"webviewkit\" as const;\n\nexport type BridgeHostKind = \"react-native\" | \"flutter\" | \"browser\" | \"unknown\";\n\n/** Stack navigation — maps to common `stackPush` / `stackPop` WebView handlers */\nexport const STACK_BRIDGE_METHODS = {\n PUSH: \"stack.push\",\n REPLACE: \"stack.replace\",\n POP: \"stack.pop\",\n RESET: \"stack.reset\",\n /** web → native: 웹 스택 깊이 변경 알림 */\n CHANGED: \"stack.changed\",\n} as const;\n\nexport type StackBridgeMethod =\n (typeof STACK_BRIDGE_METHODS)[keyof typeof STACK_BRIDGE_METHODS];\n\n/** native → web: 하드웨어 back. 응답 payload `{ handled }` */\nexport const BACK_REQUEST_METHOD = \"back.request\" as const;\n\n/** 요청에 대한 응답 envelope method (`replyTo` 필수) */\nexport const BRIDGE_RESPONSE_METHOD = \"bridge.response\" as const;\n\nexport type StackMeta = Record<string, unknown> | null;\n\nexport type StackPushPayload = { url: string; meta?: StackMeta };\nexport type StackReplacePayload = StackPushPayload;\nexport type StackResetPayload = { url: string; meta?: StackMeta };\nexport type StackChangedPayload = { depth: number; path: string };\nexport type BackRequestResult = { handled: boolean };\n\nexport type BridgeErrorBody = {\n code: BridgeErrorCode | string;\n message: string;\n};\n\nexport type BridgeEnvelope<TPayload = unknown> = {\n v: typeof BRIDGE_PROTOCOL_VERSION;\n ns: typeof BRIDGE_NAMESPACE;\n id: string;\n method: string;\n payload?: TPayload;\n error?: BridgeErrorBody;\n /** 응답일 때 원 요청 id */\n replyTo?: string;\n};\n\nexport function createBridgeId(): string {\n if (\n typeof crypto !== \"undefined\" &&\n typeof crypto.randomUUID === \"function\"\n ) {\n return crypto.randomUUID();\n }\n return `wv-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;\n}\n\nexport function createBridgeEnvelope<TPayload>(\n method: string,\n payload?: TPayload,\n id?: string\n): BridgeEnvelope<TPayload> {\n return {\n v: BRIDGE_PROTOCOL_VERSION,\n ns: BRIDGE_NAMESPACE,\n id: id ?? createBridgeId(),\n method,\n ...(payload !== undefined ? { payload } : {}),\n };\n}\n\nexport function createBridgeResponse<TPayload>(\n request: Pick<BridgeEnvelope, \"id\">,\n result: { payload?: TPayload; error?: BridgeErrorBody }\n): BridgeEnvelope<TPayload> {\n return {\n ...createBridgeEnvelope(BRIDGE_RESPONSE_METHOD, result.payload),\n replyTo: request.id,\n ...(result.error ? { error: result.error } : {}),\n };\n}\n\nexport function isBridgeEnvelope(value: unknown): value is BridgeEnvelope {\n if (!value || typeof value !== \"object\") return false;\n const o = value as BridgeEnvelope;\n return (\n o.v === BRIDGE_PROTOCOL_VERSION &&\n o.ns === BRIDGE_NAMESPACE &&\n typeof o.id === \"string\" &&\n typeof o.method === \"string\"\n );\n}\n\nexport function parseBridgeMessage(\n raw: string | unknown\n): BridgeEnvelope | null {\n try {\n const parsed = typeof raw === \"string\" ? (JSON.parse(raw) as unknown) : raw;\n return isBridgeEnvelope(parsed) ? parsed : null;\n } catch {\n // 프로토콜 밖 메시지(다른 라이브러리의 postMessage 등)는 무시한다\n return null;\n }\n}\n\nexport function serializeBridgeMessage(msg: BridgeEnvelope): string {\n return JSON.stringify(msg);\n}\n\n/** Flutter InAppWebView legacy handler names */\nexport const FLUTTER_LEGACY_STACK_HANDLERS = {\n push: \"stackPush\",\n replace: \"stackReplace\",\n pop: \"stackPop\",\n reset: \"stackReset\",\n} as const;\n\n/** Unified handler name when native listens on one channel */\nexport const FLUTTER_UNIFIED_HANDLER = \"webviewkitBridge\";\n\n/** React Native receives messages via this global handler name suggestion */\nexport const RN_BRIDGE_HANDLER = \"webviewkitBridge\";\n","import { detectBridgeHost } from \"./detect-host\";\nimport { BRIDGE_ERROR_CODES, toBridgeError } from \"./errors\";\nimport type { BridgeEnvelope, BridgeHostKind } from \"./protocol\";\nimport {\n FLUTTER_LEGACY_STACK_HANDLERS,\n FLUTTER_UNIFIED_HANDLER,\n serializeBridgeMessage,\n STACK_BRIDGE_METHODS,\n} from \"./protocol\";\n\nexport type BridgeTransportOptions = {\n /** Flutter: use stackPush/stackPop handlers (default true) */\n flutterLegacyHandlers?: boolean;\n};\n\nexport interface BridgeTransport {\n readonly host: BridgeHostKind;\n /** Flutter 는 callHandler 반환값, RN·browser 는 undefined */\n send(envelope: BridgeEnvelope): Promise<unknown>;\n}\n\nconst LEGACY_HANDLER_BY_METHOD: Record<string, string> = {\n [STACK_BRIDGE_METHODS.PUSH]: FLUTTER_LEGACY_STACK_HANDLERS.push,\n [STACK_BRIDGE_METHODS.REPLACE]: FLUTTER_LEGACY_STACK_HANDLERS.replace,\n [STACK_BRIDGE_METHODS.POP]: FLUTTER_LEGACY_STACK_HANDLERS.pop,\n [STACK_BRIDGE_METHODS.RESET]: FLUTTER_LEGACY_STACK_HANDLERS.reset,\n};\n\nfunction unavailable(host: BridgeHostKind): never {\n throw new Error(`${host} bridge is not available`);\n}\n\nfunction createReactNativeTransport(): BridgeTransport {\n return {\n host: \"react-native\",\n async send(envelope) {\n try {\n const bridge = window.ReactNativeWebView ?? unavailable(\"react-native\");\n bridge.postMessage(serializeBridgeMessage(envelope));\n return undefined;\n } catch (error) {\n throw toBridgeError(error, BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE);\n }\n },\n };\n}\n\nfunction createFlutterTransport(\n options: BridgeTransportOptions\n): BridgeTransport {\n const useLegacy = options.flutterLegacyHandlers !== false;\n\n return {\n host: \"flutter\",\n async send(envelope) {\n const bridge = window.flutter_inappwebview;\n if (!bridge?.callHandler) {\n throw toBridgeError(\n new Error(\"flutter bridge is not available\"),\n BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE\n );\n }\n const call = bridge.callHandler.bind(bridge);\n const handler = useLegacy\n ? LEGACY_HANDLER_BY_METHOD[envelope.method]\n : null;\n if (!handler) {\n return call(FLUTTER_UNIFIED_HANDLER, serializeBridgeMessage(envelope));\n }\n if (envelope.method === STACK_BRIDGE_METHODS.POP) {\n return call(handler);\n }\n const payload = envelope.payload as\n | { url?: string; meta?: unknown }\n | undefined;\n return call(handler, payload?.url ?? \"\", payload?.meta ?? null);\n },\n };\n}\n\nconst browserTransport: BridgeTransport = {\n host: \"browser\",\n async send() {\n // no native host — web-only\n return undefined;\n },\n};\n\nexport function createBridgeTransport(\n host: BridgeHostKind = detectBridgeHost(),\n options: BridgeTransportOptions = {}\n): BridgeTransport {\n if (host === \"react-native\") return createReactNativeTransport();\n if (host === \"flutter\") return createFlutterTransport(options);\n return browserTransport;\n}\n","import { BRIDGE_ERROR_CODES, BridgeError } from \"./errors\";\n\nexport type AllowUrl = (url: string) => boolean;\n\n/**\n * 기본 정책: 같은 앱 안의 경로만 허용.\n * - `/a/b?x=1` 같은 상대 경로 (`//host` 프로토콜 상대 URL 제외)\n * - 현재 origin 과 같은 절대 http(s) URL\n * `javascript:`, `data:`, 외부 도메인은 거부한다.\n */\nexport function isSafeStackUrl(url: string): boolean {\n if (url.startsWith(\"/\"))\n return !url.startsWith(\"//\") && !url.startsWith(\"/\\\\\");\n if (typeof window === \"undefined\") return false;\n try {\n const parsed = new URL(url);\n return (\n (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") &&\n parsed.origin === window.location.origin\n );\n } catch {\n return false;\n }\n}\n\n/** 같은 origin 절대 URL → 경로로 정규화. 그 밖(상대 경로·커스텀 스킴)은 그대로 */\nexport function toStackPath(url: string): string {\n if (url.startsWith(\"/\") || typeof window === \"undefined\") return url;\n try {\n const parsed = new URL(url);\n if (parsed.origin !== window.location.origin) return url;\n return parsed.pathname + parsed.search + parsed.hash;\n } catch {\n return url;\n }\n}\n\n/** payload 에서 url 을 꺼내 형식·정책 검증 후 경로로 반환. 실패 시 BridgeError */\nexport function assertStackUrl(\n payload: unknown,\n allowUrl: AllowUrl = isSafeStackUrl\n): string {\n const url = (payload as { url?: unknown } | undefined)?.url;\n if (typeof url !== \"string\" || url.trim().length === 0) {\n throw new BridgeError(\n BRIDGE_ERROR_CODES.INVALID_PAYLOAD,\n \"payload.url must be a non-empty string\"\n );\n }\n if (!allowUrl(url)) {\n throw new BridgeError(\n BRIDGE_ERROR_CODES.URL_NOT_ALLOWED,\n `url is not allowed: ${url}`\n );\n }\n return toStackPath(url);\n}\n","import { BRIDGE_TIMEOUT_MS } from \"../constants\";\nimport { detectBridgeHost } from \"./detect-host\";\nimport { BRIDGE_ERROR_CODES, BridgeError } from \"./errors\";\nimport { cancelResponse, waitForResponse } from \"./pending-responses\";\nimport {\n type BridgeEnvelope,\n createBridgeEnvelope,\n STACK_BRIDGE_METHODS,\n type StackChangedPayload,\n type StackMeta,\n type StackPushPayload,\n type StackResetPayload,\n} from \"./protocol\";\nimport type { BridgeTransport } from \"./transport\";\nimport {\n type BridgeTransportOptions,\n createBridgeTransport,\n} from \"./transport\";\nimport { type AllowUrl, assertStackUrl } from \"./url-policy\";\n\nexport type WebViewBridgeClientOptions = BridgeTransportOptions & {\n transport?: BridgeTransport;\n /** outbound stack URL 검증 (기본 isSafeStackUrl) */\n allowUrl?: AllowUrl;\n /** 요청 기본 타임아웃 ms */\n timeoutMs?: number;\n};\n\nexport interface BridgeRequestOptions {\n timeoutMs?: number;\n /**\n * RN: 네이티브가 `bridge.response`(replyTo) 로 회신할 때까지 기다린다.\n * 기본 false — 전송 즉시 resolve (1.x 네이티브 호환).\n */\n expectResponse?: boolean;\n}\n\nexport interface BridgeResult<TResult = unknown> {\n /** 전송한 요청 envelope */\n envelope: BridgeEnvelope;\n /** Flutter callHandler 반환값 또는 RN 응답 payload */\n result?: TResult;\n}\n\nfunction withTimeout<T>(\n promise: Promise<T>,\n timeoutMs: number,\n method: string\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_, reject) => {\n timer = setTimeout(\n () =>\n reject(\n new BridgeError(\n BRIDGE_ERROR_CODES.TIMEOUT,\n `${method} timed out after ${timeoutMs}ms`\n )\n ),\n timeoutMs\n );\n });\n return Promise.race([promise, timeout]).finally(() => clearTimeout(timer));\n}\n\nexport class WebViewBridgeClient {\n readonly host: ReturnType<typeof detectBridgeHost>;\n private readonly transport: BridgeTransport;\n private readonly allowUrl?: AllowUrl;\n private readonly timeoutMs: number;\n\n constructor(options: WebViewBridgeClientOptions = {}) {\n this.host = options.transport?.host ?? detectBridgeHost();\n this.transport =\n options.transport ?? createBridgeTransport(this.host, options);\n this.allowUrl = options.allowUrl;\n this.timeoutMs = options.timeoutMs ?? BRIDGE_TIMEOUT_MS;\n }\n\n /** 응답을 기다리지 않는 단방향 전송 */\n async send(envelope: BridgeEnvelope): Promise<unknown> {\n return this.transport.send(envelope);\n }\n\n async request<TPayload = unknown, TResult = unknown>(\n method: string,\n payload?: TPayload,\n options: BridgeRequestOptions = {}\n ): Promise<BridgeResult<TResult>> {\n const envelope = createBridgeEnvelope(method, payload);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const waitsForReply =\n options.expectResponse === true && this.host === \"react-native\";\n const reply = waitsForReply\n ? waitForResponse(envelope.id, timeoutMs)\n : null;\n\n try {\n const sent = await withTimeout(this.send(envelope), timeoutMs, method);\n if (!reply) return { envelope, result: sent as TResult };\n const response = await reply;\n return { envelope, result: response.payload as TResult };\n } catch (error) {\n cancelResponse(envelope.id);\n throw error;\n }\n }\n\n private async stackRequest(\n method: string,\n url: string,\n meta: StackMeta,\n options?: BridgeRequestOptions\n ) {\n const path = assertStackUrl({ url }, this.allowUrl);\n return this.request<StackPushPayload>(method, { url: path, meta }, options);\n }\n\n stackPush(\n url: string,\n meta: StackMeta = null,\n options?: BridgeRequestOptions\n ) {\n return this.stackRequest(STACK_BRIDGE_METHODS.PUSH, url, meta, options);\n }\n\n stackReplace(\n url: string,\n meta: StackMeta = null,\n options?: BridgeRequestOptions\n ) {\n return this.stackRequest(STACK_BRIDGE_METHODS.REPLACE, url, meta, options);\n }\n\n stackPop(options?: BridgeRequestOptions) {\n return this.request(STACK_BRIDGE_METHODS.POP, undefined, options);\n }\n\n async stackReset(\n url: string,\n meta: StackMeta = null,\n options?: BridgeRequestOptions\n ) {\n const path = assertStackUrl({ url }, this.allowUrl);\n return this.request<StackResetPayload>(\n STACK_BRIDGE_METHODS.RESET,\n { url: path, meta },\n options\n );\n }\n\n /** web → native 웹 스택 변경 알림 (응답 없음) */\n notifyStackChanged(payload: StackChangedPayload): Promise<unknown> {\n return this.send(\n createBridgeEnvelope(STACK_BRIDGE_METHODS.CHANGED, payload)\n );\n }\n}\n\nexport function createWebViewBridgeClient(\n options?: WebViewBridgeClientOptions\n): WebViewBridgeClient {\n return new WebViewBridgeClient(options);\n}\n","import type { BridgeRequestOptions, BridgeResult } from \"./client\";\nimport { createWebViewBridgeClient } from \"./client\";\nimport { detectBridgeHost, isNativeBridgeHost } from \"./detect-host\";\nimport type { StackMeta } from \"./protocol\";\nimport type { BridgeTransportOptions } from \"./transport\";\nimport type { AllowUrl } from \"./url-policy\";\n\nexport type StackRouterBridge = {\n push: (\n url: string,\n meta?: StackMeta,\n options?: BridgeRequestOptions\n ) => Promise<BridgeResult>;\n replace: (\n url: string,\n meta?: StackMeta,\n options?: BridgeRequestOptions\n ) => Promise<BridgeResult>;\n pop: (options?: BridgeRequestOptions) => Promise<BridgeResult>;\n reset: (\n url: string,\n meta?: StackMeta,\n options?: BridgeRequestOptions\n ) => Promise<BridgeResult>;\n};\n\nexport type CreateStackRouterBridgeOptions = BridgeTransportOptions & {\n allowUrl?: AllowUrl;\n timeoutMs?: number;\n};\n\nlet cachedBridge: StackRouterBridge | null = null;\n\n/**\n * Web → native stack navigation (Flutter `callHandler` / RN `postMessage`).\n * Returns null in browser-only environments.\n */\nexport function createStackRouterBridge(\n options?: CreateStackRouterBridgeOptions\n): StackRouterBridge | null {\n const host = detectBridgeHost();\n if (!isNativeBridgeHost(host)) return null;\n\n const client = createWebViewBridgeClient(options);\n\n return {\n push: (url, meta, requestOptions) =>\n client.stackPush(url, meta ?? null, requestOptions),\n replace: (url, meta, requestOptions) =>\n client.stackReplace(url, meta ?? null, requestOptions),\n pop: (requestOptions) => client.stackPop(requestOptions),\n reset: (url, meta, requestOptions) =>\n client.stackReset(url, meta ?? null, requestOptions),\n };\n}\n\n/** `window.stackRouterBridge` → 모듈 캐시 → 새로 생성 후 캐시 */\nexport function getStackRouterBridge(): StackRouterBridge | null {\n if (typeof window === \"undefined\") return null;\n if (window.stackRouterBridge) return window.stackRouterBridge;\n if (!cachedBridge) cachedBridge = createStackRouterBridge();\n return cachedBridge;\n}\n\nexport function installStackRouterBridge(\n options?: CreateStackRouterBridgeOptions\n): StackRouterBridge | null {\n if (typeof window === \"undefined\") return null;\n const bridge = createStackRouterBridge(options);\n if (bridge) {\n window.stackRouterBridge = bridge;\n }\n return bridge;\n}\n\n/** 테스트·호스트 전환용 캐시 초기화 */\nexport function resetStackRouterBridgeCache(): void {\n cachedBridge = null;\n}\n","import { detectBridgeHost, isNativeBridgeHost } from \"./detect-host\";\nimport { BRIDGE_ERROR_CODES, BridgeError, toBridgeError } from \"./errors\";\nimport { settleResponse } from \"./pending-responses\";\nimport {\n BACK_REQUEST_METHOD,\n BRIDGE_RESPONSE_METHOD,\n type BridgeEnvelope,\n createBridgeEnvelope,\n createBridgeResponse,\n parseBridgeMessage,\n STACK_BRIDGE_METHODS,\n type StackMeta,\n} from \"./protocol\";\nimport {\n createStackRouterBridge,\n type StackRouterBridge,\n} from \"./stack-router-bridge\";\nimport {\n type BridgeTransportOptions,\n createBridgeTransport,\n} from \"./transport\";\nimport { type AllowUrl, assertStackUrl } from \"./url-policy\";\n\ntype HandlerResult = boolean | Promise<boolean>;\n\nexport type StackRouterHostHandlers = {\n push: (url: string, meta?: StackMeta) => HandlerResult;\n replace: (url: string, meta?: StackMeta) => HandlerResult;\n pop: () => HandlerResult;\n reset: (url: string, meta?: StackMeta) => HandlerResult;\n};\n\nexport type InstallBridgeHostOptions = {\n /** Native → web stack navigation */\n stack?: StackRouterHostHandlers;\n /** Custom method handlers keyed by envelope `method` */\n handlers?: Record<\n string,\n (payload: unknown, envelope: BridgeEnvelope) => HandlerResult\n >;\n /** native → web `back.request` (하드웨어 back). true = 웹에서 처리함 */\n onBackRequest?: () => HandlerResult;\n /** Called for every valid envelope before routing */\n onMessage?: (envelope: BridgeEnvelope) => void;\n /** 검증 실패·핸들러 예외 (throw 대신 여기로 전달) */\n onError?: (error: BridgeError, envelope?: BridgeEnvelope) => void;\n /** inbound stack URL 검증 (기본 isSafeStackUrl) */\n allowUrl?: AllowUrl;\n /** 모든 inbound 요청에 `bridge.response` 회신 (back.request 는 항상 회신) */\n replyToNative?: boolean;\n /** 회신용 transport 옵션 */\n transport?: BridgeTransportOptions;\n /**\n * `window.stackRouterBridge` 설치 (web → native).\n * true 면 `createStackRouterBridge()` 로 생성한다.\n */\n exposeStackRouterBridge?: StackRouterBridge | boolean;\n /** Register `window.stackPush` / `stackPop` for Flutter native→web (default true when `stack`) */\n legacyInboundHandlers?: boolean;\n};\n\nconst STACK_URL_METHODS = {\n [STACK_BRIDGE_METHODS.PUSH]: \"push\",\n [STACK_BRIDGE_METHODS.REPLACE]: \"replace\",\n [STACK_BRIDGE_METHODS.RESET]: \"reset\",\n} as const;\n\nasync function route(\n envelope: BridgeEnvelope,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n const custom = options.handlers?.[envelope.method];\n if (custom) return Boolean(await custom(envelope.payload, envelope));\n\n if (envelope.method === BACK_REQUEST_METHOD) {\n return Boolean(await options.onBackRequest?.());\n }\n\n const stack = options.stack;\n const urlMethod =\n STACK_URL_METHODS[envelope.method as keyof typeof STACK_URL_METHODS];\n if (stack && urlMethod) {\n const url = assertStackUrl(envelope.payload, options.allowUrl);\n const meta = (envelope.payload as { meta?: StackMeta }).meta ?? null;\n return Boolean(await stack[urlMethod](url, meta));\n }\n if (stack && envelope.method === STACK_BRIDGE_METHODS.POP) {\n return Boolean(await stack.pop());\n }\n\n throw new BridgeError(\n BRIDGE_ERROR_CODES.UNKNOWN_METHOD,\n `No handler for ${envelope.method}`\n );\n}\n\nasync function reply(\n request: BridgeEnvelope,\n result: { handled: boolean; error?: BridgeError },\n options: InstallBridgeHostOptions\n) {\n const host = detectBridgeHost();\n if (!isNativeBridgeHost(host)) return;\n const response = createBridgeResponse(request, {\n payload: { handled: result.handled },\n error: result.error?.toBody(),\n });\n try {\n await createBridgeTransport(host, options.transport).send(response);\n } catch (error) {\n options.onError?.(\n toBridgeError(error, BRIDGE_ERROR_CODES.BRIDGE_UNAVAILABLE),\n response\n );\n }\n}\n\nasync function dispatchEnvelope(\n envelope: BridgeEnvelope,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n if (envelope.method === BRIDGE_RESPONSE_METHOD) {\n return settleResponse(envelope);\n }\n\n options.onMessage?.(envelope);\n\n let handled = false;\n let failure: BridgeError | undefined;\n try {\n handled = await route(envelope, options);\n } catch (error) {\n failure = toBridgeError(error, BRIDGE_ERROR_CODES.HANDLER_ERROR);\n options.onError?.(failure, envelope);\n }\n\n if (options.replyToNative || envelope.method === BACK_REQUEST_METHOD) {\n await reply(envelope, { handled, error: failure }, options);\n }\n return handled;\n}\n\n/** inbound 메시지 처리. 절대 reject 하지 않는다 (실패는 false + onError) */\nexport function handleBridgeMessage(\n raw: string | unknown,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n const envelope = parseBridgeMessage(raw);\n if (!envelope) return Promise.resolve(false);\n return dispatchEnvelope(envelope, options);\n}\n\nexport type BridgeHostCleanup = () => void;\n\nconst isDev = () =>\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\ntype GlobalKey =\n | \"webviewkitBridge\"\n | \"stackPush\"\n | \"stackReplace\"\n | \"stackPop\"\n | \"stackReset\"\n | \"stackRouterBridge\";\n\nfunction legacyCall(\n method: string,\n payload: unknown,\n options: InstallBridgeHostOptions\n): Promise<boolean> {\n return dispatchEnvelope(createBridgeEnvelope(method, payload), {\n ...options,\n replyToNative: false,\n });\n}\n\nexport function installBridgeHost(\n options: InstallBridgeHostOptions\n): BridgeHostCleanup {\n if (typeof window === \"undefined\") {\n return () => undefined;\n }\n\n const installed: Partial<Record<GlobalKey, unknown>> = {};\n const target = window as unknown as Record<GlobalKey, unknown>;\n const install = (key: GlobalKey, value: unknown) => {\n if (isDev() && target[key] !== undefined) {\n console.warn(`[webviewkit] window.${key} is being overwritten`);\n }\n target[key] = value;\n installed[key] = value;\n };\n\n install(\"webviewkitBridge\", {\n postMessage: (raw: string | unknown) => {\n void handleBridgeMessage(raw, options);\n },\n });\n\n if (options.legacyInboundHandlers !== false && options.stack) {\n install(\"stackPush\", (url: string, meta?: StackMeta) =>\n legacyCall(STACK_BRIDGE_METHODS.PUSH, { url, meta }, options)\n );\n install(\"stackReplace\", (url: string, meta?: StackMeta) =>\n legacyCall(STACK_BRIDGE_METHODS.REPLACE, { url, meta }, options)\n );\n install(\"stackPop\", () =>\n legacyCall(STACK_BRIDGE_METHODS.POP, undefined, options)\n );\n install(\"stackReset\", (url: string, meta?: StackMeta) =>\n legacyCall(STACK_BRIDGE_METHODS.RESET, { url, meta }, options)\n );\n }\n\n const outbound =\n options.exposeStackRouterBridge === true\n ? createStackRouterBridge(options.transport)\n : options.exposeStackRouterBridge || null;\n if (outbound) install(\"stackRouterBridge\", outbound);\n\n return () => {\n // 다른 설치가 덮어쓴 전역은 건드리지 않는다\n (Object.keys(installed) as GlobalKey[]).forEach((key) => {\n if (target[key] === installed[key]) delete target[key];\n });\n };\n}\n\n/** Emit a protocol envelope from web (e.g. for tests or custom native listeners) */\nexport function emitBridgeEnvelope(\n method: string,\n payload?: unknown\n): BridgeEnvelope {\n return createBridgeEnvelope(method, payload);\n}\n","import React, { type ReactNode, useEffect, useRef } from \"react\";\nimport { waitForBridgeHost } from \"./detect-host\";\nimport {\n installBridgeHost,\n type InstallBridgeHostOptions,\n type StackRouterHostHandlers,\n} from \"./host\";\nimport {\n createStackRouterBridge,\n type CreateStackRouterBridgeOptions,\n} from \"./stack-router-bridge\";\n\nexport type WebViewBridgeProviderProps = {\n children?: ReactNode;\n /** Native → web stack handlers (e.g. Next.js `router.push`) */\n stack?: StackRouterHostHandlers;\n transport?: CreateStackRouterBridgeOptions;\n /** Install `window.stackRouterBridge` for web → native */\n enableOutboundBridge?: boolean;\n hostOptions?: Omit<\n InstallBridgeHostOptions,\n \"stack\" | \"exposeStackRouterBridge\" | \"legacyInboundHandlers\"\n >;\n};\n\n/**\n * Mount once near the app root (Next.js `layout`, SPA `App`).\n * Wires protocol ingress + optional legacy window stack handlers.\n * `stack`·`hostOptions` 는 최신 값을 ref 로 읽으므로 인라인 객체여도 재설치하지 않는다.\n */\nexport function WebViewBridgeProvider({\n children = null,\n stack,\n transport,\n enableOutboundBridge = true,\n hostOptions,\n}: WebViewBridgeProviderProps) {\n const latest = useRef({ stack, transport, hostOptions });\n latest.current = { stack, transport, hostOptions };\n const hasStack = Boolean(stack);\n\n useEffect(() => {\n const call =\n <K extends keyof StackRouterHostHandlers>(key: K) =>\n (...args: Parameters<StackRouterHostHandlers[K]>) => {\n const handler = latest.current.stack?.[key] as\n | ((\n ...a: Parameters<StackRouterHostHandlers[K]>\n ) => boolean | Promise<boolean>)\n | undefined;\n return handler ? handler(...args) : false;\n };\n\n const options = latest.current.hostOptions;\n const cleanups: (() => void)[] = [];\n cleanups.push(\n installBridgeHost({\n ...options,\n onMessage: (envelope) =>\n latest.current.hostOptions?.onMessage?.(envelope),\n onError: (error, envelope) =>\n latest.current.hostOptions?.onError?.(error, envelope),\n onBackRequest: () =>\n latest.current.hostOptions?.onBackRequest?.() ?? false,\n stack: hasStack\n ? {\n push: call(\"push\"),\n replace: call(\"replace\"),\n pop: call(\"pop\"),\n reset: call(\"reset\"),\n }\n : undefined,\n legacyInboundHandlers: hasStack,\n })\n );\n\n // Flutter 는 platformReady 이후에 브릿지가 붙을 수 있다 → 감지 후 outbound 설치\n const abort = new AbortController();\n if (enableOutboundBridge) {\n void waitForBridgeHost({ signal: abort.signal }).then(() => {\n if (abort.signal.aborted) return;\n const outbound = createStackRouterBridge(latest.current.transport);\n if (!outbound) return;\n window.stackRouterBridge = outbound;\n cleanups.push(() => {\n if (window.stackRouterBridge === outbound)\n delete window.stackRouterBridge;\n });\n });\n }\n\n return () => {\n abort.abort();\n cleanups.forEach((cleanup) => cleanup());\n };\n }, [enableOutboundBridge, hasStack]);\n\n return <>{children}</>;\n}\n","import type React from \"react\";\nimport type { StackBridgeSyncOptions } from \"./stack-router/use-stack-bridge-sync\";\n\nexport interface Activity {\n /** 정적 경로 또는 동적 세그먼트 패턴 (`/detail/:id`) */\n path: string;\n element: React.ReactNode;\n /** true 면 스택에서 빠져도 인스턴스(state)를 보관했다가 같은 path 로 돌아오면 되살린다 */\n keepAlive?: boolean;\n}\n\nexport type StackTransitionType = \"slide\" | \"fade\" | \"none\";\n\nexport type RestoreStackPolicy = \"with-root\" | \"top-only\";\n\nexport interface StackRouterProviderProps {\n initialActivity: Activity;\n Activities?: Activity[];\n maxWidth?: string;\n /** true면 각 페이지 상단에 `StackHeader` 렌더 (페이지와 함께 전환) */\n isShowHeader?: boolean;\n /** 개발 시 스택 로드맵 오버레이 (기본: NODE_ENV === \"development\") */\n enableDevTools?: boolean;\n transition?: StackTransitionType;\n /** 전환 시간 ms (기본 STACK_TRANSITION_MS) */\n duration?: number;\n /** 새로고침·딥링크 진입 시 스택 복원 정책 (기본 \"with-root\") */\n restoreStack?: RestoreStackPolicy;\n /** keepAlive 페이지 최대 보관 수 (기본 KEEP_ALIVE_LIMIT, 0 이면 보관 안 함) */\n keepAliveLimit?: number;\n /** 스택 top 에서부터 children 을 마운트할 최대 페이지 수 (기본 제한 없음, 1 미만은 1) */\n maxMountedPages?: number;\n /** env(safe-area-inset-*) padding 적용 */\n safeArea?: boolean;\n /** 루트에서 back 했을 때 (앱 종료·WebView 닫기 위임) */\n onBackAtRoot?: () => void;\n /** 등록되지 않은 경로로 이동하려 할 때 */\n onNotFound?: (path: string) => void;\n /** 네이티브 브릿지 연동 */\n bridge?: boolean | StackBridgeSyncOptions;\n}\n\nexport interface VisiblePage {\n path: string;\n element: React.ReactNode;\n}\n\nexport enum Direction {\n FORWARD = \"forward\",\n BACKWARD = \"backward\",\n}\n\nexport type DirectionType = Direction.FORWARD | Direction.BACKWARD;\n\nexport enum HistoryAction {\n PUSH = \"PUSH\",\n POP = \"POP\",\n REPLACE = \"REPLACE\",\n}\n\nexport interface HistoryState {\n /** pathname + search */\n path: string;\n data?: unknown;\n action?: HistoryAction;\n /** 스택 엔트리 고유 key */\n key?: string;\n /** 스택 내 위치 (0 = root) */\n index?: number;\n}\n\nexport type HistoryListener = (state: HistoryState) => void;\n","import { BACK_TIMEOUT_MS } from \"./constants\";\nimport { HistoryAction, HistoryListener, HistoryState } from \"./type\";\n\ntype HistoryEntryState = Omit<HistoryState, \"path\" | \"action\">;\n\nconst isBrowser = () => typeof window !== \"undefined\";\n\nconst listeners = new Set<HistoryListener>();\n\nconst currentPath = () => window.location.pathname + window.location.search;\n\nconst onPopState = (event: PopStateEvent) => {\n const state: HistoryState = {\n path: currentPath(),\n ...((event.state as HistoryState | null) ?? {}),\n action: HistoryAction.POP,\n };\n listeners.forEach((listener) => listener(state));\n};\n\n/**\n * `window.history` 래퍼.\n * - 리스너는 브라우저 popstate(뒤로·앞으로·`go`)에서만 호출된다.\n * - push/replace 는 동기 실행이며 리스너를 호출하지 않는다 (호출자가 상태를 직접 갱신).\n * - popstate 구독은 첫 리스너 등록 시점에 건다 (import 부작용 없음).\n */\nexport const history = {\n push: (path: string, state: HistoryEntryState = {}) => {\n if (!isBrowser()) return;\n window.history.pushState(\n { ...state, path, action: HistoryAction.PUSH },\n \"\",\n path\n );\n },\n\n replace: (path: string, state: HistoryEntryState = {}) => {\n if (!isBrowser()) return;\n window.history.replaceState(\n { ...state, path, action: HistoryAction.REPLACE },\n \"\",\n path\n );\n },\n\n /** `history.go(delta)` 후 popstate 가 오면 true, BACK_TIMEOUT_MS 안에 오지 않으면 false */\n travel: (delta: number): Promise<boolean> => {\n if (!isBrowser()) return Promise.resolve(false);\n return new Promise<boolean>((resolve) => {\n const finish = (popped: boolean) => {\n window.clearTimeout(timer);\n window.removeEventListener(\"popstate\", onPop);\n resolve(popped);\n };\n const onPop = () => finish(true);\n const timer = window.setTimeout(() => finish(false), BACK_TIMEOUT_MS);\n window.addEventListener(\"popstate\", onPop);\n window.history.go(delta);\n });\n },\n\n back: (): Promise<boolean> => history.travel(-1),\n\n forward: () => {\n if (!isBrowser()) return;\n window.history.forward();\n },\n\n go: (delta: number) => {\n if (!isBrowser()) return;\n window.history.go(delta);\n },\n\n getCurrentState: (): HistoryState => {\n if (!isBrowser()) return { path: \"/\" };\n const state = window.history.state as HistoryState | null;\n return state?.path ? state : { path: currentPath() };\n },\n\n addListener: (listener: HistoryListener) => {\n if (!isBrowser()) return () => false;\n if (listeners.size === 0) {\n window.addEventListener(\"popstate\", onPopState);\n }\n listeners.add(listener);\n return () => {\n const removed = listeners.delete(listener);\n if (listeners.size === 0) {\n window.removeEventListener(\"popstate\", onPopState);\n }\n return removed;\n };\n },\n};\n","import React from \"react\";\n\nexport interface StackDevRoadmapProps {\n /** 스택에 쌓인 페이지 경로 (아래 → 위 순) */\n pages: { path: string }[];\n currentPath: string;\n /** false면 렌더하지 않음 */\n visible?: boolean;\n}\n\n/**\n * 개발 환경에서 스택 깊이·경로를 눈으로 확인하는 로드맵 오버레이.\n * StackRouterProvider `enableDevTools` 와 함께 사용합니다.\n */\nexport function StackDevRoadmap({\n pages,\n currentPath,\n visible = true,\n}: StackDevRoadmapProps) {\n if (!visible || pages.length === 0) return null;\n\n const depth = pages.length;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n aria-label={`WebViewKit stack depth ${depth}`}\n style={{\n position: \"fixed\",\n bottom: 12,\n right: 12,\n zIndex: 2147483646,\n minWidth: 200,\n maxWidth: 320,\n padding: \"10px 12px\",\n borderRadius: 10,\n background: \"rgba(7, 11, 18, 0.92)\",\n border: \"1px solid rgba(0, 232, 184, 0.35)\",\n color: \"#e8eef4\",\n fontFamily:\n 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", monospace',\n fontSize: 11,\n lineHeight: 1.45,\n boxShadow: \"0 8px 24px rgba(0,0,0,0.35)\",\n pointerEvents: \"none\",\n }}\n >\n <div style={{ display: \"flex\", justifyContent: \"space-between\", gap: 8 }}>\n <span style={{ color: \"#00e8b8\", fontWeight: 700 }}>WebViewKit</span>\n <span style={{ color: \"#94a3b8\" }}>stack × {depth}</span>\n </div>\n\n {/* 점 → 선 로드맵 */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 0,\n marginTop: 10,\n padding: \"4px 0\",\n }}\n >\n {pages.map((page, index) => {\n const isCurrent = page.path === currentPath;\n const isLast = index === pages.length - 1;\n return (\n <React.Fragment key={`${page.path}-${index}`}>\n {index > 0 && (\n <span\n style={{\n width: 14,\n height: 2,\n background: isLast\n ? \"linear-gradient(90deg,#334155,#00e8b8)\"\n : \"#334155\",\n flexShrink: 0,\n }}\n />\n )}\n <span\n title={page.path}\n style={{\n width: isCurrent ? 12 : 8,\n height: isCurrent ? 12 : 8,\n borderRadius: \"50%\",\n flexShrink: 0,\n background: isCurrent ? \"#00e8b8\" : \"#475569\",\n boxShadow: isCurrent\n ? \"0 0 10px rgba(0,232,184,0.85)\"\n : \"none\",\n transition: \"all 0.2s ease\",\n }}\n />\n </React.Fragment>\n );\n })}\n </div>\n\n <ol style={{ margin: \"8px 0 0\", paddingLeft: 18, color: \"#cbd5e1\" }}>\n {pages.map((page, index) => {\n const isCurrent = index === pages.length - 1;\n return (\n <li\n key={`${page.path}-${index}`}\n style={{\n fontWeight: isCurrent ? 600 : 400,\n color: isCurrent ? \"#00e8b8\" : \"#94a3b8\",\n }}\n >\n {page.path}\n {isCurrent ? \" ← top\" : \"\"}\n </li>\n );\n })}\n </ol>\n </div>\n );\n}\n","import styled from \"@emotion/styled\";\nimport React from \"react\";\nimport { useStackRouter } from \"../stack-router-provider\";\n\ninterface BackRouterProps {\n /** 스크린리더 라벨 */\n label?: string;\n}\n\nconst BackRouter = ({ label = \"뒤로 가기\" }: BackRouterProps) => {\n const { back } = useStackRouter();\n return (\n <BackButton type=\"button\" aria-label={label} onClick={() => back()}>\n <BackIcon />\n </BackButton>\n );\n};\n\nexport default BackRouter;\n\n/**\n styles\n */\n\nconst BackButton = styled.button`\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border: none;\n background: none;\n cursor: pointer;\n padding: 8px;\n border-radius: 50%;\n transition: all 0.2s;\n color: var(--wvk-back-color, #000000);\n\n &:hover {\n color: var(--wvk-back-hover-color, #666666);\n }\n\n &:active {\n color: var(--wvk-back-active-color, #999999);\n }\n`;\n\nconst BackIcon = () => (\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M12 20L4 12L12 4\"\n stroke=\"currentColor\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n);\n","import styled from \"@emotion/styled\";\nimport React, {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useRef,\n} from \"react\";\nimport {\n DEV_MOUNTED_PAGES_WARN,\n KEEP_ALIVE_LIMIT,\n STACK_TRANSITION_MS,\n} from \"../constants\";\nimport { StackDevRoadmap } from \"../stack-dev/stack-dev-roadmap\";\nimport type {\n Activity,\n HistoryState,\n StackRouterProviderProps,\n VisiblePage,\n} from \"../type\";\nimport StackHeader from \"./_components/header\";\nimport StackPage from \"./_components/stack-page\";\nimport { ActivityContext } from \"./activity-context\";\nimport { getRenderedPages, type StackEntry } from \"./stack-reducer\";\nimport { usePrefersReducedMotion } from \"./use-prefers-reduced-motion\";\nimport { useStackBridgeSync } from \"./use-stack-bridge-sync\";\nimport { useStackNavigation } from \"./use-stack-navigation\";\n\nexport interface StackRouterContextValue {\n currentPath: string;\n /** top 엔트리의 history state */\n currentState: HistoryState;\n depth: number;\n canGoBack: boolean;\n isTransitioning: boolean;\n entries: StackEntry[];\n /** 1.x 호환 */\n visiblePages: VisiblePage[];\n Activities: Activity[];\n initialActivity: Activity;\n push: (path: string, data?: unknown) => boolean;\n replace: (path: string, data?: unknown) => boolean;\n reset: (path: string, data?: unknown) => boolean;\n /** 루트만 남기고 path 를 push 한다 (스택: [루트, path]) */\n resetPush: (path: string, data?: unknown) => boolean;\n back: () => boolean;\n pop: (count?: number) => boolean;\n popTo: (path: string) => boolean;\n /** @deprecated 스택과 동기화되지 않는다. 브라우저 forward 는 popstate 로 처리된다 */\n forward: () => void;\n}\n\nconst StackRouterContext = createContext<StackRouterContextValue | null>(null);\n\nexport const useStackRouter = () => {\n const context = useContext(StackRouterContext);\n if (!context) {\n throw new Error(\"useStackRouter must be used within a StackRouterProvider\");\n }\n return context;\n};\n\nconst isDevEnv = () =>\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"development\";\n\nconst MIN_MOUNTED_PAGES = 1;\n/** 보관(cached) 페이지의 useActivity().index */\nconst CACHED_ACTIVITY_INDEX = -1;\n\nconst StackRouterProvider = ({\n initialActivity,\n Activities = [],\n maxWidth = \"600px\",\n isShowHeader = false,\n enableDevTools,\n transition = \"slide\",\n duration = STACK_TRANSITION_MS,\n restoreStack = \"with-root\",\n keepAliveLimit = KEEP_ALIVE_LIMIT,\n maxMountedPages,\n safeArea = false,\n onBackAtRoot,\n onNotFound,\n bridge,\n}: StackRouterProviderProps) => {\n const reducedMotion = usePrefersReducedMotion();\n const effectiveDuration =\n transition === \"none\" || reducedMotion ? 0 : duration;\n\n const navigation = useStackNavigation({\n initialActivity,\n activities: Activities,\n duration: effectiveDuration,\n restoreStack,\n keepAliveLimit,\n onBackAtRoot,\n onNotFound,\n });\n const { state, endTransition } = navigation;\n\n const elementFor = (pattern: string) =>\n Activities.find((activity) => activity.path === pattern)?.element ??\n (initialActivity.path === pattern ? initialActivity.element : null);\n\n const top = state.entries[state.entries.length - 1];\n\n const value = useMemo<StackRouterContextValue>(\n () => ({\n currentPath: top.path,\n currentState: {\n path: top.path,\n data: top.data,\n key: top.key,\n index: state.entries.length - 1,\n },\n depth: state.entries.length,\n canGoBack: state.entries.length > 1,\n isTransitioning: state.transition !== null,\n entries: state.entries,\n visiblePages: state.entries.map((entry) => ({\n path: entry.path,\n element: elementFor(entry.pattern),\n })),\n Activities,\n initialActivity,\n push: navigation.push,\n replace: navigation.replace,\n reset: navigation.reset,\n resetPush: navigation.resetPush,\n back: navigation.back,\n pop: navigation.pop,\n popTo: navigation.popTo,\n forward: () => window.history.forward(),\n }),\n [state, Activities, initialActivity, navigation]\n );\n\n useStackBridgeSync(bridge, value, onBackAtRoot);\n\n const direction = state.transition?.type ?? \"push\";\n const pages = getRenderedPages(state);\n const stackIndexByKey = new Map(\n state.entries.map((entry, index) => [entry.key, index])\n );\n // useActivity().index: 스택 위치. 퇴장 중이면 빠지기 전 위치, 보관 중이면 -1\n const activityIndexOf = (entry: StackEntry) => {\n const stackIndex = stackIndexByKey.get(entry.key);\n if (stackIndex !== undefined) return stackIndex;\n const leavingIndex = state.leaving.findIndex(\n (item) => item.key === entry.key\n );\n return leavingIndex === -1\n ? CACHED_ACTIVITY_INDEX\n : state.entries.length + leavingIndex;\n };\n const mountLimit =\n maxMountedPages === undefined || !Number.isFinite(maxMountedPages)\n ? Infinity\n : Math.max(MIN_MOUNTED_PAGES, maxMountedPages);\n // 직전 렌더에서 마운트돼 있던 key. 퇴장 페이지를 슬라이드만 하려고 새로 마운트하지 않기 위함\n const mountedKeysRef = useRef<Set<string>>(new Set());\n const wasMounted = mountedKeysRef.current;\n const shouldMount = (page: (typeof pages)[number]) => {\n const { entry, pageState } = page;\n // cached 페이지와 keepAlive 엔트리는 항상 마운트\n if (pageState === \"cached\" || entry.keepAlive) return true;\n const stackIndex = stackIndexByKey.get(entry.key);\n // 스택 밖(퇴장 중) 페이지는 이미 마운트돼 있던 경우에만 유지\n if (stackIndex === undefined) return wasMounted.has(entry.key);\n if (pageState === \"enter\" || pageState === \"exit\") return true;\n return state.entries.length - stackIndex <= mountLimit;\n };\n const mountedKeys = new Set(\n pages.filter(shouldMount).map((page) => page.entry.key)\n );\n mountedKeysRef.current = mountedKeys;\n const mountedCount = mountedKeys.size;\n\n // DOM 이동은 스크롤 위치를 초기화하므로 key 의 최초 렌더 순서로 DOM 순서를 고정한다.\n // 쌓임 순서는 getRenderedPages 위치(zIndex)로 표현한다.\n const domOrderRef = useRef<string[]>([]);\n const currentKeys = new Set(pages.map((page) => page.entry.key));\n const knownKeys = new Set(domOrderRef.current);\n domOrderRef.current = [\n ...domOrderRef.current.filter((key) => currentKeys.has(key)),\n ...pages.map((page) => page.entry.key).filter((key) => !knownKeys.has(key)),\n ];\n const domOrder = domOrderRef.current;\n const domPages = pages\n .map((page, index) => ({ page, index }))\n .sort(\n (a, b) =>\n domOrder.indexOf(a.page.entry.key) - domOrder.indexOf(b.page.entry.key)\n );\n\n const hasWarnedRef = useRef(false);\n useEffect(() => {\n if (\n hasWarnedRef.current ||\n !isDevEnv() ||\n mountedCount <= DEV_MOUNTED_PAGES_WARN\n ) {\n return;\n }\n hasWarnedRef.current = true;\n console.warn(\n `[webviewkit] 마운트된 페이지가 ${mountedCount}개입니다. 메모리 사용이 커질 수 있으니 maxMountedPages 로 상한을 두세요.`\n );\n }, [mountedCount]);\n\n const showDevTools = enableDevTools ?? isDevEnv();\n\n return (\n <StackRouterContext.Provider value={value}>\n <LayoutContainer safeArea={safeArea}>\n <Layout maxWidth={maxWidth} data-testid=\"layout\">\n <PageContainer>\n {domPages.map(({ page, index }) => {\n const { entry, pageState, isTop } = page;\n return (\n <ActivityContext.Provider\n key={entry.key}\n value={{\n key: entry.key,\n path: entry.path,\n pattern: entry.pattern,\n params: entry.params,\n query: entry.query,\n data: entry.data,\n index: activityIndexOf(entry),\n isTop,\n isCached: pageState === \"cached\",\n revision: entry.revision ?? 0,\n }}\n >\n <StackPage\n pageState={pageState}\n direction={direction}\n transitionType={transition}\n duration={effectiveDuration}\n zIndex={index}\n isTop={isTop}\n onAnimationEnd={\n pageState === \"enter\" ? endTransition : undefined\n }\n >\n {mountedKeys.has(entry.key) && isShowHeader && (\n <StackHeader />\n )}\n {mountedKeys.has(entry.key)\n ? elementFor(entry.pattern)\n : null}\n </StackPage>\n </ActivityContext.Provider>\n );\n })}\n </PageContainer>\n </Layout>\n </LayoutContainer>\n <StackDevRoadmap\n visible={showDevTools}\n pages={state.entries.map((entry) => ({ path: entry.path }))}\n currentPath={top.path}\n />\n </StackRouterContext.Provider>\n );\n};\n\nexport default StackRouterProvider;\nexport { StackRouterProvider };\n\n/**styles */\nconst LayoutContainer = styled.div<{ safeArea: boolean }>`\n width: 100%;\n height: 100vh;\n height: 100dvh;\n display: flex;\n justify-content: center;\n background: var(--wvk-page-bg, #ffffff);\n box-sizing: border-box;\n ${({ safeArea }) =>\n safeArea\n ? `padding: env(safe-area-inset-top) env(safe-area-inset-right)\n env(safe-area-inset-bottom) env(safe-area-inset-left);`\n : \"\"}\n`;\n\nconst Layout = styled.div<{ maxWidth: string }>`\n width: 100%;\n max-width: ${({ maxWidth }) => maxWidth};\n height: 100%;\n display: flex;\n flex-direction: column;\n position: relative;\n overflow: hidden;\n`;\n\nconst PageContainer = styled.div`\n position: relative;\n flex: 1;\n width: 100%;\n overflow: hidden;\n`;\n","import styled from \"@emotion/styled\";\nimport React, { useContext } from \"react\";\nimport { ActivityContext } from \"../activity-context\";\nimport { useStackRouter } from \"../stack-router-provider\";\nimport BackRouter from \"./back-router\";\n\ninterface StackHeaderProps {\n /** 기본: 이 헤더가 속한 페이지의 path */\n title?: React.ReactNode;\n}\n\n/**\n * 페이지 안에 있으면 그 페이지 기준(제목·back 버튼)으로 그려 페이지와 함께 전환된다.\n * 페이지 밖이면 현재 top 기준.\n */\nconst Header = ({ title }: StackHeaderProps) => {\n const activity = useContext(ActivityContext);\n const { currentPath, canGoBack } = useStackRouter();\n const path = activity?.path ?? currentPath;\n const showBack = activity ? activity.index > 0 : canGoBack;\n\n return (\n <StyledHeader>\n {showBack && <BackRouter />}\n <StyledTitle>{title ?? path}</StyledTitle>\n </StyledHeader>\n );\n};\n\n/**\n styles\n */\n\nconst StyledHeader = styled.header`\n position: sticky;\n top: 0;\n z-index: 1;\n width: 100%;\n height: 64px;\n flex-shrink: 0;\n box-sizing: border-box;\n background-color: var(--wvk-header-bg, #ffffff);\n border-bottom: 1px solid var(--wvk-header-border, #e5e7eb);\n display: flex;\n align-items: center;\n padding: 0 1rem;\n`;\n\nconst StyledTitle = styled.h1`\n margin: 0;\n min-width: 0;\n font-size: 1.25rem;\n font-weight: 600;\n color: var(--wvk-header-color, #111827);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n`;\n\nexport default Header;\n","import { createContext, useContext, useEffect, useRef } from \"react\";\n\nexport interface ActivityContextValue {\n key: string;\n path: string;\n pattern: string;\n params: Record<string, string>;\n query: Record<string, string>;\n data?: unknown;\n /** 스택 내 위치 (0 = root). 퇴장 중이면 빠지기 전 위치, 보관 중이면 -1 */\n index: number;\n isTop: boolean;\n /** keepAlive 로 보관 중인 페이지 (스택에서는 빠졌지만 마운트 유지) */\n isCached: boolean;\n /** 이 인스턴스가 새 data 로 재사용(보관본 되살리기·resetPush 재사용)된 횟수 */\n revision: number;\n}\n\nexport const ActivityContext = createContext<ActivityContextValue | null>(null);\n\n/** 현재 페이지(Activity) 자신의 path·params·query·data */\nexport function useActivity(): ActivityContextValue {\n const context = useContext(ActivityContext);\n if (!context) {\n throw new Error(\n \"useActivity must be used inside a StackRouterProvider page\"\n );\n }\n return context;\n}\n\n/** `/detail/:id` → `{ id }` */\nexport function useParams<\n TParams extends Record<string, string> = Record<string, string>,\n>(): TParams {\n return useActivity().params as TParams;\n}\n\n/**\n * 이 페이지 인스턴스가 새 data 로 재사용될 때마다 1회 호출: 보관본이 되살아날 때,\n * resetPush 가 스택 안 인스턴스를 재사용할 때. 첫 마운트에는 호출하지 않는다\n */\nexport function useOnRevive(callback: (data: unknown) => void): void {\n const { revision, data } = useActivity();\n const callbackRef = useRef(callback);\n callbackRef.current = callback;\n const lastRevisionRef = useRef(revision);\n\n useEffect(() => {\n if (revision > lastRevisionRef.current) callbackRef.current(data);\n lastRevisionRef.current = revision;\n }, [revision, data]);\n}\n","import { css, keyframes } from \"@emotion/react\";\nimport styled from \"@emotion/styled\";\nimport React, { useLayoutEffect, useRef } from \"react\";\nimport type { StackTransitionType } from \"../../type\";\nimport type { PageState } from \"../stack-reducer\";\n\ntype Direction = \"push\" | \"pop\";\n\n/**\n * iOS UINavigationController 전환을 따른다.\n * - 위 페이지: 화면 오른쪽 끝 ↔ 0, 왼쪽 가장자리 그림자\n * - 아래 페이지: 0 ↔ -30% 패럴랙스, 투명도 대신 검은 dim 레이어\n * - 곡선: 빠르게 출발해 천천히 멈추는 iOS 기본 감속 곡선\n */\nconst IOS_EASING = \"cubic-bezier(0.32, 0.72, 0, 1)\";\nconst FADE_EASING = \"ease\";\nconst PARALLAX_OFFSET = \"-30%\";\nconst EDGE_SHADOW = \"var(--wvk-edge-shadow, -6px 0 24px rgba(0, 0, 0, 0.12))\";\n\n// 그림자는 dim 과 함께 나타나고 사라진다. 고정이면 back 끝까지 진하게 남는다\nconst coverIn = keyframes`\n from { transform: translate3d(100%, 0, 0); box-shadow: none; }\n to { transform: translate3d(0, 0, 0); box-shadow: ${EDGE_SHADOW}; }\n`;\nconst coverOut = keyframes`\n from { transform: translate3d(0, 0, 0); box-shadow: ${EDGE_SHADOW}; }\n to { transform: translate3d(100%, 0, 0); box-shadow: none; }\n`;\nconst parallaxOut = keyframes`\n from { transform: translate3d(0, 0, 0); }\n to { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }\n`;\nconst parallaxIn = keyframes`\n from { transform: translate3d(${PARALLAX_OFFSET}, 0, 0); }\n to { transform: translate3d(0, 0, 0); }\n`;\nconst dimIn = keyframes`\n from { opacity: 0; }\n to { opacity: 1; }\n`;\nconst dimOut = keyframes`\n from { opacity: 1; }\n to { opacity: 0; }\n`;\nconst fadeIn = keyframes`\n from { opacity: 0; }\n to { opacity: 1; }\n`;\nconst fadeOut = keyframes`\n from { opacity: 1; }\n to { opacity: 0; }\n`;\n\ntype Layer = \"upper\" | \"lower\";\n\n/** push 의 enter·pop 의 exit 는 위에서 움직이는 페이지, 나머지는 아래 페이지 */\nconst layerOf = (direction: Direction, pageState: \"enter\" | \"exit\"): Layer =>\n (direction === \"push\") === (pageState === \"enter\") ? \"upper\" : \"lower\";\n\nfunction slideStyles(\n direction: Direction,\n pageState: \"enter\" | \"exit\",\n duration: number\n) {\n const timing = `${duration}ms ${IOS_EASING} forwards`;\n if (layerOf(direction, pageState) === \"upper\") {\n return css`\n animation: ${direction === \"push\" ? coverIn : coverOut} ${timing};\n `;\n }\n return css`\n animation: ${direction === \"push\" ? parallaxOut : parallaxIn} ${timing};\n &::after {\n content: \"\";\n /* transform 중인 페이지 기준 fixed = 스크롤과 무관하게 페이지 전체를 덮음 */\n position: fixed;\n inset: 0;\n pointer-events: none;\n background: var(--wvk-dim-color, rgba(0, 0, 0, 0.12));\n animation: ${direction === \"push\" ? dimIn : dimOut} ${timing};\n }\n `;\n}\n\ninterface PageWrapperProps {\n pageState: PageState;\n direction: Direction;\n transitionType: StackTransitionType;\n duration: number;\n zIndex: number;\n}\n\nconst PageWrapper = styled.div<PageWrapperProps>`\n position: absolute;\n inset: 0;\n overflow: auto;\n -webkit-overflow-scrolling: touch;\n background: var(--wvk-page-bg, #ffffff);\n z-index: ${({ zIndex }) => zIndex};\n visibility: ${({ pageState }) =>\n pageState === \"covered\" || pageState === \"cached\" ? \"hidden\" : \"visible\"};\n ${({ pageState, direction, transitionType, duration }) => {\n if (pageState !== \"enter\" && pageState !== \"exit\") return \"\";\n if (transitionType === \"none\" || duration === 0) return \"\";\n if (transitionType === \"fade\") {\n return css`\n will-change: opacity;\n animation: ${pageState === \"enter\" ? fadeIn : fadeOut} ${duration}ms\n ${FADE_EASING} forwards;\n `;\n }\n return css`\n will-change: transform;\n ${slideStyles(direction, pageState, duration)}\n `;\n }}\n`;\n\ninterface StackPageProps extends PageWrapperProps {\n isTop: boolean;\n onAnimationEnd?: () => void;\n children: React.ReactNode;\n}\n\n/** 스택 한 장. top 이 아니면 inert·aria-hidden (스크린리더·포커스 차단) */\nexport default function StackPage({\n isTop,\n onAnimationEnd,\n children,\n ...wrapperProps\n}: StackPageProps) {\n const ref = useRef<HTMLDivElement>(null);\n\n useLayoutEffect(() => {\n // ponytail: React 18/19 의 inert prop 처리가 달라 DOM 속성을 직접 토글\n ref.current?.toggleAttribute(\"inert\", !isTop);\n }, [isTop]);\n\n return (\n <PageWrapper\n ref={ref}\n {...wrapperProps}\n data-state={wrapperProps.pageState}\n aria-hidden={isTop ? undefined : true}\n onAnimationEnd={(event) => {\n // dim(::after) 애니메이션 종료는 무시하고 페이지 자체 전환만 본다\n if (event.target === event.currentTarget && !event.pseudoElement) {\n onAnimationEnd?.();\n }\n }}\n >\n {children}\n </PageWrapper>\n );\n}\n","export interface StackEntry {\n key: string;\n /** 실제 URL (pathname + search) */\n path: string;\n /** 매칭된 Activity path 패턴 */\n pattern: string;\n params: Record<string, string>;\n query: Record<string, string>;\n data?: unknown;\n /** true 면 스택에서 빠져도 보관 목록(cached)에 남긴다 */\n keepAlive?: boolean;\n /** 기존 인스턴스를 새 data 로 재사용(REVIVE·RESET_PUSH)할 때마다 1씩 오른다. 없으면 0 */\n revision?: number;\n}\n\nexport type StackTransition =\n | { type: \"push\"; enterKey: string; exitKey: string }\n | { type: \"pop\"; enterKey: string; exitKeys: string[] }\n | null;\n\nexport interface StackState {\n entries: StackEntry[];\n /** pop 애니메이션 중인 엔트리. END_TRANSITION 에서 제거 */\n leaving: StackEntry[];\n transition: StackTransition;\n /** 스택에서 빠졌지만 살려 둔 keepAlive 엔트리 (오래된 → 최근) */\n cached: StackEntry[];\n /** 스택 안 keepAlive 엔트리를 포함한 최대 보관 수. 0 이면 보관 안 함 */\n cacheLimit: number;\n}\n\nexport type StackAction =\n | { type: \"PUSH\"; entry: StackEntry; animate: boolean }\n | { type: \"REPLACE\"; entry: StackEntry }\n | { type: \"POP_TO\"; index: number; animate: boolean }\n | { type: \"RESET\"; entry: StackEntry }\n | { type: \"RESET_PUSH\"; entry: StackEntry; animate: boolean }\n | { type: \"RESTORE\"; entries: StackEntry[] }\n | {\n type: \"REVIVE\";\n entry: StackEntry;\n direction: \"push\" | \"pop\";\n /** 되살린 뒤 entry 의 스택 위치 */\n index: number;\n animate: boolean;\n }\n | { type: \"END_TRANSITION\" };\n\nconst topOf = (entries: StackEntry[]) => entries[entries.length - 1];\n\n/** 기존 인스턴스를 재사용한다는 표시 (useOnRevive 트리거) */\nconst bumpRevision = (entry: StackEntry): StackEntry => ({\n ...entry,\n revision: (entry.revision ?? 0) + 1,\n});\n\nexport function createStackState(\n entry: StackEntry,\n cacheLimit = 0\n): StackState {\n return {\n entries: [entry],\n leaving: [],\n transition: null,\n cached: [],\n cacheLimit,\n };\n}\n\n/** 스택에서 빠진 keepAlive 엔트리를 보관 목록 뒤에 붙인 새 목록 */\nfunction cacheEntries(state: StackState, removed: StackEntry[]): StackEntry[] {\n const { entries, cached, cacheLimit } = state;\n const incoming = removed.filter((entry) => entry.keepAlive);\n if (cacheLimit <= 0 || incoming.length === 0) return cached;\n const incomingPaths = new Set(incoming.map((entry) => entry.path));\n const merged = [\n ...cached.filter((entry) => !incomingPaths.has(entry.path)),\n ...incoming,\n ];\n const capacity = cacheLimit - entries.filter((e) => e.keepAlive).length;\n return capacity > 0 ? merged.slice(-capacity) : [];\n}\n\n/** replace·reset 의 새 엔트리와 path 가 같은 보관본·지워질 엔트리는 버린다 */\nfunction withoutPath(list: StackEntry[], path: string): StackEntry[] {\n return list.filter((entry) => entry.path !== path);\n}\n\n/** 퇴장 중이던 엔트리 중 결과 스택에 없는 것만 보관한다 (END_TRANSITION 과 공용) */\nfunction flushLeaving(state: StackState, nextEntries: StackEntry[]) {\n const alive = new Set(nextEntries.map((entry) => entry.key));\n const removed = state.leaving.filter((entry) => !alive.has(entry.key));\n return cacheEntries({ ...state, entries: nextEntries }, removed);\n}\n\n/** 보관 목록에서 되살린 엔트리를 스택에 올린다 */\nfunction revive(\n state: StackState,\n action: Extract<StackAction, { type: \"REVIVE\" }>\n): StackState {\n const { direction, index, animate } = action;\n const entry = bumpRevision(action.entry);\n const previousTop = topOf(state.entries);\n const entries = [...state.entries.slice(0, index), entry];\n const removed = state.entries.slice(index);\n const cached = state.cached.filter((item) => item.key !== entry.key);\n const base = { ...state, entries, cached };\n if (!animate || (direction === \"pop\" && removed.length === 0)) {\n return {\n ...base,\n cached: cacheEntries(base, removed),\n leaving: [],\n transition: null,\n };\n }\n if (direction === \"push\") {\n // 이전 top 이 스택에서 빠졌으면 퇴장 애니메이션 동안만 leaving 에 둔다\n const stillInStack = !removed.includes(previousTop);\n return {\n ...base,\n cached: cacheEntries(\n base,\n removed.filter((item) => item !== previousTop)\n ),\n leaving: stillInStack ? [] : [previousTop],\n transition: {\n type: \"push\",\n enterKey: entry.key,\n exitKey: previousTop.key,\n },\n };\n }\n return {\n ...base,\n leaving: removed,\n transition: {\n type: \"pop\",\n enterKey: entry.key,\n exitKeys: removed.map((item) => item.key),\n },\n };\n}\n\n/** path 가 같은 되살릴 엔트리를 찾는다. includeRemovable 이면 지워질 스택 쪽(keepAlive)을 먼저 본다 */\nexport function findRevivable(\n state: StackState,\n path: string,\n opts: { includeRemovable?: boolean } = {}\n): StackEntry | undefined {\n const matches = (entry: StackEntry) => entry.path === path;\n const fromStack = opts.includeRemovable\n ? [...state.entries.slice(1)]\n .reverse()\n .find((entry) => entry.keepAlive && matches(entry))\n : undefined;\n return (\n fromStack ?? [...state.cached].reverse().find((entry) => matches(entry))\n );\n}\n\nconst OVERWRITES_LEAVING = new Set<StackAction[\"type\"]>([\n \"PUSH\",\n \"POP_TO\",\n \"RESET\",\n \"RESET_PUSH\",\n \"RESTORE\",\n \"REVIVE\",\n]);\n\nexport function stackReducer(\n state: StackState,\n action: StackAction\n): StackState {\n if (!OVERWRITES_LEAVING.has(action.type) || state.leaving.length === 0) {\n return reduce(state, action);\n }\n // 전환 중 다른 액션이 leaving 을 덮어쓰기 전에 퇴장 중인 keepAlive 를 보관한다\n const settled = { ...state, leaving: [] };\n const next = reduce(settled, action);\n if (next === settled) return state;\n return reduce(\n { ...settled, cached: flushLeaving(state, next.entries) },\n action\n );\n}\n\nfunction reduce(state: StackState, action: StackAction): StackState {\n switch (action.type) {\n case \"PUSH\": {\n const previousTop = topOf(state.entries);\n return {\n ...state,\n entries: [...state.entries, action.entry],\n leaving: [],\n transition: action.animate\n ? {\n type: \"push\",\n enterKey: action.entry.key,\n exitKey: previousTop.key,\n }\n : null,\n };\n }\n case \"REPLACE\": {\n const entries = [...state.entries.slice(0, -1), action.entry];\n const { path } = action.entry;\n return {\n ...state,\n entries,\n cached: cacheEntries(\n { ...state, entries, cached: withoutPath(state.cached, path) },\n withoutPath([topOf(state.entries)], path)\n ),\n };\n }\n case \"POP_TO\": {\n const index = Math.max(0, action.index);\n if (index >= state.entries.length - 1) return state;\n const entries = state.entries.slice(0, index + 1);\n const leaving = state.entries.slice(index + 1);\n if (!action.animate) {\n return {\n ...state,\n entries,\n leaving: [],\n transition: null,\n cached: cacheEntries({ ...state, entries }, leaving),\n };\n }\n return {\n ...state,\n entries,\n leaving,\n transition: {\n type: \"pop\",\n enterKey: topOf(entries).key,\n exitKeys: leaving.map((entry) => entry.key),\n },\n };\n }\n case \"RESET\": {\n const next = createStackState(action.entry, state.cacheLimit);\n const { path } = action.entry;\n return {\n ...next,\n cached: cacheEntries(\n {\n ...state,\n entries: next.entries,\n cached: withoutPath(state.cached, path),\n },\n withoutPath(state.entries, path)\n ),\n };\n }\n case \"REVIVE\":\n return revive(state, action);\n case \"RESET_PUSH\": {\n // 루트만 남기고 새 엔트리를 쌓는다. 이전 top 은 퇴장 애니메이션 동안만 남긴다\n const [root] = state.entries;\n const previousTop = topOf(state.entries);\n // 재사용하는 엔트리(같은 key)는 보관하지 않고 원래 있던 곳에서 뺀다\n const reusedKey = action.entry.key;\n const isReused = [...state.entries, ...state.cached].some(\n (entry) => entry.key === reusedKey\n );\n const entries = [\n root,\n isReused ? bumpRevision(action.entry) : action.entry,\n ];\n const sameTop = previousTop.key === reusedKey;\n // animate 면 이전 top 은 END_TRANSITION 에서 보관하고, 나머지는 지금 보관한다\n const dropped = (\n action.animate ? state.entries.slice(1, -1) : state.entries.slice(1)\n ).filter((entry) => entry.key !== reusedKey);\n const cached = state.cached.filter((entry) => entry.key !== reusedKey);\n const exiting = action.animate && !sameTop;\n return {\n ...state,\n entries,\n cached: cacheEntries({ ...state, entries, cached }, dropped),\n leaving: exiting ? [previousTop] : [],\n transition: exiting\n ? {\n type: \"push\",\n enterKey: action.entry.key,\n exitKey: previousTop.key,\n }\n : null,\n };\n }\n case \"RESTORE\":\n return {\n ...state,\n entries: action.entries,\n leaving: [],\n transition: null,\n };\n case \"END_TRANSITION\": {\n if (!state.transition && state.leaving.length === 0) return state;\n // resetPush 로 루트가 leaving 에 남은 경우처럼 스택에 아직 있는 엔트리는 보관하지 않는다\n return {\n ...state,\n leaving: [],\n transition: null,\n cached: flushLeaving(state, state.entries),\n };\n }\n default:\n return state;\n }\n}\n\nexport type PageState = \"enter\" | \"exit\" | \"idle\" | \"covered\" | \"cached\";\n\n/** 렌더 순서(아래 → 위)와 각 페이지의 data-state */\nexport function getRenderedPages(\n state: StackState\n): { entry: StackEntry; pageState: PageState; isTop: boolean }[] {\n const { entries, leaving, transition, cached } = state;\n const top = topOf(entries);\n // push 중 퇴장하는 엔트리(resetPush)는 새 top 아래에 그린다\n const ordered =\n transition?.type === \"push\"\n ? [...entries.slice(0, -1), ...leaving, top]\n : [...entries, ...leaving];\n const cachedPages = cached.map((entry) => ({\n entry,\n pageState: \"cached\" as PageState,\n isTop: false,\n }));\n const stackPages = ordered.map((entry) => {\n const isTop = entry.key === top.key;\n let pageState: PageState = isTop ? \"idle\" : \"covered\";\n if (transition?.type === \"push\") {\n if (entry.key === transition.enterKey) pageState = \"enter\";\n if (entry.key === transition.exitKey) pageState = \"exit\";\n }\n if (transition?.type === \"pop\") {\n if (entry.key === transition.enterKey) pageState = \"enter\";\n if (transition.exitKeys.includes(entry.key)) pageState = \"exit\";\n }\n return { entry, pageState, isTop };\n });\n return [...cachedPages, ...stackPages];\n}\n","import { useEffect, useState } from \"react\";\n\nconst QUERY = \"(prefers-reduced-motion: reduce)\";\n\nconst getMediaQuery = () =>\n typeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n ? window.matchMedia(QUERY)\n : null;\n\n/** OS \"동작 줄이기\" 설정 */\nexport function usePrefersReducedMotion(): boolean {\n const [reduced, setReduced] = useState(\n () => getMediaQuery()?.matches ?? false\n );\n\n useEffect(() => {\n const mediaQuery = getMediaQuery();\n if (!mediaQuery) return;\n const onChange = () => setReduced(mediaQuery.matches);\n mediaQuery.addEventListener?.(\"change\", onChange);\n return () => mediaQuery.removeEventListener?.(\"change\", onChange);\n }, []);\n\n return reduced;\n}\n","import { useEffect, useRef } from \"react\";\nimport { createWebViewBridgeClient } from \"../bridge/client\";\nimport { detectBridgeHost, isNativeBridgeHost } from \"../bridge/detect-host\";\nimport type { BridgeError } from \"../bridge/errors\";\nimport { installBridgeHost } from \"../bridge/host\";\nimport type { BridgeEnvelope } from \"../bridge/protocol\";\nimport type { AllowUrl } from \"../bridge/url-policy\";\n\nexport interface StackBridgeSyncOptions {\n allowUrl?: AllowUrl;\n onError?: (error: BridgeError, envelope?: BridgeEnvelope) => void;\n /** 웹 스택 변경 시 `stack.changed` 전송 (기본 true) */\n emitStackChanged?: boolean;\n}\n\ninterface StackRouterLike {\n depth: number;\n currentPath: string;\n canGoBack: boolean;\n push: (path: string) => boolean;\n replace: (path: string) => boolean;\n reset: (path: string) => boolean;\n back: () => boolean;\n}\n\n/**\n * StackRouterProvider ↔ 네이티브 브릿지 연결.\n * - native `stack.*` → 라우터 push/replace/reset/back\n * - native `back.request` → canGoBack 이면 back, 아니면 onBackAtRoot. `{ handled }` 회신\n * - web 스택 변경 → `stack.changed { depth, path }`\n */\nexport function useStackBridgeSync(\n bridge: boolean | StackBridgeSyncOptions | undefined,\n router: StackRouterLike,\n onBackAtRoot?: () => void\n): void {\n const enabled = Boolean(bridge);\n const options = typeof bridge === \"object\" ? bridge : {};\n const latest = useRef({ router, options, onBackAtRoot });\n latest.current = { router, options, onBackAtRoot };\n\n useEffect(() => {\n if (!enabled) return;\n return installBridgeHost({\n allowUrl: latest.current.options.allowUrl,\n onError: (error, envelope) =>\n latest.current.options.onError?.(error, envelope),\n stack: {\n push: (url) => latest.current.router.push(url),\n replace: (url) => latest.current.router.replace(url),\n reset: (url) => latest.current.router.reset(url),\n pop: () => latest.current.router.back(),\n },\n onBackRequest: () => {\n const current = latest.current;\n if (current.router.canGoBack) return current.router.back();\n current.onBackAtRoot?.();\n return false;\n },\n });\n }, [enabled]);\n\n const { depth, currentPath } = router;\n const emit = enabled && options.emitStackChanged !== false;\n useEffect(() => {\n if (!emit || !isNativeBridgeHost(detectBridgeHost())) return;\n createWebViewBridgeClient()\n .notifyStackChanged({ depth, path: currentPath })\n .catch((error: BridgeError) => latest.current.options.onError?.(error));\n }, [emit, depth, currentPath]);\n}\n","import { useCallback, useEffect, useReducer, useRef } from \"react\";\nimport { createBridgeId } from \"../bridge/protocol\";\nimport { KEEP_ALIVE_LIMIT, TRANSITION_END_GRACE_MS } from \"../constants\";\nimport { history } from \"../history\";\nimport type { Activity, HistoryState, RestoreStackPolicy } from \"../type\";\nimport { findActivity, type PathMatch } from \"./match-path\";\nimport {\n createStackState,\n findRevivable,\n type StackEntry,\n stackReducer,\n type StackState,\n} from \"./stack-reducer\";\n\nexport interface StackNavigationOptions {\n initialActivity: Activity;\n activities: Activity[];\n /** 0 이면 애니메이션 없이 즉시 전환 */\n duration: number;\n restoreStack: RestoreStackPolicy;\n /** keepAlive 페이지 최대 보관 수. 0 이면 보관·되살리기 안 함 */\n keepAliveLimit: number;\n onBackAtRoot?: () => void;\n onNotFound?: (path: string) => void;\n}\n\nexport interface StackNavigation {\n state: StackState;\n push: (path: string, data?: unknown) => boolean;\n replace: (path: string, data?: unknown) => boolean;\n reset: (path: string, data?: unknown) => boolean;\n resetPush: (path: string, data?: unknown) => boolean;\n back: () => boolean;\n pop: (count?: number) => boolean;\n popTo: (path: string) => boolean;\n endTransition: () => void;\n}\n\nconst isDev = () =>\n typeof process !== \"undefined\" && process.env?.NODE_ENV !== \"production\";\n\n/** cacheLimit 이 0 이면 keepAlive 라우트도 일반 엔트리로 만든다 (기능 끔) */\nfunction createEntry(\n hit: { activity: Activity; match: PathMatch },\n path: string,\n cacheLimit: number,\n data?: unknown,\n key: string = createBridgeId()\n): StackEntry {\n return {\n key,\n path,\n pattern: hit.activity.path,\n params: hit.match.params,\n query: hit.match.query,\n data,\n keepAlive: hit.activity.keepAlive === true && cacheLimit > 0,\n };\n}\n\nconst currentUrl = () => window.location.pathname + window.location.search;\n\n/** 스택 상태 + 내비게이션. 모든 브라우저 이동(back/forward)은 popstate 한 경로로 처리 */\nexport function useStackNavigation(\n options: StackNavigationOptions\n): StackNavigation {\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const [state, dispatch] = useReducer(stackReducer, undefined, () => {\n const { initialActivity } = options;\n const cacheLimit = options.keepAliveLimit ?? KEEP_ALIVE_LIMIT;\n return createStackState(\n createEntry(\n { activity: initialActivity, match: { params: {}, query: {} } },\n initialActivity.path,\n cacheLimit\n ),\n cacheLimit\n );\n });\n const stateRef = useRef(state);\n stateRef.current = state;\n // keepAliveLimit 은 마운트 시 1회만 읽는다 (state.cacheLimit)\n const newEntry = (\n hit: { activity: Activity; match: PathMatch },\n path: string,\n data?: unknown,\n key?: string\n ) => createEntry(hit, path, stateRef.current.cacheLimit, data, key);\n\n // 전환 중 입력 잠금 (같은 tick 연타까지 막기 위해 ref)\n const busyRef = useRef(false);\n // 루트로 되감을 때(reset·resetPush) 오는 popstate 는 스택에 반영하지 않는다\n const ignorePopRef = useRef(0);\n // history.go 가 끝나기 전 다른 history 조작이 끼면 스택과 URL 이 어긋나므로 잠근다\n const pendingTravelRef = useRef(0);\n const isLocked = () => busyRef.current || pendingTravelRef.current > 0;\n\n const travel = (delta: number, ignorePop: boolean) => {\n pendingTravelRef.current += 1;\n if (ignorePop) ignorePopRef.current += 1;\n return history.travel(delta).then((popped) => {\n pendingTravelRef.current -= 1;\n if (!popped && ignorePop) {\n ignorePopRef.current = Math.max(0, ignorePopRef.current - 1);\n }\n return popped;\n });\n };\n\n const resolve = useCallback((path: string) => {\n const { activities, initialActivity } = optionsRef.current;\n return findActivity([...activities, initialActivity], path);\n }, []);\n\n const resolveOrNotify = useCallback(\n (path: string) => {\n const hit = resolve(path);\n if (!hit) {\n if (isDev()) {\n console.warn(`[webviewkit] No activity matches \"${path}\"`);\n }\n optionsRef.current.onNotFound?.(path);\n }\n return hit;\n },\n [resolve]\n );\n\n const animate = () => optionsRef.current.duration > 0;\n\n const push = useCallback(\n (path: string, data?: unknown) => {\n if (isLocked()) return false;\n const hit = resolveOrNotify(path);\n if (!hit) return false;\n const { entries } = stateRef.current;\n const revived = findRevivable(stateRef.current, path);\n const entry = revived ? { ...revived, data } : newEntry(hit, path, data);\n busyRef.current = true;\n history.push(path, { key: entry.key, index: entries.length, data });\n dispatch(\n revived\n ? {\n type: \"REVIVE\",\n entry,\n direction: \"push\",\n index: entries.length,\n animate: animate(),\n }\n : { type: \"PUSH\", entry, animate: animate() }\n );\n return true;\n },\n [resolveOrNotify]\n );\n\n const replace = useCallback(\n (path: string, data?: unknown) => {\n if (isLocked()) return false;\n const hit = resolveOrNotify(path);\n if (!hit) return false;\n const entry = newEntry(hit, path, data);\n history.replace(path, {\n key: entry.key,\n index: stateRef.current.entries.length - 1,\n data,\n });\n dispatch({ type: \"REPLACE\", entry });\n return true;\n },\n [resolveOrNotify]\n );\n\n const reset = useCallback(\n (path: string, data?: unknown) => {\n if (isLocked()) return false;\n const hit = resolveOrNotify(path);\n if (!hit) return false;\n const entry = newEntry(hit, path, data);\n const depth = stateRef.current.entries.length;\n dispatch({ type: \"RESET\", entry });\n // 현재 항목만 replace 하면 지운 페이지들이 history 에 남아 브라우저 back 으로 되살아난다\n const commit = () => {\n history.replace(path, { key: entry.key, index: 0, data });\n };\n if (depth === 1) commit();\n else void travel(-(depth - 1), true).then(commit);\n return true;\n },\n [resolveOrNotify]\n );\n\n const resetPush = useCallback(\n (path: string, data?: unknown) => {\n const { entries } = stateRef.current;\n if (entries.length === 1) return push(path, data);\n if (isLocked()) return false;\n const hit = resolveOrNotify(path);\n if (!hit) return false;\n const revivable = findRevivable(stateRef.current, path, {\n includeRemovable: true,\n });\n const entry = revivable\n ? { ...revivable, data }\n : newEntry(hit, path, data);\n busyRef.current = true;\n dispatch({ type: \"RESET_PUSH\", entry, animate: animate() });\n // 루트로 되감은 뒤 push 해야 앞으로 가기 기록까지 정리된다\n void travel(-(entries.length - 1), true).then(() => {\n history.push(path, { key: entry.key, index: 1, data });\n });\n return true;\n },\n [push, resolveOrNotify]\n );\n\n const pop = useCallback((count: number = 1) => {\n if (isLocked()) return false;\n const { entries } = stateRef.current;\n if (entries.length <= 1) {\n optionsRef.current.onBackAtRoot?.();\n return false;\n }\n const delta = Math.min(Math.max(1, count), entries.length - 1);\n const targetIndex = entries.length - 1 - delta;\n busyRef.current = true;\n // push 와 같이 클릭 tick 에서 바로 전환을 시작한다. popstate 를 기다리면\n // 브라우저가 history traversal 동안 프레임을 늦춰 애니메이션이 시작되지 않는다.\n // 뒤따르는 popstate 는 key 가 이미 top 이라 onPop 에서 no-op 이 된다.\n dispatch({ type: \"POP_TO\", index: targetIndex, animate: animate() });\n void travel(-delta, false);\n return true;\n }, []);\n\n const back = useCallback(() => pop(1), [pop]);\n\n const popTo = useCallback(\n (path: string) => {\n const { entries } = stateRef.current;\n for (let i = entries.length - 2; i >= 0; i -= 1) {\n if (entries[i].path === path || entries[i].pattern === path) {\n return pop(entries.length - 1 - i);\n }\n }\n return false;\n },\n [pop]\n );\n\n const endTransition = useCallback(() => {\n dispatch({ type: \"END_TRANSITION\" });\n }, []);\n\n // popstate (브라우저·하드웨어 back, forward, history.go)\n useEffect(() => {\n const onPop = (historyState: HistoryState) => {\n if (ignorePopRef.current > 0) {\n ignorePopRef.current -= 1;\n return;\n }\n const { entries } = stateRef.current;\n const index = historyState.key\n ? entries.findIndex((entry) => entry.key === historyState.key)\n : -1;\n if (index !== -1) {\n if (index < entries.length - 1) {\n busyRef.current = true;\n dispatch({ type: \"POP_TO\", index, animate: animate() });\n }\n return;\n }\n const cachedEntry = historyState.key\n ? stateRef.current.cached.find((item) => item.key === historyState.key)\n : undefined;\n const targetIndex = historyState.index;\n if (\n cachedEntry &&\n typeof targetIndex === \"number\" &&\n // 루트 자리(0)는 되살리지 않는다. 아래 일반 처리(reset)로 넘긴다\n targetIndex >= 1 &&\n targetIndex <= entries.length\n ) {\n busyRef.current = true;\n dispatch({\n type: \"REVIVE\",\n entry: { ...cachedEntry, data: historyState.data },\n direction: targetIndex === entries.length ? \"push\" : \"pop\",\n index: targetIndex,\n animate: animate(),\n });\n return;\n }\n const hit = resolveOrNotify(historyState.path);\n if (!hit) {\n busyRef.current = false;\n return;\n }\n const entry = newEntry(\n hit,\n historyState.path,\n historyState.data,\n historyState.key\n );\n if (\n typeof historyState.index === \"number\" &&\n historyState.index === entries.length\n ) {\n busyRef.current = true;\n dispatch({ type: \"PUSH\", entry, animate: animate() });\n return;\n }\n dispatch({ type: \"RESET\", entry });\n };\n const removeListener = history.addListener(onPop);\n return () => {\n removeListener();\n };\n }, [resolveOrNotify]);\n\n // 새로고침·딥링크 복원 (마운트 1회, StrictMode 재실행 방지)\n const restoredRef = useRef(false);\n useEffect(() => {\n if (restoredRef.current) return;\n restoredRef.current = true;\n\n const root = stateRef.current.entries[0];\n const url = currentUrl();\n const hit = url === root.path ? null : resolve(url);\n if (!hit || hit.activity === optionsRef.current.initialActivity) {\n history.replace(root.path, { key: root.key, index: 0 });\n return;\n }\n\n const savedData = (history.getCurrentState() as HistoryState).data;\n const top = newEntry(hit, url, savedData);\n if (optionsRef.current.restoreStack === \"top-only\") {\n history.replace(url, { key: top.key, index: 0, data: savedData });\n dispatch({ type: \"RESTORE\", entries: [top] });\n return;\n }\n history.replace(root.path, { key: root.key, index: 0 });\n history.push(url, { key: top.key, index: 1, data: savedData });\n dispatch({ type: \"RESTORE\", entries: [root, top] });\n }, [resolve]);\n\n // 전환 종료 안전 타이머 (animationend 누락·jsdom 대비)\n useEffect(() => {\n if (!state.transition) {\n busyRef.current = false;\n return;\n }\n const timer = setTimeout(\n endTransition,\n optionsRef.current.duration + TRANSITION_END_GRACE_MS\n );\n return () => clearTimeout(timer);\n }, [state, endTransition]);\n\n return {\n state,\n push,\n replace,\n reset,\n resetPush,\n back,\n pop,\n popTo,\n endTransition,\n };\n}\n","import type { Activity } from \"../type\";\n\nexport interface PathMatch {\n params: Record<string, string>;\n query: Record<string, string>;\n}\n\nconst splitSegments = (pathname: string) =>\n pathname.split(\"/\").filter((segment) => segment.length > 0);\n\nconst safeDecode = (value: string) => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nexport function parseQuery(search: string): Record<string, string> {\n const query: Record<string, string> = {};\n new URLSearchParams(search).forEach((value, key) => {\n query[key] = value;\n });\n return query;\n}\n\n/**\n * `pattern`(`/detail/:id`)과 `url`(`/detail/3?tab=a#x`)을 비교한다.\n * 끝의 `/`와 `#hash`는 무시한다. 불일치면 null.\n */\nexport function matchPath(pattern: string, url: string): PathMatch | null {\n const [withoutHash] = url.split(\"#\");\n const queryIndex = withoutHash.indexOf(\"?\");\n const pathname =\n queryIndex === -1 ? withoutHash : withoutHash.slice(0, queryIndex);\n const search = queryIndex === -1 ? \"\" : withoutHash.slice(queryIndex);\n\n const patternSegments = splitSegments(pattern);\n const pathSegments = splitSegments(pathname);\n if (patternSegments.length !== pathSegments.length) return null;\n\n const params: Record<string, string> = {};\n for (let i = 0; i < patternSegments.length; i += 1) {\n const expected = patternSegments[i];\n const actual = pathSegments[i];\n if (expected.startsWith(\":\")) {\n params[expected.slice(1)] = safeDecode(actual);\n } else if (expected !== actual) {\n return null;\n }\n }\n\n return { params, query: parseQuery(search) };\n}\n\n/** 등록 순서대로 첫 매칭 Activity */\nexport function findActivity(\n activities: Activity[],\n url: string\n): { activity: Activity; match: PathMatch } | null {\n for (const activity of activities) {\n const match = matchPath(activity.path, url);\n if (match) return { activity, match };\n }\n return null;\n}\n"],"mappings":"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","names":["reply","Direction","HistoryAction","import_react","import_jsx_runtime","currentPath","React","import_styled","import_styled","import_react","import_react","import_react","import_jsx_runtime","currentPath","styled","import_react","import_styled","import_jsx_runtime","styled","import_react","_a","import_react","currentPath","import_react","isDev","entry","import_jsx_runtime","_a","_b","styled","import_jsx_runtime","styled"]}
|