@ait-co/polyfill 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -3
- package/dist/auto.cjs +919 -0
- package/dist/auto.cjs.map +1 -0
- package/dist/auto.d.cts +1 -0
- package/dist/auto.js +18 -6
- package/dist/auto.js.map +1 -1
- package/dist/detect.cjs +84 -0
- package/dist/detect.cjs.map +1 -0
- package/dist/detect.d.cts +50 -0
- package/dist/detect.d.cts.map +1 -0
- package/dist/index.cjs +982 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +222 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.ts +26 -27
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +68 -8
- package/dist/index.js.map +1 -1
- package/dist/shims/clipboard.cjs +192 -0
- package/dist/shims/clipboard.cjs.map +1 -0
- package/dist/shims/clipboard.d.cts +26 -0
- package/dist/shims/clipboard.d.cts.map +1 -0
- package/dist/shims/geolocation.cjs +356 -0
- package/dist/shims/geolocation.cjs.map +1 -0
- package/dist/shims/geolocation.d.cts +41 -0
- package/dist/shims/geolocation.d.cts.map +1 -0
- package/dist/shims/network.cjs +290 -0
- package/dist/shims/network.cjs.map +1 -0
- package/dist/shims/network.d.cts +56 -0
- package/dist/shims/network.d.cts.map +1 -0
- package/dist/shims/share.cjs +239 -0
- package/dist/shims/share.cjs.map +1 -0
- package/dist/shims/share.d.cts +26 -0
- package/dist/shims/share.d.cts.map +1 -0
- package/dist/shims/vibrate-semantic.d.ts +27 -0
- package/dist/shims/vibrate-semantic.d.ts.map +1 -0
- package/dist/shims/vibrate-semantic.js +150 -0
- package/dist/shims/vibrate-semantic.js.map +1 -0
- package/dist/shims/vibrate.cjs +235 -0
- package/dist/shims/vibrate.cjs.map +1 -0
- package/dist/shims/vibrate.d.cts +43 -0
- package/dist/shims/vibrate.d.cts.map +1 -0
- package/dist/shims/vibrate.d.ts +16 -5
- package/dist/shims/vibrate.d.ts.map +1 -1
- package/dist/shims/vibrate.js +19 -7
- package/dist/shims/vibrate.js.map +1 -1
- package/package.json +73 -19
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto.cjs","names":["BACKUP_KEY","SNAPSHOT_KEY","BACKUP_KEY","SNAPSHOT_KEY","#status"],"sources":["../src/detect.ts","../src/shims/_install-helpers.ts","../src/shims/clipboard.ts","../src/shims/geolocation.ts","../src/shims/network.ts","../src/shims/share.ts","../src/shims/vibrate.ts","../src/index.ts","../src/auto.ts"],"sourcesContent":["/**\n * Environment detection: are we running inside Apps in Toss, or a plain browser?\n *\n * Strategy: call the SDK's `getAppsInTossGlobals()` — a synchronous export\n * that returns the runtime's Toss globals (deploymentId, brand name, …)\n * inside the Apps in Toss runtime and throws (RN bridge unavailable)\n * anywhere else. The SDK itself is an **optional** peer dependency; if its\n * module can't be imported we are definitely not inside Toss.\n *\n * Just having the SDK module resolvable is not enough — apps can bundle it\n * and still run in a plain browser. We need the bridge probe to confirm.\n *\n * UA sniffing (spoofable) is avoided. We do call `getAppsInTossGlobals`, but\n * that's a constant read from the bridge — no permission dialogs, no\n * analytics fire. In a plain browser the bridge lookup fails fast (sync\n * throw, microsecond-scale), so the startup cost is negligible.\n */\n\nlet cached: boolean | undefined;\n\n/**\n * Reset the cached detection result. Primarily for tests.\n */\nexport function resetDetection(): void {\n cached = undefined;\n}\n\n/**\n * Synchronous read of the cached detection result. Returns:\n * - `true` / `false` if an override is active or the async detection has\n * already resolved\n * - `undefined` if detection hasn't run yet\n *\n * Used by spec-sync APIs (e.g. `navigator.canShare`) that can't `await`\n * detection.\n */\nexport function isTossEnvironmentCached(): boolean | undefined {\n const force = globalThis.__AIT_POLYFILL_FORCE__;\n if (force === 'toss') return true;\n if (force === 'browser') return false;\n return cached;\n}\n\n/**\n * Returns `true` iff we detect we are running in an environment where the\n * Apps in Toss SDK (`@apps-in-toss/web-framework`) is present and usable.\n *\n * Async because we use dynamic `import()` to probe the optional peer dep\n * without forcing it into the consumer's bundle.\n */\nexport async function isTossEnvironment(): Promise<boolean> {\n // Override check precedes cache so `devtools` / tests can flip the result\n // mid-session without a `resetDetection()` call.\n const force = globalThis.__AIT_POLYFILL_FORCE__;\n if (force === 'toss') return true;\n if (force === 'browser') return false;\n\n if (cached !== undefined) return cached;\n\n const mod = await loadTossSdk();\n if (typeof mod?.getAppsInTossGlobals !== 'function') {\n cached = false;\n return cached;\n }\n // Inside Toss the bridge returns a populated globals object. In a plain\n // browser the RN bridge isn't attached and the call throws — that's our\n // signal. Any non-throwing call with an object return is treated as Toss.\n try {\n const globals = mod.getAppsInTossGlobals();\n cached = Boolean(globals) && typeof globals === 'object';\n } catch {\n cached = false;\n }\n return cached;\n}\n\n/**\n * Lazy SDK accessor — returns the module if available, else `null`. Callers\n * are expected to `await` and null-check. Never throws.\n */\nexport async function loadTossSdk(): Promise<typeof import('@apps-in-toss/web-framework') | null> {\n try {\n return await import('@apps-in-toss/web-framework');\n } catch {\n return null;\n }\n}\n","/**\n * Shared helpers for installing shims on `navigator`.\n *\n * Chromium now marks a handful of `navigator` properties (e.g. `geolocation`,\n * `clipboard`) as non-configurable **own** properties on the instance. That\n * means a plain `Object.defineProperty(navigator, 'x', …)` throws\n * `TypeError: Cannot redefine property`.\n *\n * The workaround is to shim at the prototype level — `Navigator.prototype`\n * keeps these as configurable accessors, so we can swap them there and every\n * instance that falls through to the prototype (including `window.navigator`)\n * sees the shim. We only reach for the prototype when the instance-level\n * assignment refuses.\n *\n * For restoration we remember the descriptor chain (instance + prototype) so\n * `uninstall()` puts the browser back in its original state.\n */\n\ntype PropertyLocation = 'instance' | 'prototype';\n\nexport interface InstallSnapshot {\n /** Where we ended up writing the shim. */\n location: PropertyLocation;\n /** Original descriptor at that location (may be undefined if nothing was there). */\n originalDescriptor: PropertyDescriptor | undefined;\n /** `true` iff the original property lived on the instance before we touched it. */\n instanceHadOwn: boolean;\n}\n\n/**\n * Install `descriptor` at `navigator[prop]`. Prefer instance-level; if the\n * browser refuses (property is non-configurable on the instance), install on\n * `Navigator.prototype` instead.\n *\n * Returns a snapshot describing where the original value was, which\n * `restoreNavigatorProperty` uses to undo the install.\n */\nexport function installNavigatorProperty(\n prop: string,\n descriptor: PropertyDescriptor,\n): InstallSnapshot {\n const nav = navigator as unknown as Record<PropertyKey, unknown>;\n const instanceDesc = Object.getOwnPropertyDescriptor(nav, prop);\n const instanceHadOwn = instanceDesc !== undefined;\n\n // Fast path: instance-level property is missing or configurable.\n if (!instanceDesc || instanceDesc.configurable) {\n try {\n Object.defineProperty(nav, prop, descriptor);\n return { location: 'instance', originalDescriptor: instanceDesc, instanceHadOwn };\n } catch {\n // Fall through to prototype-level install.\n }\n }\n\n // Prototype-level install. Drop the instance-level shadow so the prototype\n // accessor is visible to readers on `navigator`.\n const proto = Object.getPrototypeOf(nav) as object;\n const protoDesc = Object.getOwnPropertyDescriptor(proto, prop);\n\n if (instanceHadOwn) {\n // Try to remove the instance-level shadow. On non-configurable it throws —\n // we deliberately ignore that; prototype-level install still wins because\n // the prototype accessor shows through when we read via `navigator[prop]`.\n try {\n delete nav[prop];\n } catch {\n /* non-configurable own — leave it; prototype install still useful */\n }\n }\n\n Object.defineProperty(proto, prop, descriptor);\n return { location: 'prototype', originalDescriptor: protoDesc, instanceHadOwn };\n}\n\n/**\n * Reverse the install recorded in `snapshot`. If the original descriptor was\n * `undefined` (property didn't exist before), delete the property instead of\n * re-defining it.\n */\nexport function restoreNavigatorProperty(prop: string, snapshot: InstallSnapshot): void {\n const target =\n snapshot.location === 'instance'\n ? (navigator as unknown as Record<PropertyKey, unknown>)\n : (Object.getPrototypeOf(navigator) as object);\n\n if (snapshot.originalDescriptor) {\n try {\n Object.defineProperty(target, prop, snapshot.originalDescriptor);\n } catch {\n /* descriptor was non-configurable upstream; we can't undo — rare. */\n }\n } else {\n try {\n delete (target as Record<PropertyKey, unknown>)[prop];\n } catch {\n /* non-configurable — rare. */\n }\n }\n\n // If our install pushed past an instance shadow, we leave the instance alone\n // — the descriptor we captured for `instanceHadOwn: true` lives on the\n // instance and was not modified at install time.\n}\n\n/**\n * Method-level install snapshot. Captured per-key so `restoreObjectMethods`\n * can distinguish \"was an own property, reassign it\" from \"was inherited,\n * delete the override so the prototype method surfaces again\".\n */\nexport interface MethodInstallSnapshot {\n target: object;\n methods: Record<string, { hadOwn: boolean; original: unknown }>;\n}\n\n/**\n * Mutate methods on an existing object rather than replacing the object\n * itself. This is the path we take for `navigator.geolocation`, `navigator.share`,\n * and `navigator.vibrate` in Chromium, where the slot on `navigator` is a\n * non-configurable own property that we cannot replace — but the methods\n * themselves (or the methods on the referenced object) are still\n * `configurable: true, writable: true`.\n *\n * Each replacement is installed via plain assignment. If any slot is not\n * writable (e.g. frozen object), install is aborted and previously-applied\n * replacements are rolled back, so the caller observes an atomic \"all or\n * nothing\" failure as `null`. The caller is expected to degrade gracefully\n * (e.g. log a one-time `console.warn`) when that happens.\n */\nexport function installObjectMethods(\n target: object,\n replacements: Record<string, (...args: never[]) => unknown>,\n): MethodInstallSnapshot | null {\n const methods: Record<string, { hadOwn: boolean; original: unknown }> = {};\n const applied: string[] = [];\n const bag = target as Record<string, unknown>;\n\n for (const key of Object.keys(replacements)) {\n const hadOwn = Object.hasOwn(target, key);\n const original = bag[key];\n try {\n bag[key] = replacements[key] as unknown;\n } catch {\n // Non-writable / frozen. Roll back and return null.\n for (const applieKey of applied) {\n const prev = methods[applieKey];\n if (!prev) continue;\n if (prev.hadOwn) {\n bag[applieKey] = prev.original;\n } else {\n delete bag[applieKey];\n }\n }\n return null;\n }\n // Verify the assignment actually stuck — silent-failure descriptors (e.g.\n // `writable: false` without strict mode) can skip the throw and leave the\n // original value in place. Treat that the same as a throw.\n if (bag[key] !== (replacements[key] as unknown)) {\n for (const applieKey of applied) {\n const prev = methods[applieKey];\n if (!prev) continue;\n if (prev.hadOwn) {\n bag[applieKey] = prev.original;\n } else {\n delete bag[applieKey];\n }\n }\n return null;\n }\n methods[key] = { hadOwn, original };\n applied.push(key);\n }\n\n return { target, methods };\n}\n\n/**\n * Reverse an `installObjectMethods` snapshot. Reassigns originals for slots\n * that were own properties before install; deletes the override for slots\n * that were inherited (so the prototype method surfaces again).\n */\nexport function restoreObjectMethods(snapshot: MethodInstallSnapshot): void {\n const bag = snapshot.target as Record<string, unknown>;\n for (const key of Object.keys(snapshot.methods)) {\n const entry = snapshot.methods[key];\n if (!entry) continue;\n try {\n if (entry.hadOwn) {\n bag[key] = entry.original;\n } else {\n delete bag[key];\n }\n } catch {\n /* frozen between install and restore — rare. */\n }\n }\n}\n","/**\n * `navigator.clipboard` shim.\n *\n * Inside Apps in Toss → routes `readText` / `writeText` through the SDK\n * (`getClipboardText` / `setClipboardText`).\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.clipboard`.\n * If the browser doesn't implement it, the standard `TypeError` / `DOMException`\n * surfaces unchanged — we don't paper over missing support.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n type InstallSnapshot,\n installNavigatorProperty,\n restoreNavigatorProperty,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/clipboard.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/clipboard.snapshot');\n\ninterface BackupHost {\n [BACKUP_KEY]?: Clipboard | undefined;\n [SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n}\n\n/**\n * Produces a Clipboard-compatible object whose `readText` / `writeText` methods\n * route to the SDK when in Toss, else fall through to the supplied `fallback`.\n */\nfunction createClipboardShim(fallback: Clipboard | undefined): Clipboard {\n const shim = {\n async readText(): Promise<string> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n if (sdk?.getClipboardText) {\n return sdk.getClipboardText();\n }\n }\n if (!fallback) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.readText is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return fallback.readText();\n },\n\n async writeText(text: string): Promise<void> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n if (sdk?.setClipboardText) {\n return sdk.setClipboardText(text);\n }\n }\n if (!fallback) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.writeText is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return fallback.writeText(text);\n },\n\n // `read` / `write` (ClipboardItem-based) are passed through to the\n // fallback when in browser mode; the SDK has no rich-content counterpart,\n // so in Toss mode they throw.\n async read(): Promise<ClipboardItems> {\n if (await isTossEnvironment()) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.read (rich content) is not supported in the Apps in Toss environment. Use readText instead.',\n 'NotSupportedError',\n );\n }\n if (!fallback?.read) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.read is not available.',\n 'NotSupportedError',\n );\n }\n return fallback.read();\n },\n\n async write(items: ClipboardItems): Promise<void> {\n if (await isTossEnvironment()) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.write (rich content) is not supported in the Apps in Toss environment. Use writeText instead.',\n 'NotSupportedError',\n );\n }\n if (!fallback?.write) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.write is not available.',\n 'NotSupportedError',\n );\n }\n return fallback.write(items);\n },\n\n // EventTarget passthrough. `navigator.clipboard` extends EventTarget in the\n // spec; mini-apps rarely use it. We forward to the fallback when one exists;\n // in Toss mode (no fallback) we silently drop subscriptions — the SDK emits\n // no clipboard events, so there is nothing to dispatch. This is lossy but\n // preserves the spec-compatible shape.\n addEventListener: (\n ...args: Parameters<EventTarget['addEventListener']>\n ): ReturnType<EventTarget['addEventListener']> => fallback?.addEventListener(...args),\n removeEventListener: (\n ...args: Parameters<EventTarget['removeEventListener']>\n ): ReturnType<EventTarget['removeEventListener']> => fallback?.removeEventListener(...args),\n // Returns `false` in Toss mode (no backing EventTarget). A caller that reads\n // this as \"default action cancelled\" should check context — there are no\n // listeners to run because the SDK doesn't surface clipboard events.\n dispatchEvent: (event: Event): boolean => fallback?.dispatchEvent(event) ?? false,\n } satisfies Clipboard;\n\n return shim;\n}\n\n/**\n * Install the `navigator.clipboard` shim.\n *\n * @returns an uninstall function that restores the original `navigator.clipboard`.\n * Calling install twice without uninstalling is a no-op on the second call\n * and returns the same uninstall function.\n */\nexport function installClipboardShim(): () => void {\n if (typeof navigator === 'undefined') {\n // No-op in non-DOM environments (pure Node).\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n // Already installed. Use `in` (not `!== undefined`) because the stored\n // backup is legitimately `undefined` when the browser has no native\n // `navigator.clipboard` — without this, we'd re-wrap on each install.\n // Note: the returned uninstall is global. Any caller's uninstall fully\n // removes the shim; callers do not have independent install handles.\n return () => uninstallClipboardShim();\n }\n\n const original = navigator.clipboard as Clipboard | undefined;\n host[BACKUP_KEY] = original;\n\n const shim = createClipboardShim(original);\n host[SNAPSHOT_KEY] = installNavigatorProperty('clipboard', {\n value: shim,\n configurable: true,\n writable: true,\n });\n\n return uninstallClipboardShim;\n}\n\n/**\n * Remove the shim and restore the pre-install shape.\n */\nexport function uninstallClipboardShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreNavigatorProperty('clipboard', snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * `navigator.geolocation` shim.\n *\n * Inside Apps in Toss → routes through the SDK:\n * - `getCurrentPosition` → `getCurrentLocation({ accuracy })`\n * - `watchPosition` / `clearWatch` → `startUpdateLocation({ onEvent, onError, options })`\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.geolocation`.\n * If neither is available, the error callback receives a `GeolocationPositionError`.\n *\n * Install strategy: **method-level**. We do **not** replace `navigator.geolocation`\n * itself — Chromium marks that slot as a non-configurable own property, which\n * both `defineProperty(navigator, 'geolocation', …)` and the prototype-level\n * fallback cannot override (the instance shadow blocks prototype reads). We\n * instead mutate the methods on the existing `Geolocation` object, whose own\n * method descriptors are configurable+writable in every browser we've seen.\n *\n * SDK/Web shape mismatch handled here:\n * - SDK `Accuracy` is a numeric enum (1 = Lowest … 6 = BestForNavigation); the\n * standard `PositionOptions.enableHighAccuracy` is a boolean. We map\n * `true → Accuracy.High (4, \"~10m\")` and `false → Accuracy.Balanced (3)`.\n * `Highest (5)` / `BestForNavigation (6)` are available but carry a battery\n * cost that's rarely what mini-apps want; consumers who need them should\n * call the SDK directly.\n * - SDK coords lack `speed`; we surface `null` (per the W3C spec when unknown).\n * - SDK `startUpdateLocation` returns an `unsubscribe` fn; we wrap it behind\n * a numeric watch id so `clearWatch(id)` behaves like the standard.\n *\n * Caveat: watch ids reset whenever the shim is uninstalled and reinstalled;\n * they are not stable across such cycles. Ids obtained before uninstall\n * cannot be cleared after uninstall — `clearWatch(id)` on the restored native\n * `navigator.geolocation` uses a different id space, so the SDK subscription\n * leaks. Consumers should `clearWatch` all outstanding ids before calling\n * `uninstall()`.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/geolocation.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/geolocation.snapshot');\n\ninterface BackupHost {\n [BACKUP_KEY]?: { target: Geolocation } | undefined;\n [SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\n// SDK Accuracy enum values. We don't import the enum at runtime (peer is\n// optional), so we hard-code the numeric constants used by the SDK. Stable\n// ABI per the SDK's exported numeric enum.\nconst ACCURACY_BALANCED = 3;\nconst ACCURACY_HIGH = 4;\n\ninterface SdkLocationCoords {\n latitude: number;\n longitude: number;\n altitude: number;\n accuracy: number;\n altitudeAccuracy: number;\n heading: number;\n}\n\ninterface SdkLocation {\n timestamp: number;\n coords: SdkLocationCoords;\n}\n\nfunction toStandardPosition(sdk: SdkLocation): GeolocationPosition {\n const coordsData = {\n latitude: sdk.coords.latitude,\n longitude: sdk.coords.longitude,\n altitude: sdk.coords.altitude,\n accuracy: sdk.coords.accuracy,\n altitudeAccuracy: sdk.coords.altitudeAccuracy,\n heading: sdk.coords.heading,\n // SDK does not surface speed. Per spec, null means \"unknown\".\n speed: null,\n };\n const coords: GeolocationCoordinates = {\n ...coordsData,\n toJSON() {\n return { ...coordsData };\n },\n };\n return {\n coords,\n timestamp: sdk.timestamp,\n toJSON() {\n return { coords: { ...coordsData }, timestamp: sdk.timestamp };\n },\n };\n}\n\nfunction toPositionError(code: 1 | 2 | 3, message: string): GeolocationPositionError {\n // Prefer the real constructor when available (every real browser ships it).\n // The spec says GeolocationPositionError is not constructable, so we fall\n // through to a fabricated object whose prototype is patched via\n // `setPrototypeOf` — that keeps `instanceof` checks in consumer code working\n // and picks up the spec's PERMISSION_DENIED / POSITION_UNAVAILABLE / TIMEOUT\n // constants from the real prototype rather than hard-coding them (avoids\n // drift if the spec ever grows a new code).\n const Ctor = (globalThis as { GeolocationPositionError?: unknown }).GeolocationPositionError;\n if (typeof Ctor === 'function') {\n const proto = (Ctor as { prototype?: object }).prototype;\n if (proto) {\n const shape: { code: number; message: string } = { code, message };\n Object.setPrototypeOf(shape, proto);\n return shape as GeolocationPositionError;\n }\n }\n // jsdom / last-resort fallback: fabricate the spec shape with hard-coded\n // constants since there's no prototype to delegate to.\n return {\n code,\n message,\n PERMISSION_DENIED: 1,\n POSITION_UNAVAILABLE: 2,\n TIMEOUT: 3,\n } as GeolocationPositionError;\n}\n\nfunction accuracyFromOptions(options: PositionOptions | undefined): number {\n return options?.enableHighAccuracy ? ACCURACY_HIGH : ACCURACY_BALANCED;\n}\n\n/**\n * Minimal view of the native `Geolocation` methods we forward to. We pass\n * the **captured originals** here, not a reference to `navigator.geolocation`\n * itself — after install the methods on that object ARE the shim, so using\n * `navigator.geolocation.getCurrentPosition(…)` as a fallback would infinite-loop.\n */\ninterface GeolocationFallback {\n getCurrentPosition: Geolocation['getCurrentPosition'] | undefined;\n watchPosition: Geolocation['watchPosition'] | undefined;\n clearWatch: Geolocation['clearWatch'] | undefined;\n}\n\ninterface GeolocationShim {\n getCurrentPosition: Geolocation['getCurrentPosition'];\n watchPosition: Geolocation['watchPosition'];\n clearWatch: Geolocation['clearWatch'];\n}\n\nfunction createGeolocationShim(fallback: GeolocationFallback): GeolocationShim {\n // Numeric watch id → SDK unsubscribe fn. Keeps the shim's API in line with\n // the standard even though the SDK issues unsubscribe closures instead.\n // `pendingWatches` closes the race where `clearWatch` is called before the\n // async `watchPosition` installer resolves — without it we'd leak the SDK\n // subscription.\n let nextWatchId = 1;\n const sdkWatches = new Map<number, () => void>();\n const nativeWatches = new Map<number, number>();\n const pendingWatches = new Map<number, { cancelled: boolean }>();\n\n const shim: GeolocationShim = {\n getCurrentPosition(success, error, options) {\n void (async () => {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { getCurrentLocation?: unknown } | null)?.getCurrentLocation;\n if (typeof fn === 'function') {\n try {\n const loc = (await (fn as (o: { accuracy: number }) => Promise<SdkLocation>)({\n accuracy: accuracyFromOptions(options),\n })) as SdkLocation;\n success(toStandardPosition(loc));\n } catch (e) {\n error?.(\n toPositionError(\n 2,\n e instanceof Error ? e.message : '[@ait-co/polyfill] getCurrentLocation failed.',\n ),\n );\n }\n return;\n }\n }\n if (!fallback.getCurrentPosition) {\n error?.(\n toPositionError(\n 2,\n '[@ait-co/polyfill] navigator.geolocation is not available in this environment.',\n ),\n );\n return;\n }\n fallback.getCurrentPosition(success, error, options);\n })();\n },\n\n watchPosition(success, error, options) {\n const id = nextWatchId++;\n const pending = { cancelled: false };\n pendingWatches.set(id, pending);\n\n void (async () => {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { startUpdateLocation?: unknown } | null)?.startUpdateLocation;\n if (typeof fn === 'function') {\n if (pending.cancelled) {\n pendingWatches.delete(id);\n return;\n }\n const unsubscribe = (\n fn as (p: {\n onEvent: (loc: SdkLocation) => void;\n onError: (err: unknown) => void;\n options: { accuracy: number; timeInterval: number; distanceInterval: number };\n }) => () => void\n )({\n onEvent: (loc) => success(toStandardPosition(loc)),\n onError: (err) =>\n error?.(\n toPositionError(\n 2,\n err instanceof Error\n ? err.message\n : '[@ait-co/polyfill] startUpdateLocation failed.',\n ),\n ),\n options: {\n accuracy: accuracyFromOptions(options),\n // Sensible defaults — web `watchPosition` has no analogues.\n // Consumers needing sub-second updates should use the SDK directly.\n timeInterval: 1000,\n distanceInterval: 0,\n },\n });\n if (pending.cancelled) {\n unsubscribe();\n pendingWatches.delete(id);\n return;\n }\n sdkWatches.set(id, unsubscribe);\n pendingWatches.delete(id);\n return;\n }\n }\n if (!fallback.watchPosition) {\n pendingWatches.delete(id);\n error?.(\n toPositionError(\n 2,\n '[@ait-co/polyfill] navigator.geolocation is not available in this environment.',\n ),\n );\n return;\n }\n if (pending.cancelled) {\n pendingWatches.delete(id);\n return;\n }\n const nativeId = fallback.watchPosition(success, error, options);\n if (pending.cancelled) {\n fallback.clearWatch?.(nativeId);\n pendingWatches.delete(id);\n return;\n }\n nativeWatches.set(id, nativeId);\n pendingWatches.delete(id);\n })();\n\n return id;\n },\n\n clearWatch(id) {\n const pending = pendingWatches.get(id);\n if (pending) {\n pending.cancelled = true;\n pendingWatches.delete(id);\n return;\n }\n const unsubscribe = sdkWatches.get(id);\n if (unsubscribe) {\n unsubscribe();\n sdkWatches.delete(id);\n return;\n }\n const nativeId = nativeWatches.get(id);\n if (nativeId !== undefined && fallback.clearWatch) {\n fallback.clearWatch(nativeId);\n nativeWatches.delete(id);\n }\n },\n };\n\n return shim;\n}\n\nexport function installGeolocationShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n return () => uninstallGeolocationShim();\n }\n\n const target = navigator.geolocation as Geolocation | undefined;\n if (!target) {\n // No `navigator.geolocation` at all (rare — jsdom may expose it, real\n // browsers always do). Nothing for the shim to mutate; bail quietly.\n host[BACKUP_KEY] = undefined;\n return () => uninstallGeolocationShim();\n }\n\n // Capture the native methods BEFORE we patch so the shim's fallback path\n // doesn't recurse through itself.\n const fallback: GeolocationFallback = {\n getCurrentPosition: target.getCurrentPosition?.bind(target),\n watchPosition: target.watchPosition?.bind(target),\n clearWatch: target.clearWatch?.bind(target),\n };\n\n const shim = createGeolocationShim(fallback);\n\n const snapshot = installObjectMethods(target, {\n getCurrentPosition: shim.getCurrentPosition as (...args: never[]) => unknown,\n watchPosition: shim.watchPosition as (...args: never[]) => unknown,\n clearWatch: shim.clearWatch as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n // Method slots frozen — can't install. No-op uninstall.\n host[BACKUP_KEY] = undefined;\n return () => uninstallGeolocationShim();\n }\n\n host[BACKUP_KEY] = { target };\n host[SNAPSHOT_KEY] = snapshot;\n\n return uninstallGeolocationShim;\n}\n\nexport function uninstallGeolocationShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * `navigator.onLine` + `navigator.connection` shim.\n *\n * Inside Apps in Toss → seeded from SDK `getNetworkStatus()` on install and\n * refreshed on read (throttled):\n * - `'OFFLINE'` → `onLine = false`\n * - `'WIFI'` → `onLine = true`, `effectiveType = '4g'` (no web wifi value)\n * - `'2G'/'3G'/'4G'/'5G'` → `onLine = true`, `effectiveType = <lowercased>`\n * - `'WWAN'/'UNKNOWN'` → `onLine = true`, `effectiveType = '4g'` (best guess)\n *\n * Outside Apps in Toss → both `navigator.onLine` and `navigator.connection`\n * read through to the native value. Install installs own-instance getters\n * that consult the Toss-seeded cache first; when the cache is empty (which\n * it always is in browser mode), the getter temporarily removes its own\n * shadow, reads the prototype value, and reinstates the shadow.\n *\n * Uninstall `delete`s the instance-level override so the prototype descriptor\n * (where `onLine` and `connection` actually live in real browsers) becomes\n * visible again. We never mutate the prototype — doing so would throw in\n * browsers where the descriptor is non-configurable.\n *\n * Browser-compat caveat (Chromium): `navigator.onLine` and `navigator.connection`\n * are value slots, not methods, so the method-level install trick we use for\n * `geolocation`/`share`/`vibrate` does not apply here. When Chromium marks the\n * instance descriptor as non-configurable AND the prototype descriptor is also\n * non-configurable, we cannot install. In that case the shim logs a one-time\n * `console.warn` and leaves the native values in place — consumers keep the\n * browser's own `onLine`/`connection` values; the SDK-synced state is simply\n * disabled for that session.\n *\n * Caveat: the Web NetworkInformation API is evented (`change` fires on\n * transitions). The SDK exposes only a one-shot query, so listeners attached\n * to `navigator.connection` are accepted but never fire from a `change` event\n * unless the shim observes a real status transition. Synthesising richer\n * events via polling is tracked in TODO.md.\n *\n * Lifecycle: `navigator.connection` is a ShimConnection instance that lives in\n * the install closure. On uninstall the instance-level override is removed,\n * but listeners the consumer attached to the old instance stay bound to that\n * (now-orphan) object and will not see events from a subsequent install.\n * Consumers should re-attach listeners after each install.\n *\n * Seed-boundary race: in Toss mode, reads before the install-time SDK seed\n * completes fall through to the native `navigator.connection`. After the seed\n * lands, subsequent reads return the shim's ShimConnection. Consumers that\n * specifically need the ShimConnection instance (e.g., to attach `change`\n * listeners that fire on Toss network transitions) should wait a microtask\n * after `install()` before attaching listeners, or accept that pre-seed\n * reads may return the native object.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n type InstallSnapshot,\n installNavigatorProperty,\n restoreNavigatorProperty,\n} from './_install-helpers.js';\n\nconst INSTALLED_KEY = Symbol.for('@ait-co/polyfill/network.installed');\nconst ON_LINE_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/network.onLine.snapshot');\nconst CONNECTION_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/network.connection.snapshot');\n\ninterface BackupHost {\n [INSTALLED_KEY]?: boolean;\n [ON_LINE_SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n [CONNECTION_SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n}\n\ntype SdkNetworkStatus = 'OFFLINE' | 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'WWAN' | 'UNKNOWN';\ntype EffectiveType = 'slow-2g' | '2g' | '3g' | '4g';\n\nconst REFRESH_THROTTLE_MS = 500;\n\nfunction statusToOnline(status: SdkNetworkStatus): boolean {\n return status !== 'OFFLINE';\n}\n\nfunction statusToEffectiveType(status: SdkNetworkStatus): EffectiveType {\n switch (status) {\n case '2G':\n return '2g';\n case '3G':\n return '3g';\n default:\n return '4g';\n }\n}\n\nfunction statusToConnectionType(status: SdkNetworkStatus): string {\n switch (status) {\n case 'WIFI':\n return 'wifi';\n case '2G':\n case '3G':\n case '4G':\n case '5G':\n case 'WWAN':\n return 'cellular';\n case 'OFFLINE':\n return 'none';\n default:\n return 'unknown';\n }\n}\n\n// Symbol-keyed setter: the install closure can mutate status without exposing\n// a `setStatus` name on `navigator.connection` (real NetworkInformation has\n// no mutator). `Object.getOwnPropertySymbols(navigator.connection)` returns\n// nothing, so casual enumeration can't find it. A determined caller walking\n// the prototype chain (`Object.getOwnPropertySymbols(Object.getPrototypeOf(...))`)\n// can still surface the symbol — there is no trust boundary between polyfill\n// and consumer code in the same realm, so this is a discouragement, not a\n// security control.\nconst SET_STATUS = Symbol('@ait-co/polyfill/network.setStatus');\n\nclass ShimConnection extends EventTarget {\n #status: SdkNetworkStatus | null = null;\n onchange: ((this: ShimConnection, ev: Event) => unknown) | null = null;\n\n constructor() {\n super();\n // Forward `change` events to the legacy `onchange` handler for parity with\n // the NetworkInformation API.\n this.addEventListener('change', (ev) => this.onchange?.call(this, ev));\n }\n\n [SET_STATUS](next: SdkNetworkStatus | null): void {\n this.#status = next;\n }\n\n get effectiveType(): EffectiveType {\n return statusToEffectiveType(this.#status ?? 'UNKNOWN');\n }\n // `downlink` / `rtt` / `saveData` are placeholders — the SDK does not expose\n // these. We return 0/false rather than fabricate plausible numbers. Noted\n // in CLAUDE.md.\n get downlink(): number {\n return 0;\n }\n get rtt(): number {\n return 0;\n }\n get saveData(): boolean {\n return false;\n }\n get type(): string {\n return statusToConnectionType(this.#status ?? 'UNKNOWN');\n }\n}\n\nexport function installNetworkShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (host[INSTALLED_KEY]) {\n return () => uninstallNetworkShim();\n }\n host[INSTALLED_KEY] = true;\n\n // Per-install state. Kept in closure so uninstall/reinstall cycles don't\n // leak state between instances (module-scope would leak across tests).\n let cachedStatus: SdkNetworkStatus | null = null;\n let lastRefresh = 0;\n let inflight: Promise<void> | null = null;\n const connection = new ShimConnection();\n\n async function refresh(): Promise<void> {\n // Coalesce concurrent refreshes — without this, rapid reads during an\n // in-flight SDK call each set `lastRefresh` and return early, without\n // anyone actually fetching fresh data.\n if (inflight) return inflight;\n const now = Date.now();\n if (now - lastRefresh < REFRESH_THROTTLE_MS) return;\n inflight = (async () => {\n try {\n if (!(await isTossEnvironment())) return;\n const sdk = await loadTossSdk();\n const fn = (sdk as { getNetworkStatus?: unknown } | null)?.getNetworkStatus;\n if (typeof fn !== 'function') return;\n const next = (await (fn as () => Promise<SdkNetworkStatus>)()) as SdkNetworkStatus;\n const prev = cachedStatus;\n cachedStatus = next;\n connection[SET_STATUS](next);\n // Only dispatch `change` on real transitions — the null → X seed on\n // first install is learning, not a transition, and would otherwise\n // mis-trigger consumer handlers.\n if (prev !== null && prev !== next) {\n connection.dispatchEvent(new Event('change'));\n }\n } catch {\n // Advisory — refresh failures keep the prior cache. `void refresh()`\n // callers would otherwise surface unhandled rejections if\n // isTossEnvironment / loadTossSdk / getNetworkStatus ever throw.\n } finally {\n lastRefresh = Date.now();\n inflight = null;\n }\n })();\n return inflight;\n }\n\n // Capture the native values **before** we install so the getters can fall\n // through without needing to temporarily remove their own shadow (which is\n // incompatible with prototype-level installs — Chromium keeps\n // `navigator.onLine` / `connection` non-configurable on the instance, so we\n // may end up installing on Navigator.prototype instead).\n const nativeOnLine = (navigator as Navigator & { onLine?: boolean }).onLine;\n const nativeConnection = (navigator as Navigator & { connection?: unknown }).connection;\n\n // Seed the cache on install so the first sync read is meaningful.\n void refresh();\n\n // Guard both descriptor installs with try/catch. These properties are value\n // slots that the plan calls out as not having a method-level equivalent;\n // when Chromium makes them non-configurable at both the instance and the\n // prototype, `installNavigatorProperty` may throw. In that case we warn once\n // and proceed — consumers keep the browser's native values.\n let installWarned = false;\n const warnNonConfigurable = (e: unknown): void => {\n if (installWarned) return;\n installWarned = true;\n console.warn(\n '[@ait-co/polyfill] navigator.onLine/connection is non-configurable in this browser; Toss network status sync disabled.',\n e,\n );\n };\n\n try {\n host[ON_LINE_SNAPSHOT_KEY] = installNavigatorProperty('onLine', {\n configurable: true,\n get() {\n void refresh();\n if (cachedStatus !== null) return statusToOnline(cachedStatus);\n return nativeOnLine ?? true;\n },\n });\n } catch (e) {\n warnNonConfigurable(e);\n }\n\n try {\n host[CONNECTION_SNAPSHOT_KEY] = installNavigatorProperty('connection', {\n configurable: true,\n get() {\n void refresh();\n if (cachedStatus === null && nativeConnection !== undefined) return nativeConnection;\n return connection;\n },\n });\n } catch (e) {\n warnNonConfigurable(e);\n }\n\n return uninstallNetworkShim;\n}\n\nexport function uninstallNetworkShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!host[INSTALLED_KEY]) return;\n\n const onLineSnap = host[ON_LINE_SNAPSHOT_KEY];\n if (onLineSnap) restoreNavigatorProperty('onLine', onLineSnap);\n const connSnap = host[CONNECTION_SNAPSHOT_KEY];\n if (connSnap) restoreNavigatorProperty('connection', connSnap);\n\n delete host[INSTALLED_KEY];\n delete host[ON_LINE_SNAPSHOT_KEY];\n delete host[CONNECTION_SNAPSHOT_KEY];\n}\n","/**\n * `navigator.share` shim.\n *\n * Inside Apps in Toss → routes through SDK `share({ message })`. The SDK only\n * accepts a single `message` string, so we concatenate `title`, `text`, and\n * `url` with newline separators (skipping missing/empty values).\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.share`, or\n * throws `NotSupportedError` if unavailable.\n *\n * Install strategy: **method-level** on `navigator`. Assigning\n * `navigator.share = fn` creates an own property that shadows the prototype\n * method. Uninstall deletes the own shadow so the prototype method surfaces\n * again. We do not mutate `Navigator.prototype` — in real browsers its\n * descriptor may be non-configurable, which would throw on reassignment.\n *\n * Caveat: the SDK's share has no counterpart for `files` (Web Share Level 2).\n * `canShare({ files })` returns `false` whenever the sync-accessible detection\n * says Toss is active (or is being forced via the test override).\n */\n\nimport { isTossEnvironment, isTossEnvironmentCached, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst SHARE_BACKUP_KEY = Symbol.for('@ait-co/polyfill/share.original');\nconst SHARE_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/share.snapshot');\n\ntype ShareFn = (data?: ShareData) => Promise<void>;\ntype CanShareFn = (data?: ShareData) => boolean;\n\ninterface Backup {\n share: ShareFn | undefined;\n canShare: CanShareFn | undefined;\n}\n\ninterface BackupHost {\n [SHARE_BACKUP_KEY]?: Backup | undefined;\n [SHARE_SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\nfunction buildSdkMessage(data: ShareData | undefined): string {\n // Use presence checks rather than truthiness so an intentionally empty\n // string in one field is handled correctly alongside a non-empty sibling.\n const parts: string[] = [];\n if (data?.title != null && data.title !== '') parts.push(data.title);\n if (data?.text != null && data.text !== '') parts.push(data.text);\n if (data?.url != null && data.url !== '') parts.push(data.url);\n return parts.join('\\n');\n}\n\nasync function shareShim(data?: ShareData): Promise<void> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { share?: unknown } | null)?.share;\n if (typeof fn === 'function') {\n const message = buildSdkMessage(data);\n if (!message) {\n throw new TypeError(\n '[@ait-co/polyfill] navigator.share requires at least one of title, text, or url.',\n );\n }\n try {\n await (fn as (o: { message: string }) => Promise<void>)({ message });\n } catch (e) {\n // Spec says navigator.share rejects with a DOMException. Wrap SDK\n // errors as AbortError (the most common cause is user cancellation),\n // attaching the original as `.cause` for Sentry-style telemetry.\n const message_ = e instanceof Error ? e.message : String(e);\n const wrapped = new DOMException(message_, 'AbortError');\n if (e instanceof Error) {\n (wrapped as Error).cause = e;\n }\n throw wrapped;\n }\n return;\n }\n }\n const host = navigator as unknown as BackupHost;\n const backup = host[SHARE_BACKUP_KEY];\n const original = backup?.share;\n if (!original) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.share is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return original(data);\n}\n\nfunction canShareShim(data?: ShareData): boolean {\n const hasFiles = Boolean(data?.files && data.files.length > 0);\n const toss = isTossEnvironmentCached();\n\n if (hasFiles) {\n // SDK does not share files. If we know we're in Toss (or it's being\n // forced), say so honestly. If detection hasn't resolved yet, be\n // pessimistic — a false negative is safer than promising a capability\n // we'll turn around and deny.\n if (toss === true) return false;\n if (toss === undefined) return false;\n }\n\n // Toss with non-file payloads: true iff there's at least one field.\n if (toss === true) {\n return Boolean(\n (data?.title != null && data.title !== '') ||\n (data?.text != null && data.text !== '') ||\n (data?.url != null && data.url !== ''),\n );\n }\n\n // `toss === undefined` (detection not resolved) with non-file payload falls\n // through to the browser-native answer. Rationale: `canShare` is rarely\n // load-bearing — consumers care about `share()` itself, which awaits the\n // async detection correctly. A false-negative here would needlessly hide a\n // Share button while detection settles.\n // Browser path: delegate to native when present.\n const host = navigator as unknown as BackupHost;\n const backup = host[SHARE_BACKUP_KEY];\n const originalCanShare = backup?.canShare;\n if (originalCanShare) {\n return originalCanShare(data);\n }\n return Boolean(\n (data?.title != null && data.title !== '') ||\n (data?.text != null && data.text !== '') ||\n (data?.url != null && data.url !== ''),\n );\n}\n\nexport function installShareShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (SHARE_BACKUP_KEY in host) {\n // Already installed. Use `in` so the absence of `share` / `canShare` on\n // the pre-install navigator (legitimately stored as `undefined`) doesn't\n // re-trigger install.\n return () => uninstallShareShim();\n }\n\n const nav = navigator as Navigator & {\n share?: ShareFn;\n canShare?: CanShareFn;\n };\n // Capture the native methods BEFORE patching, bound to `navigator` so that\n // fallback calls keep the correct `this` and never recurse through our shim.\n host[SHARE_BACKUP_KEY] = {\n share: nav.share ? nav.share.bind(navigator) : undefined,\n canShare: nav.canShare ? nav.canShare.bind(navigator) : undefined,\n };\n\n const snapshot = installObjectMethods(navigator, {\n share: shareShim as (...args: never[]) => unknown,\n canShare: canShareShim as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n // Slots frozen. Back out the backup bookkeeping so a later install can retry.\n delete host[SHARE_BACKUP_KEY];\n return () => uninstallShareShim();\n }\n\n host[SHARE_SNAPSHOT_KEY] = snapshot;\n return uninstallShareShim;\n}\n\nexport function uninstallShareShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(SHARE_BACKUP_KEY in host)) return;\n\n const snapshot = host[SHARE_SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n\n delete host[SHARE_BACKUP_KEY];\n delete host[SHARE_SNAPSHOT_KEY];\n}\n","/**\n * `navigator.vibrate` shim.\n *\n * Inside Apps in Toss → best-effort mapping to SDK `generateHapticFeedback`.\n * Single-duration calls land in three buckets so the qualitative SDK haptic\n * tracks intensity a little more closely than the original two-bucket split:\n * - `vibrate(0)` → no-op (web standard: cancels pending vibration)\n * - `vibrate(1..20ms)` → `tickWeak`\n * - `vibrate(21..45ms)` → `tickMedium`\n * - `vibrate(>=46ms)` → `basicMedium`\n * - `vibrate(number[])` → iterates \"on\" segments (even indices) as `tap`\n * pulses with `setTimeout` gaps. Per-element ms mapping is intentionally\n * skipped: arrays in the wild are mostly rhythmic patterns, and the SDK\n * has no \"stronger heavy\" variant to reach for, so per-pulse precision\n * buys little. Callers needing intent should use `vibrateSemantic`.\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.vibrate`,\n * or returns `false` when unavailable (matches the spec — browsers that don't\n * support vibration simply return `false`).\n *\n * Install strategy: **method-level** on `navigator`. We assign our wrapper to\n * `navigator.vibrate` (creating an own shadow over the prototype method) and\n * delete it on uninstall so the prototype re-surfaces. We do not mutate\n * `Navigator.prototype` itself — browsers may mark it non-configurable.\n *\n * Caveats (documented in CLAUDE.md as the known lossy trade-off):\n * - SDK haptics are qualitative (\"tickWeak\", \"basicMedium\"), not millisecond\n * durations. The shim approximates intensity from duration but cannot\n * reproduce exact patterns. Length-only mapping cannot recover semantic\n * intent (success vs. error vs. warning); use `vibrateSemantic` for that.\n * - Arrays are fired sequentially via `setTimeout`; gaps between pulses are\n * honoured only as \"time until the next tap\", not as silent-vs-vibrating.\n * - `vibrate` is spec'd as **synchronous**; the SDK call is async. We return\n * `true` immediately (fire-and-forget). Errors from the SDK are swallowed.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/vibrate.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/vibrate.snapshot');\n\ntype VibrateFn = (pattern: VibratePattern) => boolean;\n\ninterface BackupHost {\n [BACKUP_KEY]?: VibrateFn | undefined;\n [SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\n// Mapping thresholds chosen so the existing dog-food cases keep their old\n// haptic (vibrate(20) → tickWeak, vibrate(50)+ → basicMedium) while a 21–45ms\n// nudge — too long for \"tick\", too short for \"basic\" — gets `tickMedium`.\nconst TICK_WEAK_MAX_MS = 20;\nconst TICK_MEDIUM_MAX_MS = 45;\n\ntype HapticType =\n | 'tickWeak'\n | 'tap'\n | 'tickMedium'\n | 'softMedium'\n | 'basicWeak'\n | 'basicMedium'\n | 'success'\n | 'error'\n | 'wiggle'\n | 'confetti';\n\nexport async function haptic(type: HapticType): Promise<void> {\n const sdk = await loadTossSdk();\n const fn = (sdk as { generateHapticFeedback?: unknown } | null)?.generateHapticFeedback;\n if (typeof fn === 'function') {\n try {\n await (fn as (o: { type: HapticType }) => Promise<void>)({ type });\n } catch {\n // Best-effort; spec-level `vibrate` cannot surface errors.\n }\n }\n}\n\nfunction durationToHaptic(duration: number): HapticType {\n if (duration <= TICK_WEAK_MAX_MS) return 'tickWeak';\n if (duration <= TICK_MEDIUM_MAX_MS) return 'tickMedium';\n return 'basicMedium';\n}\n\nfunction vibrateShim(pattern: VibratePattern): boolean {\n // Matches the spec: `vibrate(0)` or `vibrate([])` cancels pending vibration.\n // We can't cancel an in-flight SDK haptic (no cancel API), but we still\n // forward the cancel to the browser fallback so native vibration stops.\n const arr = Array.isArray(pattern) ? pattern : [pattern];\n if (arr.length === 0 || arr.every((n) => n === 0)) {\n void (async () => {\n if (!(await isTossEnvironment())) {\n const host = navigator as unknown as BackupHost;\n host[BACKUP_KEY]?.(pattern);\n }\n })();\n return true;\n }\n\n void (async () => {\n if (await isTossEnvironment()) {\n if (!Array.isArray(pattern)) {\n await haptic(durationToHaptic(pattern));\n return;\n }\n // Even indices = \"on\" durations, odd indices = pauses. `pattern[i]` is\n // `number | undefined` under `noUncheckedIndexedAccess`; the `undefined`\n // case only arises on out-of-bounds, which our length bound prevents.\n for (let i = 0; i < pattern.length; i += 2) {\n const on = pattern[i];\n if (on === undefined) break;\n if (on > 0) {\n await haptic('tap');\n }\n const pause = pattern[i + 1];\n if (typeof pause === 'number' && pause > 0) {\n await new Promise<void>((r) => setTimeout(r, pause));\n }\n }\n return;\n }\n const host = navigator as unknown as BackupHost;\n const original = host[BACKUP_KEY];\n original?.(pattern);\n })();\n\n return true;\n}\n\nexport function installVibrateShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n return () => uninstallVibrateShim();\n }\n\n const nav = navigator as Navigator & { vibrate?: VibrateFn };\n // Capture the native method BEFORE we patch, bound to `navigator` so our\n // fallback call keeps the correct `this` and never recurses into our shim.\n host[BACKUP_KEY] = nav.vibrate ? nav.vibrate.bind(navigator) : undefined;\n\n const snapshot = installObjectMethods(navigator, {\n vibrate: vibrateShim as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n delete host[BACKUP_KEY];\n return () => uninstallVibrateShim();\n }\n\n host[SNAPSHOT_KEY] = snapshot;\n return uninstallVibrateShim;\n}\n\nexport function uninstallVibrateShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * @ait-co/polyfill\n *\n * Write Apps in Toss mini-apps using standard Web APIs\n * (`navigator.clipboard`, `navigator.geolocation`, …). This polyfill routes\n * calls through the Apps in Toss SDK **only when we detect we are actually\n * running inside the Toss app** — in every other environment (a plain browser,\n * local dev, tests) the shims are not installed and the browser's native\n * implementations are used as-is.\n *\n * Unofficial community project. Not affiliated with Toss.\n */\n\nexport { isTossEnvironment, isTossEnvironmentCached, loadTossSdk } from './detect.js';\nexport { installClipboardShim, uninstallClipboardShim } from './shims/clipboard.js';\nexport { installGeolocationShim, uninstallGeolocationShim } from './shims/geolocation.js';\nexport { installNetworkShim, uninstallNetworkShim } from './shims/network.js';\nexport { installShareShim, uninstallShareShim } from './shims/share.js';\nexport { installVibrateShim, uninstallVibrateShim } from './shims/vibrate.js';\nexport { type VibrateIntent, vibrateSemantic } from './shims/vibrate-semantic.js';\n\nimport { isTossEnvironment } from './detect.js';\nimport { installClipboardShim, uninstallClipboardShim } from './shims/clipboard.js';\nimport { installGeolocationShim, uninstallGeolocationShim } from './shims/geolocation.js';\nimport { installNetworkShim, uninstallNetworkShim } from './shims/network.js';\nimport { installShareShim, uninstallShareShim } from './shims/share.js';\nimport { installVibrateShim, uninstallVibrateShim } from './shims/vibrate.js';\n\nexport const VERSION: string = __VERSION__;\n\nconst NOOP = (): void => {};\n\n/**\n * Install every shim this library ships, but only if we detect an Apps in\n * Toss runtime. In a plain browser `install()` is a no-op — the browser's\n * native APIs stay untouched.\n *\n * Returns a promise that resolves with an uninstall function. If the\n * environment turns out not to be Toss, the uninstall function is a no-op.\n *\n * Install order (when active): clipboard → geolocation → share → vibrate →\n * network. Not atomic on failure — if a per-shim install throws (e.g., a\n * consumer pinned a target navigator property as non-configurable), earlier\n * shims are already in place. Callers should catch and invoke the returned\n * uninstall to roll back.\n */\nexport async function install(): Promise<() => void> {\n if (!(await isTossEnvironment())) return NOOP;\n const uninstalls = [\n installClipboardShim(),\n installGeolocationShim(),\n installShareShim(),\n installVibrateShim(),\n installNetworkShim(),\n ];\n return () => {\n for (const fn of uninstalls) fn();\n };\n}\n\n/**\n * Uninstall every shim installed by `install()`. Safe to call when no shim is\n * installed — each installer's uninstall is a no-op in that case.\n */\nexport function uninstall(): void {\n uninstallClipboardShim();\n uninstallGeolocationShim();\n uninstallShareShim();\n uninstallVibrateShim();\n uninstallNetworkShim();\n}\n","/**\n * Side-effect entry point: `import '@ait-co/polyfill/auto'`\n *\n * Kicks off detection and, if we're inside Apps in Toss, installs every shim\n * this library ships. In a plain browser this is a no-op — browser native\n * APIs stay untouched. No-op idempotent: importing the entry more than once\n * doesn't re-install.\n *\n * Use this when you want the \"just add the dep\" experience. If you need to\n * observe when the polyfill actually attached (to gate init logic) or to tear\n * it down, import `install` / `uninstall` from `@ait-co/polyfill` directly.\n */\n\nimport { install } from './index.js';\n\nvoid install();\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,IAAI;;;;;;;;;;AAkBJ,SAAgB,0BAA+C;CAC7D,MAAM,QAAQ,WAAW;AACzB,KAAI,UAAU,OAAQ,QAAO;AAC7B,KAAI,UAAU,UAAW,QAAO;AAChC,QAAO;;;;;;;;;AAUT,eAAsB,oBAAsC;CAG1D,MAAM,QAAQ,WAAW;AACzB,KAAI,UAAU,OAAQ,QAAO;AAC7B,KAAI,UAAU,UAAW,QAAO;AAEhC,KAAI,WAAW,KAAA,EAAW,QAAO;CAEjC,MAAM,MAAM,MAAM,aAAa;AAC/B,KAAI,OAAO,KAAK,yBAAyB,YAAY;AACnD,WAAS;AACT,SAAO;;AAKT,KAAI;EACF,MAAM,UAAU,IAAI,sBAAsB;AAC1C,WAAS,QAAQ,QAAQ,IAAI,OAAO,YAAY;SAC1C;AACN,WAAS;;AAEX,QAAO;;;;;;AAOT,eAAsB,cAA4E;AAChG,KAAI;AACF,SAAO,MAAM,OAAO;SACd;AACN,SAAO;;;;;;;;;;;;;AC/CX,SAAgB,yBACd,MACA,YACiB;CACjB,MAAM,MAAM;CACZ,MAAM,eAAe,OAAO,yBAAyB,KAAK,KAAK;CAC/D,MAAM,iBAAiB,iBAAiB,KAAA;AAGxC,KAAI,CAAC,gBAAgB,aAAa,aAChC,KAAI;AACF,SAAO,eAAe,KAAK,MAAM,WAAW;AAC5C,SAAO;GAAE,UAAU;GAAY,oBAAoB;GAAc;GAAgB;SAC3E;CAOV,MAAM,QAAQ,OAAO,eAAe,IAAI;CACxC,MAAM,YAAY,OAAO,yBAAyB,OAAO,KAAK;AAE9D,KAAI,eAIF,KAAI;AACF,SAAO,IAAI;SACL;AAKV,QAAO,eAAe,OAAO,MAAM,WAAW;AAC9C,QAAO;EAAE,UAAU;EAAa,oBAAoB;EAAW;EAAgB;;;;;;;AAQjF,SAAgB,yBAAyB,MAAc,UAAiC;CACtF,MAAM,SACJ,SAAS,aAAa,aACjB,YACA,OAAO,eAAe,UAAU;AAEvC,KAAI,SAAS,mBACX,KAAI;AACF,SAAO,eAAe,QAAQ,MAAM,SAAS,mBAAmB;SAC1D;KAIR,KAAI;AACF,SAAQ,OAAwC;SAC1C;;;;;;;;;;;;;;;;AAkCZ,SAAgB,qBACd,QACA,cAC8B;CAC9B,MAAM,UAAkE,EAAE;CAC1E,MAAM,UAAoB,EAAE;CAC5B,MAAM,MAAM;AAEZ,MAAK,MAAM,OAAO,OAAO,KAAK,aAAa,EAAE;EAC3C,MAAM,SAAS,OAAO,OAAO,QAAQ,IAAI;EACzC,MAAM,WAAW,IAAI;AACrB,MAAI;AACF,OAAI,OAAO,aAAa;UAClB;AAEN,QAAK,MAAM,aAAa,SAAS;IAC/B,MAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,OACP,KAAI,aAAa,KAAK;QAEtB,QAAO,IAAI;;AAGf,UAAO;;AAKT,MAAI,IAAI,SAAU,aAAa,MAAkB;AAC/C,QAAK,MAAM,aAAa,SAAS;IAC/B,MAAM,OAAO,QAAQ;AACrB,QAAI,CAAC,KAAM;AACX,QAAI,KAAK,OACP,KAAI,aAAa,KAAK;QAEtB,QAAO,IAAI;;AAGf,UAAO;;AAET,UAAQ,OAAO;GAAE;GAAQ;GAAU;AACnC,UAAQ,KAAK,IAAI;;AAGnB,QAAO;EAAE;EAAQ;EAAS;;;;;;;AAQ5B,SAAgB,qBAAqB,UAAuC;CAC1E,MAAM,MAAM,SAAS;AACrB,MAAK,MAAM,OAAO,OAAO,KAAK,SAAS,QAAQ,EAAE;EAC/C,MAAM,QAAQ,SAAS,QAAQ;AAC/B,MAAI,CAAC,MAAO;AACZ,MAAI;AACF,OAAI,MAAM,OACR,KAAI,OAAO,MAAM;OAEjB,QAAO,IAAI;UAEP;;;;;;;;;;;;;;;AC/KZ,MAAMA,eAAa,OAAO,IAAI,sCAAsC;AACpE,MAAMC,iBAAe,OAAO,IAAI,sCAAsC;;;;;AAWtE,SAAS,oBAAoB,UAA4C;AAsFvE,QArFa;EACX,MAAM,WAA4B;AAChC,OAAI,MAAM,mBAAmB,EAAE;IAC7B,MAAM,MAAM,MAAM,aAAa;AAC/B,QAAI,KAAK,iBACP,QAAO,IAAI,kBAAkB;;AAGjC,OAAI,CAAC,SACH,OAAM,IAAI,aACR,yFACA,oBACD;AAEH,UAAO,SAAS,UAAU;;EAG5B,MAAM,UAAU,MAA6B;AAC3C,OAAI,MAAM,mBAAmB,EAAE;IAC7B,MAAM,MAAM,MAAM,aAAa;AAC/B,QAAI,KAAK,iBACP,QAAO,IAAI,iBAAiB,KAAK;;AAGrC,OAAI,CAAC,SACH,OAAM,IAAI,aACR,0FACA,oBACD;AAEH,UAAO,SAAS,UAAU,KAAK;;EAMjC,MAAM,OAAgC;AACpC,OAAI,MAAM,mBAAmB,CAC3B,OAAM,IAAI,aACR,sIACA,oBACD;AAEH,OAAI,CAAC,UAAU,KACb,OAAM,IAAI,aACR,iEACA,oBACD;AAEH,UAAO,SAAS,MAAM;;EAGxB,MAAM,MAAM,OAAsC;AAChD,OAAI,MAAM,mBAAmB,CAC3B,OAAM,IAAI,aACR,wIACA,oBACD;AAEH,OAAI,CAAC,UAAU,MACb,OAAM,IAAI,aACR,kEACA,oBACD;AAEH,UAAO,SAAS,MAAM,MAAM;;EAQ9B,mBACE,GAAG,SAC6C,UAAU,iBAAiB,GAAG,KAAK;EACrF,sBACE,GAAG,SACgD,UAAU,oBAAoB,GAAG,KAAK;EAI3F,gBAAgB,UAA0B,UAAU,cAAc,MAAM,IAAI;EAC7E;;;;;;;;;AAYH,SAAgB,uBAAmC;AACjD,KAAI,OAAO,cAAc,YAEvB,cAAa;CAGf,MAAM,OAAO;AACb,KAAID,gBAAc,KAMhB,cAAa,wBAAwB;CAGvC,MAAM,WAAW,UAAU;AAC3B,MAAKA,gBAAc;AAGnB,MAAKC,kBAAgB,yBAAyB,aAAa;EACzD,OAFW,oBAAoB,SAAS;EAGxC,cAAc;EACd,UAAU;EACX,CAAC;AAEF,QAAO;;;;;AAMT,SAAgB,yBAA+B;AAC7C,KAAI,OAAO,cAAc,YAAa;CACtC,MAAM,OAAO;AACb,KAAI,EAAED,gBAAc,MAAO;CAE3B,MAAM,WAAW,KAAKC;AACtB,KAAI,SAAU,0BAAyB,aAAa,SAAS;AAC7D,QAAO,KAAKD;AACZ,QAAO,KAAKC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3Hd,MAAMC,eAAa,OAAO,IAAI,wCAAwC;AACtE,MAAMC,iBAAe,OAAO,IAAI,wCAAwC;AAUxE,MAAM,oBAAoB;AAC1B,MAAM,gBAAgB;AAgBtB,SAAS,mBAAmB,KAAuC;CACjE,MAAM,aAAa;EACjB,UAAU,IAAI,OAAO;EACrB,WAAW,IAAI,OAAO;EACtB,UAAU,IAAI,OAAO;EACrB,UAAU,IAAI,OAAO;EACrB,kBAAkB,IAAI,OAAO;EAC7B,SAAS,IAAI,OAAO;EAEpB,OAAO;EACR;AAOD,QAAO;EACL,QAPqC;GACrC,GAAG;GACH,SAAS;AACP,WAAO,EAAE,GAAG,YAAY;;GAE3B;EAGC,WAAW,IAAI;EACf,SAAS;AACP,UAAO;IAAE,QAAQ,EAAE,GAAG,YAAY;IAAE,WAAW,IAAI;IAAW;;EAEjE;;AAGH,SAAS,gBAAgB,MAAiB,SAA2C;CAQnF,MAAM,OAAQ,WAAsD;AACpE,KAAI,OAAO,SAAS,YAAY;EAC9B,MAAM,QAAS,KAAgC;AAC/C,MAAI,OAAO;GACT,MAAM,QAA2C;IAAE;IAAM;IAAS;AAClE,UAAO,eAAe,OAAO,MAAM;AACnC,UAAO;;;AAKX,QAAO;EACL;EACA;EACA,mBAAmB;EACnB,sBAAsB;EACtB,SAAS;EACV;;AAGH,SAAS,oBAAoB,SAA8C;AACzE,QAAO,SAAS,qBAAqB,gBAAgB;;AAqBvD,SAAS,sBAAsB,UAAgD;CAM7E,IAAI,cAAc;CAClB,MAAM,6BAAa,IAAI,KAAyB;CAChD,MAAM,gCAAgB,IAAI,KAAqB;CAC/C,MAAM,iCAAiB,IAAI,KAAqC;AAuIhE,QArI8B;EAC5B,mBAAmB,SAAS,OAAO,SAAS;AAC1C,IAAM,YAAY;AAChB,QAAI,MAAM,mBAAmB,EAAE;KAE7B,MAAM,MADM,MAAM,aAAa,GAC8B;AAC7D,SAAI,OAAO,OAAO,YAAY;AAC5B,UAAI;AAIF,eAAQ,mBAHK,MAAO,GAAyD,EAC3E,UAAU,oBAAoB,QAAQ,EACvC,CAAC,CAC6B,CAAC;eACzB,GAAG;AACV,eACE,gBACE,GACA,aAAa,QAAQ,EAAE,UAAU,gDAClC,CACF;;AAEH;;;AAGJ,QAAI,CAAC,SAAS,oBAAoB;AAChC,aACE,gBACE,GACA,iFACD,CACF;AACD;;AAEF,aAAS,mBAAmB,SAAS,OAAO,QAAQ;OAClD;;EAGN,cAAc,SAAS,OAAO,SAAS;GACrC,MAAM,KAAK;GACX,MAAM,UAAU,EAAE,WAAW,OAAO;AACpC,kBAAe,IAAI,IAAI,QAAQ;AAE/B,IAAM,YAAY;AAChB,QAAI,MAAM,mBAAmB,EAAE;KAE7B,MAAM,MADM,MAAM,aAAa,GAC+B;AAC9D,SAAI,OAAO,OAAO,YAAY;AAC5B,UAAI,QAAQ,WAAW;AACrB,sBAAe,OAAO,GAAG;AACzB;;MAEF,MAAM,cACJ,GAKA;OACA,UAAU,QAAQ,QAAQ,mBAAmB,IAAI,CAAC;OAClD,UAAU,QACR,QACE,gBACE,GACA,eAAe,QACX,IAAI,UACJ,iDACL,CACF;OACH,SAAS;QACP,UAAU,oBAAoB,QAAQ;QAGtC,cAAc;QACd,kBAAkB;QACnB;OACF,CAAC;AACF,UAAI,QAAQ,WAAW;AACrB,oBAAa;AACb,sBAAe,OAAO,GAAG;AACzB;;AAEF,iBAAW,IAAI,IAAI,YAAY;AAC/B,qBAAe,OAAO,GAAG;AACzB;;;AAGJ,QAAI,CAAC,SAAS,eAAe;AAC3B,oBAAe,OAAO,GAAG;AACzB,aACE,gBACE,GACA,iFACD,CACF;AACD;;AAEF,QAAI,QAAQ,WAAW;AACrB,oBAAe,OAAO,GAAG;AACzB;;IAEF,MAAM,WAAW,SAAS,cAAc,SAAS,OAAO,QAAQ;AAChE,QAAI,QAAQ,WAAW;AACrB,cAAS,aAAa,SAAS;AAC/B,oBAAe,OAAO,GAAG;AACzB;;AAEF,kBAAc,IAAI,IAAI,SAAS;AAC/B,mBAAe,OAAO,GAAG;OACvB;AAEJ,UAAO;;EAGT,WAAW,IAAI;GACb,MAAM,UAAU,eAAe,IAAI,GAAG;AACtC,OAAI,SAAS;AACX,YAAQ,YAAY;AACpB,mBAAe,OAAO,GAAG;AACzB;;GAEF,MAAM,cAAc,WAAW,IAAI,GAAG;AACtC,OAAI,aAAa;AACf,iBAAa;AACb,eAAW,OAAO,GAAG;AACrB;;GAEF,MAAM,WAAW,cAAc,IAAI,GAAG;AACtC,OAAI,aAAa,KAAA,KAAa,SAAS,YAAY;AACjD,aAAS,WAAW,SAAS;AAC7B,kBAAc,OAAO,GAAG;;;EAG7B;;AAKH,SAAgB,yBAAqC;AACnD,KAAI,OAAO,cAAc,YACvB,cAAa;CAGf,MAAM,OAAO;AACb,KAAID,gBAAc,KAChB,cAAa,0BAA0B;CAGzC,MAAM,SAAS,UAAU;AACzB,KAAI,CAAC,QAAQ;AAGX,OAAKA,gBAAc,KAAA;AACnB,eAAa,0BAA0B;;CAWzC,MAAM,OAAO,sBANyB;EACpC,oBAAoB,OAAO,oBAAoB,KAAK,OAAO;EAC3D,eAAe,OAAO,eAAe,KAAK,OAAO;EACjD,YAAY,OAAO,YAAY,KAAK,OAAO;EAC5C,CAE2C;CAE5C,MAAM,WAAW,qBAAqB,QAAQ;EAC5C,oBAAoB,KAAK;EACzB,eAAe,KAAK;EACpB,YAAY,KAAK;EAClB,CAAC;AAEF,KAAI,CAAC,UAAU;AAEb,OAAKA,gBAAc,KAAA;AACnB,eAAa,0BAA0B;;AAGzC,MAAKA,gBAAc,EAAE,QAAQ;AAC7B,MAAKC,kBAAgB;AAErB,QAAO;;AAGT,SAAgB,2BAAiC;AAC/C,KAAI,OAAO,cAAc,YAAa;CACtC,MAAM,OAAO;AACb,KAAI,EAAED,gBAAc,MAAO;CAE3B,MAAM,WAAW,KAAKC;AACtB,KAAI,SAAU,sBAAqB,SAAS;AAC5C,QAAO,KAAKD;AACZ,QAAO,KAAKC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClSd,MAAM,gBAAgB,OAAO,IAAI,qCAAqC;AACtE,MAAM,uBAAuB,OAAO,IAAI,2CAA2C;AACnF,MAAM,0BAA0B,OAAO,IAAI,+CAA+C;AAW1F,MAAM,sBAAsB;AAE5B,SAAS,eAAe,QAAmC;AACzD,QAAO,WAAW;;AAGpB,SAAS,sBAAsB,QAAyC;AACtE,SAAQ,QAAR;EACE,KAAK,KACH,QAAO;EACT,KAAK,KACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,uBAAuB,QAAkC;AAChE,SAAQ,QAAR;EACE,KAAK,OACH,QAAO;EACT,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK,OACH,QAAO;EACT,KAAK,UACH,QAAO;EACT,QACE,QAAO;;;AAYb,MAAM,aAAa,OAAO,qCAAqC;AAE/D,IAAM,iBAAN,cAA6B,YAAY;CACvC,UAAmC;CACnC,WAAkE;CAElE,cAAc;AACZ,SAAO;AAGP,OAAK,iBAAiB,WAAW,OAAO,KAAK,UAAU,KAAK,MAAM,GAAG,CAAC;;CAGxE,CAAC,YAAY,MAAqC;AAChD,QAAA,SAAe;;CAGjB,IAAI,gBAA+B;AACjC,SAAO,sBAAsB,MAAA,UAAgB,UAAU;;CAKzD,IAAI,WAAmB;AACrB,SAAO;;CAET,IAAI,MAAc;AAChB,SAAO;;CAET,IAAI,WAAoB;AACtB,SAAO;;CAET,IAAI,OAAe;AACjB,SAAO,uBAAuB,MAAA,UAAgB,UAAU;;;AAI5D,SAAgB,qBAAiC;AAC/C,KAAI,OAAO,cAAc,YACvB,cAAa;CAGf,MAAM,OAAO;AACb,KAAI,KAAK,eACP,cAAa,sBAAsB;AAErC,MAAK,iBAAiB;CAItB,IAAI,eAAwC;CAC5C,IAAI,cAAc;CAClB,IAAI,WAAiC;CACrC,MAAM,aAAa,IAAI,gBAAgB;CAEvC,eAAe,UAAyB;AAItC,MAAI,SAAU,QAAO;AAErB,MADY,KAAK,KAAK,GACZ,cAAc,oBAAqB;AAC7C,cAAY,YAAY;AACtB,OAAI;AACF,QAAI,CAAE,MAAM,mBAAmB,CAAG;IAElC,MAAM,MADM,MAAM,aAAa,GAC4B;AAC3D,QAAI,OAAO,OAAO,WAAY;IAC9B,MAAM,OAAQ,MAAO,IAAwC;IAC7D,MAAM,OAAO;AACb,mBAAe;AACf,eAAW,YAAY,KAAK;AAI5B,QAAI,SAAS,QAAQ,SAAS,KAC5B,YAAW,cAAc,IAAI,MAAM,SAAS,CAAC;WAEzC,WAIE;AACR,kBAAc,KAAK,KAAK;AACxB,eAAW;;MAEX;AACJ,SAAO;;CAQT,MAAM,eAAgB,UAA+C;CACrE,MAAM,mBAAoB,UAAmD;AAGxE,UAAS;CAOd,IAAI,gBAAgB;CACpB,MAAM,uBAAuB,MAAqB;AAChD,MAAI,cAAe;AACnB,kBAAgB;AAChB,UAAQ,KACN,0HACA,EACD;;AAGH,KAAI;AACF,OAAK,wBAAwB,yBAAyB,UAAU;GAC9D,cAAc;GACd,MAAM;AACC,aAAS;AACd,QAAI,iBAAiB,KAAM,QAAO,eAAe,aAAa;AAC9D,WAAO,gBAAgB;;GAE1B,CAAC;UACK,GAAG;AACV,sBAAoB,EAAE;;AAGxB,KAAI;AACF,OAAK,2BAA2B,yBAAyB,cAAc;GACrE,cAAc;GACd,MAAM;AACC,aAAS;AACd,QAAI,iBAAiB,QAAQ,qBAAqB,KAAA,EAAW,QAAO;AACpE,WAAO;;GAEV,CAAC;UACK,GAAG;AACV,sBAAoB,EAAE;;AAGxB,QAAO;;AAGT,SAAgB,uBAA6B;AAC3C,KAAI,OAAO,cAAc,YAAa;CACtC,MAAM,OAAO;AACb,KAAI,CAAC,KAAK,eAAgB;CAE1B,MAAM,aAAa,KAAK;AACxB,KAAI,WAAY,0BAAyB,UAAU,WAAW;CAC9D,MAAM,WAAW,KAAK;AACtB,KAAI,SAAU,0BAAyB,cAAc,SAAS;AAE9D,QAAO,KAAK;AACZ,QAAO,KAAK;AACZ,QAAO,KAAK;;;;;;;;;;;;;;;;;;;;;;;;AClPd,MAAM,mBAAmB,OAAO,IAAI,kCAAkC;AACtE,MAAM,qBAAqB,OAAO,IAAI,kCAAkC;AAexE,SAAS,gBAAgB,MAAqC;CAG5D,MAAM,QAAkB,EAAE;AAC1B,KAAI,MAAM,SAAS,QAAQ,KAAK,UAAU,GAAI,OAAM,KAAK,KAAK,MAAM;AACpE,KAAI,MAAM,QAAQ,QAAQ,KAAK,SAAS,GAAI,OAAM,KAAK,KAAK,KAAK;AACjE,KAAI,MAAM,OAAO,QAAQ,KAAK,QAAQ,GAAI,OAAM,KAAK,KAAK,IAAI;AAC9D,QAAO,MAAM,KAAK,KAAK;;AAGzB,eAAe,UAAU,MAAiC;AACxD,KAAI,MAAM,mBAAmB,EAAE;EAE7B,MAAM,MADM,MAAM,aAAa,GACiB;AAChD,MAAI,OAAO,OAAO,YAAY;GAC5B,MAAM,UAAU,gBAAgB,KAAK;AACrC,OAAI,CAAC,QACH,OAAM,IAAI,UACR,mFACD;AAEH,OAAI;AACF,UAAO,GAAiD,EAAE,SAAS,CAAC;YAC7D,GAAG;IAIV,MAAM,WAAW,aAAa,QAAQ,EAAE,UAAU,OAAO,EAAE;IAC3D,MAAM,UAAU,IAAI,aAAa,UAAU,aAAa;AACxD,QAAI,aAAa,MACd,SAAkB,QAAQ;AAE7B,UAAM;;AAER;;;CAKJ,MAAM,WAFO,UACO,mBACK;AACzB,KAAI,CAAC,SACH,OAAM,IAAI,aACR,4EACA,oBACD;AAEH,QAAO,SAAS,KAAK;;AAGvB,SAAS,aAAa,MAA2B;CAC/C,MAAM,WAAW,QAAQ,MAAM,SAAS,KAAK,MAAM,SAAS,EAAE;CAC9D,MAAM,OAAO,yBAAyB;AAEtC,KAAI,UAAU;AAKZ,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,SAAS,KAAA,EAAW,QAAO;;AAIjC,KAAI,SAAS,KACX,QAAO,QACJ,MAAM,SAAS,QAAQ,KAAK,UAAU,MACpC,MAAM,QAAQ,QAAQ,KAAK,SAAS,MACpC,MAAM,OAAO,QAAQ,KAAK,QAAQ,GACtC;CAWH,MAAM,mBAFO,UACO,mBACa;AACjC,KAAI,iBACF,QAAO,iBAAiB,KAAK;AAE/B,QAAO,QACJ,MAAM,SAAS,QAAQ,KAAK,UAAU,MACpC,MAAM,QAAQ,QAAQ,KAAK,SAAS,MACpC,MAAM,OAAO,QAAQ,KAAK,QAAQ,GACtC;;AAGH,SAAgB,mBAA+B;AAC7C,KAAI,OAAO,cAAc,YACvB,cAAa;CAGf,MAAM,OAAO;AACb,KAAI,oBAAoB,KAItB,cAAa,oBAAoB;CAGnC,MAAM,MAAM;AAMZ,MAAK,oBAAoB;EACvB,OAAO,IAAI,QAAQ,IAAI,MAAM,KAAK,UAAU,GAAG,KAAA;EAC/C,UAAU,IAAI,WAAW,IAAI,SAAS,KAAK,UAAU,GAAG,KAAA;EACzD;CAED,MAAM,WAAW,qBAAqB,WAAW;EAC/C,OAAO;EACP,UAAU;EACX,CAAC;AAEF,KAAI,CAAC,UAAU;AAEb,SAAO,KAAK;AACZ,eAAa,oBAAoB;;AAGnC,MAAK,sBAAsB;AAC3B,QAAO;;AAGT,SAAgB,qBAA2B;AACzC,KAAI,OAAO,cAAc,YAAa;CACtC,MAAM,OAAO;AACb,KAAI,EAAE,oBAAoB,MAAO;CAEjC,MAAM,WAAW,KAAK;AACtB,KAAI,SAAU,sBAAqB,SAAS;AAE5C,QAAO,KAAK;AACZ,QAAO,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3Id,MAAM,aAAa,OAAO,IAAI,oCAAoC;AAClE,MAAM,eAAe,OAAO,IAAI,oCAAoC;AAYpE,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAc3B,eAAsB,OAAO,MAAiC;CAE5D,MAAM,MADM,MAAM,aAAa,GACkC;AACjE,KAAI,OAAO,OAAO,WAChB,KAAI;AACF,QAAO,GAAkD,EAAE,MAAM,CAAC;SAC5D;;AAMZ,SAAS,iBAAiB,UAA8B;AACtD,KAAI,YAAY,iBAAkB,QAAO;AACzC,KAAI,YAAY,mBAAoB,QAAO;AAC3C,QAAO;;AAGT,SAAS,YAAY,SAAkC;CAIrD,MAAM,MAAM,MAAM,QAAQ,QAAQ,GAAG,UAAU,CAAC,QAAQ;AACxD,KAAI,IAAI,WAAW,KAAK,IAAI,OAAO,MAAM,MAAM,EAAE,EAAE;AACjD,GAAM,YAAY;AAChB,OAAI,CAAE,MAAM,mBAAmB,CAChB,WACR,cAAc,QAAQ;MAE3B;AACJ,SAAO;;AAGT,EAAM,YAAY;AAChB,MAAI,MAAM,mBAAmB,EAAE;AAC7B,OAAI,CAAC,MAAM,QAAQ,QAAQ,EAAE;AAC3B,UAAM,OAAO,iBAAiB,QAAQ,CAAC;AACvC;;AAKF,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,GAAG;IAC1C,MAAM,KAAK,QAAQ;AACnB,QAAI,OAAO,KAAA,EAAW;AACtB,QAAI,KAAK,EACP,OAAM,OAAO,MAAM;IAErB,MAAM,QAAQ,QAAQ,IAAI;AAC1B,QAAI,OAAO,UAAU,YAAY,QAAQ,EACvC,OAAM,IAAI,SAAe,MAAM,WAAW,GAAG,MAAM,CAAC;;AAGxD;;EAGF,MAAM,WADO,UACS;AACtB,aAAW,QAAQ;KACjB;AAEJ,QAAO;;AAGT,SAAgB,qBAAiC;AAC/C,KAAI,OAAO,cAAc,YACvB,cAAa;CAGf,MAAM,OAAO;AACb,KAAI,cAAc,KAChB,cAAa,sBAAsB;CAGrC,MAAM,MAAM;AAGZ,MAAK,cAAc,IAAI,UAAU,IAAI,QAAQ,KAAK,UAAU,GAAG,KAAA;CAE/D,MAAM,WAAW,qBAAqB,WAAW,EAC/C,SAAS,aACV,CAAC;AAEF,KAAI,CAAC,UAAU;AACb,SAAO,KAAK;AACZ,eAAa,sBAAsB;;AAGrC,MAAK,gBAAgB;AACrB,QAAO;;AAGT,SAAgB,uBAA6B;AAC3C,KAAI,OAAO,cAAc,YAAa;CACtC,MAAM,OAAO;AACb,KAAI,EAAE,cAAc,MAAO;CAE3B,MAAM,WAAW,KAAK;AACtB,KAAI,SAAU,sBAAqB,SAAS;AAC5C,QAAO,KAAK;AACZ,QAAO,KAAK;;;;AC5Id,MAAM,aAAmB;;;;;;;;;;;;;;;AAgBzB,eAAsB,UAA+B;AACnD,KAAI,CAAE,MAAM,mBAAmB,CAAG,QAAO;CACzC,MAAM,aAAa;EACjB,sBAAsB;EACtB,wBAAwB;EACxB,kBAAkB;EAClB,oBAAoB;EACpB,oBAAoB;EACrB;AACD,cAAa;AACX,OAAK,MAAM,MAAM,WAAY,KAAI;;;;;;;;;;;;;;;;;ACzChC,SAAS"}
|
package/dist/auto.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/auto.js
CHANGED
|
@@ -771,10 +771,18 @@ function uninstallShareShim() {
|
|
|
771
771
|
/**
|
|
772
772
|
* `navigator.vibrate` shim.
|
|
773
773
|
*
|
|
774
|
-
* Inside Apps in Toss → best-effort mapping to SDK `generateHapticFeedback
|
|
774
|
+
* Inside Apps in Toss → best-effort mapping to SDK `generateHapticFeedback`.
|
|
775
|
+
* Single-duration calls land in three buckets so the qualitative SDK haptic
|
|
776
|
+
* tracks intensity a little more closely than the original two-bucket split:
|
|
775
777
|
* - `vibrate(0)` → no-op (web standard: cancels pending vibration)
|
|
776
|
-
* - `vibrate(
|
|
777
|
-
* - `vibrate(
|
|
778
|
+
* - `vibrate(1..20ms)` → `tickWeak`
|
|
779
|
+
* - `vibrate(21..45ms)` → `tickMedium`
|
|
780
|
+
* - `vibrate(>=46ms)` → `basicMedium`
|
|
781
|
+
* - `vibrate(number[])` → iterates "on" segments (even indices) as `tap`
|
|
782
|
+
* pulses with `setTimeout` gaps. Per-element ms mapping is intentionally
|
|
783
|
+
* skipped: arrays in the wild are mostly rhythmic patterns, and the SDK
|
|
784
|
+
* has no "stronger heavy" variant to reach for, so per-pulse precision
|
|
785
|
+
* buys little. Callers needing intent should use `vibrateSemantic`.
|
|
778
786
|
*
|
|
779
787
|
* Outside Apps in Toss → defers to the browser's native `navigator.vibrate`,
|
|
780
788
|
* or returns `false` when unavailable (matches the spec — browsers that don't
|
|
@@ -788,7 +796,8 @@ function uninstallShareShim() {
|
|
|
788
796
|
* Caveats (documented in CLAUDE.md as the known lossy trade-off):
|
|
789
797
|
* - SDK haptics are qualitative ("tickWeak", "basicMedium"), not millisecond
|
|
790
798
|
* durations. The shim approximates intensity from duration but cannot
|
|
791
|
-
* reproduce exact patterns.
|
|
799
|
+
* reproduce exact patterns. Length-only mapping cannot recover semantic
|
|
800
|
+
* intent (success vs. error vs. warning); use `vibrateSemantic` for that.
|
|
792
801
|
* - Arrays are fired sequentially via `setTimeout`; gaps between pulses are
|
|
793
802
|
* honoured only as "time until the next tap", not as silent-vs-vibrating.
|
|
794
803
|
* - `vibrate` is spec'd as **synchronous**; the SDK call is async. We return
|
|
@@ -796,7 +805,8 @@ function uninstallShareShim() {
|
|
|
796
805
|
*/
|
|
797
806
|
const BACKUP_KEY = Symbol.for("@ait-co/polyfill/vibrate.original");
|
|
798
807
|
const SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/vibrate.snapshot");
|
|
799
|
-
const
|
|
808
|
+
const TICK_WEAK_MAX_MS = 20;
|
|
809
|
+
const TICK_MEDIUM_MAX_MS = 45;
|
|
800
810
|
async function haptic(type) {
|
|
801
811
|
const fn = (await loadTossSdk())?.generateHapticFeedback;
|
|
802
812
|
if (typeof fn === "function") try {
|
|
@@ -804,7 +814,9 @@ async function haptic(type) {
|
|
|
804
814
|
} catch {}
|
|
805
815
|
}
|
|
806
816
|
function durationToHaptic(duration) {
|
|
807
|
-
|
|
817
|
+
if (duration <= TICK_WEAK_MAX_MS) return "tickWeak";
|
|
818
|
+
if (duration <= TICK_MEDIUM_MAX_MS) return "tickMedium";
|
|
819
|
+
return "basicMedium";
|
|
808
820
|
}
|
|
809
821
|
function vibrateShim(pattern) {
|
|
810
822
|
const arr = Array.isArray(pattern) ? pattern : [pattern];
|
package/dist/auto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto.js","names":["BACKUP_KEY","SNAPSHOT_KEY","BACKUP_KEY","SNAPSHOT_KEY","#status"],"sources":["../src/detect.ts","../src/shims/_install-helpers.ts","../src/shims/clipboard.ts","../src/shims/geolocation.ts","../src/shims/network.ts","../src/shims/share.ts","../src/shims/vibrate.ts","../src/index.ts","../src/auto.ts"],"sourcesContent":["/**\n * Environment detection: are we running inside Apps in Toss, or a plain browser?\n *\n * Strategy: call the SDK's `getAppsInTossGlobals()` — a synchronous export\n * that returns the runtime's Toss globals (deploymentId, brand name, …)\n * inside the Apps in Toss runtime and throws (RN bridge unavailable)\n * anywhere else. The SDK itself is an **optional** peer dependency; if its\n * module can't be imported we are definitely not inside Toss.\n *\n * Just having the SDK module resolvable is not enough — apps can bundle it\n * and still run in a plain browser. We need the bridge probe to confirm.\n *\n * UA sniffing (spoofable) is avoided. We do call `getAppsInTossGlobals`, but\n * that's a constant read from the bridge — no permission dialogs, no\n * analytics fire. In a plain browser the bridge lookup fails fast (sync\n * throw, microsecond-scale), so the startup cost is negligible.\n */\n\nlet cached: boolean | undefined;\n\n/**\n * Reset the cached detection result. Primarily for tests.\n */\nexport function resetDetection(): void {\n cached = undefined;\n}\n\n/**\n * Synchronous read of the cached detection result. Returns:\n * - `true` / `false` if an override is active or the async detection has\n * already resolved\n * - `undefined` if detection hasn't run yet\n *\n * Used by spec-sync APIs (e.g. `navigator.canShare`) that can't `await`\n * detection.\n */\nexport function isTossEnvironmentCached(): boolean | undefined {\n const force = globalThis.__AIT_POLYFILL_FORCE__;\n if (force === 'toss') return true;\n if (force === 'browser') return false;\n return cached;\n}\n\n/**\n * Returns `true` iff we detect we are running in an environment where the\n * Apps in Toss SDK (`@apps-in-toss/web-framework`) is present and usable.\n *\n * Async because we use dynamic `import()` to probe the optional peer dep\n * without forcing it into the consumer's bundle.\n */\nexport async function isTossEnvironment(): Promise<boolean> {\n // Override check precedes cache so `devtools` / tests can flip the result\n // mid-session without a `resetDetection()` call.\n const force = globalThis.__AIT_POLYFILL_FORCE__;\n if (force === 'toss') return true;\n if (force === 'browser') return false;\n\n if (cached !== undefined) return cached;\n\n const mod = await loadTossSdk();\n if (typeof mod?.getAppsInTossGlobals !== 'function') {\n cached = false;\n return cached;\n }\n // Inside Toss the bridge returns a populated globals object. In a plain\n // browser the RN bridge isn't attached and the call throws — that's our\n // signal. Any non-throwing call with an object return is treated as Toss.\n try {\n const globals = mod.getAppsInTossGlobals();\n cached = Boolean(globals) && typeof globals === 'object';\n } catch {\n cached = false;\n }\n return cached;\n}\n\n/**\n * Lazy SDK accessor — returns the module if available, else `null`. Callers\n * are expected to `await` and null-check. Never throws.\n */\nexport async function loadTossSdk(): Promise<typeof import('@apps-in-toss/web-framework') | null> {\n try {\n return await import('@apps-in-toss/web-framework');\n } catch {\n return null;\n }\n}\n","/**\n * Shared helpers for installing shims on `navigator`.\n *\n * Chromium now marks a handful of `navigator` properties (e.g. `geolocation`,\n * `clipboard`) as non-configurable **own** properties on the instance. That\n * means a plain `Object.defineProperty(navigator, 'x', …)` throws\n * `TypeError: Cannot redefine property`.\n *\n * The workaround is to shim at the prototype level — `Navigator.prototype`\n * keeps these as configurable accessors, so we can swap them there and every\n * instance that falls through to the prototype (including `window.navigator`)\n * sees the shim. We only reach for the prototype when the instance-level\n * assignment refuses.\n *\n * For restoration we remember the descriptor chain (instance + prototype) so\n * `uninstall()` puts the browser back in its original state.\n */\n\ntype PropertyLocation = 'instance' | 'prototype';\n\nexport interface InstallSnapshot {\n /** Where we ended up writing the shim. */\n location: PropertyLocation;\n /** Original descriptor at that location (may be undefined if nothing was there). */\n originalDescriptor: PropertyDescriptor | undefined;\n /** `true` iff the original property lived on the instance before we touched it. */\n instanceHadOwn: boolean;\n}\n\n/**\n * Install `descriptor` at `navigator[prop]`. Prefer instance-level; if the\n * browser refuses (property is non-configurable on the instance), install on\n * `Navigator.prototype` instead.\n *\n * Returns a snapshot describing where the original value was, which\n * `restoreNavigatorProperty` uses to undo the install.\n */\nexport function installNavigatorProperty(\n prop: string,\n descriptor: PropertyDescriptor,\n): InstallSnapshot {\n const nav = navigator as unknown as Record<PropertyKey, unknown>;\n const instanceDesc = Object.getOwnPropertyDescriptor(nav, prop);\n const instanceHadOwn = instanceDesc !== undefined;\n\n // Fast path: instance-level property is missing or configurable.\n if (!instanceDesc || instanceDesc.configurable) {\n try {\n Object.defineProperty(nav, prop, descriptor);\n return { location: 'instance', originalDescriptor: instanceDesc, instanceHadOwn };\n } catch {\n // Fall through to prototype-level install.\n }\n }\n\n // Prototype-level install. Drop the instance-level shadow so the prototype\n // accessor is visible to readers on `navigator`.\n const proto = Object.getPrototypeOf(nav) as object;\n const protoDesc = Object.getOwnPropertyDescriptor(proto, prop);\n\n if (instanceHadOwn) {\n // Try to remove the instance-level shadow. On non-configurable it throws —\n // we deliberately ignore that; prototype-level install still wins because\n // the prototype accessor shows through when we read via `navigator[prop]`.\n try {\n delete nav[prop];\n } catch {\n /* non-configurable own — leave it; prototype install still useful */\n }\n }\n\n Object.defineProperty(proto, prop, descriptor);\n return { location: 'prototype', originalDescriptor: protoDesc, instanceHadOwn };\n}\n\n/**\n * Reverse the install recorded in `snapshot`. If the original descriptor was\n * `undefined` (property didn't exist before), delete the property instead of\n * re-defining it.\n */\nexport function restoreNavigatorProperty(prop: string, snapshot: InstallSnapshot): void {\n const target =\n snapshot.location === 'instance'\n ? (navigator as unknown as Record<PropertyKey, unknown>)\n : (Object.getPrototypeOf(navigator) as object);\n\n if (snapshot.originalDescriptor) {\n try {\n Object.defineProperty(target, prop, snapshot.originalDescriptor);\n } catch {\n /* descriptor was non-configurable upstream; we can't undo — rare. */\n }\n } else {\n try {\n delete (target as Record<PropertyKey, unknown>)[prop];\n } catch {\n /* non-configurable — rare. */\n }\n }\n\n // If our install pushed past an instance shadow, we leave the instance alone\n // — the descriptor we captured for `instanceHadOwn: true` lives on the\n // instance and was not modified at install time.\n}\n\n/**\n * Method-level install snapshot. Captured per-key so `restoreObjectMethods`\n * can distinguish \"was an own property, reassign it\" from \"was inherited,\n * delete the override so the prototype method surfaces again\".\n */\nexport interface MethodInstallSnapshot {\n target: object;\n methods: Record<string, { hadOwn: boolean; original: unknown }>;\n}\n\n/**\n * Mutate methods on an existing object rather than replacing the object\n * itself. This is the path we take for `navigator.geolocation`, `navigator.share`,\n * and `navigator.vibrate` in Chromium, where the slot on `navigator` is a\n * non-configurable own property that we cannot replace — but the methods\n * themselves (or the methods on the referenced object) are still\n * `configurable: true, writable: true`.\n *\n * Each replacement is installed via plain assignment. If any slot is not\n * writable (e.g. frozen object), install is aborted and previously-applied\n * replacements are rolled back, so the caller observes an atomic \"all or\n * nothing\" failure as `null`. The caller is expected to degrade gracefully\n * (e.g. log a one-time `console.warn`) when that happens.\n */\nexport function installObjectMethods(\n target: object,\n replacements: Record<string, (...args: never[]) => unknown>,\n): MethodInstallSnapshot | null {\n const methods: Record<string, { hadOwn: boolean; original: unknown }> = {};\n const applied: string[] = [];\n const bag = target as Record<string, unknown>;\n\n for (const key of Object.keys(replacements)) {\n const hadOwn = Object.hasOwn(target, key);\n const original = bag[key];\n try {\n bag[key] = replacements[key] as unknown;\n } catch {\n // Non-writable / frozen. Roll back and return null.\n for (const applieKey of applied) {\n const prev = methods[applieKey];\n if (!prev) continue;\n if (prev.hadOwn) {\n bag[applieKey] = prev.original;\n } else {\n delete bag[applieKey];\n }\n }\n return null;\n }\n // Verify the assignment actually stuck — silent-failure descriptors (e.g.\n // `writable: false` without strict mode) can skip the throw and leave the\n // original value in place. Treat that the same as a throw.\n if (bag[key] !== (replacements[key] as unknown)) {\n for (const applieKey of applied) {\n const prev = methods[applieKey];\n if (!prev) continue;\n if (prev.hadOwn) {\n bag[applieKey] = prev.original;\n } else {\n delete bag[applieKey];\n }\n }\n return null;\n }\n methods[key] = { hadOwn, original };\n applied.push(key);\n }\n\n return { target, methods };\n}\n\n/**\n * Reverse an `installObjectMethods` snapshot. Reassigns originals for slots\n * that were own properties before install; deletes the override for slots\n * that were inherited (so the prototype method surfaces again).\n */\nexport function restoreObjectMethods(snapshot: MethodInstallSnapshot): void {\n const bag = snapshot.target as Record<string, unknown>;\n for (const key of Object.keys(snapshot.methods)) {\n const entry = snapshot.methods[key];\n if (!entry) continue;\n try {\n if (entry.hadOwn) {\n bag[key] = entry.original;\n } else {\n delete bag[key];\n }\n } catch {\n /* frozen between install and restore — rare. */\n }\n }\n}\n","/**\n * `navigator.clipboard` shim.\n *\n * Inside Apps in Toss → routes `readText` / `writeText` through the SDK\n * (`getClipboardText` / `setClipboardText`).\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.clipboard`.\n * If the browser doesn't implement it, the standard `TypeError` / `DOMException`\n * surfaces unchanged — we don't paper over missing support.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n type InstallSnapshot,\n installNavigatorProperty,\n restoreNavigatorProperty,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/clipboard.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/clipboard.snapshot');\n\ninterface BackupHost {\n [BACKUP_KEY]?: Clipboard | undefined;\n [SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n}\n\n/**\n * Produces a Clipboard-compatible object whose `readText` / `writeText` methods\n * route to the SDK when in Toss, else fall through to the supplied `fallback`.\n */\nfunction createClipboardShim(fallback: Clipboard | undefined): Clipboard {\n const shim = {\n async readText(): Promise<string> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n if (sdk?.getClipboardText) {\n return sdk.getClipboardText();\n }\n }\n if (!fallback) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.readText is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return fallback.readText();\n },\n\n async writeText(text: string): Promise<void> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n if (sdk?.setClipboardText) {\n return sdk.setClipboardText(text);\n }\n }\n if (!fallback) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.writeText is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return fallback.writeText(text);\n },\n\n // `read` / `write` (ClipboardItem-based) are passed through to the\n // fallback when in browser mode; the SDK has no rich-content counterpart,\n // so in Toss mode they throw.\n async read(): Promise<ClipboardItems> {\n if (await isTossEnvironment()) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.read (rich content) is not supported in the Apps in Toss environment. Use readText instead.',\n 'NotSupportedError',\n );\n }\n if (!fallback?.read) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.read is not available.',\n 'NotSupportedError',\n );\n }\n return fallback.read();\n },\n\n async write(items: ClipboardItems): Promise<void> {\n if (await isTossEnvironment()) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.write (rich content) is not supported in the Apps in Toss environment. Use writeText instead.',\n 'NotSupportedError',\n );\n }\n if (!fallback?.write) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.write is not available.',\n 'NotSupportedError',\n );\n }\n return fallback.write(items);\n },\n\n // EventTarget passthrough. `navigator.clipboard` extends EventTarget in the\n // spec; mini-apps rarely use it. We forward to the fallback when one exists;\n // in Toss mode (no fallback) we silently drop subscriptions — the SDK emits\n // no clipboard events, so there is nothing to dispatch. This is lossy but\n // preserves the spec-compatible shape.\n addEventListener: (\n ...args: Parameters<EventTarget['addEventListener']>\n ): ReturnType<EventTarget['addEventListener']> => fallback?.addEventListener(...args),\n removeEventListener: (\n ...args: Parameters<EventTarget['removeEventListener']>\n ): ReturnType<EventTarget['removeEventListener']> => fallback?.removeEventListener(...args),\n // Returns `false` in Toss mode (no backing EventTarget). A caller that reads\n // this as \"default action cancelled\" should check context — there are no\n // listeners to run because the SDK doesn't surface clipboard events.\n dispatchEvent: (event: Event): boolean => fallback?.dispatchEvent(event) ?? false,\n } satisfies Clipboard;\n\n return shim;\n}\n\n/**\n * Install the `navigator.clipboard` shim.\n *\n * @returns an uninstall function that restores the original `navigator.clipboard`.\n * Calling install twice without uninstalling is a no-op on the second call\n * and returns the same uninstall function.\n */\nexport function installClipboardShim(): () => void {\n if (typeof navigator === 'undefined') {\n // No-op in non-DOM environments (pure Node).\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n // Already installed. Use `in` (not `!== undefined`) because the stored\n // backup is legitimately `undefined` when the browser has no native\n // `navigator.clipboard` — without this, we'd re-wrap on each install.\n // Note: the returned uninstall is global. Any caller's uninstall fully\n // removes the shim; callers do not have independent install handles.\n return () => uninstallClipboardShim();\n }\n\n const original = navigator.clipboard as Clipboard | undefined;\n host[BACKUP_KEY] = original;\n\n const shim = createClipboardShim(original);\n host[SNAPSHOT_KEY] = installNavigatorProperty('clipboard', {\n value: shim,\n configurable: true,\n writable: true,\n });\n\n return uninstallClipboardShim;\n}\n\n/**\n * Remove the shim and restore the pre-install shape.\n */\nexport function uninstallClipboardShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreNavigatorProperty('clipboard', snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * `navigator.geolocation` shim.\n *\n * Inside Apps in Toss → routes through the SDK:\n * - `getCurrentPosition` → `getCurrentLocation({ accuracy })`\n * - `watchPosition` / `clearWatch` → `startUpdateLocation({ onEvent, onError, options })`\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.geolocation`.\n * If neither is available, the error callback receives a `GeolocationPositionError`.\n *\n * Install strategy: **method-level**. We do **not** replace `navigator.geolocation`\n * itself — Chromium marks that slot as a non-configurable own property, which\n * both `defineProperty(navigator, 'geolocation', …)` and the prototype-level\n * fallback cannot override (the instance shadow blocks prototype reads). We\n * instead mutate the methods on the existing `Geolocation` object, whose own\n * method descriptors are configurable+writable in every browser we've seen.\n *\n * SDK/Web shape mismatch handled here:\n * - SDK `Accuracy` is a numeric enum (1 = Lowest … 6 = BestForNavigation); the\n * standard `PositionOptions.enableHighAccuracy` is a boolean. We map\n * `true → Accuracy.High (4, \"~10m\")` and `false → Accuracy.Balanced (3)`.\n * `Highest (5)` / `BestForNavigation (6)` are available but carry a battery\n * cost that's rarely what mini-apps want; consumers who need them should\n * call the SDK directly.\n * - SDK coords lack `speed`; we surface `null` (per the W3C spec when unknown).\n * - SDK `startUpdateLocation` returns an `unsubscribe` fn; we wrap it behind\n * a numeric watch id so `clearWatch(id)` behaves like the standard.\n *\n * Caveat: watch ids reset whenever the shim is uninstalled and reinstalled;\n * they are not stable across such cycles. Ids obtained before uninstall\n * cannot be cleared after uninstall — `clearWatch(id)` on the restored native\n * `navigator.geolocation` uses a different id space, so the SDK subscription\n * leaks. Consumers should `clearWatch` all outstanding ids before calling\n * `uninstall()`.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/geolocation.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/geolocation.snapshot');\n\ninterface BackupHost {\n [BACKUP_KEY]?: { target: Geolocation } | undefined;\n [SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\n// SDK Accuracy enum values. We don't import the enum at runtime (peer is\n// optional), so we hard-code the numeric constants used by the SDK. Stable\n// ABI per the SDK's exported numeric enum.\nconst ACCURACY_BALANCED = 3;\nconst ACCURACY_HIGH = 4;\n\ninterface SdkLocationCoords {\n latitude: number;\n longitude: number;\n altitude: number;\n accuracy: number;\n altitudeAccuracy: number;\n heading: number;\n}\n\ninterface SdkLocation {\n timestamp: number;\n coords: SdkLocationCoords;\n}\n\nfunction toStandardPosition(sdk: SdkLocation): GeolocationPosition {\n const coordsData = {\n latitude: sdk.coords.latitude,\n longitude: sdk.coords.longitude,\n altitude: sdk.coords.altitude,\n accuracy: sdk.coords.accuracy,\n altitudeAccuracy: sdk.coords.altitudeAccuracy,\n heading: sdk.coords.heading,\n // SDK does not surface speed. Per spec, null means \"unknown\".\n speed: null,\n };\n const coords: GeolocationCoordinates = {\n ...coordsData,\n toJSON() {\n return { ...coordsData };\n },\n };\n return {\n coords,\n timestamp: sdk.timestamp,\n toJSON() {\n return { coords: { ...coordsData }, timestamp: sdk.timestamp };\n },\n };\n}\n\nfunction toPositionError(code: 1 | 2 | 3, message: string): GeolocationPositionError {\n // Prefer the real constructor when available (every real browser ships it).\n // The spec says GeolocationPositionError is not constructable, so we fall\n // through to a fabricated object whose prototype is patched via\n // `setPrototypeOf` — that keeps `instanceof` checks in consumer code working\n // and picks up the spec's PERMISSION_DENIED / POSITION_UNAVAILABLE / TIMEOUT\n // constants from the real prototype rather than hard-coding them (avoids\n // drift if the spec ever grows a new code).\n const Ctor = (globalThis as { GeolocationPositionError?: unknown }).GeolocationPositionError;\n if (typeof Ctor === 'function') {\n const proto = (Ctor as { prototype?: object }).prototype;\n if (proto) {\n const shape: { code: number; message: string } = { code, message };\n Object.setPrototypeOf(shape, proto);\n return shape as GeolocationPositionError;\n }\n }\n // jsdom / last-resort fallback: fabricate the spec shape with hard-coded\n // constants since there's no prototype to delegate to.\n return {\n code,\n message,\n PERMISSION_DENIED: 1,\n POSITION_UNAVAILABLE: 2,\n TIMEOUT: 3,\n } as GeolocationPositionError;\n}\n\nfunction accuracyFromOptions(options: PositionOptions | undefined): number {\n return options?.enableHighAccuracy ? ACCURACY_HIGH : ACCURACY_BALANCED;\n}\n\n/**\n * Minimal view of the native `Geolocation` methods we forward to. We pass\n * the **captured originals** here, not a reference to `navigator.geolocation`\n * itself — after install the methods on that object ARE the shim, so using\n * `navigator.geolocation.getCurrentPosition(…)` as a fallback would infinite-loop.\n */\ninterface GeolocationFallback {\n getCurrentPosition: Geolocation['getCurrentPosition'] | undefined;\n watchPosition: Geolocation['watchPosition'] | undefined;\n clearWatch: Geolocation['clearWatch'] | undefined;\n}\n\ninterface GeolocationShim {\n getCurrentPosition: Geolocation['getCurrentPosition'];\n watchPosition: Geolocation['watchPosition'];\n clearWatch: Geolocation['clearWatch'];\n}\n\nfunction createGeolocationShim(fallback: GeolocationFallback): GeolocationShim {\n // Numeric watch id → SDK unsubscribe fn. Keeps the shim's API in line with\n // the standard even though the SDK issues unsubscribe closures instead.\n // `pendingWatches` closes the race where `clearWatch` is called before the\n // async `watchPosition` installer resolves — without it we'd leak the SDK\n // subscription.\n let nextWatchId = 1;\n const sdkWatches = new Map<number, () => void>();\n const nativeWatches = new Map<number, number>();\n const pendingWatches = new Map<number, { cancelled: boolean }>();\n\n const shim: GeolocationShim = {\n getCurrentPosition(success, error, options) {\n void (async () => {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { getCurrentLocation?: unknown } | null)?.getCurrentLocation;\n if (typeof fn === 'function') {\n try {\n const loc = (await (fn as (o: { accuracy: number }) => Promise<SdkLocation>)({\n accuracy: accuracyFromOptions(options),\n })) as SdkLocation;\n success(toStandardPosition(loc));\n } catch (e) {\n error?.(\n toPositionError(\n 2,\n e instanceof Error ? e.message : '[@ait-co/polyfill] getCurrentLocation failed.',\n ),\n );\n }\n return;\n }\n }\n if (!fallback.getCurrentPosition) {\n error?.(\n toPositionError(\n 2,\n '[@ait-co/polyfill] navigator.geolocation is not available in this environment.',\n ),\n );\n return;\n }\n fallback.getCurrentPosition(success, error, options);\n })();\n },\n\n watchPosition(success, error, options) {\n const id = nextWatchId++;\n const pending = { cancelled: false };\n pendingWatches.set(id, pending);\n\n void (async () => {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { startUpdateLocation?: unknown } | null)?.startUpdateLocation;\n if (typeof fn === 'function') {\n if (pending.cancelled) {\n pendingWatches.delete(id);\n return;\n }\n const unsubscribe = (\n fn as (p: {\n onEvent: (loc: SdkLocation) => void;\n onError: (err: unknown) => void;\n options: { accuracy: number; timeInterval: number; distanceInterval: number };\n }) => () => void\n )({\n onEvent: (loc) => success(toStandardPosition(loc)),\n onError: (err) =>\n error?.(\n toPositionError(\n 2,\n err instanceof Error\n ? err.message\n : '[@ait-co/polyfill] startUpdateLocation failed.',\n ),\n ),\n options: {\n accuracy: accuracyFromOptions(options),\n // Sensible defaults — web `watchPosition` has no analogues.\n // Consumers needing sub-second updates should use the SDK directly.\n timeInterval: 1000,\n distanceInterval: 0,\n },\n });\n if (pending.cancelled) {\n unsubscribe();\n pendingWatches.delete(id);\n return;\n }\n sdkWatches.set(id, unsubscribe);\n pendingWatches.delete(id);\n return;\n }\n }\n if (!fallback.watchPosition) {\n pendingWatches.delete(id);\n error?.(\n toPositionError(\n 2,\n '[@ait-co/polyfill] navigator.geolocation is not available in this environment.',\n ),\n );\n return;\n }\n if (pending.cancelled) {\n pendingWatches.delete(id);\n return;\n }\n const nativeId = fallback.watchPosition(success, error, options);\n if (pending.cancelled) {\n fallback.clearWatch?.(nativeId);\n pendingWatches.delete(id);\n return;\n }\n nativeWatches.set(id, nativeId);\n pendingWatches.delete(id);\n })();\n\n return id;\n },\n\n clearWatch(id) {\n const pending = pendingWatches.get(id);\n if (pending) {\n pending.cancelled = true;\n pendingWatches.delete(id);\n return;\n }\n const unsubscribe = sdkWatches.get(id);\n if (unsubscribe) {\n unsubscribe();\n sdkWatches.delete(id);\n return;\n }\n const nativeId = nativeWatches.get(id);\n if (nativeId !== undefined && fallback.clearWatch) {\n fallback.clearWatch(nativeId);\n nativeWatches.delete(id);\n }\n },\n };\n\n return shim;\n}\n\nexport function installGeolocationShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n return () => uninstallGeolocationShim();\n }\n\n const target = navigator.geolocation as Geolocation | undefined;\n if (!target) {\n // No `navigator.geolocation` at all (rare — jsdom may expose it, real\n // browsers always do). Nothing for the shim to mutate; bail quietly.\n host[BACKUP_KEY] = undefined;\n return () => uninstallGeolocationShim();\n }\n\n // Capture the native methods BEFORE we patch so the shim's fallback path\n // doesn't recurse through itself.\n const fallback: GeolocationFallback = {\n getCurrentPosition: target.getCurrentPosition?.bind(target),\n watchPosition: target.watchPosition?.bind(target),\n clearWatch: target.clearWatch?.bind(target),\n };\n\n const shim = createGeolocationShim(fallback);\n\n const snapshot = installObjectMethods(target, {\n getCurrentPosition: shim.getCurrentPosition as (...args: never[]) => unknown,\n watchPosition: shim.watchPosition as (...args: never[]) => unknown,\n clearWatch: shim.clearWatch as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n // Method slots frozen — can't install. No-op uninstall.\n host[BACKUP_KEY] = undefined;\n return () => uninstallGeolocationShim();\n }\n\n host[BACKUP_KEY] = { target };\n host[SNAPSHOT_KEY] = snapshot;\n\n return uninstallGeolocationShim;\n}\n\nexport function uninstallGeolocationShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * `navigator.onLine` + `navigator.connection` shim.\n *\n * Inside Apps in Toss → seeded from SDK `getNetworkStatus()` on install and\n * refreshed on read (throttled):\n * - `'OFFLINE'` → `onLine = false`\n * - `'WIFI'` → `onLine = true`, `effectiveType = '4g'` (no web wifi value)\n * - `'2G'/'3G'/'4G'/'5G'` → `onLine = true`, `effectiveType = <lowercased>`\n * - `'WWAN'/'UNKNOWN'` → `onLine = true`, `effectiveType = '4g'` (best guess)\n *\n * Outside Apps in Toss → both `navigator.onLine` and `navigator.connection`\n * read through to the native value. Install installs own-instance getters\n * that consult the Toss-seeded cache first; when the cache is empty (which\n * it always is in browser mode), the getter temporarily removes its own\n * shadow, reads the prototype value, and reinstates the shadow.\n *\n * Uninstall `delete`s the instance-level override so the prototype descriptor\n * (where `onLine` and `connection` actually live in real browsers) becomes\n * visible again. We never mutate the prototype — doing so would throw in\n * browsers where the descriptor is non-configurable.\n *\n * Browser-compat caveat (Chromium): `navigator.onLine` and `navigator.connection`\n * are value slots, not methods, so the method-level install trick we use for\n * `geolocation`/`share`/`vibrate` does not apply here. When Chromium marks the\n * instance descriptor as non-configurable AND the prototype descriptor is also\n * non-configurable, we cannot install. In that case the shim logs a one-time\n * `console.warn` and leaves the native values in place — consumers keep the\n * browser's own `onLine`/`connection` values; the SDK-synced state is simply\n * disabled for that session.\n *\n * Caveat: the Web NetworkInformation API is evented (`change` fires on\n * transitions). The SDK exposes only a one-shot query, so listeners attached\n * to `navigator.connection` are accepted but never fire from a `change` event\n * unless the shim observes a real status transition. Synthesising richer\n * events via polling is tracked in TODO.md.\n *\n * Lifecycle: `navigator.connection` is a ShimConnection instance that lives in\n * the install closure. On uninstall the instance-level override is removed,\n * but listeners the consumer attached to the old instance stay bound to that\n * (now-orphan) object and will not see events from a subsequent install.\n * Consumers should re-attach listeners after each install.\n *\n * Seed-boundary race: in Toss mode, reads before the install-time SDK seed\n * completes fall through to the native `navigator.connection`. After the seed\n * lands, subsequent reads return the shim's ShimConnection. Consumers that\n * specifically need the ShimConnection instance (e.g., to attach `change`\n * listeners that fire on Toss network transitions) should wait a microtask\n * after `install()` before attaching listeners, or accept that pre-seed\n * reads may return the native object.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n type InstallSnapshot,\n installNavigatorProperty,\n restoreNavigatorProperty,\n} from './_install-helpers.js';\n\nconst INSTALLED_KEY = Symbol.for('@ait-co/polyfill/network.installed');\nconst ON_LINE_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/network.onLine.snapshot');\nconst CONNECTION_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/network.connection.snapshot');\n\ninterface BackupHost {\n [INSTALLED_KEY]?: boolean;\n [ON_LINE_SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n [CONNECTION_SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n}\n\ntype SdkNetworkStatus = 'OFFLINE' | 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'WWAN' | 'UNKNOWN';\ntype EffectiveType = 'slow-2g' | '2g' | '3g' | '4g';\n\nconst REFRESH_THROTTLE_MS = 500;\n\nfunction statusToOnline(status: SdkNetworkStatus): boolean {\n return status !== 'OFFLINE';\n}\n\nfunction statusToEffectiveType(status: SdkNetworkStatus): EffectiveType {\n switch (status) {\n case '2G':\n return '2g';\n case '3G':\n return '3g';\n default:\n return '4g';\n }\n}\n\nfunction statusToConnectionType(status: SdkNetworkStatus): string {\n switch (status) {\n case 'WIFI':\n return 'wifi';\n case '2G':\n case '3G':\n case '4G':\n case '5G':\n case 'WWAN':\n return 'cellular';\n case 'OFFLINE':\n return 'none';\n default:\n return 'unknown';\n }\n}\n\n// Symbol-keyed setter: the install closure can mutate status without exposing\n// a `setStatus` name on `navigator.connection` (real NetworkInformation has\n// no mutator). `Object.getOwnPropertySymbols(navigator.connection)` returns\n// nothing, so casual enumeration can't find it. A determined caller walking\n// the prototype chain (`Object.getOwnPropertySymbols(Object.getPrototypeOf(...))`)\n// can still surface the symbol — there is no trust boundary between polyfill\n// and consumer code in the same realm, so this is a discouragement, not a\n// security control.\nconst SET_STATUS = Symbol('@ait-co/polyfill/network.setStatus');\n\nclass ShimConnection extends EventTarget {\n #status: SdkNetworkStatus | null = null;\n onchange: ((this: ShimConnection, ev: Event) => unknown) | null = null;\n\n constructor() {\n super();\n // Forward `change` events to the legacy `onchange` handler for parity with\n // the NetworkInformation API.\n this.addEventListener('change', (ev) => this.onchange?.call(this, ev));\n }\n\n [SET_STATUS](next: SdkNetworkStatus | null): void {\n this.#status = next;\n }\n\n get effectiveType(): EffectiveType {\n return statusToEffectiveType(this.#status ?? 'UNKNOWN');\n }\n // `downlink` / `rtt` / `saveData` are placeholders — the SDK does not expose\n // these. We return 0/false rather than fabricate plausible numbers. Noted\n // in CLAUDE.md.\n get downlink(): number {\n return 0;\n }\n get rtt(): number {\n return 0;\n }\n get saveData(): boolean {\n return false;\n }\n get type(): string {\n return statusToConnectionType(this.#status ?? 'UNKNOWN');\n }\n}\n\nexport function installNetworkShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (host[INSTALLED_KEY]) {\n return () => uninstallNetworkShim();\n }\n host[INSTALLED_KEY] = true;\n\n // Per-install state. Kept in closure so uninstall/reinstall cycles don't\n // leak state between instances (module-scope would leak across tests).\n let cachedStatus: SdkNetworkStatus | null = null;\n let lastRefresh = 0;\n let inflight: Promise<void> | null = null;\n const connection = new ShimConnection();\n\n async function refresh(): Promise<void> {\n // Coalesce concurrent refreshes — without this, rapid reads during an\n // in-flight SDK call each set `lastRefresh` and return early, without\n // anyone actually fetching fresh data.\n if (inflight) return inflight;\n const now = Date.now();\n if (now - lastRefresh < REFRESH_THROTTLE_MS) return;\n inflight = (async () => {\n try {\n if (!(await isTossEnvironment())) return;\n const sdk = await loadTossSdk();\n const fn = (sdk as { getNetworkStatus?: unknown } | null)?.getNetworkStatus;\n if (typeof fn !== 'function') return;\n const next = (await (fn as () => Promise<SdkNetworkStatus>)()) as SdkNetworkStatus;\n const prev = cachedStatus;\n cachedStatus = next;\n connection[SET_STATUS](next);\n // Only dispatch `change` on real transitions — the null → X seed on\n // first install is learning, not a transition, and would otherwise\n // mis-trigger consumer handlers.\n if (prev !== null && prev !== next) {\n connection.dispatchEvent(new Event('change'));\n }\n } catch {\n // Advisory — refresh failures keep the prior cache. `void refresh()`\n // callers would otherwise surface unhandled rejections if\n // isTossEnvironment / loadTossSdk / getNetworkStatus ever throw.\n } finally {\n lastRefresh = Date.now();\n inflight = null;\n }\n })();\n return inflight;\n }\n\n // Capture the native values **before** we install so the getters can fall\n // through without needing to temporarily remove their own shadow (which is\n // incompatible with prototype-level installs — Chromium keeps\n // `navigator.onLine` / `connection` non-configurable on the instance, so we\n // may end up installing on Navigator.prototype instead).\n const nativeOnLine = (navigator as Navigator & { onLine?: boolean }).onLine;\n const nativeConnection = (navigator as Navigator & { connection?: unknown }).connection;\n\n // Seed the cache on install so the first sync read is meaningful.\n void refresh();\n\n // Guard both descriptor installs with try/catch. These properties are value\n // slots that the plan calls out as not having a method-level equivalent;\n // when Chromium makes them non-configurable at both the instance and the\n // prototype, `installNavigatorProperty` may throw. In that case we warn once\n // and proceed — consumers keep the browser's native values.\n let installWarned = false;\n const warnNonConfigurable = (e: unknown): void => {\n if (installWarned) return;\n installWarned = true;\n console.warn(\n '[@ait-co/polyfill] navigator.onLine/connection is non-configurable in this browser; Toss network status sync disabled.',\n e,\n );\n };\n\n try {\n host[ON_LINE_SNAPSHOT_KEY] = installNavigatorProperty('onLine', {\n configurable: true,\n get() {\n void refresh();\n if (cachedStatus !== null) return statusToOnline(cachedStatus);\n return nativeOnLine ?? true;\n },\n });\n } catch (e) {\n warnNonConfigurable(e);\n }\n\n try {\n host[CONNECTION_SNAPSHOT_KEY] = installNavigatorProperty('connection', {\n configurable: true,\n get() {\n void refresh();\n if (cachedStatus === null && nativeConnection !== undefined) return nativeConnection;\n return connection;\n },\n });\n } catch (e) {\n warnNonConfigurable(e);\n }\n\n return uninstallNetworkShim;\n}\n\nexport function uninstallNetworkShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!host[INSTALLED_KEY]) return;\n\n const onLineSnap = host[ON_LINE_SNAPSHOT_KEY];\n if (onLineSnap) restoreNavigatorProperty('onLine', onLineSnap);\n const connSnap = host[CONNECTION_SNAPSHOT_KEY];\n if (connSnap) restoreNavigatorProperty('connection', connSnap);\n\n delete host[INSTALLED_KEY];\n delete host[ON_LINE_SNAPSHOT_KEY];\n delete host[CONNECTION_SNAPSHOT_KEY];\n}\n","/**\n * `navigator.share` shim.\n *\n * Inside Apps in Toss → routes through SDK `share({ message })`. The SDK only\n * accepts a single `message` string, so we concatenate `title`, `text`, and\n * `url` with newline separators (skipping missing/empty values).\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.share`, or\n * throws `NotSupportedError` if unavailable.\n *\n * Install strategy: **method-level** on `navigator`. Assigning\n * `navigator.share = fn` creates an own property that shadows the prototype\n * method. Uninstall deletes the own shadow so the prototype method surfaces\n * again. We do not mutate `Navigator.prototype` — in real browsers its\n * descriptor may be non-configurable, which would throw on reassignment.\n *\n * Caveat: the SDK's share has no counterpart for `files` (Web Share Level 2).\n * `canShare({ files })` returns `false` whenever the sync-accessible detection\n * says Toss is active (or is being forced via the test override).\n */\n\nimport { isTossEnvironment, isTossEnvironmentCached, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst SHARE_BACKUP_KEY = Symbol.for('@ait-co/polyfill/share.original');\nconst SHARE_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/share.snapshot');\n\ntype ShareFn = (data?: ShareData) => Promise<void>;\ntype CanShareFn = (data?: ShareData) => boolean;\n\ninterface Backup {\n share: ShareFn | undefined;\n canShare: CanShareFn | undefined;\n}\n\ninterface BackupHost {\n [SHARE_BACKUP_KEY]?: Backup | undefined;\n [SHARE_SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\nfunction buildSdkMessage(data: ShareData | undefined): string {\n // Use presence checks rather than truthiness so an intentionally empty\n // string in one field is handled correctly alongside a non-empty sibling.\n const parts: string[] = [];\n if (data?.title != null && data.title !== '') parts.push(data.title);\n if (data?.text != null && data.text !== '') parts.push(data.text);\n if (data?.url != null && data.url !== '') parts.push(data.url);\n return parts.join('\\n');\n}\n\nasync function shareShim(data?: ShareData): Promise<void> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { share?: unknown } | null)?.share;\n if (typeof fn === 'function') {\n const message = buildSdkMessage(data);\n if (!message) {\n throw new TypeError(\n '[@ait-co/polyfill] navigator.share requires at least one of title, text, or url.',\n );\n }\n try {\n await (fn as (o: { message: string }) => Promise<void>)({ message });\n } catch (e) {\n // Spec says navigator.share rejects with a DOMException. Wrap SDK\n // errors as AbortError (the most common cause is user cancellation),\n // attaching the original as `.cause` for Sentry-style telemetry.\n const message_ = e instanceof Error ? e.message : String(e);\n const wrapped = new DOMException(message_, 'AbortError');\n if (e instanceof Error) {\n (wrapped as Error).cause = e;\n }\n throw wrapped;\n }\n return;\n }\n }\n const host = navigator as unknown as BackupHost;\n const backup = host[SHARE_BACKUP_KEY];\n const original = backup?.share;\n if (!original) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.share is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return original(data);\n}\n\nfunction canShareShim(data?: ShareData): boolean {\n const hasFiles = Boolean(data?.files && data.files.length > 0);\n const toss = isTossEnvironmentCached();\n\n if (hasFiles) {\n // SDK does not share files. If we know we're in Toss (or it's being\n // forced), say so honestly. If detection hasn't resolved yet, be\n // pessimistic — a false negative is safer than promising a capability\n // we'll turn around and deny.\n if (toss === true) return false;\n if (toss === undefined) return false;\n }\n\n // Toss with non-file payloads: true iff there's at least one field.\n if (toss === true) {\n return Boolean(\n (data?.title != null && data.title !== '') ||\n (data?.text != null && data.text !== '') ||\n (data?.url != null && data.url !== ''),\n );\n }\n\n // `toss === undefined` (detection not resolved) with non-file payload falls\n // through to the browser-native answer. Rationale: `canShare` is rarely\n // load-bearing — consumers care about `share()` itself, which awaits the\n // async detection correctly. A false-negative here would needlessly hide a\n // Share button while detection settles.\n // Browser path: delegate to native when present.\n const host = navigator as unknown as BackupHost;\n const backup = host[SHARE_BACKUP_KEY];\n const originalCanShare = backup?.canShare;\n if (originalCanShare) {\n return originalCanShare(data);\n }\n return Boolean(\n (data?.title != null && data.title !== '') ||\n (data?.text != null && data.text !== '') ||\n (data?.url != null && data.url !== ''),\n );\n}\n\nexport function installShareShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (SHARE_BACKUP_KEY in host) {\n // Already installed. Use `in` so the absence of `share` / `canShare` on\n // the pre-install navigator (legitimately stored as `undefined`) doesn't\n // re-trigger install.\n return () => uninstallShareShim();\n }\n\n const nav = navigator as Navigator & {\n share?: ShareFn;\n canShare?: CanShareFn;\n };\n // Capture the native methods BEFORE patching, bound to `navigator` so that\n // fallback calls keep the correct `this` and never recurse through our shim.\n host[SHARE_BACKUP_KEY] = {\n share: nav.share ? nav.share.bind(navigator) : undefined,\n canShare: nav.canShare ? nav.canShare.bind(navigator) : undefined,\n };\n\n const snapshot = installObjectMethods(navigator, {\n share: shareShim as (...args: never[]) => unknown,\n canShare: canShareShim as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n // Slots frozen. Back out the backup bookkeeping so a later install can retry.\n delete host[SHARE_BACKUP_KEY];\n return () => uninstallShareShim();\n }\n\n host[SHARE_SNAPSHOT_KEY] = snapshot;\n return uninstallShareShim;\n}\n\nexport function uninstallShareShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(SHARE_BACKUP_KEY in host)) return;\n\n const snapshot = host[SHARE_SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n\n delete host[SHARE_BACKUP_KEY];\n delete host[SHARE_SNAPSHOT_KEY];\n}\n","/**\n * `navigator.vibrate` shim.\n *\n * Inside Apps in Toss → best-effort mapping to SDK `generateHapticFeedback`:\n * - `vibrate(0)` → no-op (web standard: cancels pending vibration)\n * - `vibrate(number)`: short (< 40ms) → `tickWeak`, long (≥ 40ms) → `basicMedium`\n * - `vibrate(number[])`: iterate \"on\" segments (even indices) as `tap` pulses\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.vibrate`,\n * or returns `false` when unavailable (matches the spec — browsers that don't\n * support vibration simply return `false`).\n *\n * Install strategy: **method-level** on `navigator`. We assign our wrapper to\n * `navigator.vibrate` (creating an own shadow over the prototype method) and\n * delete it on uninstall so the prototype re-surfaces. We do not mutate\n * `Navigator.prototype` itself — browsers may mark it non-configurable.\n *\n * Caveats (documented in CLAUDE.md as the known lossy trade-off):\n * - SDK haptics are qualitative (\"tickWeak\", \"basicMedium\"), not millisecond\n * durations. The shim approximates intensity from duration but cannot\n * reproduce exact patterns.\n * - Arrays are fired sequentially via `setTimeout`; gaps between pulses are\n * honoured only as \"time until the next tap\", not as silent-vs-vibrating.\n * - `vibrate` is spec'd as **synchronous**; the SDK call is async. We return\n * `true` immediately (fire-and-forget). Errors from the SDK are swallowed.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/vibrate.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/vibrate.snapshot');\n\ntype VibrateFn = (pattern: VibratePattern) => boolean;\n\ninterface BackupHost {\n [BACKUP_KEY]?: VibrateFn | undefined;\n [SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\nconst SHORT_VIBRATION_MS = 40;\n\ntype HapticType =\n | 'tickWeak'\n | 'tap'\n | 'tickMedium'\n | 'softMedium'\n | 'basicWeak'\n | 'basicMedium'\n | 'success'\n | 'error'\n | 'wiggle'\n | 'confetti';\n\nasync function haptic(type: HapticType): Promise<void> {\n const sdk = await loadTossSdk();\n const fn = (sdk as { generateHapticFeedback?: unknown } | null)?.generateHapticFeedback;\n if (typeof fn === 'function') {\n try {\n await (fn as (o: { type: HapticType }) => Promise<void>)({ type });\n } catch {\n // Best-effort; spec-level `vibrate` cannot surface errors.\n }\n }\n}\n\nfunction durationToHaptic(duration: number): HapticType {\n return duration < SHORT_VIBRATION_MS ? 'tickWeak' : 'basicMedium';\n}\n\nfunction vibrateShim(pattern: VibratePattern): boolean {\n // Matches the spec: `vibrate(0)` or `vibrate([])` cancels pending vibration.\n // We can't cancel an in-flight SDK haptic (no cancel API), but we still\n // forward the cancel to the browser fallback so native vibration stops.\n const arr = Array.isArray(pattern) ? pattern : [pattern];\n if (arr.length === 0 || arr.every((n) => n === 0)) {\n void (async () => {\n if (!(await isTossEnvironment())) {\n const host = navigator as unknown as BackupHost;\n host[BACKUP_KEY]?.(pattern);\n }\n })();\n return true;\n }\n\n void (async () => {\n if (await isTossEnvironment()) {\n if (!Array.isArray(pattern)) {\n await haptic(durationToHaptic(pattern));\n return;\n }\n // Even indices = \"on\" durations, odd indices = pauses. `pattern[i]` is\n // `number | undefined` under `noUncheckedIndexedAccess`; the `undefined`\n // case only arises on out-of-bounds, which our length bound prevents.\n for (let i = 0; i < pattern.length; i += 2) {\n const on = pattern[i];\n if (on === undefined) break;\n if (on > 0) {\n await haptic('tap');\n }\n const pause = pattern[i + 1];\n if (typeof pause === 'number' && pause > 0) {\n await new Promise<void>((r) => setTimeout(r, pause));\n }\n }\n return;\n }\n const host = navigator as unknown as BackupHost;\n const original = host[BACKUP_KEY];\n original?.(pattern);\n })();\n\n return true;\n}\n\nexport function installVibrateShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n return () => uninstallVibrateShim();\n }\n\n const nav = navigator as Navigator & { vibrate?: VibrateFn };\n // Capture the native method BEFORE we patch, bound to `navigator` so our\n // fallback call keeps the correct `this` and never recurses into our shim.\n host[BACKUP_KEY] = nav.vibrate ? nav.vibrate.bind(navigator) : undefined;\n\n const snapshot = installObjectMethods(navigator, {\n vibrate: vibrateShim as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n delete host[BACKUP_KEY];\n return () => uninstallVibrateShim();\n }\n\n host[SNAPSHOT_KEY] = snapshot;\n return uninstallVibrateShim;\n}\n\nexport function uninstallVibrateShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * @ait-co/polyfill\n *\n * Write Apps in Toss mini-apps using standard Web APIs\n * (`navigator.clipboard`, `navigator.geolocation`, …). This polyfill routes\n * calls through the Apps in Toss SDK **only when we detect we are actually\n * running inside the Toss app** — in every other environment (a plain browser,\n * local dev, tests) the shims are not installed and the browser's native\n * implementations are used as-is.\n *\n * Unofficial community project. Not affiliated with Toss.\n */\n\nexport { isTossEnvironment, isTossEnvironmentCached, loadTossSdk } from './detect.js';\nexport { installClipboardShim, uninstallClipboardShim } from './shims/clipboard.js';\nexport { installGeolocationShim, uninstallGeolocationShim } from './shims/geolocation.js';\nexport { installNetworkShim, uninstallNetworkShim } from './shims/network.js';\nexport { installShareShim, uninstallShareShim } from './shims/share.js';\nexport { installVibrateShim, uninstallVibrateShim } from './shims/vibrate.js';\n\nimport { isTossEnvironment } from './detect.js';\nimport { installClipboardShim, uninstallClipboardShim } from './shims/clipboard.js';\nimport { installGeolocationShim, uninstallGeolocationShim } from './shims/geolocation.js';\nimport { installNetworkShim, uninstallNetworkShim } from './shims/network.js';\nimport { installShareShim, uninstallShareShim } from './shims/share.js';\nimport { installVibrateShim, uninstallVibrateShim } from './shims/vibrate.js';\n\nexport const VERSION: string = __VERSION__;\n\nconst NOOP = (): void => {};\n\n/**\n * Install every shim this library ships, but only if we detect an Apps in\n * Toss runtime. In a plain browser `install()` is a no-op — the browser's\n * native APIs stay untouched.\n *\n * Returns a promise that resolves with an uninstall function. If the\n * environment turns out not to be Toss, the uninstall function is a no-op.\n *\n * Install order (when active): clipboard → geolocation → share → vibrate →\n * network. Not atomic on failure — if a per-shim install throws (e.g., a\n * consumer pinned a target navigator property as non-configurable), earlier\n * shims are already in place. Callers should catch and invoke the returned\n * uninstall to roll back.\n */\nexport async function install(): Promise<() => void> {\n if (!(await isTossEnvironment())) return NOOP;\n const uninstalls = [\n installClipboardShim(),\n installGeolocationShim(),\n installShareShim(),\n installVibrateShim(),\n installNetworkShim(),\n ];\n return () => {\n for (const fn of uninstalls) fn();\n };\n}\n\n/**\n * Uninstall every shim installed by `install()`. Safe to call when no shim is\n * installed — each installer's uninstall is a no-op in that case.\n */\nexport function uninstall(): void {\n uninstallClipboardShim();\n uninstallGeolocationShim();\n uninstallShareShim();\n uninstallVibrateShim();\n uninstallNetworkShim();\n}\n","/**\n * Side-effect entry point: `import '@ait-co/polyfill/auto'`\n *\n * Kicks off detection and, if we're inside Apps in Toss, installs every shim\n * this library ships. In a plain browser this is a no-op — browser native\n * APIs stay untouched. No-op idempotent: importing the entry more than once\n * doesn't re-install.\n *\n * Use this when you want the \"just add the dep\" experience. If you need to\n * observe when the polyfill actually attached (to gate init logic) or to tear\n * it down, import `install` / `uninstall` from `@ait-co/polyfill` directly.\n */\n\nimport { install } from './index.js';\n\nvoid install();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auto.js","names":["BACKUP_KEY","SNAPSHOT_KEY","BACKUP_KEY","SNAPSHOT_KEY","#status"],"sources":["../src/detect.ts","../src/shims/_install-helpers.ts","../src/shims/clipboard.ts","../src/shims/geolocation.ts","../src/shims/network.ts","../src/shims/share.ts","../src/shims/vibrate.ts","../src/index.ts","../src/auto.ts"],"sourcesContent":["/**\n * Environment detection: are we running inside Apps in Toss, or a plain browser?\n *\n * Strategy: call the SDK's `getAppsInTossGlobals()` — a synchronous export\n * that returns the runtime's Toss globals (deploymentId, brand name, …)\n * inside the Apps in Toss runtime and throws (RN bridge unavailable)\n * anywhere else. The SDK itself is an **optional** peer dependency; if its\n * module can't be imported we are definitely not inside Toss.\n *\n * Just having the SDK module resolvable is not enough — apps can bundle it\n * and still run in a plain browser. We need the bridge probe to confirm.\n *\n * UA sniffing (spoofable) is avoided. We do call `getAppsInTossGlobals`, but\n * that's a constant read from the bridge — no permission dialogs, no\n * analytics fire. In a plain browser the bridge lookup fails fast (sync\n * throw, microsecond-scale), so the startup cost is negligible.\n */\n\nlet cached: boolean | undefined;\n\n/**\n * Reset the cached detection result. Primarily for tests.\n */\nexport function resetDetection(): void {\n cached = undefined;\n}\n\n/**\n * Synchronous read of the cached detection result. Returns:\n * - `true` / `false` if an override is active or the async detection has\n * already resolved\n * - `undefined` if detection hasn't run yet\n *\n * Used by spec-sync APIs (e.g. `navigator.canShare`) that can't `await`\n * detection.\n */\nexport function isTossEnvironmentCached(): boolean | undefined {\n const force = globalThis.__AIT_POLYFILL_FORCE__;\n if (force === 'toss') return true;\n if (force === 'browser') return false;\n return cached;\n}\n\n/**\n * Returns `true` iff we detect we are running in an environment where the\n * Apps in Toss SDK (`@apps-in-toss/web-framework`) is present and usable.\n *\n * Async because we use dynamic `import()` to probe the optional peer dep\n * without forcing it into the consumer's bundle.\n */\nexport async function isTossEnvironment(): Promise<boolean> {\n // Override check precedes cache so `devtools` / tests can flip the result\n // mid-session without a `resetDetection()` call.\n const force = globalThis.__AIT_POLYFILL_FORCE__;\n if (force === 'toss') return true;\n if (force === 'browser') return false;\n\n if (cached !== undefined) return cached;\n\n const mod = await loadTossSdk();\n if (typeof mod?.getAppsInTossGlobals !== 'function') {\n cached = false;\n return cached;\n }\n // Inside Toss the bridge returns a populated globals object. In a plain\n // browser the RN bridge isn't attached and the call throws — that's our\n // signal. Any non-throwing call with an object return is treated as Toss.\n try {\n const globals = mod.getAppsInTossGlobals();\n cached = Boolean(globals) && typeof globals === 'object';\n } catch {\n cached = false;\n }\n return cached;\n}\n\n/**\n * Lazy SDK accessor — returns the module if available, else `null`. Callers\n * are expected to `await` and null-check. Never throws.\n */\nexport async function loadTossSdk(): Promise<typeof import('@apps-in-toss/web-framework') | null> {\n try {\n return await import('@apps-in-toss/web-framework');\n } catch {\n return null;\n }\n}\n","/**\n * Shared helpers for installing shims on `navigator`.\n *\n * Chromium now marks a handful of `navigator` properties (e.g. `geolocation`,\n * `clipboard`) as non-configurable **own** properties on the instance. That\n * means a plain `Object.defineProperty(navigator, 'x', …)` throws\n * `TypeError: Cannot redefine property`.\n *\n * The workaround is to shim at the prototype level — `Navigator.prototype`\n * keeps these as configurable accessors, so we can swap them there and every\n * instance that falls through to the prototype (including `window.navigator`)\n * sees the shim. We only reach for the prototype when the instance-level\n * assignment refuses.\n *\n * For restoration we remember the descriptor chain (instance + prototype) so\n * `uninstall()` puts the browser back in its original state.\n */\n\ntype PropertyLocation = 'instance' | 'prototype';\n\nexport interface InstallSnapshot {\n /** Where we ended up writing the shim. */\n location: PropertyLocation;\n /** Original descriptor at that location (may be undefined if nothing was there). */\n originalDescriptor: PropertyDescriptor | undefined;\n /** `true` iff the original property lived on the instance before we touched it. */\n instanceHadOwn: boolean;\n}\n\n/**\n * Install `descriptor` at `navigator[prop]`. Prefer instance-level; if the\n * browser refuses (property is non-configurable on the instance), install on\n * `Navigator.prototype` instead.\n *\n * Returns a snapshot describing where the original value was, which\n * `restoreNavigatorProperty` uses to undo the install.\n */\nexport function installNavigatorProperty(\n prop: string,\n descriptor: PropertyDescriptor,\n): InstallSnapshot {\n const nav = navigator as unknown as Record<PropertyKey, unknown>;\n const instanceDesc = Object.getOwnPropertyDescriptor(nav, prop);\n const instanceHadOwn = instanceDesc !== undefined;\n\n // Fast path: instance-level property is missing or configurable.\n if (!instanceDesc || instanceDesc.configurable) {\n try {\n Object.defineProperty(nav, prop, descriptor);\n return { location: 'instance', originalDescriptor: instanceDesc, instanceHadOwn };\n } catch {\n // Fall through to prototype-level install.\n }\n }\n\n // Prototype-level install. Drop the instance-level shadow so the prototype\n // accessor is visible to readers on `navigator`.\n const proto = Object.getPrototypeOf(nav) as object;\n const protoDesc = Object.getOwnPropertyDescriptor(proto, prop);\n\n if (instanceHadOwn) {\n // Try to remove the instance-level shadow. On non-configurable it throws —\n // we deliberately ignore that; prototype-level install still wins because\n // the prototype accessor shows through when we read via `navigator[prop]`.\n try {\n delete nav[prop];\n } catch {\n /* non-configurable own — leave it; prototype install still useful */\n }\n }\n\n Object.defineProperty(proto, prop, descriptor);\n return { location: 'prototype', originalDescriptor: protoDesc, instanceHadOwn };\n}\n\n/**\n * Reverse the install recorded in `snapshot`. If the original descriptor was\n * `undefined` (property didn't exist before), delete the property instead of\n * re-defining it.\n */\nexport function restoreNavigatorProperty(prop: string, snapshot: InstallSnapshot): void {\n const target =\n snapshot.location === 'instance'\n ? (navigator as unknown as Record<PropertyKey, unknown>)\n : (Object.getPrototypeOf(navigator) as object);\n\n if (snapshot.originalDescriptor) {\n try {\n Object.defineProperty(target, prop, snapshot.originalDescriptor);\n } catch {\n /* descriptor was non-configurable upstream; we can't undo — rare. */\n }\n } else {\n try {\n delete (target as Record<PropertyKey, unknown>)[prop];\n } catch {\n /* non-configurable — rare. */\n }\n }\n\n // If our install pushed past an instance shadow, we leave the instance alone\n // — the descriptor we captured for `instanceHadOwn: true` lives on the\n // instance and was not modified at install time.\n}\n\n/**\n * Method-level install snapshot. Captured per-key so `restoreObjectMethods`\n * can distinguish \"was an own property, reassign it\" from \"was inherited,\n * delete the override so the prototype method surfaces again\".\n */\nexport interface MethodInstallSnapshot {\n target: object;\n methods: Record<string, { hadOwn: boolean; original: unknown }>;\n}\n\n/**\n * Mutate methods on an existing object rather than replacing the object\n * itself. This is the path we take for `navigator.geolocation`, `navigator.share`,\n * and `navigator.vibrate` in Chromium, where the slot on `navigator` is a\n * non-configurable own property that we cannot replace — but the methods\n * themselves (or the methods on the referenced object) are still\n * `configurable: true, writable: true`.\n *\n * Each replacement is installed via plain assignment. If any slot is not\n * writable (e.g. frozen object), install is aborted and previously-applied\n * replacements are rolled back, so the caller observes an atomic \"all or\n * nothing\" failure as `null`. The caller is expected to degrade gracefully\n * (e.g. log a one-time `console.warn`) when that happens.\n */\nexport function installObjectMethods(\n target: object,\n replacements: Record<string, (...args: never[]) => unknown>,\n): MethodInstallSnapshot | null {\n const methods: Record<string, { hadOwn: boolean; original: unknown }> = {};\n const applied: string[] = [];\n const bag = target as Record<string, unknown>;\n\n for (const key of Object.keys(replacements)) {\n const hadOwn = Object.hasOwn(target, key);\n const original = bag[key];\n try {\n bag[key] = replacements[key] as unknown;\n } catch {\n // Non-writable / frozen. Roll back and return null.\n for (const applieKey of applied) {\n const prev = methods[applieKey];\n if (!prev) continue;\n if (prev.hadOwn) {\n bag[applieKey] = prev.original;\n } else {\n delete bag[applieKey];\n }\n }\n return null;\n }\n // Verify the assignment actually stuck — silent-failure descriptors (e.g.\n // `writable: false` without strict mode) can skip the throw and leave the\n // original value in place. Treat that the same as a throw.\n if (bag[key] !== (replacements[key] as unknown)) {\n for (const applieKey of applied) {\n const prev = methods[applieKey];\n if (!prev) continue;\n if (prev.hadOwn) {\n bag[applieKey] = prev.original;\n } else {\n delete bag[applieKey];\n }\n }\n return null;\n }\n methods[key] = { hadOwn, original };\n applied.push(key);\n }\n\n return { target, methods };\n}\n\n/**\n * Reverse an `installObjectMethods` snapshot. Reassigns originals for slots\n * that were own properties before install; deletes the override for slots\n * that were inherited (so the prototype method surfaces again).\n */\nexport function restoreObjectMethods(snapshot: MethodInstallSnapshot): void {\n const bag = snapshot.target as Record<string, unknown>;\n for (const key of Object.keys(snapshot.methods)) {\n const entry = snapshot.methods[key];\n if (!entry) continue;\n try {\n if (entry.hadOwn) {\n bag[key] = entry.original;\n } else {\n delete bag[key];\n }\n } catch {\n /* frozen between install and restore — rare. */\n }\n }\n}\n","/**\n * `navigator.clipboard` shim.\n *\n * Inside Apps in Toss → routes `readText` / `writeText` through the SDK\n * (`getClipboardText` / `setClipboardText`).\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.clipboard`.\n * If the browser doesn't implement it, the standard `TypeError` / `DOMException`\n * surfaces unchanged — we don't paper over missing support.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n type InstallSnapshot,\n installNavigatorProperty,\n restoreNavigatorProperty,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/clipboard.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/clipboard.snapshot');\n\ninterface BackupHost {\n [BACKUP_KEY]?: Clipboard | undefined;\n [SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n}\n\n/**\n * Produces a Clipboard-compatible object whose `readText` / `writeText` methods\n * route to the SDK when in Toss, else fall through to the supplied `fallback`.\n */\nfunction createClipboardShim(fallback: Clipboard | undefined): Clipboard {\n const shim = {\n async readText(): Promise<string> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n if (sdk?.getClipboardText) {\n return sdk.getClipboardText();\n }\n }\n if (!fallback) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.readText is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return fallback.readText();\n },\n\n async writeText(text: string): Promise<void> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n if (sdk?.setClipboardText) {\n return sdk.setClipboardText(text);\n }\n }\n if (!fallback) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.writeText is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return fallback.writeText(text);\n },\n\n // `read` / `write` (ClipboardItem-based) are passed through to the\n // fallback when in browser mode; the SDK has no rich-content counterpart,\n // so in Toss mode they throw.\n async read(): Promise<ClipboardItems> {\n if (await isTossEnvironment()) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.read (rich content) is not supported in the Apps in Toss environment. Use readText instead.',\n 'NotSupportedError',\n );\n }\n if (!fallback?.read) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.read is not available.',\n 'NotSupportedError',\n );\n }\n return fallback.read();\n },\n\n async write(items: ClipboardItems): Promise<void> {\n if (await isTossEnvironment()) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.write (rich content) is not supported in the Apps in Toss environment. Use writeText instead.',\n 'NotSupportedError',\n );\n }\n if (!fallback?.write) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.clipboard.write is not available.',\n 'NotSupportedError',\n );\n }\n return fallback.write(items);\n },\n\n // EventTarget passthrough. `navigator.clipboard` extends EventTarget in the\n // spec; mini-apps rarely use it. We forward to the fallback when one exists;\n // in Toss mode (no fallback) we silently drop subscriptions — the SDK emits\n // no clipboard events, so there is nothing to dispatch. This is lossy but\n // preserves the spec-compatible shape.\n addEventListener: (\n ...args: Parameters<EventTarget['addEventListener']>\n ): ReturnType<EventTarget['addEventListener']> => fallback?.addEventListener(...args),\n removeEventListener: (\n ...args: Parameters<EventTarget['removeEventListener']>\n ): ReturnType<EventTarget['removeEventListener']> => fallback?.removeEventListener(...args),\n // Returns `false` in Toss mode (no backing EventTarget). A caller that reads\n // this as \"default action cancelled\" should check context — there are no\n // listeners to run because the SDK doesn't surface clipboard events.\n dispatchEvent: (event: Event): boolean => fallback?.dispatchEvent(event) ?? false,\n } satisfies Clipboard;\n\n return shim;\n}\n\n/**\n * Install the `navigator.clipboard` shim.\n *\n * @returns an uninstall function that restores the original `navigator.clipboard`.\n * Calling install twice without uninstalling is a no-op on the second call\n * and returns the same uninstall function.\n */\nexport function installClipboardShim(): () => void {\n if (typeof navigator === 'undefined') {\n // No-op in non-DOM environments (pure Node).\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n // Already installed. Use `in` (not `!== undefined`) because the stored\n // backup is legitimately `undefined` when the browser has no native\n // `navigator.clipboard` — without this, we'd re-wrap on each install.\n // Note: the returned uninstall is global. Any caller's uninstall fully\n // removes the shim; callers do not have independent install handles.\n return () => uninstallClipboardShim();\n }\n\n const original = navigator.clipboard as Clipboard | undefined;\n host[BACKUP_KEY] = original;\n\n const shim = createClipboardShim(original);\n host[SNAPSHOT_KEY] = installNavigatorProperty('clipboard', {\n value: shim,\n configurable: true,\n writable: true,\n });\n\n return uninstallClipboardShim;\n}\n\n/**\n * Remove the shim and restore the pre-install shape.\n */\nexport function uninstallClipboardShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreNavigatorProperty('clipboard', snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * `navigator.geolocation` shim.\n *\n * Inside Apps in Toss → routes through the SDK:\n * - `getCurrentPosition` → `getCurrentLocation({ accuracy })`\n * - `watchPosition` / `clearWatch` → `startUpdateLocation({ onEvent, onError, options })`\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.geolocation`.\n * If neither is available, the error callback receives a `GeolocationPositionError`.\n *\n * Install strategy: **method-level**. We do **not** replace `navigator.geolocation`\n * itself — Chromium marks that slot as a non-configurable own property, which\n * both `defineProperty(navigator, 'geolocation', …)` and the prototype-level\n * fallback cannot override (the instance shadow blocks prototype reads). We\n * instead mutate the methods on the existing `Geolocation` object, whose own\n * method descriptors are configurable+writable in every browser we've seen.\n *\n * SDK/Web shape mismatch handled here:\n * - SDK `Accuracy` is a numeric enum (1 = Lowest … 6 = BestForNavigation); the\n * standard `PositionOptions.enableHighAccuracy` is a boolean. We map\n * `true → Accuracy.High (4, \"~10m\")` and `false → Accuracy.Balanced (3)`.\n * `Highest (5)` / `BestForNavigation (6)` are available but carry a battery\n * cost that's rarely what mini-apps want; consumers who need them should\n * call the SDK directly.\n * - SDK coords lack `speed`; we surface `null` (per the W3C spec when unknown).\n * - SDK `startUpdateLocation` returns an `unsubscribe` fn; we wrap it behind\n * a numeric watch id so `clearWatch(id)` behaves like the standard.\n *\n * Caveat: watch ids reset whenever the shim is uninstalled and reinstalled;\n * they are not stable across such cycles. Ids obtained before uninstall\n * cannot be cleared after uninstall — `clearWatch(id)` on the restored native\n * `navigator.geolocation` uses a different id space, so the SDK subscription\n * leaks. Consumers should `clearWatch` all outstanding ids before calling\n * `uninstall()`.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/geolocation.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/geolocation.snapshot');\n\ninterface BackupHost {\n [BACKUP_KEY]?: { target: Geolocation } | undefined;\n [SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\n// SDK Accuracy enum values. We don't import the enum at runtime (peer is\n// optional), so we hard-code the numeric constants used by the SDK. Stable\n// ABI per the SDK's exported numeric enum.\nconst ACCURACY_BALANCED = 3;\nconst ACCURACY_HIGH = 4;\n\ninterface SdkLocationCoords {\n latitude: number;\n longitude: number;\n altitude: number;\n accuracy: number;\n altitudeAccuracy: number;\n heading: number;\n}\n\ninterface SdkLocation {\n timestamp: number;\n coords: SdkLocationCoords;\n}\n\nfunction toStandardPosition(sdk: SdkLocation): GeolocationPosition {\n const coordsData = {\n latitude: sdk.coords.latitude,\n longitude: sdk.coords.longitude,\n altitude: sdk.coords.altitude,\n accuracy: sdk.coords.accuracy,\n altitudeAccuracy: sdk.coords.altitudeAccuracy,\n heading: sdk.coords.heading,\n // SDK does not surface speed. Per spec, null means \"unknown\".\n speed: null,\n };\n const coords: GeolocationCoordinates = {\n ...coordsData,\n toJSON() {\n return { ...coordsData };\n },\n };\n return {\n coords,\n timestamp: sdk.timestamp,\n toJSON() {\n return { coords: { ...coordsData }, timestamp: sdk.timestamp };\n },\n };\n}\n\nfunction toPositionError(code: 1 | 2 | 3, message: string): GeolocationPositionError {\n // Prefer the real constructor when available (every real browser ships it).\n // The spec says GeolocationPositionError is not constructable, so we fall\n // through to a fabricated object whose prototype is patched via\n // `setPrototypeOf` — that keeps `instanceof` checks in consumer code working\n // and picks up the spec's PERMISSION_DENIED / POSITION_UNAVAILABLE / TIMEOUT\n // constants from the real prototype rather than hard-coding them (avoids\n // drift if the spec ever grows a new code).\n const Ctor = (globalThis as { GeolocationPositionError?: unknown }).GeolocationPositionError;\n if (typeof Ctor === 'function') {\n const proto = (Ctor as { prototype?: object }).prototype;\n if (proto) {\n const shape: { code: number; message: string } = { code, message };\n Object.setPrototypeOf(shape, proto);\n return shape as GeolocationPositionError;\n }\n }\n // jsdom / last-resort fallback: fabricate the spec shape with hard-coded\n // constants since there's no prototype to delegate to.\n return {\n code,\n message,\n PERMISSION_DENIED: 1,\n POSITION_UNAVAILABLE: 2,\n TIMEOUT: 3,\n } as GeolocationPositionError;\n}\n\nfunction accuracyFromOptions(options: PositionOptions | undefined): number {\n return options?.enableHighAccuracy ? ACCURACY_HIGH : ACCURACY_BALANCED;\n}\n\n/**\n * Minimal view of the native `Geolocation` methods we forward to. We pass\n * the **captured originals** here, not a reference to `navigator.geolocation`\n * itself — after install the methods on that object ARE the shim, so using\n * `navigator.geolocation.getCurrentPosition(…)` as a fallback would infinite-loop.\n */\ninterface GeolocationFallback {\n getCurrentPosition: Geolocation['getCurrentPosition'] | undefined;\n watchPosition: Geolocation['watchPosition'] | undefined;\n clearWatch: Geolocation['clearWatch'] | undefined;\n}\n\ninterface GeolocationShim {\n getCurrentPosition: Geolocation['getCurrentPosition'];\n watchPosition: Geolocation['watchPosition'];\n clearWatch: Geolocation['clearWatch'];\n}\n\nfunction createGeolocationShim(fallback: GeolocationFallback): GeolocationShim {\n // Numeric watch id → SDK unsubscribe fn. Keeps the shim's API in line with\n // the standard even though the SDK issues unsubscribe closures instead.\n // `pendingWatches` closes the race where `clearWatch` is called before the\n // async `watchPosition` installer resolves — without it we'd leak the SDK\n // subscription.\n let nextWatchId = 1;\n const sdkWatches = new Map<number, () => void>();\n const nativeWatches = new Map<number, number>();\n const pendingWatches = new Map<number, { cancelled: boolean }>();\n\n const shim: GeolocationShim = {\n getCurrentPosition(success, error, options) {\n void (async () => {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { getCurrentLocation?: unknown } | null)?.getCurrentLocation;\n if (typeof fn === 'function') {\n try {\n const loc = (await (fn as (o: { accuracy: number }) => Promise<SdkLocation>)({\n accuracy: accuracyFromOptions(options),\n })) as SdkLocation;\n success(toStandardPosition(loc));\n } catch (e) {\n error?.(\n toPositionError(\n 2,\n e instanceof Error ? e.message : '[@ait-co/polyfill] getCurrentLocation failed.',\n ),\n );\n }\n return;\n }\n }\n if (!fallback.getCurrentPosition) {\n error?.(\n toPositionError(\n 2,\n '[@ait-co/polyfill] navigator.geolocation is not available in this environment.',\n ),\n );\n return;\n }\n fallback.getCurrentPosition(success, error, options);\n })();\n },\n\n watchPosition(success, error, options) {\n const id = nextWatchId++;\n const pending = { cancelled: false };\n pendingWatches.set(id, pending);\n\n void (async () => {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { startUpdateLocation?: unknown } | null)?.startUpdateLocation;\n if (typeof fn === 'function') {\n if (pending.cancelled) {\n pendingWatches.delete(id);\n return;\n }\n const unsubscribe = (\n fn as (p: {\n onEvent: (loc: SdkLocation) => void;\n onError: (err: unknown) => void;\n options: { accuracy: number; timeInterval: number; distanceInterval: number };\n }) => () => void\n )({\n onEvent: (loc) => success(toStandardPosition(loc)),\n onError: (err) =>\n error?.(\n toPositionError(\n 2,\n err instanceof Error\n ? err.message\n : '[@ait-co/polyfill] startUpdateLocation failed.',\n ),\n ),\n options: {\n accuracy: accuracyFromOptions(options),\n // Sensible defaults — web `watchPosition` has no analogues.\n // Consumers needing sub-second updates should use the SDK directly.\n timeInterval: 1000,\n distanceInterval: 0,\n },\n });\n if (pending.cancelled) {\n unsubscribe();\n pendingWatches.delete(id);\n return;\n }\n sdkWatches.set(id, unsubscribe);\n pendingWatches.delete(id);\n return;\n }\n }\n if (!fallback.watchPosition) {\n pendingWatches.delete(id);\n error?.(\n toPositionError(\n 2,\n '[@ait-co/polyfill] navigator.geolocation is not available in this environment.',\n ),\n );\n return;\n }\n if (pending.cancelled) {\n pendingWatches.delete(id);\n return;\n }\n const nativeId = fallback.watchPosition(success, error, options);\n if (pending.cancelled) {\n fallback.clearWatch?.(nativeId);\n pendingWatches.delete(id);\n return;\n }\n nativeWatches.set(id, nativeId);\n pendingWatches.delete(id);\n })();\n\n return id;\n },\n\n clearWatch(id) {\n const pending = pendingWatches.get(id);\n if (pending) {\n pending.cancelled = true;\n pendingWatches.delete(id);\n return;\n }\n const unsubscribe = sdkWatches.get(id);\n if (unsubscribe) {\n unsubscribe();\n sdkWatches.delete(id);\n return;\n }\n const nativeId = nativeWatches.get(id);\n if (nativeId !== undefined && fallback.clearWatch) {\n fallback.clearWatch(nativeId);\n nativeWatches.delete(id);\n }\n },\n };\n\n return shim;\n}\n\nexport function installGeolocationShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n return () => uninstallGeolocationShim();\n }\n\n const target = navigator.geolocation as Geolocation | undefined;\n if (!target) {\n // No `navigator.geolocation` at all (rare — jsdom may expose it, real\n // browsers always do). Nothing for the shim to mutate; bail quietly.\n host[BACKUP_KEY] = undefined;\n return () => uninstallGeolocationShim();\n }\n\n // Capture the native methods BEFORE we patch so the shim's fallback path\n // doesn't recurse through itself.\n const fallback: GeolocationFallback = {\n getCurrentPosition: target.getCurrentPosition?.bind(target),\n watchPosition: target.watchPosition?.bind(target),\n clearWatch: target.clearWatch?.bind(target),\n };\n\n const shim = createGeolocationShim(fallback);\n\n const snapshot = installObjectMethods(target, {\n getCurrentPosition: shim.getCurrentPosition as (...args: never[]) => unknown,\n watchPosition: shim.watchPosition as (...args: never[]) => unknown,\n clearWatch: shim.clearWatch as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n // Method slots frozen — can't install. No-op uninstall.\n host[BACKUP_KEY] = undefined;\n return () => uninstallGeolocationShim();\n }\n\n host[BACKUP_KEY] = { target };\n host[SNAPSHOT_KEY] = snapshot;\n\n return uninstallGeolocationShim;\n}\n\nexport function uninstallGeolocationShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * `navigator.onLine` + `navigator.connection` shim.\n *\n * Inside Apps in Toss → seeded from SDK `getNetworkStatus()` on install and\n * refreshed on read (throttled):\n * - `'OFFLINE'` → `onLine = false`\n * - `'WIFI'` → `onLine = true`, `effectiveType = '4g'` (no web wifi value)\n * - `'2G'/'3G'/'4G'/'5G'` → `onLine = true`, `effectiveType = <lowercased>`\n * - `'WWAN'/'UNKNOWN'` → `onLine = true`, `effectiveType = '4g'` (best guess)\n *\n * Outside Apps in Toss → both `navigator.onLine` and `navigator.connection`\n * read through to the native value. Install installs own-instance getters\n * that consult the Toss-seeded cache first; when the cache is empty (which\n * it always is in browser mode), the getter temporarily removes its own\n * shadow, reads the prototype value, and reinstates the shadow.\n *\n * Uninstall `delete`s the instance-level override so the prototype descriptor\n * (where `onLine` and `connection` actually live in real browsers) becomes\n * visible again. We never mutate the prototype — doing so would throw in\n * browsers where the descriptor is non-configurable.\n *\n * Browser-compat caveat (Chromium): `navigator.onLine` and `navigator.connection`\n * are value slots, not methods, so the method-level install trick we use for\n * `geolocation`/`share`/`vibrate` does not apply here. When Chromium marks the\n * instance descriptor as non-configurable AND the prototype descriptor is also\n * non-configurable, we cannot install. In that case the shim logs a one-time\n * `console.warn` and leaves the native values in place — consumers keep the\n * browser's own `onLine`/`connection` values; the SDK-synced state is simply\n * disabled for that session.\n *\n * Caveat: the Web NetworkInformation API is evented (`change` fires on\n * transitions). The SDK exposes only a one-shot query, so listeners attached\n * to `navigator.connection` are accepted but never fire from a `change` event\n * unless the shim observes a real status transition. Synthesising richer\n * events via polling is tracked in TODO.md.\n *\n * Lifecycle: `navigator.connection` is a ShimConnection instance that lives in\n * the install closure. On uninstall the instance-level override is removed,\n * but listeners the consumer attached to the old instance stay bound to that\n * (now-orphan) object and will not see events from a subsequent install.\n * Consumers should re-attach listeners after each install.\n *\n * Seed-boundary race: in Toss mode, reads before the install-time SDK seed\n * completes fall through to the native `navigator.connection`. After the seed\n * lands, subsequent reads return the shim's ShimConnection. Consumers that\n * specifically need the ShimConnection instance (e.g., to attach `change`\n * listeners that fire on Toss network transitions) should wait a microtask\n * after `install()` before attaching listeners, or accept that pre-seed\n * reads may return the native object.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n type InstallSnapshot,\n installNavigatorProperty,\n restoreNavigatorProperty,\n} from './_install-helpers.js';\n\nconst INSTALLED_KEY = Symbol.for('@ait-co/polyfill/network.installed');\nconst ON_LINE_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/network.onLine.snapshot');\nconst CONNECTION_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/network.connection.snapshot');\n\ninterface BackupHost {\n [INSTALLED_KEY]?: boolean;\n [ON_LINE_SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n [CONNECTION_SNAPSHOT_KEY]?: InstallSnapshot | undefined;\n}\n\ntype SdkNetworkStatus = 'OFFLINE' | 'WIFI' | '2G' | '3G' | '4G' | '5G' | 'WWAN' | 'UNKNOWN';\ntype EffectiveType = 'slow-2g' | '2g' | '3g' | '4g';\n\nconst REFRESH_THROTTLE_MS = 500;\n\nfunction statusToOnline(status: SdkNetworkStatus): boolean {\n return status !== 'OFFLINE';\n}\n\nfunction statusToEffectiveType(status: SdkNetworkStatus): EffectiveType {\n switch (status) {\n case '2G':\n return '2g';\n case '3G':\n return '3g';\n default:\n return '4g';\n }\n}\n\nfunction statusToConnectionType(status: SdkNetworkStatus): string {\n switch (status) {\n case 'WIFI':\n return 'wifi';\n case '2G':\n case '3G':\n case '4G':\n case '5G':\n case 'WWAN':\n return 'cellular';\n case 'OFFLINE':\n return 'none';\n default:\n return 'unknown';\n }\n}\n\n// Symbol-keyed setter: the install closure can mutate status without exposing\n// a `setStatus` name on `navigator.connection` (real NetworkInformation has\n// no mutator). `Object.getOwnPropertySymbols(navigator.connection)` returns\n// nothing, so casual enumeration can't find it. A determined caller walking\n// the prototype chain (`Object.getOwnPropertySymbols(Object.getPrototypeOf(...))`)\n// can still surface the symbol — there is no trust boundary between polyfill\n// and consumer code in the same realm, so this is a discouragement, not a\n// security control.\nconst SET_STATUS = Symbol('@ait-co/polyfill/network.setStatus');\n\nclass ShimConnection extends EventTarget {\n #status: SdkNetworkStatus | null = null;\n onchange: ((this: ShimConnection, ev: Event) => unknown) | null = null;\n\n constructor() {\n super();\n // Forward `change` events to the legacy `onchange` handler for parity with\n // the NetworkInformation API.\n this.addEventListener('change', (ev) => this.onchange?.call(this, ev));\n }\n\n [SET_STATUS](next: SdkNetworkStatus | null): void {\n this.#status = next;\n }\n\n get effectiveType(): EffectiveType {\n return statusToEffectiveType(this.#status ?? 'UNKNOWN');\n }\n // `downlink` / `rtt` / `saveData` are placeholders — the SDK does not expose\n // these. We return 0/false rather than fabricate plausible numbers. Noted\n // in CLAUDE.md.\n get downlink(): number {\n return 0;\n }\n get rtt(): number {\n return 0;\n }\n get saveData(): boolean {\n return false;\n }\n get type(): string {\n return statusToConnectionType(this.#status ?? 'UNKNOWN');\n }\n}\n\nexport function installNetworkShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (host[INSTALLED_KEY]) {\n return () => uninstallNetworkShim();\n }\n host[INSTALLED_KEY] = true;\n\n // Per-install state. Kept in closure so uninstall/reinstall cycles don't\n // leak state between instances (module-scope would leak across tests).\n let cachedStatus: SdkNetworkStatus | null = null;\n let lastRefresh = 0;\n let inflight: Promise<void> | null = null;\n const connection = new ShimConnection();\n\n async function refresh(): Promise<void> {\n // Coalesce concurrent refreshes — without this, rapid reads during an\n // in-flight SDK call each set `lastRefresh` and return early, without\n // anyone actually fetching fresh data.\n if (inflight) return inflight;\n const now = Date.now();\n if (now - lastRefresh < REFRESH_THROTTLE_MS) return;\n inflight = (async () => {\n try {\n if (!(await isTossEnvironment())) return;\n const sdk = await loadTossSdk();\n const fn = (sdk as { getNetworkStatus?: unknown } | null)?.getNetworkStatus;\n if (typeof fn !== 'function') return;\n const next = (await (fn as () => Promise<SdkNetworkStatus>)()) as SdkNetworkStatus;\n const prev = cachedStatus;\n cachedStatus = next;\n connection[SET_STATUS](next);\n // Only dispatch `change` on real transitions — the null → X seed on\n // first install is learning, not a transition, and would otherwise\n // mis-trigger consumer handlers.\n if (prev !== null && prev !== next) {\n connection.dispatchEvent(new Event('change'));\n }\n } catch {\n // Advisory — refresh failures keep the prior cache. `void refresh()`\n // callers would otherwise surface unhandled rejections if\n // isTossEnvironment / loadTossSdk / getNetworkStatus ever throw.\n } finally {\n lastRefresh = Date.now();\n inflight = null;\n }\n })();\n return inflight;\n }\n\n // Capture the native values **before** we install so the getters can fall\n // through without needing to temporarily remove their own shadow (which is\n // incompatible with prototype-level installs — Chromium keeps\n // `navigator.onLine` / `connection` non-configurable on the instance, so we\n // may end up installing on Navigator.prototype instead).\n const nativeOnLine = (navigator as Navigator & { onLine?: boolean }).onLine;\n const nativeConnection = (navigator as Navigator & { connection?: unknown }).connection;\n\n // Seed the cache on install so the first sync read is meaningful.\n void refresh();\n\n // Guard both descriptor installs with try/catch. These properties are value\n // slots that the plan calls out as not having a method-level equivalent;\n // when Chromium makes them non-configurable at both the instance and the\n // prototype, `installNavigatorProperty` may throw. In that case we warn once\n // and proceed — consumers keep the browser's native values.\n let installWarned = false;\n const warnNonConfigurable = (e: unknown): void => {\n if (installWarned) return;\n installWarned = true;\n console.warn(\n '[@ait-co/polyfill] navigator.onLine/connection is non-configurable in this browser; Toss network status sync disabled.',\n e,\n );\n };\n\n try {\n host[ON_LINE_SNAPSHOT_KEY] = installNavigatorProperty('onLine', {\n configurable: true,\n get() {\n void refresh();\n if (cachedStatus !== null) return statusToOnline(cachedStatus);\n return nativeOnLine ?? true;\n },\n });\n } catch (e) {\n warnNonConfigurable(e);\n }\n\n try {\n host[CONNECTION_SNAPSHOT_KEY] = installNavigatorProperty('connection', {\n configurable: true,\n get() {\n void refresh();\n if (cachedStatus === null && nativeConnection !== undefined) return nativeConnection;\n return connection;\n },\n });\n } catch (e) {\n warnNonConfigurable(e);\n }\n\n return uninstallNetworkShim;\n}\n\nexport function uninstallNetworkShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!host[INSTALLED_KEY]) return;\n\n const onLineSnap = host[ON_LINE_SNAPSHOT_KEY];\n if (onLineSnap) restoreNavigatorProperty('onLine', onLineSnap);\n const connSnap = host[CONNECTION_SNAPSHOT_KEY];\n if (connSnap) restoreNavigatorProperty('connection', connSnap);\n\n delete host[INSTALLED_KEY];\n delete host[ON_LINE_SNAPSHOT_KEY];\n delete host[CONNECTION_SNAPSHOT_KEY];\n}\n","/**\n * `navigator.share` shim.\n *\n * Inside Apps in Toss → routes through SDK `share({ message })`. The SDK only\n * accepts a single `message` string, so we concatenate `title`, `text`, and\n * `url` with newline separators (skipping missing/empty values).\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.share`, or\n * throws `NotSupportedError` if unavailable.\n *\n * Install strategy: **method-level** on `navigator`. Assigning\n * `navigator.share = fn` creates an own property that shadows the prototype\n * method. Uninstall deletes the own shadow so the prototype method surfaces\n * again. We do not mutate `Navigator.prototype` — in real browsers its\n * descriptor may be non-configurable, which would throw on reassignment.\n *\n * Caveat: the SDK's share has no counterpart for `files` (Web Share Level 2).\n * `canShare({ files })` returns `false` whenever the sync-accessible detection\n * says Toss is active (or is being forced via the test override).\n */\n\nimport { isTossEnvironment, isTossEnvironmentCached, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst SHARE_BACKUP_KEY = Symbol.for('@ait-co/polyfill/share.original');\nconst SHARE_SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/share.snapshot');\n\ntype ShareFn = (data?: ShareData) => Promise<void>;\ntype CanShareFn = (data?: ShareData) => boolean;\n\ninterface Backup {\n share: ShareFn | undefined;\n canShare: CanShareFn | undefined;\n}\n\ninterface BackupHost {\n [SHARE_BACKUP_KEY]?: Backup | undefined;\n [SHARE_SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\nfunction buildSdkMessage(data: ShareData | undefined): string {\n // Use presence checks rather than truthiness so an intentionally empty\n // string in one field is handled correctly alongside a non-empty sibling.\n const parts: string[] = [];\n if (data?.title != null && data.title !== '') parts.push(data.title);\n if (data?.text != null && data.text !== '') parts.push(data.text);\n if (data?.url != null && data.url !== '') parts.push(data.url);\n return parts.join('\\n');\n}\n\nasync function shareShim(data?: ShareData): Promise<void> {\n if (await isTossEnvironment()) {\n const sdk = await loadTossSdk();\n const fn = (sdk as { share?: unknown } | null)?.share;\n if (typeof fn === 'function') {\n const message = buildSdkMessage(data);\n if (!message) {\n throw new TypeError(\n '[@ait-co/polyfill] navigator.share requires at least one of title, text, or url.',\n );\n }\n try {\n await (fn as (o: { message: string }) => Promise<void>)({ message });\n } catch (e) {\n // Spec says navigator.share rejects with a DOMException. Wrap SDK\n // errors as AbortError (the most common cause is user cancellation),\n // attaching the original as `.cause` for Sentry-style telemetry.\n const message_ = e instanceof Error ? e.message : String(e);\n const wrapped = new DOMException(message_, 'AbortError');\n if (e instanceof Error) {\n (wrapped as Error).cause = e;\n }\n throw wrapped;\n }\n return;\n }\n }\n const host = navigator as unknown as BackupHost;\n const backup = host[SHARE_BACKUP_KEY];\n const original = backup?.share;\n if (!original) {\n throw new DOMException(\n '[@ait-co/polyfill] navigator.share is not available in this environment.',\n 'NotSupportedError',\n );\n }\n return original(data);\n}\n\nfunction canShareShim(data?: ShareData): boolean {\n const hasFiles = Boolean(data?.files && data.files.length > 0);\n const toss = isTossEnvironmentCached();\n\n if (hasFiles) {\n // SDK does not share files. If we know we're in Toss (or it's being\n // forced), say so honestly. If detection hasn't resolved yet, be\n // pessimistic — a false negative is safer than promising a capability\n // we'll turn around and deny.\n if (toss === true) return false;\n if (toss === undefined) return false;\n }\n\n // Toss with non-file payloads: true iff there's at least one field.\n if (toss === true) {\n return Boolean(\n (data?.title != null && data.title !== '') ||\n (data?.text != null && data.text !== '') ||\n (data?.url != null && data.url !== ''),\n );\n }\n\n // `toss === undefined` (detection not resolved) with non-file payload falls\n // through to the browser-native answer. Rationale: `canShare` is rarely\n // load-bearing — consumers care about `share()` itself, which awaits the\n // async detection correctly. A false-negative here would needlessly hide a\n // Share button while detection settles.\n // Browser path: delegate to native when present.\n const host = navigator as unknown as BackupHost;\n const backup = host[SHARE_BACKUP_KEY];\n const originalCanShare = backup?.canShare;\n if (originalCanShare) {\n return originalCanShare(data);\n }\n return Boolean(\n (data?.title != null && data.title !== '') ||\n (data?.text != null && data.text !== '') ||\n (data?.url != null && data.url !== ''),\n );\n}\n\nexport function installShareShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (SHARE_BACKUP_KEY in host) {\n // Already installed. Use `in` so the absence of `share` / `canShare` on\n // the pre-install navigator (legitimately stored as `undefined`) doesn't\n // re-trigger install.\n return () => uninstallShareShim();\n }\n\n const nav = navigator as Navigator & {\n share?: ShareFn;\n canShare?: CanShareFn;\n };\n // Capture the native methods BEFORE patching, bound to `navigator` so that\n // fallback calls keep the correct `this` and never recurse through our shim.\n host[SHARE_BACKUP_KEY] = {\n share: nav.share ? nav.share.bind(navigator) : undefined,\n canShare: nav.canShare ? nav.canShare.bind(navigator) : undefined,\n };\n\n const snapshot = installObjectMethods(navigator, {\n share: shareShim as (...args: never[]) => unknown,\n canShare: canShareShim as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n // Slots frozen. Back out the backup bookkeeping so a later install can retry.\n delete host[SHARE_BACKUP_KEY];\n return () => uninstallShareShim();\n }\n\n host[SHARE_SNAPSHOT_KEY] = snapshot;\n return uninstallShareShim;\n}\n\nexport function uninstallShareShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(SHARE_BACKUP_KEY in host)) return;\n\n const snapshot = host[SHARE_SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n\n delete host[SHARE_BACKUP_KEY];\n delete host[SHARE_SNAPSHOT_KEY];\n}\n","/**\n * `navigator.vibrate` shim.\n *\n * Inside Apps in Toss → best-effort mapping to SDK `generateHapticFeedback`.\n * Single-duration calls land in three buckets so the qualitative SDK haptic\n * tracks intensity a little more closely than the original two-bucket split:\n * - `vibrate(0)` → no-op (web standard: cancels pending vibration)\n * - `vibrate(1..20ms)` → `tickWeak`\n * - `vibrate(21..45ms)` → `tickMedium`\n * - `vibrate(>=46ms)` → `basicMedium`\n * - `vibrate(number[])` → iterates \"on\" segments (even indices) as `tap`\n * pulses with `setTimeout` gaps. Per-element ms mapping is intentionally\n * skipped: arrays in the wild are mostly rhythmic patterns, and the SDK\n * has no \"stronger heavy\" variant to reach for, so per-pulse precision\n * buys little. Callers needing intent should use `vibrateSemantic`.\n *\n * Outside Apps in Toss → defers to the browser's native `navigator.vibrate`,\n * or returns `false` when unavailable (matches the spec — browsers that don't\n * support vibration simply return `false`).\n *\n * Install strategy: **method-level** on `navigator`. We assign our wrapper to\n * `navigator.vibrate` (creating an own shadow over the prototype method) and\n * delete it on uninstall so the prototype re-surfaces. We do not mutate\n * `Navigator.prototype` itself — browsers may mark it non-configurable.\n *\n * Caveats (documented in CLAUDE.md as the known lossy trade-off):\n * - SDK haptics are qualitative (\"tickWeak\", \"basicMedium\"), not millisecond\n * durations. The shim approximates intensity from duration but cannot\n * reproduce exact patterns. Length-only mapping cannot recover semantic\n * intent (success vs. error vs. warning); use `vibrateSemantic` for that.\n * - Arrays are fired sequentially via `setTimeout`; gaps between pulses are\n * honoured only as \"time until the next tap\", not as silent-vs-vibrating.\n * - `vibrate` is spec'd as **synchronous**; the SDK call is async. We return\n * `true` immediately (fire-and-forget). Errors from the SDK are swallowed.\n */\n\nimport { isTossEnvironment, loadTossSdk } from '../detect.js';\nimport {\n installObjectMethods,\n type MethodInstallSnapshot,\n restoreObjectMethods,\n} from './_install-helpers.js';\n\nconst BACKUP_KEY = Symbol.for('@ait-co/polyfill/vibrate.original');\nconst SNAPSHOT_KEY = Symbol.for('@ait-co/polyfill/vibrate.snapshot');\n\ntype VibrateFn = (pattern: VibratePattern) => boolean;\n\ninterface BackupHost {\n [BACKUP_KEY]?: VibrateFn | undefined;\n [SNAPSHOT_KEY]?: MethodInstallSnapshot | undefined;\n}\n\n// Mapping thresholds chosen so the existing dog-food cases keep their old\n// haptic (vibrate(20) → tickWeak, vibrate(50)+ → basicMedium) while a 21–45ms\n// nudge — too long for \"tick\", too short for \"basic\" — gets `tickMedium`.\nconst TICK_WEAK_MAX_MS = 20;\nconst TICK_MEDIUM_MAX_MS = 45;\n\ntype HapticType =\n | 'tickWeak'\n | 'tap'\n | 'tickMedium'\n | 'softMedium'\n | 'basicWeak'\n | 'basicMedium'\n | 'success'\n | 'error'\n | 'wiggle'\n | 'confetti';\n\nexport async function haptic(type: HapticType): Promise<void> {\n const sdk = await loadTossSdk();\n const fn = (sdk as { generateHapticFeedback?: unknown } | null)?.generateHapticFeedback;\n if (typeof fn === 'function') {\n try {\n await (fn as (o: { type: HapticType }) => Promise<void>)({ type });\n } catch {\n // Best-effort; spec-level `vibrate` cannot surface errors.\n }\n }\n}\n\nfunction durationToHaptic(duration: number): HapticType {\n if (duration <= TICK_WEAK_MAX_MS) return 'tickWeak';\n if (duration <= TICK_MEDIUM_MAX_MS) return 'tickMedium';\n return 'basicMedium';\n}\n\nfunction vibrateShim(pattern: VibratePattern): boolean {\n // Matches the spec: `vibrate(0)` or `vibrate([])` cancels pending vibration.\n // We can't cancel an in-flight SDK haptic (no cancel API), but we still\n // forward the cancel to the browser fallback so native vibration stops.\n const arr = Array.isArray(pattern) ? pattern : [pattern];\n if (arr.length === 0 || arr.every((n) => n === 0)) {\n void (async () => {\n if (!(await isTossEnvironment())) {\n const host = navigator as unknown as BackupHost;\n host[BACKUP_KEY]?.(pattern);\n }\n })();\n return true;\n }\n\n void (async () => {\n if (await isTossEnvironment()) {\n if (!Array.isArray(pattern)) {\n await haptic(durationToHaptic(pattern));\n return;\n }\n // Even indices = \"on\" durations, odd indices = pauses. `pattern[i]` is\n // `number | undefined` under `noUncheckedIndexedAccess`; the `undefined`\n // case only arises on out-of-bounds, which our length bound prevents.\n for (let i = 0; i < pattern.length; i += 2) {\n const on = pattern[i];\n if (on === undefined) break;\n if (on > 0) {\n await haptic('tap');\n }\n const pause = pattern[i + 1];\n if (typeof pause === 'number' && pause > 0) {\n await new Promise<void>((r) => setTimeout(r, pause));\n }\n }\n return;\n }\n const host = navigator as unknown as BackupHost;\n const original = host[BACKUP_KEY];\n original?.(pattern);\n })();\n\n return true;\n}\n\nexport function installVibrateShim(): () => void {\n if (typeof navigator === 'undefined') {\n return () => {};\n }\n\n const host = navigator as unknown as BackupHost;\n if (BACKUP_KEY in host) {\n return () => uninstallVibrateShim();\n }\n\n const nav = navigator as Navigator & { vibrate?: VibrateFn };\n // Capture the native method BEFORE we patch, bound to `navigator` so our\n // fallback call keeps the correct `this` and never recurses into our shim.\n host[BACKUP_KEY] = nav.vibrate ? nav.vibrate.bind(navigator) : undefined;\n\n const snapshot = installObjectMethods(navigator, {\n vibrate: vibrateShim as (...args: never[]) => unknown,\n });\n\n if (!snapshot) {\n delete host[BACKUP_KEY];\n return () => uninstallVibrateShim();\n }\n\n host[SNAPSHOT_KEY] = snapshot;\n return uninstallVibrateShim;\n}\n\nexport function uninstallVibrateShim(): void {\n if (typeof navigator === 'undefined') return;\n const host = navigator as unknown as BackupHost;\n if (!(BACKUP_KEY in host)) return;\n\n const snapshot = host[SNAPSHOT_KEY];\n if (snapshot) restoreObjectMethods(snapshot);\n delete host[BACKUP_KEY];\n delete host[SNAPSHOT_KEY];\n}\n","/**\n * @ait-co/polyfill\n *\n * Write Apps in Toss mini-apps using standard Web APIs\n * (`navigator.clipboard`, `navigator.geolocation`, …). This polyfill routes\n * calls through the Apps in Toss SDK **only when we detect we are actually\n * running inside the Toss app** — in every other environment (a plain browser,\n * local dev, tests) the shims are not installed and the browser's native\n * implementations are used as-is.\n *\n * Unofficial community project. Not affiliated with Toss.\n */\n\nexport { isTossEnvironment, isTossEnvironmentCached, loadTossSdk } from './detect.js';\nexport { installClipboardShim, uninstallClipboardShim } from './shims/clipboard.js';\nexport { installGeolocationShim, uninstallGeolocationShim } from './shims/geolocation.js';\nexport { installNetworkShim, uninstallNetworkShim } from './shims/network.js';\nexport { installShareShim, uninstallShareShim } from './shims/share.js';\nexport { installVibrateShim, uninstallVibrateShim } from './shims/vibrate.js';\nexport { type VibrateIntent, vibrateSemantic } from './shims/vibrate-semantic.js';\n\nimport { isTossEnvironment } from './detect.js';\nimport { installClipboardShim, uninstallClipboardShim } from './shims/clipboard.js';\nimport { installGeolocationShim, uninstallGeolocationShim } from './shims/geolocation.js';\nimport { installNetworkShim, uninstallNetworkShim } from './shims/network.js';\nimport { installShareShim, uninstallShareShim } from './shims/share.js';\nimport { installVibrateShim, uninstallVibrateShim } from './shims/vibrate.js';\n\nexport const VERSION: string = __VERSION__;\n\nconst NOOP = (): void => {};\n\n/**\n * Install every shim this library ships, but only if we detect an Apps in\n * Toss runtime. In a plain browser `install()` is a no-op — the browser's\n * native APIs stay untouched.\n *\n * Returns a promise that resolves with an uninstall function. If the\n * environment turns out not to be Toss, the uninstall function is a no-op.\n *\n * Install order (when active): clipboard → geolocation → share → vibrate →\n * network. Not atomic on failure — if a per-shim install throws (e.g., a\n * consumer pinned a target navigator property as non-configurable), earlier\n * shims are already in place. Callers should catch and invoke the returned\n * uninstall to roll back.\n */\nexport async function install(): Promise<() => void> {\n if (!(await isTossEnvironment())) return NOOP;\n const uninstalls = [\n installClipboardShim(),\n installGeolocationShim(),\n installShareShim(),\n installVibrateShim(),\n installNetworkShim(),\n ];\n return () => {\n for (const fn of uninstalls) fn();\n };\n}\n\n/**\n * Uninstall every shim installed by `install()`. Safe to call when no shim is\n * installed — each installer's uninstall is a no-op in that case.\n */\nexport function uninstall(): void {\n uninstallClipboardShim();\n uninstallGeolocationShim();\n uninstallShareShim();\n uninstallVibrateShim();\n uninstallNetworkShim();\n}\n","/**\n * Side-effect entry point: `import '@ait-co/polyfill/auto'`\n *\n * Kicks off detection and, if we're inside Apps in Toss, installs every shim\n * this library ships. In a plain browser this is a no-op — browser native\n * APIs stay untouched. No-op idempotent: importing the entry more than once\n * doesn't re-install.\n *\n * Use this when you want the \"just add the dep\" experience. If you need to\n * observe when the polyfill actually attached (to gate init logic) or to tear\n * it down, import `install` / `uninstall` from `@ait-co/polyfill` directly.\n */\n\nimport { install } from './index.js';\n\nvoid install();\n"],"mappings":"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"}
|