@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.
Files changed (47) hide show
  1. package/README.md +53 -3
  2. package/dist/auto.cjs +919 -0
  3. package/dist/auto.cjs.map +1 -0
  4. package/dist/auto.d.cts +1 -0
  5. package/dist/auto.js +18 -6
  6. package/dist/auto.js.map +1 -1
  7. package/dist/detect.cjs +84 -0
  8. package/dist/detect.cjs.map +1 -0
  9. package/dist/detect.d.cts +50 -0
  10. package/dist/detect.d.cts.map +1 -0
  11. package/dist/index.cjs +982 -0
  12. package/dist/index.cjs.map +1 -0
  13. package/dist/index.d.cts +222 -0
  14. package/dist/index.d.cts.map +1 -0
  15. package/dist/index.d.ts +26 -27
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +68 -8
  18. package/dist/index.js.map +1 -1
  19. package/dist/shims/clipboard.cjs +192 -0
  20. package/dist/shims/clipboard.cjs.map +1 -0
  21. package/dist/shims/clipboard.d.cts +26 -0
  22. package/dist/shims/clipboard.d.cts.map +1 -0
  23. package/dist/shims/geolocation.cjs +356 -0
  24. package/dist/shims/geolocation.cjs.map +1 -0
  25. package/dist/shims/geolocation.d.cts +41 -0
  26. package/dist/shims/geolocation.d.cts.map +1 -0
  27. package/dist/shims/network.cjs +290 -0
  28. package/dist/shims/network.cjs.map +1 -0
  29. package/dist/shims/network.d.cts +56 -0
  30. package/dist/shims/network.d.cts.map +1 -0
  31. package/dist/shims/share.cjs +239 -0
  32. package/dist/shims/share.cjs.map +1 -0
  33. package/dist/shims/share.d.cts +26 -0
  34. package/dist/shims/share.d.cts.map +1 -0
  35. package/dist/shims/vibrate-semantic.d.ts +27 -0
  36. package/dist/shims/vibrate-semantic.d.ts.map +1 -0
  37. package/dist/shims/vibrate-semantic.js +150 -0
  38. package/dist/shims/vibrate-semantic.js.map +1 -0
  39. package/dist/shims/vibrate.cjs +235 -0
  40. package/dist/shims/vibrate.cjs.map +1 -0
  41. package/dist/shims/vibrate.d.cts +43 -0
  42. package/dist/shims/vibrate.d.cts.map +1 -0
  43. package/dist/shims/vibrate.d.ts +16 -5
  44. package/dist/shims/vibrate.d.ts.map +1 -1
  45. package/dist/shims/vibrate.js +19 -7
  46. package/dist/shims/vibrate.js.map +1 -1
  47. package/package.json +73 -19
