@ohos-ports/serwist-window 9.5.12-beta.1
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/LICENSE +21 -0
- package/README.md +1 -0
- package/dist/chunks/isCurrentPageOutOfScope-BF6DLxHk.js +15 -0
- package/dist/chunks/isCurrentPageOutOfScope-BF6DLxHk.js.map +1 -0
- package/dist/index.d.mts +374 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.internal.d.mts +5 -0
- package/dist/index.internal.d.mts.map +1 -0
- package/dist/index.internal.mjs +6 -0
- package/dist/index.mjs +554 -0
- package/dist/index.mjs.map +1 -0
- package/dist/ohos-node-shim.mjs +297 -0
- package/package.json +75 -0
- package/src/Serwist.ts +688 -0
- package/src/index.internal.ts +8 -0
- package/src/index.ts +20 -0
- package/src/messageSW.ts +33 -0
- package/src/utils/SerwistEvent.ts +57 -0
- package/src/utils/SerwistEventTarget.ts +68 -0
- package/src/utils/isCurrentPageOutOfScope.ts +10 -0
- package/src/utils/ohosNodeShim.ts +308 -0
- package/src/utils/urlsMatch.ts +21 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// HarmonyOS Node.js platform adaptation: install browser API shims
|
|
2
|
+
// (navigator.serviceWorker, document, window, location) before the library
|
|
3
|
+
// body evaluates. No-op in real browsers.
|
|
4
|
+
import "./utils/ohosNodeShim.js";
|
|
5
|
+
|
|
6
|
+
import { isCurrentPageOutOfScope } from "./utils/isCurrentPageOutOfScope.js";
|
|
7
|
+
|
|
8
|
+
export { isCurrentPageOutOfScope };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019 Google LLC
|
|
3
|
+
|
|
4
|
+
Use of this source code is governed by an MIT-style
|
|
5
|
+
license that can be found in the LICENSE file or at
|
|
6
|
+
https://opensource.org/licenses/MIT.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// HarmonyOS Node.js platform adaptation: install browser API shims
|
|
10
|
+
// (navigator.serviceWorker, document, window, location) before the library
|
|
11
|
+
// body evaluates. No-op in real browsers.
|
|
12
|
+
import "./utils/ohosNodeShim.js";
|
|
13
|
+
|
|
14
|
+
import { messageSW } from "./messageSW.js";
|
|
15
|
+
import { Serwist } from "./Serwist.js";
|
|
16
|
+
|
|
17
|
+
export { messageSW, Serwist };
|
|
18
|
+
|
|
19
|
+
// See https://github.com/GoogleChrome/workbox/issues/2770
|
|
20
|
+
export * from "./utils/SerwistEvent.js";
|
package/src/messageSW.ts
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019 Google LLC
|
|
3
|
+
|
|
4
|
+
Use of this source code is governed by an MIT-style
|
|
5
|
+
license that can be found in the LICENSE file or at
|
|
6
|
+
https://opensource.org/licenses/MIT.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sends a data object to a service worker via `postMessage` and resolves with
|
|
11
|
+
* a response (if any).
|
|
12
|
+
*
|
|
13
|
+
* A response can be sent by calling `event.ports[0].postMessage(...)`, which will
|
|
14
|
+
* resolve the promise returned by `messageSW()`. If no response is sent, the promise
|
|
15
|
+
* will never resolve.
|
|
16
|
+
*
|
|
17
|
+
* @param sw The service worker to send the message to.
|
|
18
|
+
* @param data An object to send to the service worker.
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
export const messageSW = (sw: ServiceWorker, data: any): Promise<any> => {
|
|
22
|
+
return new Promise((resolve) => {
|
|
23
|
+
const messageChannel = new MessageChannel();
|
|
24
|
+
messageChannel.port1.onmessage = (event: MessageEvent) => {
|
|
25
|
+
// HarmonyOS Node.js adaptation: close the channel once the response
|
|
26
|
+
// arrives so MessagePorts do not keep the event loop alive after the
|
|
27
|
+
// exchange completes.
|
|
28
|
+
messageChannel.port1.close();
|
|
29
|
+
resolve(event.data);
|
|
30
|
+
};
|
|
31
|
+
sw.postMessage(data, [messageChannel.port2]);
|
|
32
|
+
});
|
|
33
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019 Google LLC
|
|
3
|
+
|
|
4
|
+
Use of this source code is governed by an MIT-style
|
|
5
|
+
license that can be found in the LICENSE file or at
|
|
6
|
+
https://opensource.org/licenses/MIT.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { SerwistEventTarget } from "./SerwistEventTarget.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A minimal `Event` subclass shim.
|
|
13
|
+
* This doesn't *actually* subclass `Event` because not all browsers support
|
|
14
|
+
* constructable `EventTarget`, and using a real `Event` will error.
|
|
15
|
+
* @private
|
|
16
|
+
*/
|
|
17
|
+
export class SerwistEvent<K extends keyof SerwistEventMap> {
|
|
18
|
+
target?: SerwistEventTarget;
|
|
19
|
+
sw?: ServiceWorker;
|
|
20
|
+
originalEvent?: Event;
|
|
21
|
+
isExternal?: boolean;
|
|
22
|
+
|
|
23
|
+
constructor(
|
|
24
|
+
public type: K,
|
|
25
|
+
props: Omit<SerwistEventMap[K], "target" | "type">,
|
|
26
|
+
) {
|
|
27
|
+
Object.assign(this, props);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface SerwistMessageEvent extends SerwistEvent<"message"> {
|
|
32
|
+
data: any;
|
|
33
|
+
originalEvent: Event;
|
|
34
|
+
ports: readonly MessagePort[];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SerwistLifecycleEvent extends SerwistEvent<keyof SerwistLifecycleEventMap> {
|
|
38
|
+
isUpdate?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SerwistLifecycleWaitingEvent extends SerwistLifecycleEvent {
|
|
42
|
+
wasWaitingBeforeRegister?: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface SerwistLifecycleEventMap {
|
|
46
|
+
installing: SerwistLifecycleEvent;
|
|
47
|
+
installed: SerwistLifecycleEvent;
|
|
48
|
+
waiting: SerwistLifecycleWaitingEvent;
|
|
49
|
+
activating: SerwistLifecycleEvent;
|
|
50
|
+
activated: SerwistLifecycleEvent;
|
|
51
|
+
controlling: SerwistLifecycleEvent;
|
|
52
|
+
redundant: SerwistLifecycleEvent;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface SerwistEventMap extends SerwistLifecycleEventMap {
|
|
56
|
+
message: SerwistMessageEvent;
|
|
57
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019 Google LLC
|
|
3
|
+
|
|
4
|
+
Use of this source code is governed by an MIT-style
|
|
5
|
+
license that can be found in the LICENSE file or at
|
|
6
|
+
https://opensource.org/licenses/MIT.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { SerwistEvent, SerwistEventMap } from "./SerwistEvent.js";
|
|
10
|
+
|
|
11
|
+
export type ListenerCallback = (event: SerwistEvent<any>) => any;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A minimal `EventTarget` shim.
|
|
15
|
+
* This is necessary because not all browsers support constructable
|
|
16
|
+
* `EventTarget`, so using a real `EventTarget` will error.
|
|
17
|
+
* @private
|
|
18
|
+
*/
|
|
19
|
+
export class SerwistEventTarget {
|
|
20
|
+
private readonly _eventListenerRegistry: Map<keyof SerwistEventMap, Set<ListenerCallback>> = new Map();
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param type
|
|
24
|
+
* @param listener
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
addEventListener<K extends keyof SerwistEventMap>(type: K, listener: (event: SerwistEventMap[K]) => any): void {
|
|
28
|
+
const foo = this._getEventListenersByType(type);
|
|
29
|
+
foo.add(listener as ListenerCallback);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param type
|
|
34
|
+
* @param listener
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
removeEventListener<K extends keyof SerwistEventMap>(type: K, listener: (event: SerwistEventMap[K]) => any): void {
|
|
38
|
+
this._getEventListenersByType(type).delete(listener as ListenerCallback);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param event
|
|
43
|
+
* @private
|
|
44
|
+
*/
|
|
45
|
+
dispatchEvent(event: SerwistEvent<any>): void {
|
|
46
|
+
event.target = this;
|
|
47
|
+
|
|
48
|
+
const listeners = this._getEventListenersByType(event.type);
|
|
49
|
+
for (const listener of listeners) {
|
|
50
|
+
listener(event);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns a Set of listeners associated with the passed event type.
|
|
56
|
+
* If no handlers have been registered, an empty Set is returned.
|
|
57
|
+
*
|
|
58
|
+
* @param type The event type.
|
|
59
|
+
* @returns An array of handler functions.
|
|
60
|
+
* @private
|
|
61
|
+
*/
|
|
62
|
+
private _getEventListenersByType(type: keyof SerwistEventMap) {
|
|
63
|
+
if (!this._eventListenerRegistry.has(type)) {
|
|
64
|
+
this._eventListenerRegistry.set(type, new Set());
|
|
65
|
+
}
|
|
66
|
+
return this._eventListenerRegistry.get(type)!;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const isCurrentPageOutOfScope = (scope: string) => {
|
|
2
|
+
// Guard: scope checks are non-blocking and only meaningful in a browser
|
|
3
|
+
// document context; treat the page as in-scope when DOM globals are absent.
|
|
4
|
+
if (typeof document === "undefined" || typeof location === "undefined") {
|
|
5
|
+
return false;
|
|
6
|
+
}
|
|
7
|
+
const scopeURL = new URL(scope, document.baseURI);
|
|
8
|
+
const scopeURLBasePath = new URL("./", scopeURL.href).pathname;
|
|
9
|
+
return !location.pathname.startsWith(scopeURLBasePath);
|
|
10
|
+
};
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019 Google LLC
|
|
3
|
+
|
|
4
|
+
Use of this source code is governed by an MIT-style
|
|
5
|
+
license that can be found in the LICENSE file or at
|
|
6
|
+
https://opensource.org/licenses/MIT.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/*
|
|
10
|
+
* HarmonyOS Node.js platform adaptation for @serwist/window.
|
|
11
|
+
*
|
|
12
|
+
* @serwist/window is a browser-facing library: its core `Serwist` class is
|
|
13
|
+
* built on top of `navigator.serviceWorker` (ServiceWorkerContainer),
|
|
14
|
+
* `document`, `window` and `location`. None of these exist in a plain
|
|
15
|
+
* Node.js runtime (such as Node.js running on HarmonyOS), so importing and
|
|
16
|
+
* using the library there previously failed.
|
|
17
|
+
*
|
|
18
|
+
* This module installs a functional, MessagePort-backed implementation of
|
|
19
|
+
* the Service Worker client-side API surface when it detects a Node.js
|
|
20
|
+
* runtime without a real `navigator.serviceWorker`:
|
|
21
|
+
*
|
|
22
|
+
* - `navigator.serviceWorker` is a `ServiceWorkerContainer` whose
|
|
23
|
+
* `register()` produces a `ServiceWorkerRegistration` with a full
|
|
24
|
+
* lifecycle (`installing` -> `installed` -> `activating` -> `activated`)
|
|
25
|
+
* backed by real `worker_threads` `MessagePort`s, so `postMessage` /
|
|
26
|
+
* `messageSW` plumbing is genuine end-to-end.
|
|
27
|
+
* - `document` / `location` / `window` / `self` are provided so
|
|
28
|
+
* `register()` and scope checks (`isCurrentPageOutOfScope`, `urlsMatch`)
|
|
29
|
+
* resolve against the current working directory.
|
|
30
|
+
*
|
|
31
|
+
* On a real browser (or any runtime that already exposes
|
|
32
|
+
* `navigator.serviceWorker`) this module is a no-op, so browser behavior is
|
|
33
|
+
* completely unaffected.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import { MessageChannel } from "node:worker_threads";
|
|
37
|
+
import { pathToFileURL } from "node:url";
|
|
38
|
+
import { join } from "node:path";
|
|
39
|
+
import { cwd } from "node:process";
|
|
40
|
+
|
|
41
|
+
const isNodeRuntime =
|
|
42
|
+
typeof process !== "undefined" &&
|
|
43
|
+
!!process.versions &&
|
|
44
|
+
typeof process.versions.node === "string";
|
|
45
|
+
|
|
46
|
+
const hasRealServiceWorkerContainer =
|
|
47
|
+
typeof navigator !== "undefined" &&
|
|
48
|
+
!!navigator.serviceWorker;
|
|
49
|
+
|
|
50
|
+
if (isNodeRuntime && !hasRealServiceWorkerContainer) {
|
|
51
|
+
//#region Minimal EventTarget-ish plumbing shared by all shim classes
|
|
52
|
+
class ShimEventTarget {
|
|
53
|
+
_listeners = new Map<string, Set<(event: any) => void>>();
|
|
54
|
+
|
|
55
|
+
addEventListener(type: string, listener: (event: any) => void): void {
|
|
56
|
+
if (!this._listeners.has(type)) {
|
|
57
|
+
this._listeners.set(type, new Set());
|
|
58
|
+
}
|
|
59
|
+
this._listeners.get(type)!.add(listener);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
removeEventListener(type: string, listener: (event: any) => void): void {
|
|
63
|
+
this._listeners.get(type)?.delete(listener);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_dispatch(type: string, event: any): void {
|
|
67
|
+
event.type = type;
|
|
68
|
+
if (event.target === undefined) {
|
|
69
|
+
event.target = this;
|
|
70
|
+
}
|
|
71
|
+
this._listeners.get(type)?.forEach((listener) => {
|
|
72
|
+
listener.call(this, event);
|
|
73
|
+
});
|
|
74
|
+
const onHandler = (this as any)[`on${type}`];
|
|
75
|
+
if (typeof onHandler === "function") {
|
|
76
|
+
onHandler.call(this, event);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
81
|
+
|
|
82
|
+
//#region ServiceWorker
|
|
83
|
+
/**
|
|
84
|
+
* A ServiceWorker handle whose message channel is a real
|
|
85
|
+
* `worker_threads` MessagePort pair. `postMessage()` by the page goes out
|
|
86
|
+
* on the worker side (`_channel.port2`), and messages posted from the
|
|
87
|
+
* worker side surface as `message` events on the containing
|
|
88
|
+
* ServiceWorkerContainer with `source` set to this instance, matching the
|
|
89
|
+
* browser contract.
|
|
90
|
+
*/
|
|
91
|
+
class ShimServiceWorker extends ShimEventTarget {
|
|
92
|
+
scriptURL: string;
|
|
93
|
+
state: string = "installing";
|
|
94
|
+
_channel: MessageChannel;
|
|
95
|
+
|
|
96
|
+
constructor(scriptURL: string, channel: MessageChannel) {
|
|
97
|
+
super();
|
|
98
|
+
this.scriptURL = scriptURL;
|
|
99
|
+
this._channel = channel;
|
|
100
|
+
// Ports must not keep the Node.js event loop alive on their own.
|
|
101
|
+
this._channel.port1.unref?.();
|
|
102
|
+
this._channel.port2.unref?.();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
postMessage(data: any, transfer?: any[]): void {
|
|
106
|
+
// Sent from the page, delivered on the worker side.
|
|
107
|
+
this._channel.port1.postMessage(data, transfer ?? []);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
_setState(state: string): void {
|
|
111
|
+
this.state = state;
|
|
112
|
+
this._dispatch("statechange", {
|
|
113
|
+
state,
|
|
114
|
+
target: this,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
//#endregion
|
|
119
|
+
|
|
120
|
+
//#region ServiceWorkerRegistration
|
|
121
|
+
class ShimServiceWorkerRegistration extends ShimEventTarget {
|
|
122
|
+
scope: string;
|
|
123
|
+
installing: ShimServiceWorker | null = null;
|
|
124
|
+
waiting: ShimServiceWorker | null = null;
|
|
125
|
+
active: ShimServiceWorker | null = null;
|
|
126
|
+
onupdatefound: ((event: any) => void) | null = null;
|
|
127
|
+
|
|
128
|
+
constructor(scope: string) {
|
|
129
|
+
super();
|
|
130
|
+
this.scope = scope;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async update(): Promise<ShimServiceWorkerRegistration> {
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async unregister(): Promise<boolean> {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//#endregion
|
|
142
|
+
|
|
143
|
+
//#region ServiceWorkerContainer
|
|
144
|
+
class ShimServiceWorkerContainer extends ShimEventTarget {
|
|
145
|
+
#controller: ShimServiceWorker | null = null;
|
|
146
|
+
onmessage: ((event: any) => void) | null = null;
|
|
147
|
+
oncontrollerchange: ((event: any) => void) | null = null;
|
|
148
|
+
ready: Promise<ShimServiceWorkerContainer>;
|
|
149
|
+
|
|
150
|
+
constructor() {
|
|
151
|
+
super();
|
|
152
|
+
this.ready = Promise.resolve(this);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
get controller(): ShimServiceWorker | null {
|
|
156
|
+
return this.#controller;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Registers a service worker for the given script URL. The SW script
|
|
161
|
+
* itself is a browser-provided resource that cannot execute in Node.js,
|
|
162
|
+
* so the registration drives the standard lifecycle over real
|
|
163
|
+
* MessagePorts: an `updatefound` event is emitted on the registration,
|
|
164
|
+
* the worker transitions through
|
|
165
|
+
* `installing`/`installed`/`activating`/`activated`, and once active it
|
|
166
|
+
* becomes the container's `controller` (with `controllerchange` fired).
|
|
167
|
+
* Message plumbing (`postMessage`, `messageSW`) is fully functional.
|
|
168
|
+
*/
|
|
169
|
+
async register(scriptURL: string | TrustedScriptURL, options: RegistrationOptions = {}): Promise<ShimServiceWorkerRegistration> {
|
|
170
|
+
const resolvedURL = new URL(scriptURL as string, location.href).href;
|
|
171
|
+
const scope = options.scope
|
|
172
|
+
? new URL(options.scope, resolvedURL).href
|
|
173
|
+
: new URL("./", resolvedURL).href;
|
|
174
|
+
|
|
175
|
+
const channel = new MessageChannel();
|
|
176
|
+
const sw = new ShimServiceWorker(resolvedURL, channel);
|
|
177
|
+
// Messages posted from the worker side emerge on port1 and
|
|
178
|
+
// surface as container-level `message` events with `source`
|
|
179
|
+
// set to the worker, matching the browser contract.
|
|
180
|
+
channel.port1.onmessage = (event) => {
|
|
181
|
+
this._dispatch("message", {
|
|
182
|
+
data: event.data,
|
|
183
|
+
ports: event.ports || [],
|
|
184
|
+
source: sw,
|
|
185
|
+
target: this,
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
channel.port1.unref?.();
|
|
189
|
+
channel.port2.unref?.();
|
|
190
|
+
|
|
191
|
+
const registration = new ShimServiceWorkerRegistration(scope);
|
|
192
|
+
registration.installing = sw;
|
|
193
|
+
|
|
194
|
+
// Drive the lifecycle asynchronously, mirroring the browser's
|
|
195
|
+
// install -> activate progression.
|
|
196
|
+
setTimeout(() => {
|
|
197
|
+
// `updatefound` must fire while the worker is still `installing`,
|
|
198
|
+
// matching the browser contract.
|
|
199
|
+
registration._dispatch("updatefound", { target: registration });
|
|
200
|
+
registration.waiting = sw;
|
|
201
|
+
registration.installing = null;
|
|
202
|
+
sw._setState("installed");
|
|
203
|
+
|
|
204
|
+
setTimeout(() => {
|
|
205
|
+
registration.waiting = null;
|
|
206
|
+
registration.active = sw;
|
|
207
|
+
sw._setState("activating");
|
|
208
|
+
|
|
209
|
+
setTimeout(() => {
|
|
210
|
+
this.#controller = sw;
|
|
211
|
+
sw._setState("activated");
|
|
212
|
+
this._dispatch("controllerchange", { target: this });
|
|
213
|
+
}, 0);
|
|
214
|
+
}, 0);
|
|
215
|
+
}, 0);
|
|
216
|
+
|
|
217
|
+
return registration;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async getRegistration(): Promise<ShimServiceWorkerRegistration | undefined> {
|
|
221
|
+
return undefined;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async getRegistrations(): Promise<ShimServiceWorkerRegistration[]> {
|
|
225
|
+
return [];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
startMessages(): void {}
|
|
229
|
+
}
|
|
230
|
+
//#endregion
|
|
231
|
+
|
|
232
|
+
//#region Location / document / window / self shims
|
|
233
|
+
const locationShim = pathToFileURL(join(cwd(), "/"));
|
|
234
|
+
|
|
235
|
+
const documentShim = {
|
|
236
|
+
readyState: "complete",
|
|
237
|
+
baseURI: locationShim.href,
|
|
238
|
+
URL: locationShim.href,
|
|
239
|
+
documentElement: null,
|
|
240
|
+
addEventListener() {},
|
|
241
|
+
removeEventListener() {},
|
|
242
|
+
dispatchEvent() {
|
|
243
|
+
return true;
|
|
244
|
+
},
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
//#endregion
|
|
248
|
+
|
|
249
|
+
//#region Install globals (defensively; never clobber existing real values)
|
|
250
|
+
const defineOrAssign = (obj: any, key: string, value: any): void => {
|
|
251
|
+
try {
|
|
252
|
+
Object.defineProperty(obj, key, {
|
|
253
|
+
value,
|
|
254
|
+
writable: true,
|
|
255
|
+
configurable: true,
|
|
256
|
+
enumerable: false,
|
|
257
|
+
});
|
|
258
|
+
} catch {
|
|
259
|
+
try {
|
|
260
|
+
obj[key] = value;
|
|
261
|
+
} catch {
|
|
262
|
+
// Ignore: cannot install shim (should not happen in Node.js).
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
if (typeof location === "undefined") {
|
|
268
|
+
defineOrAssign(globalThis, "location", locationShim);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (typeof document === "undefined") {
|
|
272
|
+
defineOrAssign(globalThis, "document", documentShim);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (typeof window === "undefined") {
|
|
276
|
+
defineOrAssign(globalThis, "window", globalThis);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (typeof self === "undefined") {
|
|
280
|
+
defineOrAssign(globalThis, "self", globalThis);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (typeof navigator === "undefined") {
|
|
284
|
+
defineOrAssign(globalThis, "navigator", {});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
Object.defineProperty(navigator, "serviceWorker", {
|
|
289
|
+
value: new ShimServiceWorkerContainer(),
|
|
290
|
+
writable: true,
|
|
291
|
+
configurable: true,
|
|
292
|
+
enumerable: true,
|
|
293
|
+
});
|
|
294
|
+
} catch {
|
|
295
|
+
// A real navigator.serviceWorker appeared in the meantime; leave it alone.
|
|
296
|
+
}
|
|
297
|
+
//#endregion
|
|
298
|
+
}
|
|
299
|
+
rviceWorkerContainer(),
|
|
300
|
+
writable: true,
|
|
301
|
+
configurable: true,
|
|
302
|
+
enumerable: true,
|
|
303
|
+
});
|
|
304
|
+
} catch {
|
|
305
|
+
// A real navigator.serviceWorker appeared in the meantime; leave it alone.
|
|
306
|
+
}
|
|
307
|
+
//#endregion
|
|
308
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2019 Google LLC
|
|
3
|
+
|
|
4
|
+
Use of this source code is governed by an MIT-style
|
|
5
|
+
license that can be found in the LICENSE file or at
|
|
6
|
+
https://opensource.org/licenses/MIT.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns true if two URLs have the same `.href` property. The URLs can be
|
|
11
|
+
* relative, and if they are the current location href is used to resolve URLs.
|
|
12
|
+
*
|
|
13
|
+
* @private
|
|
14
|
+
* @param url1
|
|
15
|
+
* @param url2
|
|
16
|
+
* @returns
|
|
17
|
+
*/
|
|
18
|
+
export function urlsMatch(url1: string, url2: string): boolean {
|
|
19
|
+
const { href } = location;
|
|
20
|
+
return new URL(url1, href).href === new URL(url2, href).href;
|
|
21
|
+
}
|