@ahnseungchan/webviewkit 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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","/** push/back 전환 기본 시간 (ms). `StackRouterProvider` `duration` 으로 조정 */\nexport const STACK_TRANSITION_MS = 300;\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\nconst slideInRight = keyframes`\n from { transform: translate3d(100%, 0, 0); }\n to { transform: translate3d(0, 0, 0); }\n`;\nconst slideOutLeft = keyframes`\n from { transform: translate3d(0, 0, 0); opacity: 1; }\n to { transform: translate3d(-30%, 0, 0); opacity: 0.6; }\n`;\nconst slideInLeft = keyframes`\n from { transform: translate3d(-30%, 0, 0); opacity: 0.6; }\n to { transform: translate3d(0, 0, 0); opacity: 1; }\n`;\nconst slideOutRight = keyframes`\n from { transform: translate3d(0, 0, 0); }\n to { transform: translate3d(100%, 0, 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\nconst SLIDE_KEYFRAMES = {\n push: { enter: slideInRight, exit: slideOutLeft },\n pop: { enter: slideInLeft, exit: slideOutRight },\n} as const;\n\nconst FADE_KEYFRAMES = { enter: fadeIn, exit: fadeOut } as const;\n\nfunction pickKeyframes(\n transition: StackTransitionType,\n direction: Direction,\n pageState: \"enter\" | \"exit\"\n) {\n if (transition === \"fade\") return FADE_KEYFRAMES[pageState];\n return SLIDE_KEYFRAMES[direction][pageState];\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 return css`\n will-change: transform, opacity;\n animation: ${pickKeyframes(transitionType, direction, pageState)}\n ${duration}ms ease-in-out forwards;\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 if (event.target === event.currentTarget) onAnimationEnd?.();\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 void history.travel(-delta).then((popped) => {\n // popstate 가 오지 않는 환경(히스토리 불일치) — 로컬 스택만 맞춘다\n if (!popped) {\n busyRef.current = false;\n dispatch({ type: \"POP_TO\", index: targetIndex, animate: false });\n }\n });\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/_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"]}