@@ -0,0 +1,356 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/detect.ts
3
+ /**
4
+ * Environment detection: are we running inside Apps in Toss, or a plain browser?
5
+ *
6
+ * Strategy: call the SDK's `getAppsInTossGlobals()` — a synchronous export
7
+ * that returns the runtime's Toss globals (deploymentId, brand name, …)
8
+ * inside the Apps in Toss runtime and throws (RN bridge unavailable)
9
+ * anywhere else. The SDK itself is an **optional** peer dependency; if its
10
+ * module can't be imported we are definitely not inside Toss.
11
+ *
12
+ * Just having the SDK module resolvable is not enough — apps can bundle it
13
+ * and still run in a plain browser. We need the bridge probe to confirm.
14
+ *
15
+ * UA sniffing (spoofable) is avoided. We do call `getAppsInTossGlobals`, but
16
+ * that's a constant read from the bridge — no permission dialogs, no
17
+ * analytics fire. In a plain browser the bridge lookup fails fast (sync
18
+ * throw, microsecond-scale), so the startup cost is negligible.
19
+ */
20
+ let cached;
21
+ /**
22
+ * Returns `true` iff we detect we are running in an environment where the
23
+ * Apps in Toss SDK (`@apps-in-toss/web-framework`) is present and usable.
24
+ *
25
+ * Async because we use dynamic `import()` to probe the optional peer dep
26
+ * without forcing it into the consumer's bundle.
27
+ */
28
+ async function isTossEnvironment() {
29
+ const force = globalThis.__AIT_POLYFILL_FORCE__;
30
+ if (force === "toss") return true;
31
+ if (force === "browser") return false;
32
+ if (cached !== void 0) return cached;
33
+ const mod = await loadTossSdk();
34
+ if (typeof mod?.getAppsInTossGlobals !== "function") {
35
+ cached = false;
36
+ return cached;
37
+ }
38
+ try {
39
+ const globals = mod.getAppsInTossGlobals();
40
+ cached = Boolean(globals) && typeof globals === "object";
41
+ } catch {
42
+ cached = false;
43
+ }
44
+ return cached;
45
+ }
46
+ /**
47
+ * Lazy SDK accessor — returns the module if available, else `null`. Callers
48
+ * are expected to `await` and null-check. Never throws.
49
+ */
50
+ async function loadTossSdk() {
51
+ try {
52
+ return await import("@apps-in-toss/web-framework");
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+ //#endregion
58
+ //#region src/shims/_install-helpers.ts
59
+ /**
60
+ * Mutate methods on an existing object rather than replacing the object
61
+ * itself. This is the path we take for `navigator.geolocation`, `navigator.share`,
62
+ * and `navigator.vibrate` in Chromium, where the slot on `navigator` is a
63
+ * non-configurable own property that we cannot replace — but the methods
64
+ * themselves (or the methods on the referenced object) are still
65
+ * `configurable: true, writable: true`.
66
+ *
67
+ * Each replacement is installed via plain assignment. If any slot is not
68
+ * writable (e.g. frozen object), install is aborted and previously-applied
69
+ * replacements are rolled back, so the caller observes an atomic "all or
70
+ * nothing" failure as `null`. The caller is expected to degrade gracefully
71
+ * (e.g. log a one-time `console.warn`) when that happens.
72
+ */
73
+ function installObjectMethods(target, replacements) {
74
+ const methods = {};
75
+ const applied = [];
76
+ const bag = target;
77
+ for (const key of Object.keys(replacements)) {
78
+ const hadOwn = Object.hasOwn(target, key);
79
+ const original = bag[key];
80
+ try {
81
+ bag[key] = replacements[key];
82
+ } catch {
83
+ for (const applieKey of applied) {
84
+ const prev = methods[applieKey];
85
+ if (!prev) continue;
86
+ if (prev.hadOwn) bag[applieKey] = prev.original;
87
+ else delete bag[applieKey];
88
+ }
89
+ return null;
90
+ }
91
+ if (bag[key] !== replacements[key]) {
92
+ for (const applieKey of applied) {
93
+ const prev = methods[applieKey];
94
+ if (!prev) continue;
95
+ if (prev.hadOwn) bag[applieKey] = prev.original;
96
+ else delete bag[applieKey];
97
+ }
98
+ return null;
99
+ }
100
+ methods[key] = {
101
+ hadOwn,
102
+ original
103
+ };
104
+ applied.push(key);
105
+ }
106
+ return {
107
+ target,
108
+ methods
109
+ };
110
+ }
111
+ /**
112
+ * Reverse an `installObjectMethods` snapshot. Reassigns originals for slots
113
+ * that were own properties before install; deletes the override for slots
114
+ * that were inherited (so the prototype method surfaces again).
115
+ */
116
+ function restoreObjectMethods(snapshot) {
117
+ const bag = snapshot.target;
118
+ for (const key of Object.keys(snapshot.methods)) {
119
+ const entry = snapshot.methods[key];
120
+ if (!entry) continue;
121
+ try {
122
+ if (entry.hadOwn) bag[key] = entry.original;
123
+ else delete bag[key];
124
+ } catch {}
125
+ }
126
+ }
127
+ //#endregion
128
+ //#region src/shims/geolocation.ts
129
+ /**
130
+ * `navigator.geolocation` shim.
131
+ *
132
+ * Inside Apps in Toss → routes through the SDK:
133
+ * - `getCurrentPosition` → `getCurrentLocation({ accuracy })`
134
+ * - `watchPosition` / `clearWatch` → `startUpdateLocation({ onEvent, onError, options })`
135
+ *
136
+ * Outside Apps in Toss → defers to the browser's native `navigator.geolocation`.
137
+ * If neither is available, the error callback receives a `GeolocationPositionError`.
138
+ *
139
+ * Install strategy: **method-level**. We do **not** replace `navigator.geolocation`
140
+ * itself — Chromium marks that slot as a non-configurable own property, which
141
+ * both `defineProperty(navigator, 'geolocation', …)` and the prototype-level
142
+ * fallback cannot override (the instance shadow blocks prototype reads). We
143
+ * instead mutate the methods on the existing `Geolocation` object, whose own
144
+ * method descriptors are configurable+writable in every browser we've seen.
145
+ *
146
+ * SDK/Web shape mismatch handled here:
147
+ * - SDK `Accuracy` is a numeric enum (1 = Lowest … 6 = BestForNavigation); the
148
+ * standard `PositionOptions.enableHighAccuracy` is a boolean. We map
149
+ * `true → Accuracy.High (4, "~10m")` and `false → Accuracy.Balanced (3)`.
150
+ * `Highest (5)` / `BestForNavigation (6)` are available but carry a battery
151
+ * cost that's rarely what mini-apps want; consumers who need them should
152
+ * call the SDK directly.
153
+ * - SDK coords lack `speed`; we surface `null` (per the W3C spec when unknown).
154
+ * - SDK `startUpdateLocation` returns an `unsubscribe` fn; we wrap it behind
155
+ * a numeric watch id so `clearWatch(id)` behaves like the standard.
156
+ *
157
+ * Caveat: watch ids reset whenever the shim is uninstalled and reinstalled;
158
+ * they are not stable across such cycles. Ids obtained before uninstall
159
+ * cannot be cleared after uninstall — `clearWatch(id)` on the restored native
160
+ * `navigator.geolocation` uses a different id space, so the SDK subscription
161
+ * leaks. Consumers should `clearWatch` all outstanding ids before calling
162
+ * `uninstall()`.
163
+ */
164
+ const BACKUP_KEY = Symbol.for("@ait-co/polyfill/geolocation.original");
165
+ const SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/geolocation.snapshot");
166
+ const ACCURACY_BALANCED = 3;
167
+ const ACCURACY_HIGH = 4;
168
+ function toStandardPosition(sdk) {
169
+ const coordsData = {
170
+ latitude: sdk.coords.latitude,
171
+ longitude: sdk.coords.longitude,
172
+ altitude: sdk.coords.altitude,
173
+ accuracy: sdk.coords.accuracy,
174
+ altitudeAccuracy: sdk.coords.altitudeAccuracy,
175
+ heading: sdk.coords.heading,
176
+ speed: null
177
+ };
178
+ return {
179
+ coords: {
180
+ ...coordsData,
181
+ toJSON() {
182
+ return { ...coordsData };
183
+ }
184
+ },
185
+ timestamp: sdk.timestamp,
186
+ toJSON() {
187
+ return {
188
+ coords: { ...coordsData },
189
+ timestamp: sdk.timestamp
190
+ };
191
+ }
192
+ };
193
+ }
194
+ function toPositionError(code, message) {
195
+ const Ctor = globalThis.GeolocationPositionError;
196
+ if (typeof Ctor === "function") {
197
+ const proto = Ctor.prototype;
198
+ if (proto) {
199
+ const shape = {
200
+ code,
201
+ message
202
+ };
203
+ Object.setPrototypeOf(shape, proto);
204
+ return shape;
205
+ }
206
+ }
207
+ return {
208
+ code,
209
+ message,
210
+ PERMISSION_DENIED: 1,
211
+ POSITION_UNAVAILABLE: 2,
212
+ TIMEOUT: 3
213
+ };
214
+ }
215
+ function accuracyFromOptions(options) {
216
+ return options?.enableHighAccuracy ? ACCURACY_HIGH : ACCURACY_BALANCED;
217
+ }
218
+ function createGeolocationShim(fallback) {
219
+ let nextWatchId = 1;
220
+ const sdkWatches = /* @__PURE__ */ new Map();
221
+ const nativeWatches = /* @__PURE__ */ new Map();
222
+ const pendingWatches = /* @__PURE__ */ new Map();
223
+ return {
224
+ getCurrentPosition(success, error, options) {
225
+ (async () => {
226
+ if (await isTossEnvironment()) {
227
+ const fn = (await loadTossSdk())?.getCurrentLocation;
228
+ if (typeof fn === "function") {
229
+ try {
230
+ success(toStandardPosition(await fn({ accuracy: accuracyFromOptions(options) })));
231
+ } catch (e) {
232
+ error?.(toPositionError(2, e instanceof Error ? e.message : "[@ait-co/polyfill] getCurrentLocation failed."));
233
+ }
234
+ return;
235
+ }
236
+ }
237
+ if (!fallback.getCurrentPosition) {
238
+ error?.(toPositionError(2, "[@ait-co/polyfill] navigator.geolocation is not available in this environment."));
239
+ return;
240
+ }
241
+ fallback.getCurrentPosition(success, error, options);
242
+ })();
243
+ },
244
+ watchPosition(success, error, options) {
245
+ const id = nextWatchId++;
246
+ const pending = { cancelled: false };
247
+ pendingWatches.set(id, pending);
248
+ (async () => {
249
+ if (await isTossEnvironment()) {
250
+ const fn = (await loadTossSdk())?.startUpdateLocation;
251
+ if (typeof fn === "function") {
252
+ if (pending.cancelled) {
253
+ pendingWatches.delete(id);
254
+ return;
255
+ }
256
+ const unsubscribe = fn({
257
+ onEvent: (loc) => success(toStandardPosition(loc)),
258
+ onError: (err) => error?.(toPositionError(2, err instanceof Error ? err.message : "[@ait-co/polyfill] startUpdateLocation failed.")),
259
+ options: {
260
+ accuracy: accuracyFromOptions(options),
261
+ timeInterval: 1e3,
262
+ distanceInterval: 0
263
+ }
264
+ });
265
+ if (pending.cancelled) {
266
+ unsubscribe();
267
+ pendingWatches.delete(id);
268
+ return;
269
+ }
270
+ sdkWatches.set(id, unsubscribe);
271
+ pendingWatches.delete(id);
272
+ return;
273
+ }
274
+ }
275
+ if (!fallback.watchPosition) {
276
+ pendingWatches.delete(id);
277
+ error?.(toPositionError(2, "[@ait-co/polyfill] navigator.geolocation is not available in this environment."));
278
+ return;
279
+ }
280
+ if (pending.cancelled) {
281
+ pendingWatches.delete(id);
282
+ return;
283
+ }
284
+ const nativeId = fallback.watchPosition(success, error, options);
285
+ if (pending.cancelled) {
286
+ fallback.clearWatch?.(nativeId);
287
+ pendingWatches.delete(id);
288
+ return;
289
+ }
290
+ nativeWatches.set(id, nativeId);
291
+ pendingWatches.delete(id);
292
+ })();
293
+ return id;
294
+ },
295
+ clearWatch(id) {
296
+ const pending = pendingWatches.get(id);
297
+ if (pending) {
298
+ pending.cancelled = true;
299
+ pendingWatches.delete(id);
300
+ return;
301
+ }
302
+ const unsubscribe = sdkWatches.get(id);
303
+ if (unsubscribe) {
304
+ unsubscribe();
305
+ sdkWatches.delete(id);
306
+ return;
307
+ }
308
+ const nativeId = nativeWatches.get(id);
309
+ if (nativeId !== void 0 && fallback.clearWatch) {
310
+ fallback.clearWatch(nativeId);
311
+ nativeWatches.delete(id);
312
+ }
313
+ }
314
+ };
315
+ }
316
+ function installGeolocationShim() {
317
+ if (typeof navigator === "undefined") return () => {};
318
+ const host = navigator;
319
+ if (BACKUP_KEY in host) return () => uninstallGeolocationShim();
320
+ const target = navigator.geolocation;
321
+ if (!target) {
322
+ host[BACKUP_KEY] = void 0;
323
+ return () => uninstallGeolocationShim();
324
+ }
325
+ const shim = createGeolocationShim({
326
+ getCurrentPosition: target.getCurrentPosition?.bind(target),
327
+ watchPosition: target.watchPosition?.bind(target),
328
+ clearWatch: target.clearWatch?.bind(target)
329
+ });
330
+ const snapshot = installObjectMethods(target, {
331
+ getCurrentPosition: shim.getCurrentPosition,
332
+ watchPosition: shim.watchPosition,
333
+ clearWatch: shim.clearWatch
334
+ });
335
+ if (!snapshot) {
336
+ host[BACKUP_KEY] = void 0;
337
+ return () => uninstallGeolocationShim();
338
+ }
339
+ host[BACKUP_KEY] = { target };
340
+ host[SNAPSHOT_KEY] = snapshot;
341
+ return uninstallGeolocationShim;
342
+ }
343
+ function uninstallGeolocationShim() {
344
+ if (typeof navigator === "undefined") return;
345
+ const host = navigator;
346
+ if (!(BACKUP_KEY in host)) return;
347
+ const snapshot = host[SNAPSHOT_KEY];
348
+ if (snapshot) restoreObjectMethods(snapshot);
349
+ delete host[BACKUP_KEY];
350
+ delete host[SNAPSHOT_KEY];
351
+ }
352
+ //#endregion
353
+ exports.installGeolocationShim = installGeolocationShim;
354
+ exports.uninstallGeolocationShim = uninstallGeolocationShim;
355
+
356
+ //# sourceMappingURL=geolocation.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geolocation.cjs","names":[],"sources":["../../src/detect.ts","../../src/shims/_install-helpers.ts","../../src/shims/geolocation.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.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"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ //#region src/shims/geolocation.d.ts
2
+ /**
3
+ * `navigator.geolocation` shim.
4
+ *
5
+ * Inside Apps in Toss → routes through the SDK:
6
+ * - `getCurrentPosition` → `getCurrentLocation({ accuracy })`
7
+ * - `watchPosition` / `clearWatch` → `startUpdateLocation({ onEvent, onError, options })`
8
+ *
9
+ * Outside Apps in Toss → defers to the browser's native `navigator.geolocation`.
10
+ * If neither is available, the error callback receives a `GeolocationPositionError`.
11
+ *
12
+ * Install strategy: **method-level**. We do **not** replace `navigator.geolocation`
13
+ * itself — Chromium marks that slot as a non-configurable own property, which
14
+ * both `defineProperty(navigator, 'geolocation', …)` and the prototype-level
15
+ * fallback cannot override (the instance shadow blocks prototype reads). We
16
+ * instead mutate the methods on the existing `Geolocation` object, whose own
17
+ * method descriptors are configurable+writable in every browser we've seen.
18
+ *
19
+ * SDK/Web shape mismatch handled here:
20
+ * - SDK `Accuracy` is a numeric enum (1 = Lowest … 6 = BestForNavigation); the
21
+ * standard `PositionOptions.enableHighAccuracy` is a boolean. We map
22
+ * `true → Accuracy.High (4, "~10m")` and `false → Accuracy.Balanced (3)`.
23
+ * `Highest (5)` / `BestForNavigation (6)` are available but carry a battery
24
+ * cost that's rarely what mini-apps want; consumers who need them should
25
+ * call the SDK directly.
26
+ * - SDK coords lack `speed`; we surface `null` (per the W3C spec when unknown).
27
+ * - SDK `startUpdateLocation` returns an `unsubscribe` fn; we wrap it behind
28
+ * a numeric watch id so `clearWatch(id)` behaves like the standard.
29
+ *
30
+ * Caveat: watch ids reset whenever the shim is uninstalled and reinstalled;
31
+ * they are not stable across such cycles. Ids obtained before uninstall
32
+ * cannot be cleared after uninstall — `clearWatch(id)` on the restored native
33
+ * `navigator.geolocation` uses a different id space, so the SDK subscription
34
+ * leaks. Consumers should `clearWatch` all outstanding ids before calling
35
+ * `uninstall()`.
36
+ */
37
+ declare function installGeolocationShim(): () => void;
38
+ declare function uninstallGeolocationShim(): void;
39
+ //#endregion
40
+ export { installGeolocationShim, uninstallGeolocationShim };
41
+ //# sourceMappingURL=geolocation.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geolocation.d.cts","names":[],"sources":["../../src/shims/geolocation.ts"],"mappings":";;AAsSA;;;;;AA8CA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA9CgB,sBAAA,CAAA;AAAA,iBA8CA,wBAAA,CAAA"}