@ait-co/polyfill 0.1.1 → 0.1.3
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 +29 -22
- package/dist/auto.d.ts +1 -0
- package/dist/auto.js +789 -0
- package/dist/auto.js.map +1 -0
- package/dist/detect.d.ts +12 -7
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +23 -8
- package/dist/detect.js.map +1 -1
- package/dist/index.d.ts +14 -15
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +128 -96
- package/dist/index.js.map +1 -1
- package/dist/shims/clipboard.d.ts +1 -3
- package/dist/shims/clipboard.d.ts.map +1 -1
- package/dist/shims/clipboard.js +78 -25
- package/dist/shims/clipboard.js.map +1 -1
- package/dist/shims/geolocation.d.ts.map +1 -1
- package/dist/shims/geolocation.js +77 -18
- package/dist/shims/geolocation.js.map +1 -1
- package/dist/shims/network.d.ts.map +1 -1
- package/dist/shims/network.js +85 -29
- package/dist/shims/network.js.map +1 -1
- package/dist/shims/share.d.ts.map +1 -1
- package/dist/shims/share.js +81 -23
- package/dist/shims/share.js.map +1 -1
- package/dist/shims/vibrate.d.ts.map +1 -1
- package/dist/shims/vibrate.js +77 -22
- package/dist/shims/vibrate.js.map +1 -1
- package/package.json +8 -2
package/dist/index.js
CHANGED
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Environment detection: are we running inside Apps in Toss, or a plain browser?
|
|
4
4
|
*
|
|
5
|
-
* Strategy:
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
5
|
+
* Strategy: call the SDK's `getAppsInTossGlobals()` — a synchronous export
|
|
6
|
+
* that returns the runtime's Toss globals (deploymentId, brand name, …)
|
|
7
|
+
* inside the Apps in Toss runtime and throws (RN bridge unavailable)
|
|
8
|
+
* anywhere else. The SDK itself is an **optional** peer dependency; if its
|
|
9
|
+
* module can't be imported we are definitely not inside Toss.
|
|
9
10
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Just having the SDK module resolvable is not enough — apps can bundle it
|
|
12
|
+
* and still run in a plain browser. We need the bridge probe to confirm.
|
|
13
|
+
*
|
|
14
|
+
* UA sniffing (spoofable) is avoided. We do call `getAppsInTossGlobals`, but
|
|
15
|
+
* that's a constant read from the bridge — no permission dialogs, no
|
|
16
|
+
* analytics fire. In a plain browser the bridge lookup fails fast (sync
|
|
17
|
+
* throw, microsecond-scale), so the startup cost is negligible.
|
|
13
18
|
*/
|
|
14
19
|
let cached;
|
|
15
20
|
/**
|
|
@@ -39,7 +44,17 @@ async function isTossEnvironment() {
|
|
|
39
44
|
if (force === "toss") return true;
|
|
40
45
|
if (force === "browser") return false;
|
|
41
46
|
if (cached !== void 0) return cached;
|
|
42
|
-
|
|
47
|
+
const mod = await loadTossSdk();
|
|
48
|
+
if (typeof mod?.getAppsInTossGlobals !== "function") {
|
|
49
|
+
cached = false;
|
|
50
|
+
return cached;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const globals = mod.getAppsInTossGlobals();
|
|
54
|
+
cached = Boolean(globals) && typeof globals === "object";
|
|
55
|
+
} catch {
|
|
56
|
+
cached = false;
|
|
57
|
+
}
|
|
43
58
|
return cached;
|
|
44
59
|
}
|
|
45
60
|
/**
|
|
@@ -54,6 +69,54 @@ async function loadTossSdk() {
|
|
|
54
69
|
}
|
|
55
70
|
}
|
|
56
71
|
//#endregion
|
|
72
|
+
//#region src/shims/_install-helpers.ts
|
|
73
|
+
/**
|
|
74
|
+
* Install `descriptor` at `navigator[prop]`. Prefer instance-level; if the
|
|
75
|
+
* browser refuses (property is non-configurable on the instance), install on
|
|
76
|
+
* `Navigator.prototype` instead.
|
|
77
|
+
*
|
|
78
|
+
* Returns a snapshot describing where the original value was, which
|
|
79
|
+
* `restoreNavigatorProperty` uses to undo the install.
|
|
80
|
+
*/
|
|
81
|
+
function installNavigatorProperty(prop, descriptor) {
|
|
82
|
+
const nav = navigator;
|
|
83
|
+
const instanceDesc = Object.getOwnPropertyDescriptor(nav, prop);
|
|
84
|
+
const instanceHadOwn = instanceDesc !== void 0;
|
|
85
|
+
if (!instanceDesc || instanceDesc.configurable) try {
|
|
86
|
+
Object.defineProperty(nav, prop, descriptor);
|
|
87
|
+
return {
|
|
88
|
+
location: "instance",
|
|
89
|
+
originalDescriptor: instanceDesc,
|
|
90
|
+
instanceHadOwn
|
|
91
|
+
};
|
|
92
|
+
} catch {}
|
|
93
|
+
const proto = Object.getPrototypeOf(nav);
|
|
94
|
+
const protoDesc = Object.getOwnPropertyDescriptor(proto, prop);
|
|
95
|
+
if (instanceHadOwn) try {
|
|
96
|
+
delete nav[prop];
|
|
97
|
+
} catch {}
|
|
98
|
+
Object.defineProperty(proto, prop, descriptor);
|
|
99
|
+
return {
|
|
100
|
+
location: "prototype",
|
|
101
|
+
originalDescriptor: protoDesc,
|
|
102
|
+
instanceHadOwn
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Reverse the install recorded in `snapshot`. If the original descriptor was
|
|
107
|
+
* `undefined` (property didn't exist before), delete the property instead of
|
|
108
|
+
* re-defining it.
|
|
109
|
+
*/
|
|
110
|
+
function restoreNavigatorProperty(prop, snapshot) {
|
|
111
|
+
const target = snapshot.location === "instance" ? navigator : Object.getPrototypeOf(navigator);
|
|
112
|
+
if (snapshot.originalDescriptor) try {
|
|
113
|
+
Object.defineProperty(target, prop, snapshot.originalDescriptor);
|
|
114
|
+
} catch {}
|
|
115
|
+
else try {
|
|
116
|
+
delete target[prop];
|
|
117
|
+
} catch {}
|
|
118
|
+
}
|
|
119
|
+
//#endregion
|
|
57
120
|
//#region src/shims/clipboard.ts
|
|
58
121
|
/**
|
|
59
122
|
* `navigator.clipboard` shim.
|
|
@@ -66,7 +129,7 @@ async function loadTossSdk() {
|
|
|
66
129
|
* surfaces unchanged — we don't paper over missing support.
|
|
67
130
|
*/
|
|
68
131
|
const BACKUP_KEY$2 = Symbol.for("@ait-co/polyfill/clipboard.original");
|
|
69
|
-
const
|
|
132
|
+
const SNAPSHOT_KEY$2 = Symbol.for("@ait-co/polyfill/clipboard.snapshot");
|
|
70
133
|
/**
|
|
71
134
|
* Produces a Clipboard-compatible object whose `readText` / `writeText` methods
|
|
72
135
|
* route to the SDK when in Toss, else fall through to the supplied `fallback`.
|
|
@@ -117,34 +180,24 @@ function installClipboardShim() {
|
|
|
117
180
|
if (BACKUP_KEY$2 in host) return () => uninstallClipboardShim();
|
|
118
181
|
const original = navigator.clipboard;
|
|
119
182
|
host[BACKUP_KEY$2] = original;
|
|
120
|
-
host[
|
|
121
|
-
|
|
122
|
-
Object.defineProperty(navigator, "clipboard", {
|
|
123
|
-
value: shim,
|
|
183
|
+
host[SNAPSHOT_KEY$2] = installNavigatorProperty("clipboard", {
|
|
184
|
+
value: createClipboardShim(original),
|
|
124
185
|
configurable: true,
|
|
125
186
|
writable: true
|
|
126
187
|
});
|
|
127
188
|
return uninstallClipboardShim;
|
|
128
189
|
}
|
|
129
190
|
/**
|
|
130
|
-
* Remove the shim and restore the pre-install shape.
|
|
131
|
-
* redefine so a prototype-level `navigator.clipboard` (non-configurable in real
|
|
132
|
-
* browsers) becomes visible again instead of being permanently shadowed.
|
|
191
|
+
* Remove the shim and restore the pre-install shape.
|
|
133
192
|
*/
|
|
134
193
|
function uninstallClipboardShim() {
|
|
135
194
|
if (typeof navigator === "undefined") return;
|
|
136
195
|
const host = navigator;
|
|
137
196
|
if (!(BACKUP_KEY$2 in host)) return;
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
delete navigator.clipboard;
|
|
141
|
-
if (had && navigator.clipboard !== original) Object.defineProperty(navigator, "clipboard", {
|
|
142
|
-
value: original,
|
|
143
|
-
configurable: true,
|
|
144
|
-
writable: true
|
|
145
|
-
});
|
|
197
|
+
const snapshot = host[SNAPSHOT_KEY$2];
|
|
198
|
+
if (snapshot) restoreNavigatorProperty("clipboard", snapshot);
|
|
146
199
|
delete host[BACKUP_KEY$2];
|
|
147
|
-
delete host[
|
|
200
|
+
delete host[SNAPSHOT_KEY$2];
|
|
148
201
|
}
|
|
149
202
|
//#endregion
|
|
150
203
|
//#region src/shims/geolocation.ts
|
|
@@ -177,6 +230,7 @@ function uninstallClipboardShim() {
|
|
|
177
230
|
* `uninstall()`.
|
|
178
231
|
*/
|
|
179
232
|
const BACKUP_KEY$1 = Symbol.for("@ait-co/polyfill/geolocation.original");
|
|
233
|
+
const SNAPSHOT_KEY$1 = Symbol.for("@ait-co/polyfill/geolocation.snapshot");
|
|
180
234
|
const ACCURACY_BALANCED = 3;
|
|
181
235
|
const ACCURACY_HIGH = 4;
|
|
182
236
|
function toStandardPosition(sdk) {
|
|
@@ -333,9 +387,8 @@ function installGeolocationShim() {
|
|
|
333
387
|
if (BACKUP_KEY$1 in host) return () => uninstallGeolocationShim();
|
|
334
388
|
const original = navigator.geolocation;
|
|
335
389
|
host[BACKUP_KEY$1] = original;
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
value: shim,
|
|
390
|
+
host[SNAPSHOT_KEY$1] = installNavigatorProperty("geolocation", {
|
|
391
|
+
value: createGeolocationShim(original),
|
|
339
392
|
configurable: true,
|
|
340
393
|
writable: true
|
|
341
394
|
});
|
|
@@ -345,14 +398,10 @@ function uninstallGeolocationShim() {
|
|
|
345
398
|
if (typeof navigator === "undefined") return;
|
|
346
399
|
const host = navigator;
|
|
347
400
|
if (!(BACKUP_KEY$1 in host)) return;
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
if (original !== void 0 && navigator.geolocation !== original) Object.defineProperty(navigator, "geolocation", {
|
|
351
|
-
value: original,
|
|
352
|
-
configurable: true,
|
|
353
|
-
writable: true
|
|
354
|
-
});
|
|
401
|
+
const snapshot = host[SNAPSHOT_KEY$1];
|
|
402
|
+
if (snapshot) restoreNavigatorProperty("geolocation", snapshot);
|
|
355
403
|
delete host[BACKUP_KEY$1];
|
|
404
|
+
delete host[SNAPSHOT_KEY$1];
|
|
356
405
|
}
|
|
357
406
|
//#endregion
|
|
358
407
|
//#region src/shims/network.ts
|
|
@@ -398,6 +447,8 @@ function uninstallGeolocationShim() {
|
|
|
398
447
|
* reads may return the native object.
|
|
399
448
|
*/
|
|
400
449
|
const INSTALLED_KEY = Symbol.for("@ait-co/polyfill/network.installed");
|
|
450
|
+
const ON_LINE_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/network.onLine.snapshot");
|
|
451
|
+
const CONNECTION_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/network.connection.snapshot");
|
|
401
452
|
const REFRESH_THROTTLE_MS = 500;
|
|
402
453
|
function statusToOnline(status) {
|
|
403
454
|
return status !== "OFFLINE";
|
|
@@ -477,35 +528,22 @@ function installNetworkShim() {
|
|
|
477
528
|
})();
|
|
478
529
|
return inflight;
|
|
479
530
|
}
|
|
531
|
+
const nativeOnLine = navigator.onLine;
|
|
532
|
+
const nativeConnection = navigator.connection;
|
|
480
533
|
refresh();
|
|
481
|
-
|
|
534
|
+
host[ON_LINE_SNAPSHOT_KEY] = installNavigatorProperty("onLine", {
|
|
482
535
|
configurable: true,
|
|
483
536
|
get() {
|
|
484
537
|
refresh();
|
|
485
538
|
if (cachedStatus !== null) return statusToOnline(cachedStatus);
|
|
486
|
-
|
|
487
|
-
delete navigator.onLine;
|
|
488
|
-
try {
|
|
489
|
-
return navigator.onLine;
|
|
490
|
-
} finally {
|
|
491
|
-
if (desc) Object.defineProperty(navigator, "onLine", desc);
|
|
492
|
-
}
|
|
539
|
+
return nativeOnLine ?? true;
|
|
493
540
|
}
|
|
494
541
|
});
|
|
495
|
-
|
|
542
|
+
host[CONNECTION_SNAPSHOT_KEY] = installNavigatorProperty("connection", {
|
|
496
543
|
configurable: true,
|
|
497
544
|
get() {
|
|
498
545
|
refresh();
|
|
499
|
-
if (cachedStatus === null)
|
|
500
|
-
const desc = Object.getOwnPropertyDescriptor(navigator, "connection");
|
|
501
|
-
delete navigator.connection;
|
|
502
|
-
try {
|
|
503
|
-
const native = navigator.connection;
|
|
504
|
-
if (native !== void 0) return native;
|
|
505
|
-
} finally {
|
|
506
|
-
if (desc) Object.defineProperty(navigator, "connection", desc);
|
|
507
|
-
}
|
|
508
|
-
}
|
|
546
|
+
if (cachedStatus === null && nativeConnection !== void 0) return nativeConnection;
|
|
509
547
|
return connection;
|
|
510
548
|
}
|
|
511
549
|
});
|
|
@@ -515,9 +553,13 @@ function uninstallNetworkShim() {
|
|
|
515
553
|
if (typeof navigator === "undefined") return;
|
|
516
554
|
const host = navigator;
|
|
517
555
|
if (!host[INSTALLED_KEY]) return;
|
|
518
|
-
|
|
519
|
-
|
|
556
|
+
const onLineSnap = host[ON_LINE_SNAPSHOT_KEY];
|
|
557
|
+
if (onLineSnap) restoreNavigatorProperty("onLine", onLineSnap);
|
|
558
|
+
const connSnap = host[CONNECTION_SNAPSHOT_KEY];
|
|
559
|
+
if (connSnap) restoreNavigatorProperty("connection", connSnap);
|
|
520
560
|
delete host[INSTALLED_KEY];
|
|
561
|
+
delete host[ON_LINE_SNAPSHOT_KEY];
|
|
562
|
+
delete host[CONNECTION_SNAPSHOT_KEY];
|
|
521
563
|
}
|
|
522
564
|
//#endregion
|
|
523
565
|
//#region src/shims/share.ts
|
|
@@ -536,6 +578,8 @@ function uninstallNetworkShim() {
|
|
|
536
578
|
* says Toss is active (or is being forced via the test override).
|
|
537
579
|
*/
|
|
538
580
|
const SHARE_BACKUP_KEY = Symbol.for("@ait-co/polyfill/share.original");
|
|
581
|
+
const SHARE_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/share.snapshot");
|
|
582
|
+
const CAN_SHARE_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/canShare.snapshot");
|
|
539
583
|
function buildSdkMessage(data) {
|
|
540
584
|
const parts = [];
|
|
541
585
|
if (data?.title != null && data.title !== "") parts.push(data.title);
|
|
@@ -587,12 +631,12 @@ function installShareShim() {
|
|
|
587
631
|
hadShare: "share" in nav,
|
|
588
632
|
hadCanShare: "canShare" in nav
|
|
589
633
|
};
|
|
590
|
-
|
|
634
|
+
host[SHARE_SNAPSHOT_KEY] = installNavigatorProperty("share", {
|
|
591
635
|
value: shareShim,
|
|
592
636
|
configurable: true,
|
|
593
637
|
writable: true
|
|
594
638
|
});
|
|
595
|
-
|
|
639
|
+
host[CAN_SHARE_SNAPSHOT_KEY] = installNavigatorProperty("canShare", {
|
|
596
640
|
value: canShareShim,
|
|
597
641
|
configurable: true,
|
|
598
642
|
writable: true
|
|
@@ -603,20 +647,13 @@ function uninstallShareShim() {
|
|
|
603
647
|
if (typeof navigator === "undefined") return;
|
|
604
648
|
const host = navigator;
|
|
605
649
|
if (!(SHARE_BACKUP_KEY in host)) return;
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
configurable: true,
|
|
611
|
-
writable: true
|
|
612
|
-
});
|
|
613
|
-
delete navigator.canShare;
|
|
614
|
-
if (backup?.hadCanShare && navigator.canShare !== backup.canShare) Object.defineProperty(navigator, "canShare", {
|
|
615
|
-
value: backup.canShare,
|
|
616
|
-
configurable: true,
|
|
617
|
-
writable: true
|
|
618
|
-
});
|
|
650
|
+
const shareSnap = host[SHARE_SNAPSHOT_KEY];
|
|
651
|
+
if (shareSnap) restoreNavigatorProperty("share", shareSnap);
|
|
652
|
+
const canShareSnap = host[CAN_SHARE_SNAPSHOT_KEY];
|
|
653
|
+
if (canShareSnap) restoreNavigatorProperty("canShare", canShareSnap);
|
|
619
654
|
delete host[SHARE_BACKUP_KEY];
|
|
655
|
+
delete host[SHARE_SNAPSHOT_KEY];
|
|
656
|
+
delete host[CAN_SHARE_SNAPSHOT_KEY];
|
|
620
657
|
}
|
|
621
658
|
//#endregion
|
|
622
659
|
//#region src/shims/vibrate.ts
|
|
@@ -642,7 +679,7 @@ function uninstallShareShim() {
|
|
|
642
679
|
* `true` immediately (fire-and-forget). Errors from the SDK are swallowed.
|
|
643
680
|
*/
|
|
644
681
|
const BACKUP_KEY = Symbol.for("@ait-co/polyfill/vibrate.original");
|
|
645
|
-
const
|
|
682
|
+
const SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/vibrate.snapshot");
|
|
646
683
|
const SHORT_VIBRATION_MS = 40;
|
|
647
684
|
async function haptic(type) {
|
|
648
685
|
const fn = (await loadTossSdk())?.generateHapticFeedback;
|
|
@@ -684,10 +721,8 @@ function installVibrateShim() {
|
|
|
684
721
|
if (typeof navigator === "undefined") return () => {};
|
|
685
722
|
const host = navigator;
|
|
686
723
|
if (BACKUP_KEY in host) return () => uninstallVibrateShim();
|
|
687
|
-
|
|
688
|
-
host[
|
|
689
|
-
host[HAD_KEY] = "vibrate" in nav;
|
|
690
|
-
Object.defineProperty(navigator, "vibrate", {
|
|
724
|
+
host[BACKUP_KEY] = navigator.vibrate?.bind(navigator);
|
|
725
|
+
host[SNAPSHOT_KEY] = installNavigatorProperty("vibrate", {
|
|
691
726
|
value: vibrateShim,
|
|
692
727
|
configurable: true,
|
|
693
728
|
writable: true
|
|
@@ -698,34 +733,31 @@ function uninstallVibrateShim() {
|
|
|
698
733
|
if (typeof navigator === "undefined") return;
|
|
699
734
|
const host = navigator;
|
|
700
735
|
if (!(BACKUP_KEY in host)) return;
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
delete navigator.vibrate;
|
|
704
|
-
if (had && navigator.vibrate !== original) Object.defineProperty(navigator, "vibrate", {
|
|
705
|
-
value: original,
|
|
706
|
-
configurable: true,
|
|
707
|
-
writable: true
|
|
708
|
-
});
|
|
736
|
+
const snapshot = host[SNAPSHOT_KEY];
|
|
737
|
+
if (snapshot) restoreNavigatorProperty("vibrate", snapshot);
|
|
709
738
|
delete host[BACKUP_KEY];
|
|
710
|
-
delete host[
|
|
739
|
+
delete host[SNAPSHOT_KEY];
|
|
711
740
|
}
|
|
712
741
|
//#endregion
|
|
713
742
|
//#region src/index.ts
|
|
714
|
-
const VERSION = "0.1.
|
|
743
|
+
const VERSION = "0.1.3";
|
|
744
|
+
const NOOP = () => {};
|
|
715
745
|
/**
|
|
716
|
-
* Install every shim this library ships
|
|
717
|
-
*
|
|
746
|
+
* Install every shim this library ships, but only if we detect an Apps in
|
|
747
|
+
* Toss runtime. In a plain browser `install()` is a no-op — the browser's
|
|
748
|
+
* native APIs stay untouched.
|
|
718
749
|
*
|
|
719
|
-
*
|
|
720
|
-
*
|
|
721
|
-
* independent, so order doesn't affect correctness; documented for clarity).
|
|
750
|
+
* Returns a promise that resolves with an uninstall function. If the
|
|
751
|
+
* environment turns out not to be Toss, the uninstall function is a no-op.
|
|
722
752
|
*
|
|
723
|
-
*
|
|
724
|
-
*
|
|
725
|
-
*
|
|
726
|
-
*
|
|
753
|
+
* Install order (when active): clipboard → geolocation → share → vibrate →
|
|
754
|
+
* network. Not atomic on failure — if a per-shim install throws (e.g., a
|
|
755
|
+
* consumer pinned a target navigator property as non-configurable), earlier
|
|
756
|
+
* shims are already in place. Callers should catch and invoke the returned
|
|
757
|
+
* uninstall to roll back.
|
|
727
758
|
*/
|
|
728
|
-
function install() {
|
|
759
|
+
async function install() {
|
|
760
|
+
if (!await isTossEnvironment()) return NOOP;
|
|
729
761
|
const uninstalls = [
|
|
730
762
|
installClipboardShim(),
|
|
731
763
|
installGeolocationShim(),
|