@comapeo/map-server 1.0.0-pre.0
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 +610 -0
- package/dist/context.d.ts +46 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +181 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +112 -0
- package/dist/lib/constants.d.ts +7 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +6 -0
- package/dist/lib/download-request.d.ts +17 -0
- package/dist/lib/download-request.d.ts.map +1 -0
- package/dist/lib/download-request.js +113 -0
- package/dist/lib/errors.d.ts +88 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/errors.js +158 -0
- package/dist/lib/event-stream-response.d.ts +17 -0
- package/dist/lib/event-stream-response.d.ts.map +1 -0
- package/dist/lib/event-stream-response.js +39 -0
- package/dist/lib/event-target.d.ts +9 -0
- package/dist/lib/event-target.d.ts.map +1 -0
- package/dist/lib/event-target.js +4 -0
- package/dist/lib/fetch-api.d.ts +3 -0
- package/dist/lib/fetch-api.d.ts.map +1 -0
- package/dist/lib/fetch-api.js +16 -0
- package/dist/lib/map-share.d.ts +52 -0
- package/dist/lib/map-share.d.ts.map +1 -0
- package/dist/lib/map-share.js +142 -0
- package/dist/lib/secret-stream-fetch.d.ts +7 -0
- package/dist/lib/secret-stream-fetch.d.ts.map +1 -0
- package/dist/lib/secret-stream-fetch.js +34 -0
- package/dist/lib/self-evicting-map.d.ts +16 -0
- package/dist/lib/self-evicting-map.d.ts.map +1 -0
- package/dist/lib/self-evicting-map.js +29 -0
- package/dist/lib/state-update-event.d.ts +8 -0
- package/dist/lib/state-update-event.d.ts.map +1 -0
- package/dist/lib/state-update-event.js +10 -0
- package/dist/lib/utils.d.ts +32 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +96 -0
- package/dist/middlewares/localhost-only.d.ts +11 -0
- package/dist/middlewares/localhost-only.d.ts.map +1 -0
- package/dist/middlewares/localhost-only.js +10 -0
- package/dist/middlewares/parse-request.d.ts +11 -0
- package/dist/middlewares/parse-request.d.ts.map +1 -0
- package/dist/middlewares/parse-request.js +25 -0
- package/dist/routes/downloads.d.ts +15 -0
- package/dist/routes/downloads.d.ts.map +1 -0
- package/dist/routes/downloads.js +60 -0
- package/dist/routes/map-shares.d.ts +19 -0
- package/dist/routes/map-shares.d.ts.map +1 -0
- package/dist/routes/map-shares.js +192 -0
- package/dist/routes/maps.d.ts +6 -0
- package/dist/routes/maps.d.ts.map +1 -0
- package/dist/routes/maps.js +118 -0
- package/dist/routes/root.d.ts +6 -0
- package/dist/routes/root.d.ts.map +1 -0
- package/dist/routes/root.js +29 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +96 -0
- package/node_modules/@envelop/instrumentation/LICENSE +21 -0
- package/node_modules/@envelop/instrumentation/README.md +30 -0
- package/node_modules/@envelop/instrumentation/cjs/index.js +5 -0
- package/node_modules/@envelop/instrumentation/cjs/instrumentation.js +89 -0
- package/node_modules/@envelop/instrumentation/cjs/package.json +1 -0
- package/node_modules/@envelop/instrumentation/esm/index.js +2 -0
- package/node_modules/@envelop/instrumentation/esm/instrumentation.js +82 -0
- package/node_modules/@envelop/instrumentation/package.json +57 -0
- package/node_modules/@envelop/instrumentation/typings/index.d.cts +1 -0
- package/node_modules/@envelop/instrumentation/typings/index.d.ts +1 -0
- package/node_modules/@envelop/instrumentation/typings/instrumentation.d.cts +44 -0
- package/node_modules/@envelop/instrumentation/typings/instrumentation.d.ts +44 -0
- package/node_modules/@whatwg-node/disposablestack/cjs/AsyncDisposableStack.js +73 -0
- package/node_modules/@whatwg-node/disposablestack/cjs/DisposableStack.js +62 -0
- package/node_modules/@whatwg-node/disposablestack/cjs/SupressedError.js +16 -0
- package/node_modules/@whatwg-node/disposablestack/cjs/index.js +11 -0
- package/node_modules/@whatwg-node/disposablestack/cjs/package.json +1 -0
- package/node_modules/@whatwg-node/disposablestack/cjs/symbols.js +20 -0
- package/node_modules/@whatwg-node/disposablestack/cjs/utils.js +11 -0
- package/node_modules/@whatwg-node/disposablestack/esm/AsyncDisposableStack.js +69 -0
- package/node_modules/@whatwg-node/disposablestack/esm/DisposableStack.js +58 -0
- package/node_modules/@whatwg-node/disposablestack/esm/SupressedError.js +12 -0
- package/node_modules/@whatwg-node/disposablestack/esm/index.js +7 -0
- package/node_modules/@whatwg-node/disposablestack/esm/symbols.js +16 -0
- package/node_modules/@whatwg-node/disposablestack/esm/utils.js +7 -0
- package/node_modules/@whatwg-node/disposablestack/package.json +44 -0
- package/node_modules/@whatwg-node/disposablestack/typings/AsyncDisposableStack.d.cts +15 -0
- package/node_modules/@whatwg-node/disposablestack/typings/AsyncDisposableStack.d.ts +15 -0
- package/node_modules/@whatwg-node/disposablestack/typings/DisposableStack.d.cts +14 -0
- package/node_modules/@whatwg-node/disposablestack/typings/DisposableStack.d.ts +14 -0
- package/node_modules/@whatwg-node/disposablestack/typings/SupressedError.d.cts +5 -0
- package/node_modules/@whatwg-node/disposablestack/typings/SupressedError.d.ts +5 -0
- package/node_modules/@whatwg-node/disposablestack/typings/index.d.cts +4 -0
- package/node_modules/@whatwg-node/disposablestack/typings/index.d.ts +4 -0
- package/node_modules/@whatwg-node/disposablestack/typings/symbols.d.cts +5 -0
- package/node_modules/@whatwg-node/disposablestack/typings/symbols.d.ts +5 -0
- package/node_modules/@whatwg-node/disposablestack/typings/utils.d.cts +2 -0
- package/node_modules/@whatwg-node/disposablestack/typings/utils.d.ts +2 -0
- package/node_modules/@whatwg-node/promise-helpers/cjs/index.js +270 -0
- package/node_modules/@whatwg-node/promise-helpers/cjs/package.json +1 -0
- package/node_modules/@whatwg-node/promise-helpers/esm/index.js +257 -0
- package/node_modules/@whatwg-node/promise-helpers/package.json +43 -0
- package/node_modules/@whatwg-node/promise-helpers/typings/index.d.cts +31 -0
- package/node_modules/@whatwg-node/promise-helpers/typings/index.d.ts +31 -0
- package/node_modules/@whatwg-node/server/README.md +590 -0
- package/node_modules/@whatwg-node/server/cjs/createServerAdapter.js +368 -0
- package/node_modules/@whatwg-node/server/cjs/index.js +17 -0
- package/node_modules/@whatwg-node/server/cjs/package.json +1 -0
- package/node_modules/@whatwg-node/server/cjs/plugins/types.js +0 -0
- package/node_modules/@whatwg-node/server/cjs/plugins/useContentEncoding.js +73 -0
- package/node_modules/@whatwg-node/server/cjs/plugins/useCors.js +124 -0
- package/node_modules/@whatwg-node/server/cjs/plugins/useErrorHandling.js +52 -0
- package/node_modules/@whatwg-node/server/cjs/types.js +0 -0
- package/node_modules/@whatwg-node/server/cjs/utils.js +599 -0
- package/node_modules/@whatwg-node/server/cjs/uwebsockets.js +241 -0
- package/node_modules/@whatwg-node/server/esm/createServerAdapter.js +365 -0
- package/node_modules/@whatwg-node/server/esm/index.js +11 -0
- package/node_modules/@whatwg-node/server/esm/plugins/types.js +0 -0
- package/node_modules/@whatwg-node/server/esm/plugins/useContentEncoding.js +70 -0
- package/node_modules/@whatwg-node/server/esm/plugins/useCors.js +120 -0
- package/node_modules/@whatwg-node/server/esm/plugins/useErrorHandling.js +46 -0
- package/node_modules/@whatwg-node/server/esm/types.js +0 -0
- package/node_modules/@whatwg-node/server/esm/utils.js +588 -0
- package/node_modules/@whatwg-node/server/esm/uwebsockets.js +234 -0
- package/node_modules/@whatwg-node/server/package.json +46 -0
- package/node_modules/@whatwg-node/server/typings/createServerAdapter.d.cts +19 -0
- package/node_modules/@whatwg-node/server/typings/createServerAdapter.d.ts +19 -0
- package/node_modules/@whatwg-node/server/typings/index.d.cts +11 -0
- package/node_modules/@whatwg-node/server/typings/index.d.ts +11 -0
- package/node_modules/@whatwg-node/server/typings/plugins/types.d.cts +76 -0
- package/node_modules/@whatwg-node/server/typings/plugins/types.d.ts +76 -0
- package/node_modules/@whatwg-node/server/typings/plugins/useContentEncoding.d.cts +2 -0
- package/node_modules/@whatwg-node/server/typings/plugins/useContentEncoding.d.ts +2 -0
- package/node_modules/@whatwg-node/server/typings/plugins/useCors.d.cts +14 -0
- package/node_modules/@whatwg-node/server/typings/plugins/useCors.d.ts +14 -0
- package/node_modules/@whatwg-node/server/typings/plugins/useErrorHandling.d.cts +13 -0
- package/node_modules/@whatwg-node/server/typings/plugins/useErrorHandling.d.ts +13 -0
- package/node_modules/@whatwg-node/server/typings/types.d.cts +100 -0
- package/node_modules/@whatwg-node/server/typings/types.d.ts +100 -0
- package/node_modules/@whatwg-node/server/typings/utils.d.cts +42 -0
- package/node_modules/@whatwg-node/server/typings/utils.d.ts +42 -0
- package/node_modules/@whatwg-node/server/typings/uwebsockets.d.cts +32 -0
- package/node_modules/@whatwg-node/server/typings/uwebsockets.d.ts +32 -0
- package/node_modules/tslib/CopyrightNotice.txt +15 -0
- package/node_modules/tslib/LICENSE.txt +12 -0
- package/node_modules/tslib/README.md +164 -0
- package/node_modules/tslib/SECURITY.md +41 -0
- package/node_modules/tslib/modules/index.d.ts +38 -0
- package/node_modules/tslib/modules/index.js +70 -0
- package/node_modules/tslib/modules/package.json +3 -0
- package/node_modules/tslib/package.json +47 -0
- package/node_modules/tslib/tslib.d.ts +460 -0
- package/node_modules/tslib/tslib.es6.html +1 -0
- package/node_modules/tslib/tslib.es6.js +402 -0
- package/node_modules/tslib/tslib.es6.mjs +401 -0
- package/node_modules/tslib/tslib.html +1 -0
- package/node_modules/tslib/tslib.js +484 -0
- package/package.json +87 -0
- package/src/context.ts +203 -0
- package/src/index.ts +193 -0
- package/src/lib/constants.ts +6 -0
- package/src/lib/download-request.ts +142 -0
- package/src/lib/errors.ts +187 -0
- package/src/lib/event-stream-response.ts +57 -0
- package/src/lib/event-target.ts +11 -0
- package/src/lib/fetch-api.ts +18 -0
- package/src/lib/map-share.ts +185 -0
- package/src/lib/secret-stream-fetch.ts +42 -0
- package/src/lib/self-evicting-map.ts +35 -0
- package/src/lib/state-update-event.ts +14 -0
- package/src/lib/utils.ts +110 -0
- package/src/middlewares/localhost-only.ts +16 -0
- package/src/middlewares/parse-request.ts +34 -0
- package/src/routes/downloads.ts +92 -0
- package/src/routes/map-shares.ts +246 -0
- package/src/routes/maps.ts +146 -0
- package/src/routes/root.ts +37 -0
- package/src/types.ts +152 -0
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
import { createDeferredPromise, fakePromise, handleMaybePromise, isPromise, } from '@whatwg-node/promise-helpers';
|
|
2
|
+
export { isPromise, createDeferredPromise };
|
|
3
|
+
export function isAsyncIterable(body) {
|
|
4
|
+
return (body != null && typeof body === 'object' && typeof body[Symbol.asyncIterator] === 'function');
|
|
5
|
+
}
|
|
6
|
+
function getPort(nodeRequest) {
|
|
7
|
+
if (nodeRequest.socket?.localPort) {
|
|
8
|
+
return nodeRequest.socket?.localPort;
|
|
9
|
+
}
|
|
10
|
+
const hostInHeader = nodeRequest.headers?.[':authority'] || nodeRequest.headers?.host;
|
|
11
|
+
const portInHeader = hostInHeader?.split(':')?.[1];
|
|
12
|
+
if (portInHeader) {
|
|
13
|
+
return portInHeader;
|
|
14
|
+
}
|
|
15
|
+
return 80;
|
|
16
|
+
}
|
|
17
|
+
function getHostnameWithPort(nodeRequest) {
|
|
18
|
+
if (nodeRequest.headers?.[':authority']) {
|
|
19
|
+
return nodeRequest.headers?.[':authority'];
|
|
20
|
+
}
|
|
21
|
+
if (nodeRequest.headers?.host) {
|
|
22
|
+
return nodeRequest.headers?.host;
|
|
23
|
+
}
|
|
24
|
+
const port = getPort(nodeRequest);
|
|
25
|
+
if (nodeRequest.hostname) {
|
|
26
|
+
return nodeRequest.hostname + ':' + port;
|
|
27
|
+
}
|
|
28
|
+
const localIp = nodeRequest.socket?.localAddress;
|
|
29
|
+
if (localIp && !localIp?.includes('::') && !localIp?.includes('ffff')) {
|
|
30
|
+
return `${localIp}:${port}`;
|
|
31
|
+
}
|
|
32
|
+
return 'localhost';
|
|
33
|
+
}
|
|
34
|
+
function buildFullUrl(nodeRequest) {
|
|
35
|
+
const hostnameWithPort = getHostnameWithPort(nodeRequest);
|
|
36
|
+
const protocol = nodeRequest.protocol || (nodeRequest.socket?.encrypted ? 'https' : 'http');
|
|
37
|
+
const endpoint = nodeRequest.originalUrl || nodeRequest.url || '/graphql';
|
|
38
|
+
return `${protocol}://${hostnameWithPort}${endpoint}`;
|
|
39
|
+
}
|
|
40
|
+
function isRequestBody(body) {
|
|
41
|
+
const stringTag = body[Symbol.toStringTag];
|
|
42
|
+
if (typeof body === 'string' ||
|
|
43
|
+
stringTag === 'Uint8Array' ||
|
|
44
|
+
stringTag === 'Blob' ||
|
|
45
|
+
stringTag === 'FormData' ||
|
|
46
|
+
stringTag === 'URLSearchParams' ||
|
|
47
|
+
isAsyncIterable(body)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
export function normalizeNodeRequest(nodeRequest, fetchAPI, nodeResponse, __useCustomAbortCtrl) {
|
|
53
|
+
const rawRequest = nodeRequest.raw || nodeRequest.req || nodeRequest;
|
|
54
|
+
let fullUrl = buildFullUrl(rawRequest);
|
|
55
|
+
if (nodeRequest.query) {
|
|
56
|
+
const url = new fetchAPI.URL(fullUrl);
|
|
57
|
+
for (const key in nodeRequest.query) {
|
|
58
|
+
url.searchParams.set(key, nodeRequest.query[key]);
|
|
59
|
+
}
|
|
60
|
+
fullUrl = url.toString();
|
|
61
|
+
}
|
|
62
|
+
let normalizedHeaders = nodeRequest.headers;
|
|
63
|
+
if (nodeRequest.headers?.[':method']) {
|
|
64
|
+
normalizedHeaders = {};
|
|
65
|
+
for (const key in nodeRequest.headers) {
|
|
66
|
+
if (!key.startsWith(':')) {
|
|
67
|
+
normalizedHeaders[key] = nodeRequest.headers[key];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const controller = __useCustomAbortCtrl
|
|
72
|
+
? createCustomAbortControllerSignal()
|
|
73
|
+
: new AbortController();
|
|
74
|
+
if (nodeResponse?.once) {
|
|
75
|
+
const closeEventListener = () => {
|
|
76
|
+
if (!controller.signal.aborted) {
|
|
77
|
+
Object.defineProperty(rawRequest, 'aborted', { value: true });
|
|
78
|
+
controller.abort(nodeResponse.errored ?? undefined);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
nodeResponse.once('error', closeEventListener);
|
|
82
|
+
nodeResponse.once('close', closeEventListener);
|
|
83
|
+
nodeResponse.once('finish', () => {
|
|
84
|
+
nodeResponse.removeListener('close', closeEventListener);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (nodeRequest.method === 'GET' || nodeRequest.method === 'HEAD') {
|
|
88
|
+
return new fetchAPI.Request(fullUrl, {
|
|
89
|
+
method: nodeRequest.method,
|
|
90
|
+
headers: normalizedHeaders,
|
|
91
|
+
signal: controller.signal,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Some Node server frameworks like Serverless Express sends a dummy object with body but as a Buffer not string
|
|
96
|
+
* so we do those checks to see is there something we can use directly as BodyInit
|
|
97
|
+
* because the presence of body means the request stream is already consumed and,
|
|
98
|
+
* rawRequest cannot be used as BodyInit/ReadableStream by Fetch API in this case.
|
|
99
|
+
*/
|
|
100
|
+
const maybeParsedBody = nodeRequest.body;
|
|
101
|
+
if (maybeParsedBody != null && Object.keys(maybeParsedBody).length > 0) {
|
|
102
|
+
if (isRequestBody(maybeParsedBody)) {
|
|
103
|
+
return new fetchAPI.Request(fullUrl, {
|
|
104
|
+
method: nodeRequest.method || 'GET',
|
|
105
|
+
headers: normalizedHeaders,
|
|
106
|
+
body: maybeParsedBody,
|
|
107
|
+
signal: controller.signal,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const request = new fetchAPI.Request(fullUrl, {
|
|
111
|
+
method: nodeRequest.method || 'GET',
|
|
112
|
+
headers: normalizedHeaders,
|
|
113
|
+
signal: controller.signal,
|
|
114
|
+
});
|
|
115
|
+
if (!request.headers.get('content-type')?.includes('json')) {
|
|
116
|
+
request.headers.set('content-type', 'application/json; charset=utf-8');
|
|
117
|
+
}
|
|
118
|
+
return new Proxy(request, {
|
|
119
|
+
get: (target, prop, receiver) => {
|
|
120
|
+
switch (prop) {
|
|
121
|
+
case 'json':
|
|
122
|
+
return () => fakePromise(maybeParsedBody);
|
|
123
|
+
case 'text':
|
|
124
|
+
return () => fakePromise(JSON.stringify(maybeParsedBody));
|
|
125
|
+
default:
|
|
126
|
+
if (globalThis.Bun) {
|
|
127
|
+
// workaround for https://github.com/oven-sh/bun/issues/12368
|
|
128
|
+
// Proxy.get doesn't seem to get `receiver` correctly
|
|
129
|
+
return Reflect.get(target, prop);
|
|
130
|
+
}
|
|
131
|
+
return Reflect.get(target, prop, receiver);
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// perf: instead of spreading the object, we can just pass it as is and it performs better
|
|
137
|
+
return new fetchAPI.Request(fullUrl, {
|
|
138
|
+
method: nodeRequest.method,
|
|
139
|
+
headers: normalizedHeaders,
|
|
140
|
+
signal: controller.signal,
|
|
141
|
+
// @ts-expect-error - AsyncIterable is supported as body
|
|
142
|
+
body: rawRequest,
|
|
143
|
+
duplex: 'half',
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
export function isReadable(stream) {
|
|
147
|
+
return stream.read != null;
|
|
148
|
+
}
|
|
149
|
+
export function isNodeRequest(request) {
|
|
150
|
+
return isReadable(request);
|
|
151
|
+
}
|
|
152
|
+
export function isServerResponse(stream) {
|
|
153
|
+
// Check all used functions are defined
|
|
154
|
+
return (stream != null &&
|
|
155
|
+
stream.setHeader != null &&
|
|
156
|
+
stream.end != null &&
|
|
157
|
+
stream.once != null &&
|
|
158
|
+
stream.write != null);
|
|
159
|
+
}
|
|
160
|
+
export function isReadableStream(stream) {
|
|
161
|
+
return stream != null && stream.getReader != null;
|
|
162
|
+
}
|
|
163
|
+
export function isFetchEvent(event) {
|
|
164
|
+
return event != null && event.request != null && event.respondWith != null;
|
|
165
|
+
}
|
|
166
|
+
function configureSocket(rawRequest) {
|
|
167
|
+
rawRequest?.socket?.setTimeout?.(0);
|
|
168
|
+
rawRequest?.socket?.setNoDelay?.(true);
|
|
169
|
+
rawRequest?.socket?.setKeepAlive?.(true);
|
|
170
|
+
}
|
|
171
|
+
function endResponse(serverResponse) {
|
|
172
|
+
// @ts-expect-error Avoid arguments adaptor trampoline https://v8.dev/blog/adaptor-frame
|
|
173
|
+
serverResponse.end(null, null, null);
|
|
174
|
+
}
|
|
175
|
+
function sendAsyncIterable(serverResponse, asyncIterable) {
|
|
176
|
+
let closed = false;
|
|
177
|
+
const closeEventListener = () => {
|
|
178
|
+
closed = true;
|
|
179
|
+
};
|
|
180
|
+
serverResponse.once('error', closeEventListener);
|
|
181
|
+
serverResponse.once('close', closeEventListener);
|
|
182
|
+
serverResponse.once('finish', () => {
|
|
183
|
+
serverResponse.removeListener('close', closeEventListener);
|
|
184
|
+
serverResponse.removeListener('error', closeEventListener);
|
|
185
|
+
});
|
|
186
|
+
const iterator = asyncIterable[Symbol.asyncIterator]();
|
|
187
|
+
const pump = () => iterator.next().then(({ done, value }) => {
|
|
188
|
+
if (closed || done) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
return handleMaybePromise(() => safeWrite(value, serverResponse), () => (closed ? endResponse(serverResponse) : pump()));
|
|
192
|
+
});
|
|
193
|
+
return pump();
|
|
194
|
+
}
|
|
195
|
+
function safeWrite(chunk, serverResponse) {
|
|
196
|
+
// @ts-expect-error http and http2 writes are actually compatible
|
|
197
|
+
const result = serverResponse.write(chunk);
|
|
198
|
+
if (!result) {
|
|
199
|
+
return new Promise(resolve => serverResponse.once('drain', resolve));
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const isNode1x = globalThis.process?.versions?.node?.startsWith('1');
|
|
203
|
+
export function sendNodeResponse(fetchResponse, serverResponse, nodeRequest, __useSingleWriteHead) {
|
|
204
|
+
if (serverResponse.closed || serverResponse.destroyed || serverResponse.writableEnded) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (!fetchResponse) {
|
|
208
|
+
serverResponse.statusCode = 404;
|
|
209
|
+
endResponse(serverResponse);
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
if (__useSingleWriteHead &&
|
|
213
|
+
// @ts-expect-error - headersInit is a private property
|
|
214
|
+
fetchResponse.headers?.headersInit &&
|
|
215
|
+
// @ts-expect-error - headersInit is a private property
|
|
216
|
+
!Array.isArray(fetchResponse.headers.headersInit) &&
|
|
217
|
+
// @ts-expect-error - headersInit is a private property
|
|
218
|
+
!fetchResponse.headers.headersInit.get &&
|
|
219
|
+
// @ts-expect-error - map is a private property
|
|
220
|
+
!fetchResponse.headers._map &&
|
|
221
|
+
// @ts-expect-error - _setCookies is a private property
|
|
222
|
+
!fetchResponse.headers._setCookies?.length) {
|
|
223
|
+
// @ts-expect-error - writeHead accepts headers object
|
|
224
|
+
serverResponse.writeHead(fetchResponse.status, fetchResponse.statusText,
|
|
225
|
+
// @ts-expect-error - headersInit is a private property
|
|
226
|
+
fetchResponse.headers.headersInit);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Avoid using `setHeaders` on Node.js 18 as it is broken with multiple headers with the same name
|
|
230
|
+
// @ts-expect-error - setHeaders exist
|
|
231
|
+
if (serverResponse.setHeaders && !isNode1x) {
|
|
232
|
+
// @ts-expect-error - writeHead bad typings
|
|
233
|
+
serverResponse.setHeaders(fetchResponse.headers);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
let setCookiesSet = false;
|
|
237
|
+
fetchResponse.headers.forEach((value, key) => {
|
|
238
|
+
if (key === 'set-cookie') {
|
|
239
|
+
if (setCookiesSet) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
setCookiesSet = true;
|
|
243
|
+
const setCookies = fetchResponse.headers.getSetCookie?.();
|
|
244
|
+
if (setCookies) {
|
|
245
|
+
serverResponse.setHeader('set-cookie', setCookies);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
serverResponse.setHeader(key, value);
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
// @ts-expect-error - writeHead bad typings
|
|
253
|
+
serverResponse.writeHead(fetchResponse.status, fetchResponse.statusText);
|
|
254
|
+
}
|
|
255
|
+
// @ts-expect-error - Handle the case where the response is a string
|
|
256
|
+
if (fetchResponse['bodyType'] === 'String') {
|
|
257
|
+
return handleMaybePromise(
|
|
258
|
+
// @ts-expect-error - bodyInit is a private property
|
|
259
|
+
() => safeWrite(fetchResponse.bodyInit, serverResponse), () => endResponse(serverResponse));
|
|
260
|
+
}
|
|
261
|
+
// Optimizations for node-fetch
|
|
262
|
+
const bufOfRes =
|
|
263
|
+
// @ts-expect-error - _buffer is a private property
|
|
264
|
+
fetchResponse._buffer;
|
|
265
|
+
if (bufOfRes) {
|
|
266
|
+
return handleMaybePromise(() => safeWrite(bufOfRes, serverResponse), () => endResponse(serverResponse));
|
|
267
|
+
}
|
|
268
|
+
// Other fetch implementations
|
|
269
|
+
const fetchBody = fetchResponse.body;
|
|
270
|
+
if (fetchBody == null) {
|
|
271
|
+
endResponse(serverResponse);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
if (
|
|
275
|
+
// @ts-expect-error - Uint8Array is a valid body type
|
|
276
|
+
fetchBody[Symbol.toStringTag] === 'Uint8Array') {
|
|
277
|
+
return handleMaybePromise(() => safeWrite(fetchBody, serverResponse), () => endResponse(serverResponse));
|
|
278
|
+
}
|
|
279
|
+
configureSocket(nodeRequest);
|
|
280
|
+
if (isReadable(fetchBody)) {
|
|
281
|
+
serverResponse.once('close', () => {
|
|
282
|
+
fetchBody.destroy();
|
|
283
|
+
});
|
|
284
|
+
fetchBody.pipe(serverResponse, {
|
|
285
|
+
end: true,
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (isReadableStream(fetchBody)) {
|
|
290
|
+
return sendReadableStream(nodeRequest, serverResponse, fetchBody);
|
|
291
|
+
}
|
|
292
|
+
if (isAsyncIterable(fetchBody)) {
|
|
293
|
+
return sendAsyncIterable(serverResponse, fetchBody);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
function sendReadableStream(nodeRequest, serverResponse, readableStream) {
|
|
297
|
+
const reader = readableStream.getReader();
|
|
298
|
+
nodeRequest?.once?.('error', err => {
|
|
299
|
+
reader.cancel(err).catch(() => {});
|
|
300
|
+
});
|
|
301
|
+
function pump() {
|
|
302
|
+
return reader
|
|
303
|
+
.read()
|
|
304
|
+
.then(({ done, value }) => done
|
|
305
|
+
? endResponse(serverResponse)
|
|
306
|
+
: handleMaybePromise(() => safeWrite(value, serverResponse), pump))
|
|
307
|
+
.catch(err => {
|
|
308
|
+
// If stream was aborted (e.g., via cancel()), destroy the socket with RST
|
|
309
|
+
if (err?.name === 'AbortError') {
|
|
310
|
+
if (!serverResponse.destroyed) {
|
|
311
|
+
serverResponse.destroy();
|
|
312
|
+
}
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
// For other errors, re-throw to be handled by the request handler
|
|
316
|
+
throw err;
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return pump();
|
|
320
|
+
}
|
|
321
|
+
export function isRequestInit(val) {
|
|
322
|
+
return (val != null &&
|
|
323
|
+
typeof val === 'object' &&
|
|
324
|
+
('body' in val ||
|
|
325
|
+
'cache' in val ||
|
|
326
|
+
'credentials' in val ||
|
|
327
|
+
'headers' in val ||
|
|
328
|
+
'integrity' in val ||
|
|
329
|
+
'keepalive' in val ||
|
|
330
|
+
'method' in val ||
|
|
331
|
+
'mode' in val ||
|
|
332
|
+
'redirect' in val ||
|
|
333
|
+
'referrer' in val ||
|
|
334
|
+
'referrerPolicy' in val ||
|
|
335
|
+
'signal' in val ||
|
|
336
|
+
'window' in val));
|
|
337
|
+
}
|
|
338
|
+
// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#copying_accessors
|
|
339
|
+
export function completeAssign(...args) {
|
|
340
|
+
const [target, ...sources] = args.filter(arg => arg != null && typeof arg === 'object');
|
|
341
|
+
sources.forEach(source => {
|
|
342
|
+
// modified Object.keys to Object.getOwnPropertyNames
|
|
343
|
+
// because Object.keys only returns enumerable properties
|
|
344
|
+
const descriptors = Object.getOwnPropertyNames(source).reduce((descriptors, key) => {
|
|
345
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, key);
|
|
346
|
+
if (descriptor) {
|
|
347
|
+
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
|
|
348
|
+
}
|
|
349
|
+
return descriptors;
|
|
350
|
+
}, {});
|
|
351
|
+
// By default, Object.assign copies enumerable Symbols, too
|
|
352
|
+
Object.getOwnPropertySymbols(source).forEach(sym => {
|
|
353
|
+
const descriptor = Object.getOwnPropertyDescriptor(source, sym);
|
|
354
|
+
if (descriptor?.enumerable) {
|
|
355
|
+
descriptors[sym] = descriptor;
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
Object.defineProperties(target, descriptors);
|
|
359
|
+
});
|
|
360
|
+
return target;
|
|
361
|
+
}
|
|
362
|
+
export { iterateAsyncVoid } from '@whatwg-node/promise-helpers';
|
|
363
|
+
export function handleErrorFromRequestHandler(error, ResponseCtor) {
|
|
364
|
+
return new ResponseCtor(error.stack || error.message || error.toString(), {
|
|
365
|
+
status: error.status || 500,
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
export function isolateObject(originalCtx, waitUntilFn) {
|
|
369
|
+
if (originalCtx == null) {
|
|
370
|
+
if (waitUntilFn == null) {
|
|
371
|
+
return {};
|
|
372
|
+
}
|
|
373
|
+
return {
|
|
374
|
+
waitUntil: waitUntilFn,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
return completeAssign(Object.create(originalCtx), {
|
|
378
|
+
waitUntil: waitUntilFn,
|
|
379
|
+
}, originalCtx);
|
|
380
|
+
}
|
|
381
|
+
export function handleAbortSignalAndPromiseResponse(response$, abortSignal) {
|
|
382
|
+
if (abortSignal?.aborted) {
|
|
383
|
+
throw abortSignal.reason;
|
|
384
|
+
}
|
|
385
|
+
if (isPromise(response$) && abortSignal) {
|
|
386
|
+
const deferred$ = createDeferredPromise();
|
|
387
|
+
function abortSignalFetchErrorHandler() {
|
|
388
|
+
deferred$.reject(abortSignal.reason);
|
|
389
|
+
}
|
|
390
|
+
abortSignal.addEventListener('abort', abortSignalFetchErrorHandler, { once: true });
|
|
391
|
+
response$
|
|
392
|
+
.then(function fetchSuccessHandler(res) {
|
|
393
|
+
deferred$.resolve(res);
|
|
394
|
+
})
|
|
395
|
+
.catch(function fetchErrorHandler(err) {
|
|
396
|
+
deferred$.reject(err);
|
|
397
|
+
})
|
|
398
|
+
.finally(() => {
|
|
399
|
+
abortSignal.removeEventListener('abort', abortSignalFetchErrorHandler);
|
|
400
|
+
});
|
|
401
|
+
return deferred$.promise;
|
|
402
|
+
}
|
|
403
|
+
return response$;
|
|
404
|
+
}
|
|
405
|
+
export const decompressedResponseMap = new WeakMap();
|
|
406
|
+
const supportedEncodingsByFetchAPI = new WeakMap();
|
|
407
|
+
export function getSupportedEncodings(fetchAPI) {
|
|
408
|
+
let supportedEncodings = supportedEncodingsByFetchAPI.get(fetchAPI);
|
|
409
|
+
if (!supportedEncodings) {
|
|
410
|
+
const possibleEncodings = [
|
|
411
|
+
'deflate',
|
|
412
|
+
'gzip',
|
|
413
|
+
'deflate-raw',
|
|
414
|
+
'br',
|
|
415
|
+
'zstd',
|
|
416
|
+
];
|
|
417
|
+
if (fetchAPI.DecompressionStream?.['supportedFormats']) {
|
|
418
|
+
supportedEncodings = fetchAPI.DecompressionStream['supportedFormats'];
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
supportedEncodings = possibleEncodings.filter(encoding => {
|
|
422
|
+
// deflate-raw is not supported in Node.js >v20
|
|
423
|
+
if (globalThis.process?.version?.startsWith('v2') &&
|
|
424
|
+
fetchAPI.DecompressionStream === globalThis.DecompressionStream &&
|
|
425
|
+
encoding === 'deflate-raw') {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
// eslint-disable-next-line no-new
|
|
430
|
+
new fetchAPI.DecompressionStream(encoding);
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
supportedEncodingsByFetchAPI.set(fetchAPI, supportedEncodings);
|
|
439
|
+
}
|
|
440
|
+
return supportedEncodings;
|
|
441
|
+
}
|
|
442
|
+
export function handleResponseDecompression(response, fetchAPI) {
|
|
443
|
+
const contentEncodingHeader = response?.headers.get('content-encoding');
|
|
444
|
+
if (!contentEncodingHeader || contentEncodingHeader === 'none') {
|
|
445
|
+
return response;
|
|
446
|
+
}
|
|
447
|
+
if (!response?.body) {
|
|
448
|
+
return response;
|
|
449
|
+
}
|
|
450
|
+
let decompressedResponse = decompressedResponseMap.get(response);
|
|
451
|
+
if (!decompressedResponse || decompressedResponse.bodyUsed) {
|
|
452
|
+
let decompressedBody = response.body;
|
|
453
|
+
const contentEncodings = contentEncodingHeader.split(',');
|
|
454
|
+
if (!contentEncodings.every(encoding => getSupportedEncodings(fetchAPI).includes(encoding))) {
|
|
455
|
+
return new fetchAPI.Response(`Unsupported 'Content-Encoding': ${contentEncodingHeader}`, {
|
|
456
|
+
status: 415,
|
|
457
|
+
statusText: 'Unsupported Media Type',
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
for (const contentEncoding of contentEncodings) {
|
|
461
|
+
decompressedBody = decompressedBody.pipeThrough(new fetchAPI.DecompressionStream(contentEncoding));
|
|
462
|
+
}
|
|
463
|
+
decompressedResponse = new fetchAPI.Response(decompressedBody, response);
|
|
464
|
+
decompressedResponseMap.set(response, decompressedResponse);
|
|
465
|
+
}
|
|
466
|
+
return decompressedResponse;
|
|
467
|
+
}
|
|
468
|
+
const terminateEvents = ['SIGINT', 'exit', 'SIGTERM'];
|
|
469
|
+
const disposableStacks = new Set();
|
|
470
|
+
let eventListenerRegistered = false;
|
|
471
|
+
function ensureEventListenerForDisposableStacks() {
|
|
472
|
+
if (eventListenerRegistered) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
eventListenerRegistered = true;
|
|
476
|
+
for (const event of terminateEvents) {
|
|
477
|
+
globalThis.process.once(event, function terminateHandler() {
|
|
478
|
+
return Promise.allSettled([...disposableStacks].map(stack => !stack.disposed && stack.disposeAsync()));
|
|
479
|
+
});
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
export function ensureDisposableStackRegisteredForTerminateEvents(disposableStack) {
|
|
483
|
+
if (globalThis.process) {
|
|
484
|
+
ensureEventListenerForDisposableStacks();
|
|
485
|
+
if (!disposableStacks.has(disposableStack)) {
|
|
486
|
+
disposableStacks.add(disposableStack);
|
|
487
|
+
disposableStack.defer(() => {
|
|
488
|
+
disposableStacks.delete(disposableStack);
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
class CustomAbortControllerSignal extends EventTarget {
|
|
494
|
+
aborted = false;
|
|
495
|
+
_onabort = null;
|
|
496
|
+
_reason;
|
|
497
|
+
constructor() {
|
|
498
|
+
super();
|
|
499
|
+
const nodeEvents = globalThis.process?.getBuiltinModule?.('node:events');
|
|
500
|
+
// @ts-expect-error - We know kMaxEventTargetListeners is available in node:events
|
|
501
|
+
if (nodeEvents?.kMaxEventTargetListeners) {
|
|
502
|
+
// @ts-expect-error - See https://github.com/nodejs/node/pull/55816/files#diff-03bd4f07a1006cb0daaddced702858751b20f5ab7681cb0719c1b1d80d6ca05cR31
|
|
503
|
+
this[nodeEvents.kMaxEventTargetListeners] = 0;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
throwIfAborted() {
|
|
507
|
+
if (this._nativeCtrl?.signal?.throwIfAborted) {
|
|
508
|
+
return this._nativeCtrl.signal.throwIfAborted();
|
|
509
|
+
}
|
|
510
|
+
if (this.aborted) {
|
|
511
|
+
throw this._reason;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
_nativeCtrl;
|
|
515
|
+
ensureNativeCtrl() {
|
|
516
|
+
if (!this._nativeCtrl) {
|
|
517
|
+
const isAborted = this.aborted;
|
|
518
|
+
this._nativeCtrl = new AbortController();
|
|
519
|
+
if (isAborted) {
|
|
520
|
+
this._nativeCtrl.abort(this._reason);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return this._nativeCtrl;
|
|
524
|
+
}
|
|
525
|
+
abort(reason) {
|
|
526
|
+
if (this._nativeCtrl?.abort) {
|
|
527
|
+
return this._nativeCtrl?.abort(reason);
|
|
528
|
+
}
|
|
529
|
+
this._reason = reason || new DOMException('This operation was aborted', 'AbortError');
|
|
530
|
+
this.aborted = true;
|
|
531
|
+
this.dispatchEvent(new Event('abort'));
|
|
532
|
+
}
|
|
533
|
+
get signal() {
|
|
534
|
+
if (this._nativeCtrl?.signal) {
|
|
535
|
+
return this._nativeCtrl.signal;
|
|
536
|
+
}
|
|
537
|
+
return this;
|
|
538
|
+
}
|
|
539
|
+
get reason() {
|
|
540
|
+
if (this._nativeCtrl?.signal) {
|
|
541
|
+
return this._nativeCtrl.signal.reason;
|
|
542
|
+
}
|
|
543
|
+
return this._reason;
|
|
544
|
+
}
|
|
545
|
+
get onabort() {
|
|
546
|
+
if (this._onabort) {
|
|
547
|
+
return this._onabort;
|
|
548
|
+
}
|
|
549
|
+
return this._onabort;
|
|
550
|
+
}
|
|
551
|
+
set onabort(value) {
|
|
552
|
+
if (this._nativeCtrl?.signal) {
|
|
553
|
+
this._nativeCtrl.signal.onabort = value;
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (this._onabort) {
|
|
557
|
+
this.removeEventListener('abort', this._onabort);
|
|
558
|
+
}
|
|
559
|
+
this._onabort = value;
|
|
560
|
+
if (value) {
|
|
561
|
+
this.addEventListener('abort', value);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
export function createCustomAbortControllerSignal() {
|
|
566
|
+
if (globalThis.Bun || globalThis.Deno) {
|
|
567
|
+
return new AbortController();
|
|
568
|
+
}
|
|
569
|
+
return new Proxy(new CustomAbortControllerSignal(), {
|
|
570
|
+
get(target, prop, receiver) {
|
|
571
|
+
if (prop.toString().includes('kDependantSignals')) {
|
|
572
|
+
const nativeCtrl = target.ensureNativeCtrl();
|
|
573
|
+
return Reflect.get(nativeCtrl.signal, prop, nativeCtrl.signal);
|
|
574
|
+
}
|
|
575
|
+
return Reflect.get(target, prop, receiver);
|
|
576
|
+
},
|
|
577
|
+
set(target, prop, value, receiver) {
|
|
578
|
+
if (prop.toString().includes('kDependantSignals')) {
|
|
579
|
+
const nativeCtrl = target.ensureNativeCtrl();
|
|
580
|
+
return Reflect.set(nativeCtrl.signal, prop, value, nativeCtrl.signal);
|
|
581
|
+
}
|
|
582
|
+
return Reflect.set(target, prop, value, receiver);
|
|
583
|
+
},
|
|
584
|
+
getPrototypeOf() {
|
|
585
|
+
return AbortSignal.prototype;
|
|
586
|
+
},
|
|
587
|
+
});
|
|
588
|
+
}
|