@ait-co/polyfill 0.1.2 → 0.1.4
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 +246 -113
- package/dist/auto.js.map +1 -1
- package/dist/index.d.ts +28 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +247 -114
- 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 +55 -17
- 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 +105 -18
- 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 +95 -31
- 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 +92 -28
- 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 +89 -19
- package/dist/shims/vibrate.js.map +1 -1
- package/package.json +1 -1
package/dist/auto.js
CHANGED
|
@@ -69,6 +69,122 @@ async function loadTossSdk() {
|
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
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
|
+
/**
|
|
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
|
+
}
|
|
187
|
+
//#endregion
|
|
72
188
|
//#region src/shims/clipboard.ts
|
|
73
189
|
/**
|
|
74
190
|
* `navigator.clipboard` shim.
|
|
@@ -81,7 +197,7 @@ async function loadTossSdk() {
|
|
|
81
197
|
* surfaces unchanged — we don't paper over missing support.
|
|
82
198
|
*/
|
|
83
199
|
const BACKUP_KEY$2 = Symbol.for("@ait-co/polyfill/clipboard.original");
|
|
84
|
-
const
|
|
200
|
+
const SNAPSHOT_KEY$2 = Symbol.for("@ait-co/polyfill/clipboard.snapshot");
|
|
85
201
|
/**
|
|
86
202
|
* Produces a Clipboard-compatible object whose `readText` / `writeText` methods
|
|
87
203
|
* route to the SDK when in Toss, else fall through to the supplied `fallback`.
|
|
@@ -132,34 +248,24 @@ function installClipboardShim() {
|
|
|
132
248
|
if (BACKUP_KEY$2 in host) return () => uninstallClipboardShim();
|
|
133
249
|
const original = navigator.clipboard;
|
|
134
250
|
host[BACKUP_KEY$2] = original;
|
|
135
|
-
host[
|
|
136
|
-
|
|
137
|
-
Object.defineProperty(navigator, "clipboard", {
|
|
138
|
-
value: shim,
|
|
251
|
+
host[SNAPSHOT_KEY$2] = installNavigatorProperty("clipboard", {
|
|
252
|
+
value: createClipboardShim(original),
|
|
139
253
|
configurable: true,
|
|
140
254
|
writable: true
|
|
141
255
|
});
|
|
142
256
|
return uninstallClipboardShim;
|
|
143
257
|
}
|
|
144
258
|
/**
|
|
145
|
-
* Remove the shim and restore the pre-install shape.
|
|
146
|
-
* redefine so a prototype-level `navigator.clipboard` (non-configurable in real
|
|
147
|
-
* browsers) becomes visible again instead of being permanently shadowed.
|
|
259
|
+
* Remove the shim and restore the pre-install shape.
|
|
148
260
|
*/
|
|
149
261
|
function uninstallClipboardShim() {
|
|
150
262
|
if (typeof navigator === "undefined") return;
|
|
151
263
|
const host = navigator;
|
|
152
264
|
if (!(BACKUP_KEY$2 in host)) return;
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
delete navigator.clipboard;
|
|
156
|
-
if (had && navigator.clipboard !== original) Object.defineProperty(navigator, "clipboard", {
|
|
157
|
-
value: original,
|
|
158
|
-
configurable: true,
|
|
159
|
-
writable: true
|
|
160
|
-
});
|
|
265
|
+
const snapshot = host[SNAPSHOT_KEY$2];
|
|
266
|
+
if (snapshot) restoreNavigatorProperty("clipboard", snapshot);
|
|
161
267
|
delete host[BACKUP_KEY$2];
|
|
162
|
-
delete host[
|
|
268
|
+
delete host[SNAPSHOT_KEY$2];
|
|
163
269
|
}
|
|
164
270
|
//#endregion
|
|
165
271
|
//#region src/shims/geolocation.ts
|
|
@@ -173,6 +279,13 @@ function uninstallClipboardShim() {
|
|
|
173
279
|
* Outside Apps in Toss → defers to the browser's native `navigator.geolocation`.
|
|
174
280
|
* If neither is available, the error callback receives a `GeolocationPositionError`.
|
|
175
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
|
+
*
|
|
176
289
|
* SDK/Web shape mismatch handled here:
|
|
177
290
|
* - SDK `Accuracy` is a numeric enum (1 = Lowest … 6 = BestForNavigation); the
|
|
178
291
|
* standard `PositionOptions.enableHighAccuracy` is a boolean. We map
|
|
@@ -192,6 +305,7 @@ function uninstallClipboardShim() {
|
|
|
192
305
|
* `uninstall()`.
|
|
193
306
|
*/
|
|
194
307
|
const BACKUP_KEY$1 = Symbol.for("@ait-co/polyfill/geolocation.original");
|
|
308
|
+
const SNAPSHOT_KEY$1 = Symbol.for("@ait-co/polyfill/geolocation.snapshot");
|
|
195
309
|
const ACCURACY_BALANCED = 3;
|
|
196
310
|
const ACCURACY_HIGH = 4;
|
|
197
311
|
function toStandardPosition(sdk) {
|
|
@@ -263,7 +377,7 @@ function createGeolocationShim(fallback) {
|
|
|
263
377
|
return;
|
|
264
378
|
}
|
|
265
379
|
}
|
|
266
|
-
if (!fallback) {
|
|
380
|
+
if (!fallback.getCurrentPosition) {
|
|
267
381
|
error?.(toPositionError(2, "[@ait-co/polyfill] navigator.geolocation is not available in this environment."));
|
|
268
382
|
return;
|
|
269
383
|
}
|
|
@@ -301,7 +415,7 @@ function createGeolocationShim(fallback) {
|
|
|
301
415
|
return;
|
|
302
416
|
}
|
|
303
417
|
}
|
|
304
|
-
if (!fallback) {
|
|
418
|
+
if (!fallback.watchPosition) {
|
|
305
419
|
pendingWatches.delete(id);
|
|
306
420
|
error?.(toPositionError(2, "[@ait-co/polyfill] navigator.geolocation is not available in this environment."));
|
|
307
421
|
return;
|
|
@@ -312,7 +426,7 @@ function createGeolocationShim(fallback) {
|
|
|
312
426
|
}
|
|
313
427
|
const nativeId = fallback.watchPosition(success, error, options);
|
|
314
428
|
if (pending.cancelled) {
|
|
315
|
-
fallback.clearWatch(nativeId);
|
|
429
|
+
fallback.clearWatch?.(nativeId);
|
|
316
430
|
pendingWatches.delete(id);
|
|
317
431
|
return;
|
|
318
432
|
}
|
|
@@ -335,7 +449,7 @@ function createGeolocationShim(fallback) {
|
|
|
335
449
|
return;
|
|
336
450
|
}
|
|
337
451
|
const nativeId = nativeWatches.get(id);
|
|
338
|
-
if (nativeId !== void 0 && fallback) {
|
|
452
|
+
if (nativeId !== void 0 && fallback.clearWatch) {
|
|
339
453
|
fallback.clearWatch(nativeId);
|
|
340
454
|
nativeWatches.delete(id);
|
|
341
455
|
}
|
|
@@ -346,28 +460,37 @@ function installGeolocationShim() {
|
|
|
346
460
|
if (typeof navigator === "undefined") return () => {};
|
|
347
461
|
const host = navigator;
|
|
348
462
|
if (BACKUP_KEY$1 in host) return () => uninstallGeolocationShim();
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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)
|
|
356
472
|
});
|
|
473
|
+
const snapshot = installObjectMethods(target, {
|
|
474
|
+
getCurrentPosition: shim.getCurrentPosition,
|
|
475
|
+
watchPosition: shim.watchPosition,
|
|
476
|
+
clearWatch: shim.clearWatch
|
|
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;
|
|
357
484
|
return uninstallGeolocationShim;
|
|
358
485
|
}
|
|
359
486
|
function uninstallGeolocationShim() {
|
|
360
487
|
if (typeof navigator === "undefined") return;
|
|
361
488
|
const host = navigator;
|
|
362
489
|
if (!(BACKUP_KEY$1 in host)) return;
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
if (original !== void 0 && navigator.geolocation !== original) Object.defineProperty(navigator, "geolocation", {
|
|
366
|
-
value: original,
|
|
367
|
-
configurable: true,
|
|
368
|
-
writable: true
|
|
369
|
-
});
|
|
490
|
+
const snapshot = host[SNAPSHOT_KEY$1];
|
|
491
|
+
if (snapshot) restoreObjectMethods(snapshot);
|
|
370
492
|
delete host[BACKUP_KEY$1];
|
|
493
|
+
delete host[SNAPSHOT_KEY$1];
|
|
371
494
|
}
|
|
372
495
|
//#endregion
|
|
373
496
|
//#region src/shims/network.ts
|
|
@@ -392,6 +515,15 @@ function uninstallGeolocationShim() {
|
|
|
392
515
|
* visible again. We never mutate the prototype — doing so would throw in
|
|
393
516
|
* browsers where the descriptor is non-configurable.
|
|
394
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
|
+
*
|
|
395
527
|
* Caveat: the Web NetworkInformation API is evented (`change` fires on
|
|
396
528
|
* transitions). The SDK exposes only a one-shot query, so listeners attached
|
|
397
529
|
* to `navigator.connection` are accepted but never fire from a `change` event
|
|
@@ -413,6 +545,8 @@ function uninstallGeolocationShim() {
|
|
|
413
545
|
* reads may return the native object.
|
|
414
546
|
*/
|
|
415
547
|
const INSTALLED_KEY = Symbol.for("@ait-co/polyfill/network.installed");
|
|
548
|
+
const ON_LINE_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/network.onLine.snapshot");
|
|
549
|
+
const CONNECTION_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/network.connection.snapshot");
|
|
416
550
|
const REFRESH_THROTTLE_MS = 500;
|
|
417
551
|
function statusToOnline(status) {
|
|
418
552
|
return status !== "OFFLINE";
|
|
@@ -492,47 +626,52 @@ function installNetworkShim() {
|
|
|
492
626
|
})();
|
|
493
627
|
return inflight;
|
|
494
628
|
}
|
|
629
|
+
const nativeOnLine = navigator.onLine;
|
|
630
|
+
const nativeConnection = navigator.connection;
|
|
495
631
|
refresh();
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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;
|
|
507
645
|
}
|
|
508
|
-
}
|
|
509
|
-
})
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
if (native !== void 0) return native;
|
|
520
|
-
} finally {
|
|
521
|
-
if (desc) Object.defineProperty(navigator, "connection", desc);
|
|
522
|
-
}
|
|
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;
|
|
523
657
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
658
|
+
});
|
|
659
|
+
} catch (e) {
|
|
660
|
+
warnNonConfigurable(e);
|
|
661
|
+
}
|
|
527
662
|
return uninstallNetworkShim;
|
|
528
663
|
}
|
|
529
664
|
function uninstallNetworkShim() {
|
|
530
665
|
if (typeof navigator === "undefined") return;
|
|
531
666
|
const host = navigator;
|
|
532
667
|
if (!host[INSTALLED_KEY]) return;
|
|
533
|
-
|
|
534
|
-
|
|
668
|
+
const onLineSnap = host[ON_LINE_SNAPSHOT_KEY];
|
|
669
|
+
if (onLineSnap) restoreNavigatorProperty("onLine", onLineSnap);
|
|
670
|
+
const connSnap = host[CONNECTION_SNAPSHOT_KEY];
|
|
671
|
+
if (connSnap) restoreNavigatorProperty("connection", connSnap);
|
|
535
672
|
delete host[INSTALLED_KEY];
|
|
673
|
+
delete host[ON_LINE_SNAPSHOT_KEY];
|
|
674
|
+
delete host[CONNECTION_SNAPSHOT_KEY];
|
|
536
675
|
}
|
|
537
676
|
//#endregion
|
|
538
677
|
//#region src/shims/share.ts
|
|
@@ -546,11 +685,18 @@ function uninstallNetworkShim() {
|
|
|
546
685
|
* Outside Apps in Toss → defers to the browser's native `navigator.share`, or
|
|
547
686
|
* throws `NotSupportedError` if unavailable.
|
|
548
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
|
+
*
|
|
549
694
|
* Caveat: the SDK's share has no counterpart for `files` (Web Share Level 2).
|
|
550
695
|
* `canShare({ files })` returns `false` whenever the sync-accessible detection
|
|
551
696
|
* says Toss is active (or is being forced via the test override).
|
|
552
697
|
*/
|
|
553
698
|
const SHARE_BACKUP_KEY = Symbol.for("@ait-co/polyfill/share.original");
|
|
699
|
+
const SHARE_SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/share.snapshot");
|
|
554
700
|
function buildSdkMessage(data) {
|
|
555
701
|
const parts = [];
|
|
556
702
|
if (data?.title != null && data.title !== "") parts.push(data.title);
|
|
@@ -577,7 +723,7 @@ async function shareShim(data) {
|
|
|
577
723
|
}
|
|
578
724
|
const original = navigator[SHARE_BACKUP_KEY]?.share;
|
|
579
725
|
if (!original) throw new DOMException("[@ait-co/polyfill] navigator.share is not available in this environment.", "NotSupportedError");
|
|
580
|
-
return original
|
|
726
|
+
return original(data);
|
|
581
727
|
}
|
|
582
728
|
function canShareShim(data) {
|
|
583
729
|
const hasFiles = Boolean(data?.files && data.files.length > 0);
|
|
@@ -588,7 +734,7 @@ function canShareShim(data) {
|
|
|
588
734
|
}
|
|
589
735
|
if (toss === true) return Boolean(data?.title != null && data.title !== "" || data?.text != null && data.text !== "" || data?.url != null && data.url !== "");
|
|
590
736
|
const originalCanShare = navigator[SHARE_BACKUP_KEY]?.canShare;
|
|
591
|
-
if (originalCanShare) return originalCanShare
|
|
737
|
+
if (originalCanShare) return originalCanShare(data);
|
|
592
738
|
return Boolean(data?.title != null && data.title !== "" || data?.text != null && data.text !== "" || data?.url != null && data.url !== "");
|
|
593
739
|
}
|
|
594
740
|
function installShareShim() {
|
|
@@ -597,41 +743,28 @@ function installShareShim() {
|
|
|
597
743
|
if (SHARE_BACKUP_KEY in host) return () => uninstallShareShim();
|
|
598
744
|
const nav = navigator;
|
|
599
745
|
host[SHARE_BACKUP_KEY] = {
|
|
600
|
-
share: nav.share,
|
|
601
|
-
canShare: nav.canShare
|
|
602
|
-
hadShare: "share" in nav,
|
|
603
|
-
hadCanShare: "canShare" in nav
|
|
746
|
+
share: nav.share ? nav.share.bind(navigator) : void 0,
|
|
747
|
+
canShare: nav.canShare ? nav.canShare.bind(navigator) : void 0
|
|
604
748
|
};
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
writable: true
|
|
609
|
-
});
|
|
610
|
-
Object.defineProperty(navigator, "canShare", {
|
|
611
|
-
value: canShareShim,
|
|
612
|
-
configurable: true,
|
|
613
|
-
writable: true
|
|
749
|
+
const snapshot = installObjectMethods(navigator, {
|
|
750
|
+
share: shareShim,
|
|
751
|
+
canShare: canShareShim
|
|
614
752
|
});
|
|
753
|
+
if (!snapshot) {
|
|
754
|
+
delete host[SHARE_BACKUP_KEY];
|
|
755
|
+
return () => uninstallShareShim();
|
|
756
|
+
}
|
|
757
|
+
host[SHARE_SNAPSHOT_KEY] = snapshot;
|
|
615
758
|
return uninstallShareShim;
|
|
616
759
|
}
|
|
617
760
|
function uninstallShareShim() {
|
|
618
761
|
if (typeof navigator === "undefined") return;
|
|
619
762
|
const host = navigator;
|
|
620
763
|
if (!(SHARE_BACKUP_KEY in host)) return;
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
if (backup?.hadShare && navigator.share !== backup.share) Object.defineProperty(navigator, "share", {
|
|
624
|
-
value: backup.share,
|
|
625
|
-
configurable: true,
|
|
626
|
-
writable: true
|
|
627
|
-
});
|
|
628
|
-
delete navigator.canShare;
|
|
629
|
-
if (backup?.hadCanShare && navigator.canShare !== backup.canShare) Object.defineProperty(navigator, "canShare", {
|
|
630
|
-
value: backup.canShare,
|
|
631
|
-
configurable: true,
|
|
632
|
-
writable: true
|
|
633
|
-
});
|
|
764
|
+
const snapshot = host[SHARE_SNAPSHOT_KEY];
|
|
765
|
+
if (snapshot) restoreObjectMethods(snapshot);
|
|
634
766
|
delete host[SHARE_BACKUP_KEY];
|
|
767
|
+
delete host[SHARE_SNAPSHOT_KEY];
|
|
635
768
|
}
|
|
636
769
|
//#endregion
|
|
637
770
|
//#region src/shims/vibrate.ts
|
|
@@ -647,6 +780,11 @@ function uninstallShareShim() {
|
|
|
647
780
|
* or returns `false` when unavailable (matches the spec — browsers that don't
|
|
648
781
|
* support vibration simply return `false`).
|
|
649
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
|
+
*
|
|
650
788
|
* Caveats (documented in CLAUDE.md as the known lossy trade-off):
|
|
651
789
|
* - SDK haptics are qualitative ("tickWeak", "basicMedium"), not millisecond
|
|
652
790
|
* durations. The shim approximates intensity from duration but cannot
|
|
@@ -657,7 +795,7 @@ function uninstallShareShim() {
|
|
|
657
795
|
* `true` immediately (fire-and-forget). Errors from the SDK are swallowed.
|
|
658
796
|
*/
|
|
659
797
|
const BACKUP_KEY = Symbol.for("@ait-co/polyfill/vibrate.original");
|
|
660
|
-
const
|
|
798
|
+
const SNAPSHOT_KEY = Symbol.for("@ait-co/polyfill/vibrate.snapshot");
|
|
661
799
|
const SHORT_VIBRATION_MS = 40;
|
|
662
800
|
async function haptic(type) {
|
|
663
801
|
const fn = (await loadTossSdk())?.generateHapticFeedback;
|
|
@@ -672,7 +810,7 @@ function vibrateShim(pattern) {
|
|
|
672
810
|
const arr = Array.isArray(pattern) ? pattern : [pattern];
|
|
673
811
|
if (arr.length === 0 || arr.every((n) => n === 0)) {
|
|
674
812
|
(async () => {
|
|
675
|
-
if (!await isTossEnvironment()) navigator[BACKUP_KEY]?.
|
|
813
|
+
if (!await isTossEnvironment()) navigator[BACKUP_KEY]?.(pattern);
|
|
676
814
|
})();
|
|
677
815
|
return true;
|
|
678
816
|
}
|
|
@@ -691,7 +829,8 @@ function vibrateShim(pattern) {
|
|
|
691
829
|
}
|
|
692
830
|
return;
|
|
693
831
|
}
|
|
694
|
-
navigator[BACKUP_KEY]
|
|
832
|
+
const original = navigator[BACKUP_KEY];
|
|
833
|
+
original?.(pattern);
|
|
695
834
|
})();
|
|
696
835
|
return true;
|
|
697
836
|
}
|
|
@@ -700,29 +839,23 @@ function installVibrateShim() {
|
|
|
700
839
|
const host = navigator;
|
|
701
840
|
if (BACKUP_KEY in host) return () => uninstallVibrateShim();
|
|
702
841
|
const nav = navigator;
|
|
703
|
-
host[BACKUP_KEY] = nav.vibrate;
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
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;
|
|
710
849
|
return uninstallVibrateShim;
|
|
711
850
|
}
|
|
712
851
|
function uninstallVibrateShim() {
|
|
713
852
|
if (typeof navigator === "undefined") return;
|
|
714
853
|
const host = navigator;
|
|
715
854
|
if (!(BACKUP_KEY in host)) return;
|
|
716
|
-
const
|
|
717
|
-
|
|
718
|
-
delete navigator.vibrate;
|
|
719
|
-
if (had && navigator.vibrate !== original) Object.defineProperty(navigator, "vibrate", {
|
|
720
|
-
value: original,
|
|
721
|
-
configurable: true,
|
|
722
|
-
writable: true
|
|
723
|
-
});
|
|
855
|
+
const snapshot = host[SNAPSHOT_KEY];
|
|
856
|
+
if (snapshot) restoreObjectMethods(snapshot);
|
|
724
857
|
delete host[BACKUP_KEY];
|
|
725
|
-
delete host[
|
|
858
|
+
delete host[SNAPSHOT_KEY];
|
|
726
859
|
}
|
|
727
860
|
//#endregion
|
|
728
861
|
//#region src/index.ts
|