@b9g/platform 0.1.10 → 0.1.12
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 +1 -1
- package/chunk-P57PW2II.js +11 -0
- package/package.json +35 -35
- package/src/index.d.ts +224 -15
- package/src/index.js +492 -99
- package/src/runtime.d.ts +170 -14
- package/src/runtime.js +471 -267
- package/src/shovel-config.d.ts +10 -0
- package/src/worker.d.ts +39 -0
- package/src/worker.js +285 -0
- package/src/config.d.ts +0 -146
- package/src/config.js +0 -560
- package/src/cookie-store.d.ts +0 -80
- package/src/cookie-store.js +0 -231
- package/src/single-threaded.d.ts +0 -59
- package/src/single-threaded.js +0 -109
- package/src/worker-pool.d.ts +0 -93
- package/src/worker-pool.js +0 -391
package/src/runtime.js
CHANGED
|
@@ -1,16 +1,251 @@
|
|
|
1
1
|
/// <reference types="./runtime.d.ts" />
|
|
2
|
+
import "../chunk-P57PW2II.js";
|
|
3
|
+
|
|
2
4
|
// src/runtime.ts
|
|
3
|
-
import { RequestCookieStore } from "./cookie-store.js";
|
|
4
5
|
import { AsyncContext } from "@b9g/async-context";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import {
|
|
7
|
+
configure
|
|
8
|
+
} from "@logtape/logtape";
|
|
9
|
+
function parseCookieHeader(cookieHeader) {
|
|
10
|
+
const cookies = /* @__PURE__ */ new Map();
|
|
11
|
+
if (!cookieHeader)
|
|
12
|
+
return cookies;
|
|
13
|
+
const pairs = cookieHeader.split(/;\s*/);
|
|
14
|
+
for (const pair of pairs) {
|
|
15
|
+
const [name, ...valueParts] = pair.split("=");
|
|
16
|
+
if (name) {
|
|
17
|
+
const value = valueParts.join("=");
|
|
18
|
+
cookies.set(name.trim(), decodeURIComponent(value || ""));
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return cookies;
|
|
22
|
+
}
|
|
23
|
+
function serializeCookie(cookie) {
|
|
24
|
+
let header = `${encodeURIComponent(cookie.name)}=${encodeURIComponent(cookie.value)}`;
|
|
25
|
+
if (cookie.expires !== void 0 && cookie.expires !== null) {
|
|
26
|
+
const date = new Date(cookie.expires);
|
|
27
|
+
header += `; Expires=${date.toUTCString()}`;
|
|
28
|
+
}
|
|
29
|
+
if (cookie.domain) {
|
|
30
|
+
header += `; Domain=${cookie.domain}`;
|
|
31
|
+
}
|
|
32
|
+
if (cookie.path) {
|
|
33
|
+
header += `; Path=${cookie.path}`;
|
|
34
|
+
} else {
|
|
35
|
+
header += `; Path=/`;
|
|
36
|
+
}
|
|
37
|
+
if (cookie.sameSite) {
|
|
38
|
+
header += `; SameSite=${cookie.sameSite.charAt(0).toUpperCase() + cookie.sameSite.slice(1)}`;
|
|
39
|
+
} else {
|
|
40
|
+
header += `; SameSite=Strict`;
|
|
41
|
+
}
|
|
42
|
+
if (cookie.partitioned) {
|
|
43
|
+
header += `; Partitioned`;
|
|
44
|
+
}
|
|
45
|
+
header += `; Secure`;
|
|
46
|
+
return header;
|
|
47
|
+
}
|
|
48
|
+
function parseSetCookieHeader(setCookieHeader) {
|
|
49
|
+
const parts = setCookieHeader.split(/;\s*/);
|
|
50
|
+
const [nameValue, ...attributes] = parts;
|
|
51
|
+
const [name, ...valueParts] = nameValue.split("=");
|
|
52
|
+
const value = valueParts.join("=");
|
|
53
|
+
const cookie = {
|
|
54
|
+
name: decodeURIComponent(name.trim()),
|
|
55
|
+
value: decodeURIComponent(value || "")
|
|
56
|
+
};
|
|
57
|
+
for (const attr of attributes) {
|
|
58
|
+
const [key, ...attrValueParts] = attr.split("=");
|
|
59
|
+
const attrKey = key.trim().toLowerCase();
|
|
60
|
+
const attrValue = attrValueParts.join("=").trim();
|
|
61
|
+
switch (attrKey) {
|
|
62
|
+
case "expires":
|
|
63
|
+
cookie.expires = new Date(attrValue).getTime();
|
|
64
|
+
break;
|
|
65
|
+
case "max-age":
|
|
66
|
+
cookie.expires = Date.now() + parseInt(attrValue, 10) * 1e3;
|
|
67
|
+
break;
|
|
68
|
+
case "domain":
|
|
69
|
+
cookie.domain = attrValue;
|
|
70
|
+
break;
|
|
71
|
+
case "path":
|
|
72
|
+
cookie.path = attrValue;
|
|
73
|
+
break;
|
|
74
|
+
case "secure":
|
|
75
|
+
cookie.secure = true;
|
|
76
|
+
break;
|
|
77
|
+
case "samesite":
|
|
78
|
+
cookie.sameSite = attrValue.toLowerCase();
|
|
79
|
+
break;
|
|
80
|
+
case "partitioned":
|
|
81
|
+
cookie.partitioned = true;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return cookie;
|
|
86
|
+
}
|
|
87
|
+
var RequestCookieStore = class extends EventTarget {
|
|
88
|
+
#cookies;
|
|
89
|
+
#changes;
|
|
90
|
+
// null = deleted
|
|
91
|
+
#request;
|
|
92
|
+
// Event handler for cookie changes (spec compliance)
|
|
93
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
94
|
+
onchange = null;
|
|
95
|
+
constructor(request) {
|
|
96
|
+
super();
|
|
97
|
+
this.#cookies = /* @__PURE__ */ new Map();
|
|
98
|
+
this.#changes = /* @__PURE__ */ new Map();
|
|
99
|
+
this.#request = request || null;
|
|
100
|
+
if (request) {
|
|
101
|
+
const cookieHeader = request.headers.get("cookie");
|
|
102
|
+
if (cookieHeader) {
|
|
103
|
+
const parsed = parseCookieHeader(cookieHeader);
|
|
104
|
+
for (const [name, value] of parsed) {
|
|
105
|
+
this.#cookies.set(name, { name, value });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async get(nameOrOptions) {
|
|
111
|
+
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions.name;
|
|
112
|
+
if (!name) {
|
|
113
|
+
throw new TypeError("Cookie name is required");
|
|
114
|
+
}
|
|
115
|
+
if (this.#changes.has(name)) {
|
|
116
|
+
const change = this.#changes.get(name);
|
|
117
|
+
if (change === null || change === void 0)
|
|
118
|
+
return null;
|
|
119
|
+
return {
|
|
120
|
+
name: change.name,
|
|
121
|
+
value: change.value,
|
|
122
|
+
domain: change.domain ?? void 0,
|
|
123
|
+
path: change.path,
|
|
124
|
+
expires: change.expires ?? void 0,
|
|
125
|
+
sameSite: change.sameSite,
|
|
126
|
+
partitioned: change.partitioned
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return this.#cookies.get(name) || null;
|
|
130
|
+
}
|
|
131
|
+
async getAll(nameOrOptions) {
|
|
132
|
+
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions?.name;
|
|
133
|
+
const result = [];
|
|
134
|
+
const allNames = /* @__PURE__ */ new Set([
|
|
135
|
+
...this.#cookies.keys(),
|
|
136
|
+
...this.#changes.keys()
|
|
137
|
+
]);
|
|
138
|
+
for (const cookieName of allNames) {
|
|
139
|
+
if (name && cookieName !== name)
|
|
140
|
+
continue;
|
|
141
|
+
if (this.#changes.has(cookieName) && this.#changes.get(cookieName) === null) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
const cookie = await this.get(cookieName);
|
|
145
|
+
if (cookie) {
|
|
146
|
+
result.push(cookie);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
async set(nameOrOptions, value) {
|
|
152
|
+
let cookie;
|
|
153
|
+
if (typeof nameOrOptions === "string") {
|
|
154
|
+
if (value === void 0) {
|
|
155
|
+
throw new TypeError("Cookie value is required");
|
|
156
|
+
}
|
|
157
|
+
cookie = {
|
|
158
|
+
name: nameOrOptions,
|
|
159
|
+
value,
|
|
160
|
+
path: "/",
|
|
161
|
+
sameSite: "strict"
|
|
162
|
+
};
|
|
163
|
+
} else {
|
|
164
|
+
cookie = {
|
|
165
|
+
path: "/",
|
|
166
|
+
sameSite: "strict",
|
|
167
|
+
...nameOrOptions
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
const size = cookie.name.length + cookie.value.length;
|
|
171
|
+
if (size > 4096) {
|
|
172
|
+
throw new TypeError(
|
|
173
|
+
`Cookie name+value too large: ${size} bytes (max 4096)`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
this.#changes.set(cookie.name, cookie);
|
|
177
|
+
}
|
|
178
|
+
async delete(nameOrOptions) {
|
|
179
|
+
const name = typeof nameOrOptions === "string" ? nameOrOptions : nameOrOptions.name;
|
|
180
|
+
if (!name) {
|
|
181
|
+
throw new TypeError("Cookie name is required");
|
|
182
|
+
}
|
|
183
|
+
this.#changes.set(name, null);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Get Set-Cookie headers for all changes
|
|
187
|
+
* This should be called when constructing the Response
|
|
188
|
+
*/
|
|
189
|
+
getSetCookieHeaders() {
|
|
190
|
+
const headers = [];
|
|
191
|
+
for (const [name, change] of this.#changes) {
|
|
192
|
+
if (change === null) {
|
|
193
|
+
headers.push(
|
|
194
|
+
serializeCookie({
|
|
195
|
+
name,
|
|
196
|
+
value: "",
|
|
197
|
+
expires: 0,
|
|
198
|
+
path: "/"
|
|
199
|
+
})
|
|
200
|
+
);
|
|
201
|
+
} else {
|
|
202
|
+
headers.push(serializeCookie(change));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return headers;
|
|
206
|
+
}
|
|
207
|
+
hasChanges() {
|
|
208
|
+
return this.#changes.size > 0;
|
|
209
|
+
}
|
|
210
|
+
clearChanges() {
|
|
211
|
+
this.#changes.clear();
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
var CustomLoggerStorage = class {
|
|
215
|
+
#factory;
|
|
216
|
+
constructor(factory) {
|
|
217
|
+
this.#factory = factory;
|
|
218
|
+
}
|
|
219
|
+
open(...categories) {
|
|
220
|
+
return this.#factory(...categories);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
var SERVICE_WORKER_EVENTS = ["fetch", "install", "activate"];
|
|
224
|
+
function isServiceWorkerEvent(type) {
|
|
225
|
+
return SERVICE_WORKER_EVENTS.includes(type);
|
|
226
|
+
}
|
|
10
227
|
if (import.meta.env && !import.meta.env.MODE && import.meta.env.NODE_ENV) {
|
|
11
228
|
import.meta.env.MODE = import.meta.env.NODE_ENV;
|
|
12
229
|
}
|
|
13
230
|
var cookieStoreStorage = new AsyncContext.Variable();
|
|
231
|
+
var fetchDepthStorage = new AsyncContext.Variable();
|
|
232
|
+
var MAX_FETCH_DEPTH = 10;
|
|
233
|
+
var PATCHED_KEYS = [
|
|
234
|
+
"self",
|
|
235
|
+
"fetch",
|
|
236
|
+
"caches",
|
|
237
|
+
"directories",
|
|
238
|
+
"loggers",
|
|
239
|
+
"registration",
|
|
240
|
+
"clients",
|
|
241
|
+
"skipWaiting",
|
|
242
|
+
"addEventListener",
|
|
243
|
+
"removeEventListener",
|
|
244
|
+
"dispatchEvent",
|
|
245
|
+
"WorkerGlobalScope",
|
|
246
|
+
"DedicatedWorkerGlobalScope",
|
|
247
|
+
"cookieStore"
|
|
248
|
+
];
|
|
14
249
|
function promiseWithTimeout(promise, timeoutMs, errorMessage) {
|
|
15
250
|
return Promise.race([
|
|
16
251
|
promise,
|
|
@@ -114,9 +349,7 @@ var ShovelClient = class {
|
|
|
114
349
|
}
|
|
115
350
|
// Implementation
|
|
116
351
|
postMessage(_message, _transferOrOptions) {
|
|
117
|
-
|
|
118
|
-
"[ServiceWorker] Client.postMessage() not supported in server context"
|
|
119
|
-
);
|
|
352
|
+
self.loggers.open("platform").warn("Client.postMessage() not supported in server context");
|
|
120
353
|
}
|
|
121
354
|
};
|
|
122
355
|
var ShovelWindowClient = class extends ShovelClient {
|
|
@@ -128,15 +361,11 @@ var ShovelWindowClient = class extends ShovelClient {
|
|
|
128
361
|
this.visibilityState = options.visibilityState || "hidden";
|
|
129
362
|
}
|
|
130
363
|
async focus() {
|
|
131
|
-
|
|
132
|
-
"[ServiceWorker] WindowClient.focus() not supported in server context"
|
|
133
|
-
);
|
|
364
|
+
self.loggers.open("platform").warn("WindowClient.focus() not supported in server context");
|
|
134
365
|
return this;
|
|
135
366
|
}
|
|
136
367
|
async navigate(_url) {
|
|
137
|
-
|
|
138
|
-
"[ServiceWorker] WindowClient.navigate() not supported in server context"
|
|
139
|
-
);
|
|
368
|
+
self.loggers.open("platform").warn("WindowClient.navigate() not supported in server context");
|
|
140
369
|
return null;
|
|
141
370
|
}
|
|
142
371
|
};
|
|
@@ -150,9 +379,7 @@ var ShovelClients = class {
|
|
|
150
379
|
return [];
|
|
151
380
|
}
|
|
152
381
|
async openWindow(_url) {
|
|
153
|
-
|
|
154
|
-
"[ServiceWorker] Clients.openWindow() not supported in server context"
|
|
155
|
-
);
|
|
382
|
+
self.loggers.open("platform").warn("Clients.openWindow() not supported in server context");
|
|
156
383
|
return null;
|
|
157
384
|
}
|
|
158
385
|
};
|
|
@@ -186,9 +413,7 @@ var ShovelServiceWorker = class extends EventTarget {
|
|
|
186
413
|
}
|
|
187
414
|
// Implementation
|
|
188
415
|
postMessage(_message, _transferOrOptions) {
|
|
189
|
-
|
|
190
|
-
"[ServiceWorker] ServiceWorker.postMessage() not implemented in server context"
|
|
191
|
-
);
|
|
416
|
+
self.loggers.open("platform").warn("ServiceWorker.postMessage() not implemented in server context");
|
|
192
417
|
}
|
|
193
418
|
// Internal method to update state and dispatch statechange event
|
|
194
419
|
_setState(newState) {
|
|
@@ -220,9 +445,9 @@ var ShovelServiceWorkerRegistration = class extends EventTarget {
|
|
|
220
445
|
cookies;
|
|
221
446
|
pushManager;
|
|
222
447
|
onupdatefound;
|
|
223
|
-
constructor(
|
|
448
|
+
constructor(scope = "/", scriptURL = "/") {
|
|
224
449
|
super();
|
|
225
|
-
this.scope =
|
|
450
|
+
this.scope = scope;
|
|
226
451
|
this.updateViaCache = "imports";
|
|
227
452
|
this.navigationPreload = new ShovelNavigationPreloadManager();
|
|
228
453
|
this._serviceWorker = new ShovelServiceWorker(scriptURL, "parsed");
|
|
@@ -245,9 +470,7 @@ var ShovelServiceWorkerRegistration = class extends EventTarget {
|
|
|
245
470
|
return [];
|
|
246
471
|
}
|
|
247
472
|
async showNotification(_title, _options) {
|
|
248
|
-
|
|
249
|
-
"[ServiceWorker] Notifications not supported in server context"
|
|
250
|
-
);
|
|
473
|
+
self.loggers.open("platform").warn("Notifications not supported in server context");
|
|
251
474
|
}
|
|
252
475
|
async sync() {
|
|
253
476
|
}
|
|
@@ -346,7 +569,9 @@ var ShovelServiceWorkerRegistration = class extends EventTarget {
|
|
|
346
569
|
const response = await event.getResponse();
|
|
347
570
|
const promises = event.getPromises();
|
|
348
571
|
if (promises.length > 0) {
|
|
349
|
-
Promise.allSettled(promises).catch(
|
|
572
|
+
Promise.allSettled(promises).catch(
|
|
573
|
+
(err) => self.loggers.open("platform").error`waitUntil error: ${err}`
|
|
574
|
+
);
|
|
350
575
|
}
|
|
351
576
|
if (event.cookieStore.hasChanges()) {
|
|
352
577
|
const setCookieHeaders = event.cookieStore.getSetCookieHeaders();
|
|
@@ -393,8 +618,8 @@ var ShovelServiceWorkerContainer = class extends EventTarget {
|
|
|
393
618
|
/**
|
|
394
619
|
* Get registration for a specific scope
|
|
395
620
|
*/
|
|
396
|
-
async getRegistration(
|
|
397
|
-
return this.#registrations.get(
|
|
621
|
+
async getRegistration(scope = "/") {
|
|
622
|
+
return this.#registrations.get(scope);
|
|
398
623
|
}
|
|
399
624
|
/**
|
|
400
625
|
* Get all registrations
|
|
@@ -407,26 +632,26 @@ var ShovelServiceWorkerContainer = class extends EventTarget {
|
|
|
407
632
|
*/
|
|
408
633
|
async register(scriptURL, options) {
|
|
409
634
|
const url = typeof scriptURL === "string" ? scriptURL : scriptURL.toString();
|
|
410
|
-
const
|
|
411
|
-
let
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
|
|
635
|
+
const scope = this.#normalizeScope(options?.scope || "/");
|
|
636
|
+
let registration = this.#registrations.get(scope);
|
|
637
|
+
if (registration) {
|
|
638
|
+
registration._serviceWorker.scriptURL = url;
|
|
639
|
+
registration._serviceWorker._setState("parsed");
|
|
415
640
|
} else {
|
|
416
|
-
|
|
417
|
-
this.#registrations.set(
|
|
641
|
+
registration = new ShovelServiceWorkerRegistration(scope, url);
|
|
642
|
+
this.#registrations.set(scope, registration);
|
|
418
643
|
this.dispatchEvent(new Event("updatefound"));
|
|
419
644
|
}
|
|
420
|
-
return
|
|
645
|
+
return registration;
|
|
421
646
|
}
|
|
422
647
|
/**
|
|
423
648
|
* Unregister a ServiceWorker registration
|
|
424
649
|
*/
|
|
425
|
-
async unregister(
|
|
426
|
-
const
|
|
427
|
-
if (
|
|
428
|
-
await
|
|
429
|
-
this.#registrations.delete(
|
|
650
|
+
async unregister(scope) {
|
|
651
|
+
const registration = this.#registrations.get(scope);
|
|
652
|
+
if (registration) {
|
|
653
|
+
await registration.unregister();
|
|
654
|
+
this.#registrations.delete(scope);
|
|
430
655
|
return true;
|
|
431
656
|
}
|
|
432
657
|
return false;
|
|
@@ -439,9 +664,9 @@ var ShovelServiceWorkerContainer = class extends EventTarget {
|
|
|
439
664
|
const pathname = url.pathname;
|
|
440
665
|
const matchingScope = this.#findMatchingScope(pathname);
|
|
441
666
|
if (matchingScope) {
|
|
442
|
-
const
|
|
443
|
-
if (
|
|
444
|
-
return await
|
|
667
|
+
const registration = this.#registrations.get(matchingScope);
|
|
668
|
+
if (registration && registration.ready) {
|
|
669
|
+
return await registration.handleRequest(request);
|
|
445
670
|
}
|
|
446
671
|
}
|
|
447
672
|
return null;
|
|
@@ -451,9 +676,9 @@ var ShovelServiceWorkerContainer = class extends EventTarget {
|
|
|
451
676
|
*/
|
|
452
677
|
async installAll() {
|
|
453
678
|
const installations = Array.from(this.#registrations.values()).map(
|
|
454
|
-
async (
|
|
455
|
-
await
|
|
456
|
-
await
|
|
679
|
+
async (registration) => {
|
|
680
|
+
await registration.install();
|
|
681
|
+
await registration.activate();
|
|
457
682
|
}
|
|
458
683
|
);
|
|
459
684
|
await promiseWithTimeout(
|
|
@@ -473,14 +698,14 @@ var ShovelServiceWorkerContainer = class extends EventTarget {
|
|
|
473
698
|
/**
|
|
474
699
|
* Normalize scope to ensure it starts and ends correctly
|
|
475
700
|
*/
|
|
476
|
-
#normalizeScope(
|
|
477
|
-
if (!
|
|
478
|
-
|
|
701
|
+
#normalizeScope(scope) {
|
|
702
|
+
if (!scope.startsWith("/")) {
|
|
703
|
+
scope = "/" + scope;
|
|
479
704
|
}
|
|
480
|
-
if (
|
|
481
|
-
|
|
705
|
+
if (scope !== "/" && !scope.endsWith("/")) {
|
|
706
|
+
scope = scope + "/";
|
|
482
707
|
}
|
|
483
|
-
return
|
|
708
|
+
return scope;
|
|
484
709
|
}
|
|
485
710
|
/**
|
|
486
711
|
* Find the most specific scope that matches a pathname
|
|
@@ -488,9 +713,9 @@ var ShovelServiceWorkerContainer = class extends EventTarget {
|
|
|
488
713
|
#findMatchingScope(pathname) {
|
|
489
714
|
const scopes = Array.from(this.#registrations.keys());
|
|
490
715
|
scopes.sort((a, b) => b.length - a.length);
|
|
491
|
-
for (const
|
|
492
|
-
if (pathname.startsWith(
|
|
493
|
-
return
|
|
716
|
+
for (const scope of scopes) {
|
|
717
|
+
if (pathname.startsWith(scope === "/" ? "/" : scope)) {
|
|
718
|
+
return scope;
|
|
494
719
|
}
|
|
495
720
|
}
|
|
496
721
|
return null;
|
|
@@ -542,9 +767,7 @@ var Notification = class extends EventTarget {
|
|
|
542
767
|
this.onshow = null;
|
|
543
768
|
}
|
|
544
769
|
close() {
|
|
545
|
-
|
|
546
|
-
"[ServiceWorker] Notification.close() not supported in server context"
|
|
547
|
-
);
|
|
770
|
+
self.loggers.open("platform").warn("Notification.close() not supported in server context");
|
|
548
771
|
}
|
|
549
772
|
static async requestPermission() {
|
|
550
773
|
return "denied";
|
|
@@ -609,7 +832,7 @@ var WorkerGlobalScope = class {
|
|
|
609
832
|
};
|
|
610
833
|
var DedicatedWorkerGlobalScope = class extends WorkerGlobalScope {
|
|
611
834
|
};
|
|
612
|
-
var
|
|
835
|
+
var ServiceWorkerGlobals = class {
|
|
613
836
|
// Self-reference (standard in ServiceWorkerGlobalScope)
|
|
614
837
|
// Type assertion: we provide a compatible subset of WorkerGlobalScope
|
|
615
838
|
self;
|
|
@@ -618,12 +841,15 @@ var ShovelGlobalScope = class {
|
|
|
618
841
|
registration;
|
|
619
842
|
// Storage APIs
|
|
620
843
|
caches;
|
|
621
|
-
|
|
844
|
+
directories;
|
|
845
|
+
loggers;
|
|
622
846
|
// Clients API
|
|
623
847
|
// Our custom Clients implementation provides core functionality compatible with the Web API
|
|
624
848
|
clients;
|
|
625
849
|
// Shovel-specific development features
|
|
626
850
|
#isDevelopment;
|
|
851
|
+
// Snapshot of original globals before patching (for restore())
|
|
852
|
+
#originals;
|
|
627
853
|
// Web API required properties
|
|
628
854
|
// Note: Using RequestCookieStore but typing as any for flexibility with global CookieStore type
|
|
629
855
|
// cookieStore is retrieved from AsyncContext for per-request isolation
|
|
@@ -643,9 +869,7 @@ var ShovelGlobalScope = class {
|
|
|
643
869
|
crypto;
|
|
644
870
|
// WorkerGlobalScope methods (stubs for server context)
|
|
645
871
|
importScripts(..._urls) {
|
|
646
|
-
|
|
647
|
-
"[ServiceWorker] importScripts() not supported in server context"
|
|
648
|
-
);
|
|
872
|
+
self.loggers.open("platform").warn("importScripts() not supported in server context");
|
|
649
873
|
}
|
|
650
874
|
atob(data) {
|
|
651
875
|
return globalThis.atob(data);
|
|
@@ -665,13 +889,28 @@ var ShovelGlobalScope = class {
|
|
|
665
889
|
);
|
|
666
890
|
}
|
|
667
891
|
fetch(input, init) {
|
|
668
|
-
|
|
892
|
+
const urlString = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
893
|
+
const isRelative = urlString.startsWith("/") || urlString.startsWith("./");
|
|
894
|
+
if (!isRelative) {
|
|
895
|
+
const originalFetch = this.#originals.fetch;
|
|
896
|
+
return originalFetch(input, init);
|
|
897
|
+
}
|
|
898
|
+
const currentDepth = fetchDepthStorage.get() ?? 0;
|
|
899
|
+
if (currentDepth >= MAX_FETCH_DEPTH) {
|
|
900
|
+
return Promise.reject(
|
|
901
|
+
new Error(`Maximum self-fetch depth (${MAX_FETCH_DEPTH}) exceeded`)
|
|
902
|
+
);
|
|
903
|
+
}
|
|
904
|
+
const request = new Request(new URL(urlString, "http://localhost"), init);
|
|
905
|
+
return fetchDepthStorage.run(currentDepth + 1, () => {
|
|
906
|
+
return this.registration.handleRequest(request);
|
|
907
|
+
});
|
|
669
908
|
}
|
|
670
909
|
queueMicrotask(callback) {
|
|
671
910
|
globalThis.queueMicrotask(callback);
|
|
672
911
|
}
|
|
673
912
|
reportError(e) {
|
|
674
|
-
|
|
913
|
+
self.loggers.open("platform").error`reportError: ${e}`;
|
|
675
914
|
}
|
|
676
915
|
setInterval(handler, timeout, ...args) {
|
|
677
916
|
return globalThis.setInterval(handler, timeout, ...args);
|
|
@@ -703,10 +942,16 @@ var ShovelGlobalScope = class {
|
|
|
703
942
|
onrejectionhandled;
|
|
704
943
|
onunhandledrejection;
|
|
705
944
|
constructor(options) {
|
|
706
|
-
|
|
945
|
+
const g = globalThis;
|
|
946
|
+
this.#originals = {};
|
|
947
|
+
for (const key of PATCHED_KEYS) {
|
|
948
|
+
this.#originals[key] = g[key];
|
|
949
|
+
}
|
|
950
|
+
this.self = globalThis;
|
|
707
951
|
this.registration = options.registration;
|
|
708
952
|
this.caches = options.caches;
|
|
709
|
-
this.
|
|
953
|
+
this.directories = options.directories;
|
|
954
|
+
this.loggers = options.loggers;
|
|
710
955
|
this.#isDevelopment = options.isDevelopment ?? false;
|
|
711
956
|
this.clients = this.#createClientsAPI();
|
|
712
957
|
this.serviceWorker = null;
|
|
@@ -742,28 +987,48 @@ var ShovelGlobalScope = class {
|
|
|
742
987
|
* Allows the ServiceWorker to activate immediately
|
|
743
988
|
*/
|
|
744
989
|
async skipWaiting() {
|
|
745
|
-
|
|
990
|
+
self.loggers.open("platform").info("skipWaiting() called");
|
|
746
991
|
if (!this.#isDevelopment) {
|
|
747
|
-
|
|
748
|
-
"[ServiceWorker] skipWaiting() - production graceful restart not implemented"
|
|
749
|
-
);
|
|
992
|
+
self.loggers.open("platform").info("skipWaiting() - production graceful restart not implemented");
|
|
750
993
|
}
|
|
751
994
|
}
|
|
752
995
|
/**
|
|
753
|
-
* Event target delegation to registration
|
|
996
|
+
* Event target delegation - ServiceWorker events go to registration,
|
|
997
|
+
* other events (like "message" for worker threads) go to native handler
|
|
754
998
|
*/
|
|
755
999
|
addEventListener(type, listener, options) {
|
|
756
|
-
if (listener)
|
|
1000
|
+
if (!listener)
|
|
1001
|
+
return;
|
|
1002
|
+
if (isServiceWorkerEvent(type)) {
|
|
757
1003
|
this.registration.addEventListener(type, listener, options);
|
|
1004
|
+
} else {
|
|
1005
|
+
const original = this.#originals.addEventListener;
|
|
1006
|
+
if (original) {
|
|
1007
|
+
original.call(globalThis, type, listener, options);
|
|
1008
|
+
}
|
|
758
1009
|
}
|
|
759
1010
|
}
|
|
760
1011
|
removeEventListener(type, listener, options) {
|
|
761
|
-
if (listener)
|
|
1012
|
+
if (!listener)
|
|
1013
|
+
return;
|
|
1014
|
+
if (isServiceWorkerEvent(type)) {
|
|
762
1015
|
this.registration.removeEventListener(type, listener, options);
|
|
1016
|
+
} else {
|
|
1017
|
+
const original = this.#originals.removeEventListener;
|
|
1018
|
+
if (original) {
|
|
1019
|
+
original.call(globalThis, type, listener, options);
|
|
1020
|
+
}
|
|
763
1021
|
}
|
|
764
1022
|
}
|
|
765
1023
|
dispatchEvent(event) {
|
|
766
|
-
|
|
1024
|
+
if (isServiceWorkerEvent(event.type)) {
|
|
1025
|
+
return this.registration.dispatchEvent(event);
|
|
1026
|
+
}
|
|
1027
|
+
const original = this.#originals.dispatchEvent;
|
|
1028
|
+
if (original) {
|
|
1029
|
+
return original.call(globalThis, event);
|
|
1030
|
+
}
|
|
1031
|
+
return false;
|
|
767
1032
|
}
|
|
768
1033
|
/**
|
|
769
1034
|
* Create Clients API implementation
|
|
@@ -774,211 +1039,145 @@ var ShovelGlobalScope = class {
|
|
|
774
1039
|
}
|
|
775
1040
|
/**
|
|
776
1041
|
* Install this scope as the global scope
|
|
777
|
-
*
|
|
1042
|
+
* Patches globalThis with ServiceWorker globals while maintaining self === globalThis
|
|
778
1043
|
*/
|
|
779
1044
|
install() {
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
this.postMessage = postMessage.bind(globalThis);
|
|
786
|
-
}
|
|
787
|
-
globalThis.addEventListener = this.addEventListener.bind(this);
|
|
788
|
-
globalThis.removeEventListener = this.removeEventListener.bind(this);
|
|
789
|
-
globalThis.dispatchEvent = this.dispatchEvent.bind(this);
|
|
790
|
-
if (this.caches) {
|
|
791
|
-
globalThis.caches = this.caches;
|
|
792
|
-
}
|
|
793
|
-
if (this.buckets) {
|
|
794
|
-
globalThis.buckets = this.buckets;
|
|
795
|
-
}
|
|
796
|
-
globalThis.registration = this.registration;
|
|
797
|
-
globalThis.skipWaiting = this.skipWaiting.bind(this);
|
|
798
|
-
globalThis.clients = this.clients;
|
|
799
|
-
}
|
|
800
|
-
};
|
|
801
|
-
var logger = getLogger(["worker"]);
|
|
802
|
-
async function initializeWorker() {
|
|
803
|
-
const messagePort = globalThis;
|
|
804
|
-
const sendMessage2 = (message, transfer) => {
|
|
805
|
-
if (transfer && transfer.length > 0) {
|
|
806
|
-
postMessage(message, transfer);
|
|
807
|
-
} else {
|
|
808
|
-
postMessage(message);
|
|
1045
|
+
const g = globalThis;
|
|
1046
|
+
g.WorkerGlobalScope = WorkerGlobalScope;
|
|
1047
|
+
g.DedicatedWorkerGlobalScope = DedicatedWorkerGlobalScope;
|
|
1048
|
+
if (typeof g.self === "undefined") {
|
|
1049
|
+
g.self = globalThis;
|
|
809
1050
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
var buckets;
|
|
824
|
-
async function handleFetchEvent(request) {
|
|
825
|
-
if (!currentApp || !serviceWorkerReady) {
|
|
826
|
-
throw new Error("ServiceWorker not ready");
|
|
827
|
-
}
|
|
828
|
-
if (!registration) {
|
|
829
|
-
throw new Error("ServiceWorker runtime not initialized");
|
|
830
|
-
}
|
|
831
|
-
try {
|
|
832
|
-
const response = await registration.handleRequest(request);
|
|
833
|
-
return response;
|
|
834
|
-
} catch (error) {
|
|
835
|
-
logger.error("[Worker] ServiceWorker request failed", { error });
|
|
836
|
-
console.error("[Worker] ServiceWorker request failed:", error);
|
|
837
|
-
const response = new Response("ServiceWorker request failed", {
|
|
838
|
-
status: 500
|
|
1051
|
+
g.addEventListener = this.addEventListener.bind(this);
|
|
1052
|
+
g.removeEventListener = this.removeEventListener.bind(this);
|
|
1053
|
+
g.dispatchEvent = this.dispatchEvent.bind(this);
|
|
1054
|
+
g.caches = this.caches;
|
|
1055
|
+
g.directories = this.directories;
|
|
1056
|
+
g.loggers = this.loggers;
|
|
1057
|
+
g.registration = this.registration;
|
|
1058
|
+
g.skipWaiting = this.skipWaiting.bind(this);
|
|
1059
|
+
g.clients = this.clients;
|
|
1060
|
+
g.fetch = this.fetch.bind(this);
|
|
1061
|
+
Object.defineProperty(g, "cookieStore", {
|
|
1062
|
+
get: () => cookieStoreStorage.get(),
|
|
1063
|
+
configurable: true
|
|
839
1064
|
});
|
|
840
|
-
return response;
|
|
841
1065
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
logger.info("[Worker] Creating completely fresh ServiceWorker context");
|
|
855
|
-
registration = new ShovelServiceWorkerRegistration();
|
|
856
|
-
if (!caches || !buckets) {
|
|
857
|
-
throw new Error("Runtime not initialized - missing caches or buckets");
|
|
1066
|
+
/**
|
|
1067
|
+
* Restore original globals (for testing)
|
|
1068
|
+
* Reverts all patched globals to their original values
|
|
1069
|
+
*/
|
|
1070
|
+
restore() {
|
|
1071
|
+
const g = globalThis;
|
|
1072
|
+
for (const key of PATCHED_KEYS) {
|
|
1073
|
+
const original = this.#originals[key];
|
|
1074
|
+
if (original === void 0) {
|
|
1075
|
+
delete g[key];
|
|
1076
|
+
} else {
|
|
1077
|
+
g[key] = original;
|
|
858
1078
|
}
|
|
859
|
-
scope = new ShovelGlobalScope({
|
|
860
|
-
registration,
|
|
861
|
-
caches,
|
|
862
|
-
buckets
|
|
863
|
-
});
|
|
864
|
-
scope.install();
|
|
865
|
-
_workerSelf = scope;
|
|
866
|
-
currentApp = null;
|
|
867
|
-
serviceWorkerReady = false;
|
|
868
|
-
}
|
|
869
|
-
if (loadedEntrypoint === entrypoint) {
|
|
870
|
-
logger.info("[Worker] ServiceWorker already loaded for entrypoint", {
|
|
871
|
-
entrypoint
|
|
872
|
-
});
|
|
873
|
-
return;
|
|
874
1079
|
}
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
var SHOVEL_CATEGORIES = [
|
|
1083
|
+
"cli",
|
|
1084
|
+
"build",
|
|
1085
|
+
"platform",
|
|
1086
|
+
"watcher",
|
|
1087
|
+
"worker",
|
|
1088
|
+
"single-threaded",
|
|
1089
|
+
"assets",
|
|
1090
|
+
"platform-node",
|
|
1091
|
+
"platform-bun",
|
|
1092
|
+
"platform-cloudflare",
|
|
1093
|
+
"cache",
|
|
1094
|
+
"cache-redis",
|
|
1095
|
+
"router"
|
|
1096
|
+
];
|
|
1097
|
+
var BUILTIN_SINK_PROVIDERS = {
|
|
1098
|
+
console: { module: "@logtape/logtape", factory: "getConsoleSink" },
|
|
1099
|
+
file: { module: "@logtape/file", factory: "getFileSink" },
|
|
1100
|
+
rotating: { module: "@logtape/file", factory: "getRotatingFileSink" },
|
|
1101
|
+
"stream-file": { module: "@logtape/file", factory: "getStreamFileSink" },
|
|
1102
|
+
otel: { module: "@logtape/otel", factory: "getOpenTelemetrySink" },
|
|
1103
|
+
sentry: { module: "@logtape/sentry", factory: "getSentrySink" },
|
|
1104
|
+
syslog: { module: "@logtape/syslog", factory: "getSyslogSink" },
|
|
1105
|
+
cloudwatch: {
|
|
1106
|
+
module: "@logtape/cloudwatch-logs",
|
|
1107
|
+
factory: "getCloudWatchLogsSink"
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
async function createSink(config) {
|
|
1111
|
+
const { provider, factory: preImportedFactory, ...sinkOptions } = config;
|
|
1112
|
+
if (preImportedFactory) {
|
|
1113
|
+
return preImportedFactory(sinkOptions);
|
|
1114
|
+
}
|
|
1115
|
+
const builtin = BUILTIN_SINK_PROVIDERS[provider];
|
|
1116
|
+
const modulePath = builtin?.module || provider;
|
|
1117
|
+
const factoryName = builtin?.factory || "default";
|
|
1118
|
+
const module = await import(modulePath);
|
|
1119
|
+
const factory = module[factoryName] || module.default;
|
|
1120
|
+
if (!factory) {
|
|
1121
|
+
throw new Error(
|
|
1122
|
+
`Sink module "${modulePath}" has no export "${factoryName}"`
|
|
886
1123
|
);
|
|
887
|
-
} catch (error) {
|
|
888
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
889
|
-
const errorStack = error instanceof Error ? error.stack : void 0;
|
|
890
|
-
logger.error("[Worker] Failed to load ServiceWorker", {
|
|
891
|
-
error: errorMessage,
|
|
892
|
-
stack: errorStack,
|
|
893
|
-
entrypoint
|
|
894
|
-
});
|
|
895
|
-
serviceWorkerReady = false;
|
|
896
|
-
throw error;
|
|
897
1124
|
}
|
|
1125
|
+
return factory(sinkOptions);
|
|
898
1126
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
}
|
|
910
|
-
logger.info(`[Worker-${workerId}] Creating cache storage`);
|
|
911
|
-
caches = new CustomCacheStorage(createCacheFactory({ config }));
|
|
912
|
-
logger.info(`[Worker-${workerId}] Creating bucket storage`);
|
|
913
|
-
buckets = new CustomBucketStorage(createBucketFactory({ baseDir, config }));
|
|
914
|
-
logger.info(`[Worker-${workerId}] Creating and installing scope`);
|
|
915
|
-
registration = new ShovelServiceWorkerRegistration();
|
|
916
|
-
scope = new ShovelGlobalScope({ registration, caches, buckets });
|
|
917
|
-
scope.install();
|
|
918
|
-
_workerSelf = scope;
|
|
919
|
-
logger.info(`[Worker-${workerId}] Runtime initialized successfully`);
|
|
920
|
-
} catch (error) {
|
|
921
|
-
logger.error(`[Worker-${workerId}] Failed to initialize runtime`, { error });
|
|
922
|
-
throw error;
|
|
1127
|
+
async function configureLogging(loggingConfig, options = {}) {
|
|
1128
|
+
const level = loggingConfig.level || "info";
|
|
1129
|
+
const defaultSinkConfigs = loggingConfig.sinks || [{ provider: "console" }];
|
|
1130
|
+
const categories = loggingConfig.categories || {};
|
|
1131
|
+
const reset = options.reset !== false;
|
|
1132
|
+
const sinkByKey = /* @__PURE__ */ new Map();
|
|
1133
|
+
for (const config of defaultSinkConfigs) {
|
|
1134
|
+
const key = JSON.stringify(config);
|
|
1135
|
+
if (!sinkByKey.has(key)) {
|
|
1136
|
+
sinkByKey.set(key, { config, name: `sink_${sinkByKey.size}` });
|
|
1137
|
+
}
|
|
923
1138
|
}
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
logger.info(`[Worker-${workerId}] Sending initialized message`);
|
|
932
|
-
sendMessage({ type: "initialized" });
|
|
933
|
-
} else if (message.type === "load") {
|
|
934
|
-
const loadMsg = message;
|
|
935
|
-
await loadServiceWorker(loadMsg.entrypoint);
|
|
936
|
-
sendMessage({ type: "ready", entrypoint: loadMsg.entrypoint });
|
|
937
|
-
} else if (message.type === "request") {
|
|
938
|
-
const reqMsg = message;
|
|
939
|
-
const request = new Request(reqMsg.request.url, {
|
|
940
|
-
method: reqMsg.request.method,
|
|
941
|
-
headers: reqMsg.request.headers,
|
|
942
|
-
body: reqMsg.request.body
|
|
943
|
-
});
|
|
944
|
-
const response = await handleFetchEvent(request);
|
|
945
|
-
const body = await response.arrayBuffer();
|
|
946
|
-
const headers = Object.fromEntries(response.headers.entries());
|
|
947
|
-
if (!headers["Content-Type"] && !headers["content-type"]) {
|
|
948
|
-
headers["Content-Type"] = "text/plain; charset=utf-8";
|
|
1139
|
+
for (const [_, categoryConfig] of Object.entries(categories)) {
|
|
1140
|
+
if (categoryConfig.sinks) {
|
|
1141
|
+
for (const config of categoryConfig.sinks) {
|
|
1142
|
+
const key = JSON.stringify(config);
|
|
1143
|
+
if (!sinkByKey.has(key)) {
|
|
1144
|
+
sinkByKey.set(key, { config, name: `sink_${sinkByKey.size}` });
|
|
1145
|
+
}
|
|
949
1146
|
}
|
|
950
|
-
|
|
951
|
-
type: "response",
|
|
952
|
-
response: {
|
|
953
|
-
status: response.status,
|
|
954
|
-
statusText: response.statusText,
|
|
955
|
-
headers,
|
|
956
|
-
body
|
|
957
|
-
},
|
|
958
|
-
requestID: reqMsg.requestID
|
|
959
|
-
};
|
|
960
|
-
sendMessage(responseMsg, [body]);
|
|
961
|
-
}
|
|
962
|
-
} catch (error) {
|
|
963
|
-
const errorMsg = {
|
|
964
|
-
type: "error",
|
|
965
|
-
error: error instanceof Error ? error.message : String(error),
|
|
966
|
-
stack: error instanceof Error ? error.stack : void 0,
|
|
967
|
-
requestID: message.requestID
|
|
968
|
-
};
|
|
969
|
-
sendMessage(errorMsg);
|
|
1147
|
+
}
|
|
970
1148
|
}
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1149
|
+
const sinks = {};
|
|
1150
|
+
for (const { config, name } of sinkByKey.values()) {
|
|
1151
|
+
sinks[name] = await createSink(config);
|
|
1152
|
+
}
|
|
1153
|
+
const getSinkNames = (configs) => {
|
|
1154
|
+
return configs.map((config) => sinkByKey.get(JSON.stringify(config))?.name ?? "").filter(Boolean);
|
|
1155
|
+
};
|
|
1156
|
+
const defaultSinkNames = getSinkNames(defaultSinkConfigs);
|
|
1157
|
+
const loggers = SHOVEL_CATEGORIES.map((category) => {
|
|
1158
|
+
const categoryConfig = categories[category];
|
|
1159
|
+
const categoryLevel = categoryConfig?.level || level;
|
|
1160
|
+
const categorySinks = categoryConfig?.sinks ? getSinkNames(categoryConfig.sinks) : defaultSinkNames;
|
|
1161
|
+
return {
|
|
1162
|
+
category: [category],
|
|
1163
|
+
level: categoryLevel,
|
|
1164
|
+
sinks: categorySinks
|
|
1165
|
+
};
|
|
1166
|
+
});
|
|
1167
|
+
loggers.push({
|
|
1168
|
+
category: ["logtape", "meta"],
|
|
1169
|
+
level: "warning",
|
|
1170
|
+
sinks: []
|
|
1171
|
+
});
|
|
1172
|
+
await configure({
|
|
1173
|
+
reset,
|
|
1174
|
+
sinks,
|
|
1175
|
+
loggers
|
|
978
1176
|
});
|
|
979
1177
|
}
|
|
980
1178
|
export {
|
|
981
1179
|
ActivateEvent,
|
|
1180
|
+
CustomLoggerStorage,
|
|
982
1181
|
DedicatedWorkerGlobalScope,
|
|
983
1182
|
ExtendableEvent,
|
|
984
1183
|
ExtendableMessageEvent,
|
|
@@ -987,9 +1186,10 @@ export {
|
|
|
987
1186
|
Notification,
|
|
988
1187
|
NotificationEvent,
|
|
989
1188
|
PushEvent,
|
|
1189
|
+
RequestCookieStore,
|
|
1190
|
+
ServiceWorkerGlobals,
|
|
990
1191
|
ShovelClient,
|
|
991
1192
|
ShovelClients,
|
|
992
|
-
ShovelGlobalScope,
|
|
993
1193
|
ShovelNavigationPreloadManager,
|
|
994
1194
|
ShovelPushMessageData,
|
|
995
1195
|
ShovelServiceWorker,
|
|
@@ -997,5 +1197,9 @@ export {
|
|
|
997
1197
|
ShovelServiceWorkerRegistration,
|
|
998
1198
|
ShovelWindowClient,
|
|
999
1199
|
SyncEvent,
|
|
1000
|
-
WorkerGlobalScope
|
|
1200
|
+
WorkerGlobalScope,
|
|
1201
|
+
configureLogging,
|
|
1202
|
+
parseCookieHeader,
|
|
1203
|
+
parseSetCookieHeader,
|
|
1204
|
+
serializeCookie
|
|
1001
1205
|
};
|