@ait-co/polyfill 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto.js +176 -57
- package/dist/auto.js.map +1 -1
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +177 -58
- package/dist/index.js.map +1 -1
- package/dist/shims/clipboard.js.map +1 -1
- package/dist/shims/geolocation.d.ts +7 -0
- package/dist/shims/geolocation.d.ts.map +1 -1
- package/dist/shims/geolocation.js +90 -47
- package/dist/shims/geolocation.js.map +1 -1
- package/dist/shims/network.d.ts +9 -0
- package/dist/shims/network.d.ts.map +1 -1
- package/dist/shims/network.js +39 -16
- package/dist/shims/network.js.map +1 -1
- package/dist/shims/share.d.ts +6 -0
- package/dist/shims/share.d.ts.map +1 -1
- package/dist/shims/share.js +78 -57
- package/dist/shims/share.js.map +1 -1
- package/dist/shims/vibrate.d.ts +5 -0
- package/dist/shims/vibrate.d.ts.map +1 -1
- package/dist/shims/vibrate.js +75 -45
- package/dist/shims/vibrate.js.map +1 -1
- package/package.json +11 -12
package/dist/auto.js
CHANGED
|
@@ -116,6 +116,74 @@ function restoreNavigatorProperty(prop, snapshot) {
|
|
|
116
116
|
delete target[prop];
|
|
117
117
|
} catch {}
|
|
118
118
|
}
|
|
119
|
+
/**
|
|
120
|
+
* Mutate methods on an existing object rather than replacing the object
|
|
121
|
+
* itself. This is the path we take for `navigator.geolocation`, `navigator.share`,
|
|
122
|
+
* and `navigator.vibrate` in Chromium, where the slot on `navigator` is a
|
|
123
|
+
* non-configurable own property that we cannot replace — but the methods
|
|
124
|
+
* themselves (or the methods on the referenced object) are still
|
|
125
|
+
* `configurable: true, writable: true`.
|
|
126
|
+
*
|
|
127
|
+
* Each replacement is installed via plain assignment. If any slot is not
|
|
128
|
+
* writable (e.g. frozen object), install is aborted and previously-applied
|
|
129
|
+
* replacements are rolled back, so the caller observes an atomic "all or
|
|
130
|
+
* nothing" failure as `null`. The caller is expected to degrade gracefully
|
|
131
|
+
* (e.g. log a one-time `console.warn`) when that happens.
|
|
132
|
+
*/
|
|
133
|
+
function installObjectMethods(target, replacements) {
|
|
134
|
+
const methods = {};
|
|
135
|
+
const applied = [];
|
|
136
|
+
const bag = target;
|
|
137
|
+
for (const key of Object.keys(replacements)) {
|
|
138
|
+
const hadOwn = Object.hasOwn(target, key);
|
|
139
|
+
const original = bag[key];
|
|
140
|
+
try {
|
|
141
|
+
bag[key] = replacements[key];
|
|
142
|
+
} catch {
|
|
143
|
+
for (const applieKey of applied) {
|
|
144
|
+
const prev = methods[applieKey];
|
|
145
|
+
if (!prev) continue;
|
|
146
|
+
if (prev.hadOwn) bag[applieKey] = prev.original;
|
|
147
|
+
else delete bag[applieKey];
|
|
148
|
+
}
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
if (bag[key] !== replacements[key]) {
|
|
152
|
+
for (const applieKey of applied) {
|
|
153
|
+
const prev = methods[applieKey];
|
|
154
|
+
if (!prev) continue;
|
|
155
|
+
if (prev.hadOwn) bag[applieKey] = prev.original;
|
|
156
|
+
else delete bag[applieKey];
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
methods[key] = {
|
|
161
|
+
hadOwn,
|
|
162
|
+
original
|
|
163
|
+
};
|
|
164
|
+
applied.push(key);
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
target,
|
|
168
|
+
methods
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Reverse an `installObjectMethods` snapshot. Reassigns originals for slots
|
|
173
|
+
* that were own properties before install; deletes the override for slots
|
|
174
|
+
* that were inherited (so the prototype method surfaces again).
|
|
175
|
+
*/
|
|
176
|
+
function restoreObjectMethods(snapshot) {
|
|
177
|
+
const bag = snapshot.target;
|
|
178
|
+
for (const key of Object.keys(snapshot.methods)) {
|
|
179
|
+
const entry = snapshot.methods[key];
|
|
180
|
+
if (!entry) continue;
|
|
181
|
+
try {
|
|
182
|
+
if (entry.hadOwn) bag[key] = entry.original;
|
|
183
|
+
else delete bag[key];
|
|
184
|
+
} catch {}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
119
187
|
//#endregion
|
|
120
188
|
//#region src/shims/clipboard.ts
|
|
121
189
|
/**
|
|
@@ -211,6 +279,13 @@ function uninstallClipboardShim() {
|
|
|
211
279
|
* Outside Apps in Toss → defers to the browser's native `navigator.geolocation`.
|
|
212
280
|
* If neither is available, the error callback receives a `GeolocationPositionError`.
|
|
213
281
|
*
|
|
282
|
+
* Install strategy: **method-level**. We do **not** replace `navigator.geolocation`
|
|
283
|
+
* itself — Chromium marks that slot as a non-configurable own property, which
|
|
284
|
+
* both `defineProperty(navigator, 'geolocation', …)` and the prototype-level
|
|
285
|
+
* fallback cannot override (the instance shadow blocks prototype reads). We
|
|
286
|
+
* instead mutate the methods on the existing `Geolocation` object, whose own
|
|
287
|
+
* method descriptors are configurable+writable in every browser we've seen.
|
|
288
|
+
*
|
|
214
289
|
* SDK/Web shape mismatch handled here:
|
|
215
290
|
* - SDK `Accuracy` is a numeric enum (1 = Lowest … 6 = BestForNavigation); the
|
|
216
291
|
* standard `PositionOptions.enableHighAccuracy` is a boolean. We map
|
|
@@ -302,7 +377,7 @@ function createGeolocationShim(fallback) {
|
|
|
302
377
|
return;
|
|
303
378
|
}
|
|
304
379
|
}
|
|
305
|
-
if (!fallback) {
|
|
380
|
+
if (!fallback.getCurrentPosition) {
|
|
306
381
|
error?.(toPositionError(2, "[@ait-co/polyfill] navigator.geolocation is not available in this environment."));
|
|
307
382
|
return;
|
|
308
383
|
}
|
|
@@ -340,7 +415,7 @@ function createGeolocationShim(fallback) {
|
|
|
340
415
|
return;
|
|
341
416
|
}
|
|
342
417
|
}
|
|
343
|
-
if (!fallback) {
|
|
418
|
+
if (!fallback.watchPosition) {
|
|
344
419
|
pendingWatches.delete(id);
|
|
345
420
|
error?.(toPositionError(2, "[@ait-co/polyfill] navigator.geolocation is not available in this environment."));
|
|
346
421
|
return;
|
|
@@ -351,7 +426,7 @@ function createGeolocationShim(fallback) {
|
|
|
351
426
|
}
|
|
352
427
|
const nativeId = fallback.watchPosition(success, error, options);
|
|
353
428
|
if (pending.cancelled) {
|
|
354
|
-
fallback.clearWatch(nativeId);
|
|
429
|
+
fallback.clearWatch?.(nativeId);
|
|
355
430
|
pendingWatches.delete(id);
|
|
356
431
|
return;
|
|
357
432
|
}
|
|
@@ -374,7 +449,7 @@ function createGeolocationShim(fallback) {
|
|
|
374
449
|
return;
|
|
375
450
|
}
|
|
376
451
|
const nativeId = nativeWatches.get(id);
|
|
377
|
-
if (nativeId !== void 0 && fallback) {
|
|
452
|
+
if (nativeId !== void 0 && fallback.clearWatch) {
|
|
378
453
|
fallback.clearWatch(nativeId);
|
|
379
454
|
nativeWatches.delete(id);
|
|
380
455
|
}
|
|
@@ -385,13 +460,27 @@ function installGeolocationShim() {
|
|
|
385
460
|
if (typeof navigator === "undefined") return () => {};
|
|
386
461
|
const host = navigator;
|
|
387
462
|
if (BACKUP_KEY$1 in host) return () => uninstallGeolocationShim();
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
463
|
+
const target = navigator.geolocation;
|
|
464
|
+
if (!target) {
|
|
465
|
+
host[BACKUP_KEY$1] = void 0;
|
|
466
|
+
return () => uninstallGeolocationShim();
|
|
467
|
+
}
|
|
468
|
+
const shim = createGeolocationShim({
|
|
469
|
+
getCurrentPosition: target.getCurrentPosition?.bind(target),
|
|
470
|
+
watchPosition: target.watchPosition?.bind(target),
|
|
471
|
+
clearWatch: target.clearWatch?.bind(target)
|
|
472
|
+
});
|
|
473
|
+
const snapshot = installObjectMethods(target, {
|
|
474
|
+
getCurrentPosition: shim.getCurrentPosition,
|
|
475
|
+
watchPosition: shim.watchPosition,
|
|
476
|
+
clearWatch: shim.clearWatch
|
|
394
477
|
});
|
|
478
|
+
if (!snapshot) {
|
|
479
|
+
host[BACKUP_KEY$1] = void 0;
|
|
480
|
+
return () => uninstallGeolocationShim();
|
|
481
|
+
}
|
|
482
|
+
host[BACKUP_KEY$1] = { target };
|
|
483
|
+
host[SNAPSHOT_KEY$1] = snapshot;
|
|
395
484
|
return uninstallGeolocationShim;
|
|
396
485
|
}
|
|
397
486
|
function uninstallGeolocationShim() {
|
|
@@ -399,7 +488,7 @@ function uninstallGeolocationShim() {
|
|
|
399
488
|
const host = navigator;
|
|
400
489
|
if (!(BACKUP_KEY$1 in host)) return;
|
|
401
490
|
const snapshot = host[SNAPSHOT_KEY$1];
|
|
402
|
-
if (snapshot)
|
|
491
|
+
if (snapshot) restoreObjectMethods(snapshot);
|
|
403
492
|
delete host[BACKUP_KEY$1];
|
|
404
493
|
delete host[SNAPSHOT_KEY$1];
|
|
405
494
|
}
|
|
@@ -426,6 +515,15 @@ function uninstallGeolocationShim() {
|
|
|
426
515
|
* visible again. We never mutate the prototype — doing so would throw in
|
|
427
516
|
* browsers where the descriptor is non-configurable.
|
|
428
517
|
*
|
|
518
|
+
* Browser-compat caveat (Chromium): `navigator.onLine` and `navigator.connection`
|
|
519
|
+
* are value slots, not methods, so the method-level install trick we use for
|
|
520
|
+
* `geolocation`/`share`/`vibrate` does not apply here. When Chromium marks the
|
|
521
|
+
* instance descriptor as non-configurable AND the prototype descriptor is also
|
|
522
|
+
* non-configurable, we cannot install. In that case the shim logs a one-time
|
|
523
|
+
* `console.warn` and leaves the native values in place — consumers keep the
|
|
524
|
+
* browser's own `onLine`/`connection` values; the SDK-synced state is simply
|
|
525
|
+
* disabled for that session.
|
|
526
|
+
*
|
|
429
527
|
* Caveat: the Web NetworkInformation API is evented (`change` fires on
|
|
430
528
|
* transitions). The SDK exposes only a one-shot query, so listeners attached
|
|
431
529
|
* to `navigator.connection` are accepted but never fire from a `change` event
|
|
@@ -531,22 +629,36 @@ function installNetworkShim() {
|
|
|
531
629
|
const nativeOnLine = navigator.onLine;
|
|
532
630
|
const nativeConnection = navigator.connection;
|
|
533
631
|
refresh();
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
}
|
|
549
|
-
})
|
|
632
|
+
let installWarned = false;
|
|
633
|
+
const warnNonConfigurable = (e) => {
|
|
634
|
+
if (installWarned) return;
|
|
635
|
+
installWarned = true;
|
|
636
|
+
console.warn("[@ait-co/polyfill] navigator.onLine/connection is non-configurable in this browser; Toss network status sync disabled.", e);
|
|
637
|
+
};
|
|
638
|
+
try {
|
|
639
|
+
host[ON_LINE_SNAPSHOT_KEY] = installNavigatorProperty("onLine", {
|
|
640
|
+
configurable: true,
|
|
641
|
+
get() {
|
|
642
|
+
refresh();
|
|
643
|
+
if (cachedStatus !== null) return statusToOnline(cachedStatus);
|
|
644
|
+
return nativeOnLine ?? true;
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
} catch (e) {
|
|
648
|
+
warnNonConfigurable(e);
|
|
649
|
+
}
|
|
650
|
+
try {
|
|
651
|
+
host[CONNECTION_SNAPSHOT_KEY] = installNavigatorProperty("connection", {
|
|
652
|
+
configurable: true,
|
|
653
|
+
get() {
|
|
654
|
+
refresh();
|
|
655
|
+
if (cachedStatus === null && nativeConnection !== void 0) return nativeConnection;
|
|
656
|
+
return connection;
|
|
657
|
+
}
|
|
658
|
+
});
|
|
659
|
+
} catch (e) {
|
|
660
|
+
warnNonConfigurable(e);
|
|
661
|
+
}
|
|
550
662
|
return uninstallNetworkShim;
|
|
551
663
|
}
|
|
552
664
|
function uninstallNetworkShim() {
|
|
@@ -573,13 +685,18 @@ function uninstallNetworkShim() {
|
|
|
573
685
|
* Outside Apps in Toss → defers to the browser's native `navigator.share`, or
|
|
574
686
|
* throws `NotSupportedError` if unavailable.
|
|
575
687
|
*
|
|
688
|
+
* Install strategy: **method-level** on `navigator`. Assigning
|
|
689
|
+
* `navigator.share = fn` creates an own property that shadows the prototype
|
|
690
|
+
* method. Uninstall deletes the own shadow so the prototype method surfaces
|
|
691
|
+
* again. We do not mutate `Navigator.prototype` — in real browsers its
|
|
692
|
+
* descriptor may be non-configurable, which would throw on reassignment.
|
|
693
|
+
*
|
|
576
694
|
* Caveat: the SDK's share has no counterpart for `files` (Web Share Level 2).
|
|
577
695
|
* `canShare({ files })` returns `false` whenever the sync-accessible detection
|
|
578
696
|
* says Toss is active (or is being forced via the test override).
|
|
579
697
|
*/
|
|
580
698
|
const SHARE_BACKUP_KEY = Symbol.for("@ait-co/polyfill/share.original");
|
|
581
699
|
const SHARE_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/share.snapshot");
|
|
582
|
-
const CAN_SHARE_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/canShare.snapshot");
|
|
583
700
|
function buildSdkMessage(data) {
|
|
584
701
|
const parts = [];
|
|
585
702
|
if (data?.title != null && data.title !== "") parts.push(data.title);
|
|
@@ -606,7 +723,7 @@ async function shareShim(data) {
|
|
|
606
723
|
}
|
|
607
724
|
const original = navigator[SHARE_BACKUP_KEY]?.share;
|
|
608
725
|
if (!original) throw new DOMException("[@ait-co/polyfill] navigator.share is not available in this environment.", "NotSupportedError");
|
|
609
|
-
return original
|
|
726
|
+
return original(data);
|
|
610
727
|
}
|
|
611
728
|
function canShareShim(data) {
|
|
612
729
|
const hasFiles = Boolean(data?.files && data.files.length > 0);
|
|
@@ -617,7 +734,7 @@ function canShareShim(data) {
|
|
|
617
734
|
}
|
|
618
735
|
if (toss === true) return Boolean(data?.title != null && data.title !== "" || data?.text != null && data.text !== "" || data?.url != null && data.url !== "");
|
|
619
736
|
const originalCanShare = navigator[SHARE_BACKUP_KEY]?.canShare;
|
|
620
|
-
if (originalCanShare) return originalCanShare
|
|
737
|
+
if (originalCanShare) return originalCanShare(data);
|
|
621
738
|
return Boolean(data?.title != null && data.title !== "" || data?.text != null && data.text !== "" || data?.url != null && data.url !== "");
|
|
622
739
|
}
|
|
623
740
|
function installShareShim() {
|
|
@@ -626,34 +743,28 @@ function installShareShim() {
|
|
|
626
743
|
if (SHARE_BACKUP_KEY in host) return () => uninstallShareShim();
|
|
627
744
|
const nav = navigator;
|
|
628
745
|
host[SHARE_BACKUP_KEY] = {
|
|
629
|
-
share: nav.share,
|
|
630
|
-
canShare: nav.canShare
|
|
631
|
-
hadShare: "share" in nav,
|
|
632
|
-
hadCanShare: "canShare" in nav
|
|
746
|
+
share: nav.share ? nav.share.bind(navigator) : void 0,
|
|
747
|
+
canShare: nav.canShare ? nav.canShare.bind(navigator) : void 0
|
|
633
748
|
};
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
writable: true
|
|
638
|
-
});
|
|
639
|
-
host[CAN_SHARE_SNAPSHOT_KEY] = installNavigatorProperty("canShare", {
|
|
640
|
-
value: canShareShim,
|
|
641
|
-
configurable: true,
|
|
642
|
-
writable: true
|
|
749
|
+
const snapshot = installObjectMethods(navigator, {
|
|
750
|
+
share: shareShim,
|
|
751
|
+
canShare: canShareShim
|
|
643
752
|
});
|
|
753
|
+
if (!snapshot) {
|
|
754
|
+
delete host[SHARE_BACKUP_KEY];
|
|
755
|
+
return () => uninstallShareShim();
|
|
756
|
+
}
|
|
757
|
+
host[SHARE_SNAPSHOT_KEY] = snapshot;
|
|
644
758
|
return uninstallShareShim;
|
|
645
759
|
}
|
|
646
760
|
function uninstallShareShim() {
|
|
647
761
|
if (typeof navigator === "undefined") return;
|
|
648
762
|
const host = navigator;
|
|
649
763
|
if (!(SHARE_BACKUP_KEY in host)) return;
|
|
650
|
-
const
|
|
651
|
-
if (
|
|
652
|
-
const canShareSnap = host[CAN_SHARE_SNAPSHOT_KEY];
|
|
653
|
-
if (canShareSnap) restoreNavigatorProperty("canShare", canShareSnap);
|
|
764
|
+
const snapshot = host[SHARE_SNAPSHOT_KEY];
|
|
765
|
+
if (snapshot) restoreObjectMethods(snapshot);
|
|
654
766
|
delete host[SHARE_BACKUP_KEY];
|
|
655
767
|
delete host[SHARE_SNAPSHOT_KEY];
|
|
656
|
-
delete host[CAN_SHARE_SNAPSHOT_KEY];
|
|
657
768
|
}
|
|
658
769
|
//#endregion
|
|
659
770
|
//#region src/shims/vibrate.ts
|
|
@@ -669,6 +780,11 @@ function uninstallShareShim() {
|
|
|
669
780
|
* or returns `false` when unavailable (matches the spec — browsers that don't
|
|
670
781
|
* support vibration simply return `false`).
|
|
671
782
|
*
|
|
783
|
+
* Install strategy: **method-level** on `navigator`. We assign our wrapper to
|
|
784
|
+
* `navigator.vibrate` (creating an own shadow over the prototype method) and
|
|
785
|
+
* delete it on uninstall so the prototype re-surfaces. We do not mutate
|
|
786
|
+
* `Navigator.prototype` itself — browsers may mark it non-configurable.
|
|
787
|
+
*
|
|
672
788
|
* Caveats (documented in CLAUDE.md as the known lossy trade-off):
|
|
673
789
|
* - SDK haptics are qualitative ("tickWeak", "basicMedium"), not millisecond
|
|
674
790
|
* durations. The shim approximates intensity from duration but cannot
|
|
@@ -694,7 +810,7 @@ function vibrateShim(pattern) {
|
|
|
694
810
|
const arr = Array.isArray(pattern) ? pattern : [pattern];
|
|
695
811
|
if (arr.length === 0 || arr.every((n) => n === 0)) {
|
|
696
812
|
(async () => {
|
|
697
|
-
if (!await isTossEnvironment()) navigator[BACKUP_KEY]?.
|
|
813
|
+
if (!await isTossEnvironment()) navigator[BACKUP_KEY]?.(pattern);
|
|
698
814
|
})();
|
|
699
815
|
return true;
|
|
700
816
|
}
|
|
@@ -713,7 +829,8 @@ function vibrateShim(pattern) {
|
|
|
713
829
|
}
|
|
714
830
|
return;
|
|
715
831
|
}
|
|
716
|
-
navigator[BACKUP_KEY]
|
|
832
|
+
const original = navigator[BACKUP_KEY];
|
|
833
|
+
original?.(pattern);
|
|
717
834
|
})();
|
|
718
835
|
return true;
|
|
719
836
|
}
|
|
@@ -721,12 +838,14 @@ function installVibrateShim() {
|
|
|
721
838
|
if (typeof navigator === "undefined") return () => {};
|
|
722
839
|
const host = navigator;
|
|
723
840
|
if (BACKUP_KEY in host) return () => uninstallVibrateShim();
|
|
724
|
-
|
|
725
|
-
host[
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
841
|
+
const nav = navigator;
|
|
842
|
+
host[BACKUP_KEY] = nav.vibrate ? nav.vibrate.bind(navigator) : void 0;
|
|
843
|
+
const snapshot = installObjectMethods(navigator, { vibrate: vibrateShim });
|
|
844
|
+
if (!snapshot) {
|
|
845
|
+
delete host[BACKUP_KEY];
|
|
846
|
+
return () => uninstallVibrateShim();
|
|
847
|
+
}
|
|
848
|
+
host[SNAPSHOT_KEY] = snapshot;
|
|
730
849
|
return uninstallVibrateShim;
|
|
731
850
|
}
|
|
732
851
|
function uninstallVibrateShim() {
|
|
@@ -734,7 +853,7 @@ function uninstallVibrateShim() {
|
|
|
734
853
|
const host = navigator;
|
|
735
854
|
if (!(BACKUP_KEY in host)) return;
|
|
736
855
|
const snapshot = host[SNAPSHOT_KEY];
|
|
737
|
-
if (snapshot)
|
|
856
|
+
if (snapshot) restoreObjectMethods(snapshot);
|
|
738
857
|
delete host[BACKUP_KEY];
|
|
739
858
|
delete host[SNAPSHOT_KEY];
|
|
740
859
|
}
|