acrylblends 0.8.1 → 0.9.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/dist/index.d.ts +2 -0
- package/dist/index.js +83 -7
- package/dist/index.js.map +1 -1
- package/lib/audit-BXnYsLge.d.ts +58 -0
- package/lib/cell-ChU41DZD.d.ts +32 -0
- package/lib/client-modules-CLvWOjbd.js +267 -0
- package/lib/connection-ZLEso7XL.d.ts +25 -0
- package/lib/conninfo.d.ts +1 -23
- package/lib/cordis/db-sqlite.d.ts +56 -0
- package/lib/cordis/db-sqlite.js +58 -0
- package/lib/cordis/db.d.ts +8 -0
- package/lib/cordis/db.js +1 -0
- package/lib/cordis/door.d.ts +159 -0
- package/lib/cordis/door.js +757 -0
- package/lib/cordis/inspect.d.ts +77 -0
- package/lib/cordis/inspect.js +149 -0
- package/lib/cordis/kv-db.d.ts +16 -0
- package/lib/cordis/kv-db.js +18 -0
- package/lib/cordis/kv-json.d.ts +16 -0
- package/lib/cordis/kv-json.js +44 -0
- package/lib/cordis/kv.d.ts +8 -0
- package/lib/cordis/kv.js +1 -0
- package/lib/cordis/node-server.d.ts +45 -0
- package/lib/cordis/node-server.js +93 -0
- package/lib/cordis/router-http.d.ts +56 -0
- package/lib/cordis/router-http.js +117 -0
- package/lib/cordis/router.d.ts +8 -0
- package/lib/cordis/router.js +7 -0
- package/lib/cordis/state/react.d.ts +6 -0
- package/lib/cordis/state/react.js +11 -0
- package/lib/cordis/state.d.ts +33 -0
- package/lib/cordis/state.js +163 -0
- package/lib/core-CaY8XDZ6.js +19 -0
- package/lib/database-DBHdwefi.d.ts +44 -0
- package/lib/db/conformance.d.ts +11 -0
- package/lib/db/conformance.js +267 -0
- package/lib/db/sqlite.d.ts +1 -1
- package/lib/db/sqlite.js +1 -196
- package/lib/db.d.ts +2 -1
- package/lib/{src-0hI7M7cN.js → deprecated-BP4fPt38.js} +0 -17
- package/lib/door/host.d.ts +24 -0
- package/lib/door/host.js +2 -0
- package/lib/door/page.d.ts +105 -0
- package/lib/door/page.js +1030 -0
- package/lib/door/protocol.d.ts +2 -0
- package/lib/door/protocol.js +197 -0
- package/lib/error-t4N2js2I.d.ts +8 -0
- package/lib/etag-DaKMOjty.js +135 -0
- package/lib/etag.js +1 -134
- package/lib/helpers-CvTauQT5.js +5 -0
- package/lib/http-exception-kpGJkmpi.d.ts +57 -0
- package/lib/http-exception.d.ts +1 -56
- package/lib/{index-BLTYsyc1.d.ts → index-BnGgRKTv.d.ts} +3 -39
- package/lib/index-BqVQkTnu.d.ts +98 -0
- package/lib/index-Dmst2QCQ.d.ts +44 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.js +2 -1
- package/lib/jwk-LkzeoaU8.js +117 -0
- package/lib/jwk.js +1 -116
- package/lib/jwt-CskdhEW9.js +115 -0
- package/lib/jwt.js +2 -114
- package/lib/kv/conformance.d.ts +13 -0
- package/lib/kv/conformance.js +301 -0
- package/lib/kv/db.d.ts +2 -2
- package/lib/kv/json.d.ts +1 -1
- package/lib/kv-9f-AlRKN.d.ts +39 -0
- package/lib/kv.d.ts +2 -1
- package/lib/language-D9a4zqvn.js +198 -0
- package/lib/language.js +1 -197
- package/lib/middleware-CPQ8himN.js +12 -0
- package/lib/node-server/serve-static.d.ts +0 -1
- package/lib/node-server/serve-static.js +1 -1
- package/lib/node-server.d.ts +1 -7
- package/lib/node-server.js +3 -1586
- package/lib/open-CMhnJODn.js +197 -0
- package/lib/protocol-BizVt4J6.d.ts +144 -0
- package/lib/request-id-CKVvHOO1.js +34 -0
- package/lib/request-id.js +1 -33
- package/lib/secure-headers-mP3j6Hm6.js +163 -0
- package/lib/secure-headers.js +1 -162
- package/lib/{serve-static-B849HlX2.js → serve-static-3uo_9rjF.js} +1 -4
- package/lib/server-DvgMGtzo.js +1323 -0
- package/lib/snapshot-text-D3NspDyT.js +338 -0
- package/lib/src-CwABFr6r.js +328 -0
- package/lib/timeout.d.ts +1 -1
- package/lib/timing-Cky7C1Jf.js +183 -0
- package/lib/timing.js +1 -182
- package/package.json +89 -1
- package/plugins/acryl-db/plugin.json +6 -1
- package/plugins/acryl-db-sqlite/plugin.json +4 -0
- package/plugins/acryl-db-sqlite/src/facade/node.ts +1 -1
- package/plugins/acryl-db-sqlite/src/index.ts +2 -2
- package/plugins/acryl-db-sqlite/src/open.ts +2 -2
- package/plugins/acryl-door/plugin.json +4 -1
- package/plugins/acryl-door/src/host/http.ts +2 -2
- package/plugins/acryl-door/src/host/mcp-routes.ts +1 -1
- package/plugins/acryl-door/src/host/operator-routes.ts +1 -1
- package/plugins/acryl-door/src/host/page-routes.ts +3 -3
- package/plugins/acryl-door/src/index.ts +2 -2
- package/plugins/acryl-inspect/plugin.json +4 -1
- package/plugins/acryl-inspect/src/service.ts +2 -2
- package/plugins/acryl-kv/plugin.json +6 -1
- package/plugins/acryl-kv-db/plugin.json +4 -0
- package/plugins/acryl-kv-db/src/index.ts +1 -1
- package/plugins/acryl-kv-db/src/open.ts +3 -3
- package/plugins/acryl-kv-json/plugin.json +4 -0
- package/plugins/acryl-kv-json/src/index.ts +1 -1
- package/plugins/acryl-kv-json/src/open.ts +2 -2
- package/plugins/acryl-node-server/plugin.json +5 -1
- package/plugins/acryl-node-server/src/adapter/conninfo.ts +1 -1
- package/plugins/acryl-node-server/src/adapter/early-hints.ts +1 -1
- package/plugins/acryl-node-server/src/adapter/serve-static.ts +2 -2
- package/plugins/acryl-node-server/src/adapter/websocket.ts +2 -2
- package/plugins/acryl-node-server/src/client-modules.ts +2 -2
- package/plugins/acryl-node-server/src/index.ts +1 -1
- package/plugins/acryl-router/plugin.json +11 -1
- package/plugins/acryl-router/src/connection.d.ts +25 -0
- package/plugins/acryl-router/src/core/app-base.d.ts +215 -0
- package/plugins/acryl-router/src/core/app.d.ts +19 -0
- package/plugins/acryl-router/src/core/client/client.d.ts +4 -0
- package/plugins/acryl-router/src/core/client/fetch-result-please.d.ts +35 -0
- package/plugins/acryl-router/src/core/client/index.d.ts +7 -0
- package/plugins/acryl-router/src/core/client/types.d.ts +229 -0
- package/plugins/acryl-router/src/core/client/utils.d.ts +18 -0
- package/plugins/acryl-router/src/core/compose.d.ts +14 -0
- package/plugins/acryl-router/src/core/context.d.ts +443 -0
- package/plugins/acryl-router/src/core/helper/accepts/accepts.d.ts +30 -0
- package/plugins/acryl-router/src/core/helper/accepts/index.d.ts +5 -0
- package/plugins/acryl-router/src/core/helper/conninfo/index.d.ts +5 -0
- package/plugins/acryl-router/src/core/helper/conninfo/types.d.ts +36 -0
- package/plugins/acryl-router/src/core/helper/cookie/index.d.ts +25 -0
- package/plugins/acryl-router/src/core/helper/css/common.d.ts +59 -0
- package/plugins/acryl-router/src/core/helper/css/index.d.ts +80 -0
- package/plugins/acryl-router/src/core/helper/dev/index.d.ts +20 -0
- package/plugins/acryl-router/src/core/helper/factory/index.d.ts +82 -0
- package/plugins/acryl-router/src/core/helper/html/index.d.ts +8 -0
- package/plugins/acryl-router/src/core/helper/proxy/index.d.ts +73 -0
- package/plugins/acryl-router/src/core/helper/route/index.d.ts +75 -0
- package/plugins/acryl-router/src/core/helper/ssg/index.d.ts +7 -0
- package/plugins/acryl-router/src/core/helper/ssg/middleware.d.ts +44 -0
- package/plugins/acryl-router/src/core/helper/ssg/plugins.d.ts +27 -0
- package/plugins/acryl-router/src/core/helper/ssg/ssg.d.ts +91 -0
- package/plugins/acryl-router/src/core/helper/ssg/utils.d.ts +16 -0
- package/plugins/acryl-router/src/core/helper/streaming/index.d.ts +8 -0
- package/plugins/acryl-router/src/core/helper/streaming/sse.d.ts +13 -0
- package/plugins/acryl-router/src/core/helper/streaming/stream.d.ts +3 -0
- package/plugins/acryl-router/src/core/helper/streaming/text.d.ts +3 -0
- package/plugins/acryl-router/src/core/helper/streaming/utils.d.ts +1 -0
- package/plugins/acryl-router/src/core/helper/testing/index.d.ts +13 -0
- package/plugins/acryl-router/src/core/helper/websocket/index.d.ts +70 -0
- package/plugins/acryl-router/src/core/http-exception.d.ts +58 -0
- package/plugins/acryl-router/src/core/index.d.ts +37 -0
- package/plugins/acryl-router/src/core/jsx/base.d.ts +61 -0
- package/plugins/acryl-router/src/core/jsx/children.d.ts +9 -0
- package/plugins/acryl-router/src/core/jsx/components.d.ts +15 -0
- package/plugins/acryl-router/src/core/jsx/constants.d.ts +6 -0
- package/plugins/acryl-router/src/core/jsx/context.d.ts +51 -0
- package/plugins/acryl-router/src/core/jsx/dom/components.d.ts +10 -0
- package/plugins/acryl-router/src/core/jsx/dom/context.d.ts +3 -0
- package/plugins/acryl-router/src/core/jsx/dom/css.d.ts +83 -0
- package/plugins/acryl-router/src/core/jsx/dom/hooks/index.d.ts +39 -0
- package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.d.ts +16 -0
- package/plugins/acryl-router/src/core/jsx/dom/jsx-dev-runtime.d.ts +8 -0
- package/plugins/acryl-router/src/core/jsx/dom/jsx-runtime.d.ts +7 -0
- package/plugins/acryl-router/src/core/jsx/dom/render.d.ts +73 -0
- package/plugins/acryl-router/src/core/jsx/dom/utils.d.ts +1 -0
- package/plugins/acryl-router/src/core/jsx/hooks/index.d.ts +47 -0
- package/plugins/acryl-router/src/core/jsx/index.d.ts +76 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/common.d.ts +6 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.d.ts +13 -0
- package/plugins/acryl-router/src/core/jsx/intrinsic-elements.d.ts +735 -0
- package/plugins/acryl-router/src/core/jsx/streaming.d.ts +36 -0
- package/plugins/acryl-router/src/core/jsx/types.d.ts +36 -0
- package/plugins/acryl-router/src/core/jsx/utils.d.ts +4 -0
- package/plugins/acryl-router/src/core/request/constants.d.ts +1 -0
- package/plugins/acryl-router/src/core/request.d.ts +306 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/index.d.ts +6 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/matcher.d.ts +7 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/node.d.ts +13 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.d.ts +17 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/router.d.ts +11 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/trie.d.ts +8 -0
- package/plugins/acryl-router/src/core/router/smart-router/index.d.ts +5 -0
- package/plugins/acryl-router/src/core/router/smart-router/router.d.ts +11 -0
- package/plugins/acryl-router/src/core/router/trie-router/index.d.ts +5 -0
- package/plugins/acryl-router/src/core/router/trie-router/node.d.ts +6 -0
- package/plugins/acryl-router/src/core/router/trie-router/router.d.ts +7 -0
- package/plugins/acryl-router/src/core/router/utils.d.ts +1 -0
- package/plugins/acryl-router/src/core/router.d.ts +97 -0
- package/plugins/acryl-router/src/core/types.d.ts +573 -0
- package/plugins/acryl-router/src/core/utils/accept.d.ts +6 -0
- package/plugins/acryl-router/src/core/utils/body.d.ts +79 -0
- package/plugins/acryl-router/src/core/utils/buffer.d.ts +17 -0
- package/plugins/acryl-router/src/core/utils/color.d.ts +21 -0
- package/plugins/acryl-router/src/core/utils/concurrent.d.ts +11 -0
- package/plugins/acryl-router/src/core/utils/constants.d.ts +4 -0
- package/plugins/acryl-router/src/core/utils/cookie.d.ts +41 -0
- package/plugins/acryl-router/src/core/utils/crypto.d.ts +15 -0
- package/plugins/acryl-router/src/core/utils/handler.d.ts +6 -0
- package/plugins/acryl-router/src/core/utils/headers.d.ts +8 -0
- package/plugins/acryl-router/src/core/utils/html.d.ts +44 -0
- package/plugins/acryl-router/src/core/utils/http-status.d.ts +32 -0
- package/plugins/acryl-router/src/core/utils/mime.d.ts +70 -0
- package/plugins/acryl-router/src/core/utils/stream.d.ts +31 -0
- package/plugins/acryl-router/src/core/utils/types.d.ts +128 -0
- package/plugins/acryl-router/src/core/utils/url.d.ts +44 -0
- package/plugins/acryl-router/src/core/validator/index.d.ts +7 -0
- package/plugins/acryl-router/src/core/validator/utils.d.ts +29 -0
- package/plugins/acryl-router/src/core/validator/validator.d.ts +16 -0
- package/plugins/acryl-router/src/helpers/index.d.ts +17 -0
- package/plugins/acryl-router/src/helpers/schema-validator.d.ts +54 -0
- package/plugins/acryl-router-http/plugin.json +4 -1
- package/plugins/acryl-router-http/src/index.ts +1 -1
- package/plugins/acryl-state/plugin.json +5 -1
- package/plugins/acryl-state/src/service.ts +3 -3
- package/plugins/tsconfig.json +32 -20
- package/docs/framework/UPSTREAM.md +0 -3
- package/docs/framework/upstream.json +0 -9
- package/lib/index-D4FAsBZu.d.ts +0 -85
- package/plugins/acryl-db/upstream.json +0 -18
- package/plugins/acryl-db-sqlite/upstream.json +0 -21
- package/plugins/acryl-door/upstream.json +0 -28
- package/plugins/acryl-inspect/upstream.json +0 -18
- package/plugins/acryl-kv/upstream.json +0 -18
- package/plugins/acryl-kv-db/upstream.json +0 -21
- package/plugins/acryl-kv-json/upstream.json +0 -22
- package/plugins/acryl-node-server/upstream.json +0 -21
- package/plugins/acryl-router/upstream.json +0 -20
- package/plugins/acryl-router-http/upstream.json +0 -22
- package/plugins/acryl-state/NOTICE +0 -30
- package/plugins/acryl-state/upstream.json +0 -22
- package/plugins/desktop/upstream.json +0 -12
- package/plugins/desktop-web/upstream.json +0 -12
- package/templates/todo/upstream.json +0 -12
- /package/lib/{index-CTy4N7ng.d.ts → deprecated-CTy4N7ng.d.ts} +0 -0
package/lib/node-server.js
CHANGED
|
@@ -1,1588 +1,5 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import { defineWebSocketHelper } from "./ws.js";
|
|
4
|
-
import { t as serveStatic } from "./serve-static-B849HlX2.js";
|
|
1
|
+
import { i as getRequestListener, n as serve, o as RequestError, r as upgradeWebSocket, t as createAdaptorServer } from "./server-DvgMGtzo.js";
|
|
2
|
+
import { t as serveStatic } from "./serve-static-3uo_9rjF.js";
|
|
5
3
|
import { getConnInfo } from "./node-server/conninfo.js";
|
|
6
|
-
import { n as
|
|
7
|
-
import { dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
8
|
-
import { STATUS_CODES, ServerResponse, createServer } from "node:http";
|
|
9
|
-
import { Http2ServerRequest, constants } from "node:http2";
|
|
10
|
-
import { Readable } from "node:stream";
|
|
11
|
-
import { copyFileSync, mkdirSync, readFileSync, readdirSync, realpathSync, statSync, writeFileSync } from "node:fs";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
|
-
//#region ../../plugins/acryl-node-server/src/adapter/error.ts
|
|
14
|
-
var RequestError = class extends Error {
|
|
15
|
-
constructor(message, options) {
|
|
16
|
-
super(message, options);
|
|
17
|
-
this.name = "RequestError";
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
//#endregion
|
|
21
|
-
//#region ../../plugins/acryl-node-server/src/adapter/headers.ts
|
|
22
|
-
const nonJoinedHeaders = /* @__PURE__ */ new Set([
|
|
23
|
-
"age",
|
|
24
|
-
"authorization",
|
|
25
|
-
"content-length",
|
|
26
|
-
"content-type",
|
|
27
|
-
"etag",
|
|
28
|
-
"expires",
|
|
29
|
-
"from",
|
|
30
|
-
"host",
|
|
31
|
-
"if-modified-since",
|
|
32
|
-
"if-unmodified-since",
|
|
33
|
-
"last-modified",
|
|
34
|
-
"location",
|
|
35
|
-
"max-forwards",
|
|
36
|
-
"proxy-authorization",
|
|
37
|
-
"referer",
|
|
38
|
-
"retry-after",
|
|
39
|
-
"server",
|
|
40
|
-
"user-agent"
|
|
41
|
-
]);
|
|
42
|
-
const validHeaderName = /^[!#$%&'*+\-.^_`|~\dA-Za-z]+$/;
|
|
43
|
-
const isHttpWhitespace = (code) => code === 9 || code === 10 || code === 13 || code === 32;
|
|
44
|
-
const normalizeHeaderValue = (value) => {
|
|
45
|
-
if (!isHttpWhitespace(value.charCodeAt(0)) && !isHttpWhitespace(value.charCodeAt(value.length - 1))) return value;
|
|
46
|
-
let start = 0;
|
|
47
|
-
let end = value.length;
|
|
48
|
-
while (start < end && isHttpWhitespace(value.charCodeAt(start))) start++;
|
|
49
|
-
while (end > start && isHttpWhitespace(value.charCodeAt(end - 1))) end--;
|
|
50
|
-
return value.slice(start, end);
|
|
51
|
-
};
|
|
52
|
-
const forbiddenHeaderValue = /[\0\r\n]/;
|
|
53
|
-
const GlobalHeaders = globalThis.Headers;
|
|
54
|
-
const materializeHeaders = (rawHeaders, HeadersCtor = GlobalHeaders) => {
|
|
55
|
-
const headers = new HeadersCtor();
|
|
56
|
-
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
57
|
-
const name = rawHeaders[i];
|
|
58
|
-
if (!name.startsWith(":")) headers.append(name, rawHeaders[i + 1]);
|
|
59
|
-
}
|
|
60
|
-
return headers;
|
|
61
|
-
};
|
|
62
|
-
var RequestHeaders = class {
|
|
63
|
-
#incoming;
|
|
64
|
-
#rawHeaders;
|
|
65
|
-
#headers;
|
|
66
|
-
#invalidValue;
|
|
67
|
-
constructor(incoming) {
|
|
68
|
-
this.#incoming = incoming;
|
|
69
|
-
if (incoming instanceof Http2ServerRequest) this.#rawHeaders = incoming.rawHeaders.slice();
|
|
70
|
-
}
|
|
71
|
-
get #lazyRawHeaders() {
|
|
72
|
-
return this.#rawHeaders ??= this.#incoming.rawHeaders.slice();
|
|
73
|
-
}
|
|
74
|
-
get #native() {
|
|
75
|
-
if (!this.#headers) {
|
|
76
|
-
this.#headers = materializeHeaders(this.#lazyRawHeaders);
|
|
77
|
-
this.#rawHeaders = void 0;
|
|
78
|
-
}
|
|
79
|
-
return this.#headers;
|
|
80
|
-
}
|
|
81
|
-
#normalizedName(name) {
|
|
82
|
-
if (typeof name !== "string") return;
|
|
83
|
-
if (!validHeaderName.test(name)) throw new TypeError(`Invalid header name: ${name}`);
|
|
84
|
-
return name.toLowerCase();
|
|
85
|
-
}
|
|
86
|
-
#lookupHttp1(lowerName) {
|
|
87
|
-
const headers = this.#incoming instanceof Http2ServerRequest ? void 0 : this.#incoming.headers;
|
|
88
|
-
if (!headers || nonJoinedHeaders.has(lowerName) || lowerName === "set-cookie" || lowerName === "__proto__") return;
|
|
89
|
-
if (!Object.hasOwn(headers, lowerName)) return null;
|
|
90
|
-
const rawValue = headers[lowerName];
|
|
91
|
-
if (typeof rawValue === "string") {
|
|
92
|
-
const value = normalizeHeaderValue(rawValue);
|
|
93
|
-
return forbiddenHeaderValue.test(value) ? void 0 : value;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
#lookup(rawHeaders, lowerName) {
|
|
97
|
-
const separator = lowerName === "cookie" ? "; " : ", ";
|
|
98
|
-
let value = null;
|
|
99
|
-
for (let i = 0; i < rawHeaders.length; i += 2) {
|
|
100
|
-
const rawName = rawHeaders[i];
|
|
101
|
-
if (rawName.length === lowerName.length && rawName.toLowerCase() === lowerName) {
|
|
102
|
-
const rawValue = normalizeHeaderValue(rawHeaders[i + 1]);
|
|
103
|
-
if (forbiddenHeaderValue.test(rawValue)) {
|
|
104
|
-
this.#invalidValue = true;
|
|
105
|
-
return;
|
|
106
|
-
}
|
|
107
|
-
value = value === null ? rawValue : value + separator + rawValue;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
|
-
append(name, value) {
|
|
113
|
-
this.#native.append(name, value);
|
|
114
|
-
}
|
|
115
|
-
delete(name) {
|
|
116
|
-
this.#native.delete(name);
|
|
117
|
-
}
|
|
118
|
-
get(name) {
|
|
119
|
-
const lowerName = this.#normalizedName(name);
|
|
120
|
-
if (lowerName && !this.#headers && !this.#invalidValue) {
|
|
121
|
-
const http1Value = this.#lookupHttp1(lowerName);
|
|
122
|
-
if (http1Value !== void 0) return http1Value;
|
|
123
|
-
const value = this.#lookup(this.#lazyRawHeaders, lowerName);
|
|
124
|
-
if (value !== void 0) return value;
|
|
125
|
-
}
|
|
126
|
-
return this.#native.get(name);
|
|
127
|
-
}
|
|
128
|
-
has(name) {
|
|
129
|
-
const lowerName = this.#normalizedName(name);
|
|
130
|
-
if (lowerName && !this.#headers && !this.#invalidValue) {
|
|
131
|
-
const http1Value = this.#lookupHttp1(lowerName);
|
|
132
|
-
if (http1Value !== void 0) return http1Value !== null;
|
|
133
|
-
const value = this.#lookup(this.#lazyRawHeaders, lowerName);
|
|
134
|
-
if (value !== void 0) return value !== null;
|
|
135
|
-
}
|
|
136
|
-
return this.#native.has(name);
|
|
137
|
-
}
|
|
138
|
-
set(name, value) {
|
|
139
|
-
this.#native.set(name, value);
|
|
140
|
-
}
|
|
141
|
-
getSetCookie() {
|
|
142
|
-
return this.#native.getSetCookie();
|
|
143
|
-
}
|
|
144
|
-
keys() {
|
|
145
|
-
return this.#native.keys();
|
|
146
|
-
}
|
|
147
|
-
values() {
|
|
148
|
-
return this.#native.values();
|
|
149
|
-
}
|
|
150
|
-
entries() {
|
|
151
|
-
return this.#native.entries();
|
|
152
|
-
}
|
|
153
|
-
forEach(callback, thisArg) {
|
|
154
|
-
this.#native.forEach((value, key) => {
|
|
155
|
-
callback.call(thisArg, value, key, this);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
[Symbol.iterator]() {
|
|
159
|
-
return this.entries();
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
Object.defineProperty(RequestHeaders.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
|
|
163
|
-
return `Headers (lightweight) ${inspectFn(Object.fromEntries(this), {
|
|
164
|
-
...options,
|
|
165
|
-
depth: depth == null ? null : depth - 1
|
|
166
|
-
})}`;
|
|
167
|
-
} });
|
|
168
|
-
Object.setPrototypeOf(RequestHeaders.prototype, GlobalHeaders.prototype);
|
|
169
|
-
const newHeadersFromIncoming = (incoming) => globalThis.Headers === GlobalHeaders ? new RequestHeaders(incoming) : materializeHeaders(incoming.rawHeaders, globalThis.Headers);
|
|
170
|
-
//#endregion
|
|
171
|
-
//#region ../../plugins/acryl-node-server/src/adapter/url.ts
|
|
172
|
-
const reValidRequestUrl = /^\/[!#$&-;=?-\[\]_a-z~]*$/;
|
|
173
|
-
const reDotSegment = /\/\.\.?(?:[/?#]|$)/;
|
|
174
|
-
const reValidHost = /^[a-z0-9._-]+(?::(?:[1-5]\d{3,4}|[6-9]\d{3}))?$/;
|
|
175
|
-
const buildUrl = (scheme, host, incomingUrl) => {
|
|
176
|
-
const url = `${scheme}://${host}${incomingUrl}`;
|
|
177
|
-
if (!reValidHost.test(host)) {
|
|
178
|
-
const urlObj = new URL(url);
|
|
179
|
-
if (urlObj.hostname.length !== host.length && urlObj.hostname !== (host.includes(":") ? host.replace(/:\d+$/, "") : host).toLowerCase()) throw new RequestError("Invalid host header");
|
|
180
|
-
return urlObj.href;
|
|
181
|
-
} else if (incomingUrl.length === 0) return url + "/";
|
|
182
|
-
else {
|
|
183
|
-
if (incomingUrl.charCodeAt(0) !== 47) throw new RequestError("Invalid URL");
|
|
184
|
-
if (!reValidRequestUrl.test(incomingUrl) || reDotSegment.test(incomingUrl)) return new URL(url).href;
|
|
185
|
-
return url;
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
//#endregion
|
|
189
|
-
//#region ../../plugins/acryl-node-server/src/adapter/request.ts
|
|
190
|
-
const toRequestError = (e) => {
|
|
191
|
-
if (e instanceof RequestError) return e;
|
|
192
|
-
return new RequestError(e.message, { cause: e });
|
|
193
|
-
};
|
|
194
|
-
const GlobalRequest = global.Request;
|
|
195
|
-
var Request$1 = class extends GlobalRequest {
|
|
196
|
-
constructor(input, options) {
|
|
197
|
-
if (typeof input === "object" && getRequestCache in input) {
|
|
198
|
-
const hasReplacementBody = options !== void 0 && "body" in options && options.body != null;
|
|
199
|
-
if (input[bodyConsumedDirectlyKey] && !hasReplacementBody) throw new TypeError("Cannot construct a Request with a Request object that has already been used.");
|
|
200
|
-
input = input[getRequestCache]();
|
|
201
|
-
}
|
|
202
|
-
if (typeof (options?.body)?.getReader !== "undefined") options.duplex ??= "half";
|
|
203
|
-
super(input, options);
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
const wrapBodyStream = Symbol("wrapBodyStream");
|
|
207
|
-
const byteExactEncodings = /* @__PURE__ */ new Set([
|
|
208
|
-
"latin1",
|
|
209
|
-
"binary",
|
|
210
|
-
"hex",
|
|
211
|
-
"base64",
|
|
212
|
-
"base64url"
|
|
213
|
-
]);
|
|
214
|
-
const isByteExactEncoding = (encoding) => encoding === null || byteExactEncodings.has(encoding);
|
|
215
|
-
const bodyBufferedBeforeDisconnectKey = Symbol("bodyBufferedBeforeDisconnect");
|
|
216
|
-
const bodyBufferedLengthBeforeDisconnectKey = Symbol("bodyBufferedLengthBeforeDisconnect");
|
|
217
|
-
const toBufferChunk = (chunk, encoding) => Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding ?? "utf8");
|
|
218
|
-
const isRecoverableDisconnectedIncoming = (incoming) => !(incoming instanceof Http2ServerRequest) && !!incoming.complete && !!incoming.readableAborted && typeof incoming.read === "function" && isByteExactEncoding(incoming.readableEncoding);
|
|
219
|
-
const recordBodyBufferedBeforeDisconnect = (incoming) => {
|
|
220
|
-
if (incoming.readableDidRead || !isRecoverableDisconnectedIncoming(incoming)) return;
|
|
221
|
-
const incomingWithRecovery = incoming;
|
|
222
|
-
incomingWithRecovery[bodyBufferedLengthBeforeDisconnectKey] ??= incoming.readableLength;
|
|
223
|
-
};
|
|
224
|
-
const readBodyBufferedBeforeDisconnect = (incoming, chunks) => {
|
|
225
|
-
if (incoming.readableDidRead && !chunks || !isRecoverableDisconnectedIncoming(incoming)) return;
|
|
226
|
-
const incomingWithRecovery = incoming;
|
|
227
|
-
if (incomingWithRecovery[bodyBufferedBeforeDisconnectKey] !== void 0) return incomingWithRecovery[bodyBufferedBeforeDisconnectKey];
|
|
228
|
-
let result;
|
|
229
|
-
const errored = incoming.errored;
|
|
230
|
-
if (errored && errored.code !== "ECONNRESET") result = errored;
|
|
231
|
-
else if (incomingWithRecovery[bodyBufferedLengthBeforeDisconnectKey] !== void 0 && incoming.readableLength !== incomingWithRecovery[bodyBufferedLengthBeforeDisconnectKey]) result = newBodyUnusableError();
|
|
232
|
-
else {
|
|
233
|
-
const bodyChunks = chunks ?? [];
|
|
234
|
-
const chunk = incoming.read();
|
|
235
|
-
if (chunk !== null) bodyChunks.push(toBufferChunk(chunk, incoming.readableEncoding));
|
|
236
|
-
const buffer = bodyChunks.length === 1 ? bodyChunks[0] : Buffer.concat(bodyChunks);
|
|
237
|
-
result = buffer;
|
|
238
|
-
const contentLength = incoming.headers["content-length"];
|
|
239
|
-
if (typeof contentLength === "string" && /^\d+$/.test(contentLength)) {
|
|
240
|
-
const expectedLength = Number(contentLength);
|
|
241
|
-
if (Number.isSafeInteger(expectedLength) && buffer.length !== expectedLength) result = newBodyUnusableError();
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
incomingWithRecovery[bodyBufferedBeforeDisconnectKey] = result;
|
|
245
|
-
return result;
|
|
246
|
-
};
|
|
247
|
-
const enqueueBufferedBody = (controller, buffered) => {
|
|
248
|
-
if (buffered instanceof Error) {
|
|
249
|
-
controller.error(buffered);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
if (buffered.length > 0) controller.enqueue(buffered);
|
|
253
|
-
controller.close();
|
|
254
|
-
};
|
|
255
|
-
const newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
|
256
|
-
const init = {
|
|
257
|
-
method,
|
|
258
|
-
headers,
|
|
259
|
-
signal: abortController.signal
|
|
260
|
-
};
|
|
261
|
-
if (method === "TRACE") {
|
|
262
|
-
init.method = "GET";
|
|
263
|
-
const req = new Request$1(url, init);
|
|
264
|
-
Object.defineProperty(req, "method", { get() {
|
|
265
|
-
return "TRACE";
|
|
266
|
-
} });
|
|
267
|
-
return req;
|
|
268
|
-
}
|
|
269
|
-
if (!(method === "GET" || method === "HEAD")) if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) init.body = new ReadableStream({ start(controller) {
|
|
270
|
-
controller.enqueue(incoming.rawBody);
|
|
271
|
-
controller.close();
|
|
272
|
-
} });
|
|
273
|
-
else if (incoming[wrapBodyStream]) {
|
|
274
|
-
let reader;
|
|
275
|
-
init.body = new ReadableStream({ async pull(controller) {
|
|
276
|
-
try {
|
|
277
|
-
if (!reader) {
|
|
278
|
-
const buffered = readBodyBufferedBeforeDisconnect(incoming);
|
|
279
|
-
if (buffered !== void 0) {
|
|
280
|
-
enqueueBufferedBody(controller, buffered);
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
reader ||= Readable.toWeb(incoming).getReader();
|
|
285
|
-
const { done, value } = await reader.read();
|
|
286
|
-
if (done) controller.close();
|
|
287
|
-
else controller.enqueue(value);
|
|
288
|
-
} catch (error) {
|
|
289
|
-
controller.error(error);
|
|
290
|
-
}
|
|
291
|
-
} });
|
|
292
|
-
} else {
|
|
293
|
-
const buffered = readBodyBufferedBeforeDisconnect(incoming);
|
|
294
|
-
if (buffered !== void 0) init.body = new ReadableStream({ start(controller) {
|
|
295
|
-
enqueueBufferedBody(controller, buffered);
|
|
296
|
-
} });
|
|
297
|
-
else init.body = Readable.toWeb(incoming);
|
|
298
|
-
}
|
|
299
|
-
return new Request$1(url, init);
|
|
300
|
-
};
|
|
301
|
-
const getRequestCache = Symbol("getRequestCache");
|
|
302
|
-
const requestCache = Symbol("requestCache");
|
|
303
|
-
const incomingKey = Symbol("incomingKey");
|
|
304
|
-
const urlKey = Symbol("urlKey");
|
|
305
|
-
const methodKey = Symbol("methodKey");
|
|
306
|
-
const headersKey = Symbol("headersKey");
|
|
307
|
-
const abortControllerKey = Symbol("abortControllerKey");
|
|
308
|
-
const getAbortController = Symbol("getAbortController");
|
|
309
|
-
const abortRequest = Symbol("abortRequest");
|
|
310
|
-
const bodyBufferKey = Symbol("bodyBuffer");
|
|
311
|
-
const bodyReadPromiseKey = Symbol("bodyReadPromise");
|
|
312
|
-
const bodyConsumedDirectlyKey = Symbol("bodyConsumedDirectly");
|
|
313
|
-
const bodyLockReaderKey = Symbol("bodyLockReader");
|
|
314
|
-
const abortReasonKey = Symbol("abortReason");
|
|
315
|
-
const newBodyUnusableError = () => {
|
|
316
|
-
return /* @__PURE__ */ new TypeError("Body is unusable");
|
|
317
|
-
};
|
|
318
|
-
const rejectBodyUnusable = () => {
|
|
319
|
-
return Promise.reject(newBodyUnusableError());
|
|
320
|
-
};
|
|
321
|
-
const textDecoder = new TextDecoder();
|
|
322
|
-
const consumeBodyDirectOnce = (request) => {
|
|
323
|
-
if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
|
|
324
|
-
request[bodyConsumedDirectlyKey] = true;
|
|
325
|
-
};
|
|
326
|
-
const toArrayBuffer = (buf) => {
|
|
327
|
-
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
|
|
328
|
-
};
|
|
329
|
-
const contentType = (request) => {
|
|
330
|
-
return (request[headersKey] ||= newHeadersFromIncoming(request[incomingKey])).get("content-type") || "";
|
|
331
|
-
};
|
|
332
|
-
const methodTokenRegExp = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
333
|
-
const normalizeIncomingMethod = (method) => {
|
|
334
|
-
if (typeof method !== "string" || method.length === 0) return "GET";
|
|
335
|
-
switch (method) {
|
|
336
|
-
case "DELETE":
|
|
337
|
-
case "GET":
|
|
338
|
-
case "HEAD":
|
|
339
|
-
case "OPTIONS":
|
|
340
|
-
case "PATCH":
|
|
341
|
-
case "POST":
|
|
342
|
-
case "PUT":
|
|
343
|
-
case "QUERY": return method;
|
|
344
|
-
}
|
|
345
|
-
const upper = method.toUpperCase();
|
|
346
|
-
switch (upper) {
|
|
347
|
-
case "DELETE":
|
|
348
|
-
case "GET":
|
|
349
|
-
case "HEAD":
|
|
350
|
-
case "OPTIONS":
|
|
351
|
-
case "POST":
|
|
352
|
-
case "PUT": return upper;
|
|
353
|
-
default: return method;
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
|
-
const validateDirectReadMethod = (method) => {
|
|
357
|
-
if (!methodTokenRegExp.test(method)) return /* @__PURE__ */ new TypeError(`'${method}' is not a valid HTTP method.`);
|
|
358
|
-
const normalized = method.toUpperCase();
|
|
359
|
-
if (normalized === "CONNECT" || normalized === "TRACK" || normalized === "TRACE" && method !== "TRACE") return /* @__PURE__ */ new TypeError(`'${method}' HTTP method is unsupported.`);
|
|
360
|
-
};
|
|
361
|
-
const readBodyWithFastPath = (request, method, fromBuffer) => {
|
|
362
|
-
if (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
|
|
363
|
-
const methodName = request.method;
|
|
364
|
-
if (methodName === "GET" || methodName === "HEAD") return request[getRequestCache]()[method]();
|
|
365
|
-
const methodValidationError = validateDirectReadMethod(methodName);
|
|
366
|
-
if (methodValidationError) return Promise.reject(methodValidationError);
|
|
367
|
-
if (request[requestCache]) {
|
|
368
|
-
if (methodName !== "TRACE") return request[requestCache][method]();
|
|
369
|
-
}
|
|
370
|
-
const alreadyUsedError = consumeBodyDirectOnce(request);
|
|
371
|
-
if (alreadyUsedError) return alreadyUsedError;
|
|
372
|
-
const raw = readRawBodyIfAvailable(request);
|
|
373
|
-
if (raw) {
|
|
374
|
-
const result = Promise.resolve(fromBuffer(raw, request));
|
|
375
|
-
request[bodyBufferKey] = void 0;
|
|
376
|
-
return result;
|
|
377
|
-
}
|
|
378
|
-
return readBodyDirect(request).then((buf) => {
|
|
379
|
-
const result = fromBuffer(buf, request);
|
|
380
|
-
request[bodyBufferKey] = void 0;
|
|
381
|
-
return result;
|
|
382
|
-
});
|
|
383
|
-
};
|
|
384
|
-
const readRawBodyIfAvailable = (request) => {
|
|
385
|
-
const incoming = request[incomingKey];
|
|
386
|
-
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) return incoming.rawBody;
|
|
387
|
-
};
|
|
388
|
-
const normalizeAbortError = (request, incoming) => {
|
|
389
|
-
if (incoming.errored) return incoming.errored;
|
|
390
|
-
const reason = request[abortReasonKey];
|
|
391
|
-
if (reason !== void 0) return reason instanceof Error ? reason : new Error(String(reason));
|
|
392
|
-
return /* @__PURE__ */ new Error("Client connection prematurely closed.");
|
|
393
|
-
};
|
|
394
|
-
const readBodyDirect = (request) => {
|
|
395
|
-
if (request[bodyBufferKey]) return Promise.resolve(request[bodyBufferKey]);
|
|
396
|
-
if (request[bodyReadPromiseKey]) return request[bodyReadPromiseKey];
|
|
397
|
-
const incoming = request[incomingKey];
|
|
398
|
-
if (incoming.readableDidRead) return rejectBodyUnusable();
|
|
399
|
-
const buffered = readBodyBufferedBeforeDisconnect(incoming);
|
|
400
|
-
if (buffered !== void 0) {
|
|
401
|
-
if (buffered instanceof Error) return Promise.reject(buffered);
|
|
402
|
-
request[bodyBufferKey] = buffered;
|
|
403
|
-
return Promise.resolve(buffered);
|
|
404
|
-
}
|
|
405
|
-
const promise = new Promise((resolve, reject) => {
|
|
406
|
-
const chunks = [];
|
|
407
|
-
let settled = false;
|
|
408
|
-
const finish = (callback) => {
|
|
409
|
-
if (settled) return;
|
|
410
|
-
settled = true;
|
|
411
|
-
cleanup();
|
|
412
|
-
callback();
|
|
413
|
-
};
|
|
414
|
-
const recoverCompleteBodyAfterDisconnect = (error) => {
|
|
415
|
-
const streamError = incoming.errored ?? error;
|
|
416
|
-
if (!isRecoverableDisconnectedIncoming(incoming) || streamError && streamError.code !== "ECONNRESET") return false;
|
|
417
|
-
finish(() => {
|
|
418
|
-
const recovered = readBodyBufferedBeforeDisconnect(incoming, chunks);
|
|
419
|
-
if (recovered instanceof Error) reject(recovered);
|
|
420
|
-
else if (recovered === void 0) reject(error ?? normalizeAbortError(request, incoming));
|
|
421
|
-
else {
|
|
422
|
-
request[bodyBufferKey] = recovered;
|
|
423
|
-
resolve(recovered);
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
return true;
|
|
427
|
-
};
|
|
428
|
-
const onData = (chunk) => {
|
|
429
|
-
chunks.push(toBufferChunk(chunk, incoming.readableEncoding));
|
|
430
|
-
};
|
|
431
|
-
const onEnd = () => {
|
|
432
|
-
finish(() => {
|
|
433
|
-
const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
|
|
434
|
-
request[bodyBufferKey] = buffer;
|
|
435
|
-
resolve(buffer);
|
|
436
|
-
});
|
|
437
|
-
};
|
|
438
|
-
const onError = (error) => {
|
|
439
|
-
if (recoverCompleteBodyAfterDisconnect(error)) return;
|
|
440
|
-
finish(() => {
|
|
441
|
-
reject(error);
|
|
442
|
-
});
|
|
443
|
-
};
|
|
444
|
-
const onClose = () => {
|
|
445
|
-
if (incoming.readableEnded) {
|
|
446
|
-
onEnd();
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
if (recoverCompleteBodyAfterDisconnect()) return;
|
|
450
|
-
finish(() => {
|
|
451
|
-
reject(normalizeAbortError(request, incoming));
|
|
452
|
-
});
|
|
453
|
-
};
|
|
454
|
-
const cleanup = () => {
|
|
455
|
-
incoming.off("data", onData);
|
|
456
|
-
incoming.off("end", onEnd);
|
|
457
|
-
incoming.off("error", onError);
|
|
458
|
-
incoming.off("close", onClose);
|
|
459
|
-
request[bodyReadPromiseKey] = void 0;
|
|
460
|
-
};
|
|
461
|
-
incoming.on("data", onData);
|
|
462
|
-
incoming.on("end", onEnd);
|
|
463
|
-
incoming.on("error", onError);
|
|
464
|
-
incoming.on("close", onClose);
|
|
465
|
-
queueMicrotask(() => {
|
|
466
|
-
if (settled) return;
|
|
467
|
-
if (incoming.readableEnded) onEnd();
|
|
468
|
-
else if (incoming.errored) onError(incoming.errored);
|
|
469
|
-
else if (incoming.destroyed) onClose();
|
|
470
|
-
});
|
|
471
|
-
});
|
|
472
|
-
request[bodyReadPromiseKey] = promise;
|
|
473
|
-
return promise;
|
|
474
|
-
};
|
|
475
|
-
const requestPrototype = {
|
|
476
|
-
get method() {
|
|
477
|
-
return this[methodKey];
|
|
478
|
-
},
|
|
479
|
-
get url() {
|
|
480
|
-
return this[urlKey];
|
|
481
|
-
},
|
|
482
|
-
get headers() {
|
|
483
|
-
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
|
484
|
-
},
|
|
485
|
-
[abortRequest](reason) {
|
|
486
|
-
if (this[abortReasonKey] === void 0) this[abortReasonKey] = reason;
|
|
487
|
-
const abortController = this[abortControllerKey];
|
|
488
|
-
if (abortController && !abortController.signal.aborted) abortController.abort(reason);
|
|
489
|
-
},
|
|
490
|
-
[getAbortController]() {
|
|
491
|
-
this[abortControllerKey] ||= new AbortController();
|
|
492
|
-
if (this[abortReasonKey] !== void 0 && !this[abortControllerKey].signal.aborted) this[abortControllerKey].abort(this[abortReasonKey]);
|
|
493
|
-
return this[abortControllerKey];
|
|
494
|
-
},
|
|
495
|
-
[getRequestCache]() {
|
|
496
|
-
const abortController = this[getAbortController]();
|
|
497
|
-
if (this[requestCache]) return this[requestCache];
|
|
498
|
-
const method = this.method;
|
|
499
|
-
if (this[bodyConsumedDirectlyKey] && !(method === "GET" || method === "HEAD")) {
|
|
500
|
-
this[bodyBufferKey] = void 0;
|
|
501
|
-
const init = {
|
|
502
|
-
method: method === "TRACE" ? "GET" : method,
|
|
503
|
-
headers: this.headers,
|
|
504
|
-
signal: abortController.signal
|
|
505
|
-
};
|
|
506
|
-
if (method !== "TRACE") {
|
|
507
|
-
init.body = new ReadableStream({ start(c) {
|
|
508
|
-
c.close();
|
|
509
|
-
} });
|
|
510
|
-
init.duplex = "half";
|
|
511
|
-
}
|
|
512
|
-
const req = new Request$1(this[urlKey], init);
|
|
513
|
-
if (method === "TRACE") Object.defineProperty(req, "method", { get() {
|
|
514
|
-
return "TRACE";
|
|
515
|
-
} });
|
|
516
|
-
return this[requestCache] = req;
|
|
517
|
-
}
|
|
518
|
-
return this[requestCache] = newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], abortController);
|
|
519
|
-
},
|
|
520
|
-
get body() {
|
|
521
|
-
if (!this[bodyConsumedDirectlyKey]) return this[getRequestCache]().body;
|
|
522
|
-
const request = this[getRequestCache]();
|
|
523
|
-
if (!this[bodyLockReaderKey] && request.body) this[bodyLockReaderKey] = request.body.getReader();
|
|
524
|
-
return request.body;
|
|
525
|
-
},
|
|
526
|
-
get bodyUsed() {
|
|
527
|
-
if (this[bodyConsumedDirectlyKey]) return true;
|
|
528
|
-
if (this[requestCache]) return this[requestCache].bodyUsed;
|
|
529
|
-
return false;
|
|
530
|
-
}
|
|
531
|
-
};
|
|
532
|
-
Object.defineProperty(requestPrototype, "signal", { get() {
|
|
533
|
-
return this[getAbortController]().signal;
|
|
534
|
-
} });
|
|
535
|
-
[
|
|
536
|
-
"cache",
|
|
537
|
-
"credentials",
|
|
538
|
-
"destination",
|
|
539
|
-
"integrity",
|
|
540
|
-
"mode",
|
|
541
|
-
"redirect",
|
|
542
|
-
"referrer",
|
|
543
|
-
"referrerPolicy",
|
|
544
|
-
"keepalive"
|
|
545
|
-
].forEach((k) => {
|
|
546
|
-
Object.defineProperty(requestPrototype, k, { get() {
|
|
547
|
-
return this[getRequestCache]()[k];
|
|
548
|
-
} });
|
|
549
|
-
});
|
|
550
|
-
["clone", "formData"].forEach((k) => {
|
|
551
|
-
Object.defineProperty(requestPrototype, k, { value: function() {
|
|
552
|
-
if (this[bodyConsumedDirectlyKey]) {
|
|
553
|
-
if (k === "clone") throw newBodyUnusableError();
|
|
554
|
-
return rejectBodyUnusable();
|
|
555
|
-
}
|
|
556
|
-
return this[getRequestCache]()[k]();
|
|
557
|
-
} });
|
|
558
|
-
});
|
|
559
|
-
Object.defineProperty(requestPrototype, "text", { value: function() {
|
|
560
|
-
return readBodyWithFastPath(this, "text", (buf) => textDecoder.decode(buf));
|
|
561
|
-
} });
|
|
562
|
-
Object.defineProperty(requestPrototype, "arrayBuffer", { value: function() {
|
|
563
|
-
return readBodyWithFastPath(this, "arrayBuffer", (buf) => toArrayBuffer(buf));
|
|
564
|
-
} });
|
|
565
|
-
Object.defineProperty(requestPrototype, "blob", { value: function() {
|
|
566
|
-
return readBodyWithFastPath(this, "blob", (buf, request) => {
|
|
567
|
-
const type = contentType(request);
|
|
568
|
-
return new Response(buf, type ? { headers: { "content-type": type } } : void 0).blob();
|
|
569
|
-
});
|
|
570
|
-
} });
|
|
571
|
-
Object.defineProperty(requestPrototype, "json", { value: function() {
|
|
572
|
-
if (this[bodyConsumedDirectlyKey]) return rejectBodyUnusable();
|
|
573
|
-
return this.text().then(JSON.parse);
|
|
574
|
-
} });
|
|
575
|
-
Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
|
|
576
|
-
return `Request (lightweight) ${inspectFn({
|
|
577
|
-
method: this.method,
|
|
578
|
-
url: this.url,
|
|
579
|
-
headers: this.headers,
|
|
580
|
-
nativeRequest: this[requestCache]
|
|
581
|
-
}, {
|
|
582
|
-
...options,
|
|
583
|
-
depth: depth == null ? null : depth - 1
|
|
584
|
-
})}`;
|
|
585
|
-
} });
|
|
586
|
-
Object.setPrototypeOf(requestPrototype, Request$1.prototype);
|
|
587
|
-
const newRequest = (incoming, defaultHostname) => {
|
|
588
|
-
const req = Object.create(requestPrototype);
|
|
589
|
-
req[incomingKey] = incoming;
|
|
590
|
-
req[methodKey] = normalizeIncomingMethod(incoming.method);
|
|
591
|
-
const incomingUrl = incoming.url || "";
|
|
592
|
-
if (incomingUrl[0] !== "/" && (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
|
593
|
-
if (incoming instanceof Http2ServerRequest) throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
|
594
|
-
try {
|
|
595
|
-
req[urlKey] = new URL(incomingUrl).href;
|
|
596
|
-
} catch (e) {
|
|
597
|
-
throw new RequestError("Invalid absolute URL", { cause: e });
|
|
598
|
-
}
|
|
599
|
-
return req;
|
|
600
|
-
}
|
|
601
|
-
const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
|
602
|
-
if (!host) throw new RequestError("Missing host header");
|
|
603
|
-
let scheme;
|
|
604
|
-
if (incoming instanceof Http2ServerRequest) {
|
|
605
|
-
scheme = incoming.scheme;
|
|
606
|
-
if (!(scheme === "http" || scheme === "https")) throw new RequestError("Unsupported scheme");
|
|
607
|
-
} else scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
|
608
|
-
try {
|
|
609
|
-
req[urlKey] = buildUrl(scheme, host, incomingUrl);
|
|
610
|
-
} catch (e) {
|
|
611
|
-
if (e instanceof RequestError) throw e;
|
|
612
|
-
else throw new RequestError("Invalid URL", { cause: e });
|
|
613
|
-
}
|
|
614
|
-
return req;
|
|
615
|
-
};
|
|
616
|
-
//#endregion
|
|
617
|
-
//#region ../../plugins/acryl-node-server/src/adapter/response.ts
|
|
618
|
-
const defaultContentType = "text/plain; charset=UTF-8";
|
|
619
|
-
const responseCache = Symbol("responseCache");
|
|
620
|
-
const getResponseCache = Symbol("getResponseCache");
|
|
621
|
-
const cacheKey = Symbol("cache");
|
|
622
|
-
const GlobalResponse = global.Response;
|
|
623
|
-
var Response$1 = class Response$1 {
|
|
624
|
-
#body;
|
|
625
|
-
#init;
|
|
626
|
-
[getResponseCache]() {
|
|
627
|
-
const cache = this[cacheKey];
|
|
628
|
-
const liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;
|
|
629
|
-
delete this[cacheKey];
|
|
630
|
-
return this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {
|
|
631
|
-
status: this.#init?.status,
|
|
632
|
-
statusText: this.#init?.statusText,
|
|
633
|
-
headers: liveHeaders
|
|
634
|
-
} : this.#init);
|
|
635
|
-
}
|
|
636
|
-
constructor(body, init) {
|
|
637
|
-
let headers;
|
|
638
|
-
this.#body = body;
|
|
639
|
-
if (init instanceof GlobalResponse) {
|
|
640
|
-
const cachedGlobalResponse = init[responseCache];
|
|
641
|
-
if (cachedGlobalResponse) {
|
|
642
|
-
this.#init = cachedGlobalResponse;
|
|
643
|
-
this[getResponseCache]();
|
|
644
|
-
return;
|
|
645
|
-
}
|
|
646
|
-
this.#init = init instanceof Response$1 ? init.#init : init;
|
|
647
|
-
headers = new Headers(init.headers);
|
|
648
|
-
} else this.#init = init;
|
|
649
|
-
if (body == null || typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [
|
|
650
|
-
init?.status || 200,
|
|
651
|
-
body ?? null,
|
|
652
|
-
headers || init?.headers
|
|
653
|
-
];
|
|
654
|
-
}
|
|
655
|
-
get headers() {
|
|
656
|
-
const cache = this[cacheKey];
|
|
657
|
-
if (cache) {
|
|
658
|
-
if (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || (cache[1] === null ? void 0 : { "content-type": "text/plain; charset=UTF-8" }));
|
|
659
|
-
return cache[2];
|
|
660
|
-
}
|
|
661
|
-
return this[getResponseCache]().headers;
|
|
662
|
-
}
|
|
663
|
-
get status() {
|
|
664
|
-
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
|
665
|
-
}
|
|
666
|
-
get ok() {
|
|
667
|
-
const status = this.status;
|
|
668
|
-
return status >= 200 && status < 300;
|
|
669
|
-
}
|
|
670
|
-
};
|
|
671
|
-
[
|
|
672
|
-
"body",
|
|
673
|
-
"bodyUsed",
|
|
674
|
-
"redirected",
|
|
675
|
-
"statusText",
|
|
676
|
-
"trailers",
|
|
677
|
-
"type",
|
|
678
|
-
"url"
|
|
679
|
-
].forEach((k) => {
|
|
680
|
-
Object.defineProperty(Response$1.prototype, k, { get() {
|
|
681
|
-
return this[getResponseCache]()[k];
|
|
682
|
-
} });
|
|
683
|
-
});
|
|
684
|
-
[
|
|
685
|
-
"arrayBuffer",
|
|
686
|
-
"blob",
|
|
687
|
-
"clone",
|
|
688
|
-
"formData",
|
|
689
|
-
"json",
|
|
690
|
-
"text"
|
|
691
|
-
].forEach((k) => {
|
|
692
|
-
Object.defineProperty(Response$1.prototype, k, { value: function() {
|
|
693
|
-
return this[getResponseCache]()[k]();
|
|
694
|
-
} });
|
|
695
|
-
});
|
|
696
|
-
Object.defineProperty(Response$1.prototype, Symbol.for("nodejs.util.inspect.custom"), { value: function(depth, options, inspectFn) {
|
|
697
|
-
return `Response (lightweight) ${inspectFn({
|
|
698
|
-
status: this.status,
|
|
699
|
-
headers: this.headers,
|
|
700
|
-
ok: this.ok,
|
|
701
|
-
nativeResponse: this[responseCache]
|
|
702
|
-
}, {
|
|
703
|
-
...options,
|
|
704
|
-
depth: depth == null ? null : depth - 1
|
|
705
|
-
})}`;
|
|
706
|
-
} });
|
|
707
|
-
Object.setPrototypeOf(Response$1, GlobalResponse);
|
|
708
|
-
Object.setPrototypeOf(Response$1.prototype, GlobalResponse.prototype);
|
|
709
|
-
const validRedirectUrl = /^https?:\/\/[!#-;=?-[\]_a-z~A-Z]+$/;
|
|
710
|
-
const parseRedirectUrl = (url) => {
|
|
711
|
-
if (url instanceof URL) return url.href;
|
|
712
|
-
if (validRedirectUrl.test(url)) return url;
|
|
713
|
-
return new URL(url).href;
|
|
714
|
-
};
|
|
715
|
-
const validRedirectStatuses = /* @__PURE__ */ new Set([
|
|
716
|
-
301,
|
|
717
|
-
302,
|
|
718
|
-
303,
|
|
719
|
-
307,
|
|
720
|
-
308
|
|
721
|
-
]);
|
|
722
|
-
Object.defineProperty(Response$1, "redirect", {
|
|
723
|
-
value: function redirect(url, status = 302) {
|
|
724
|
-
if (!validRedirectStatuses.has(status)) throw new RangeError("Invalid status code");
|
|
725
|
-
return new Response$1(null, {
|
|
726
|
-
status,
|
|
727
|
-
headers: { location: parseRedirectUrl(url) }
|
|
728
|
-
});
|
|
729
|
-
},
|
|
730
|
-
writable: true,
|
|
731
|
-
configurable: true
|
|
732
|
-
});
|
|
733
|
-
Object.defineProperty(Response$1, "json", {
|
|
734
|
-
value: function json(data, init) {
|
|
735
|
-
const body = JSON.stringify(data);
|
|
736
|
-
if (body === void 0) throw new TypeError("The data is not JSON serializable");
|
|
737
|
-
const initHeaders = init?.headers;
|
|
738
|
-
let headers;
|
|
739
|
-
if (initHeaders) {
|
|
740
|
-
headers = new Headers(initHeaders);
|
|
741
|
-
if (!headers.has("content-type")) headers.set("content-type", "application/json");
|
|
742
|
-
} else headers = { "content-type": "application/json" };
|
|
743
|
-
return new Response$1(body, {
|
|
744
|
-
status: init?.status ?? 200,
|
|
745
|
-
statusText: init?.statusText,
|
|
746
|
-
headers
|
|
747
|
-
});
|
|
748
|
-
},
|
|
749
|
-
writable: true,
|
|
750
|
-
configurable: true
|
|
751
|
-
});
|
|
752
|
-
//#endregion
|
|
753
|
-
//#region ../../plugins/acryl-node-server/src/adapter/utils.ts
|
|
754
|
-
async function readWithoutBlocking(readPromise) {
|
|
755
|
-
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
|
756
|
-
}
|
|
757
|
-
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
|
758
|
-
const cancel = (error) => {
|
|
759
|
-
reader.cancel(error).catch(() => {});
|
|
760
|
-
};
|
|
761
|
-
writable.on("close", cancel);
|
|
762
|
-
writable.on("error", cancel);
|
|
763
|
-
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
|
764
|
-
return reader.closed.finally(() => {
|
|
765
|
-
writable.off("close", cancel);
|
|
766
|
-
writable.off("error", cancel);
|
|
767
|
-
});
|
|
768
|
-
function handleStreamError(error) {
|
|
769
|
-
if (error) writable.destroy(error);
|
|
770
|
-
}
|
|
771
|
-
function onDrain() {
|
|
772
|
-
reader.read().then(flow, handleStreamError);
|
|
773
|
-
}
|
|
774
|
-
function flow({ done, value }) {
|
|
775
|
-
try {
|
|
776
|
-
if (done) writable.end();
|
|
777
|
-
else if (!writable.write(value)) writable.once("drain", onDrain);
|
|
778
|
-
else return reader.read().then(flow, handleStreamError);
|
|
779
|
-
} catch (e) {
|
|
780
|
-
handleStreamError(e);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
function writeFromReadableStream(stream, writable) {
|
|
785
|
-
if (stream.locked) throw new TypeError("ReadableStream is locked.");
|
|
786
|
-
else if (writable.destroyed) return;
|
|
787
|
-
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
|
788
|
-
}
|
|
789
|
-
const buildOutgoingHttpHeaders = (headers, defaultContentType) => {
|
|
790
|
-
const res = {};
|
|
791
|
-
if (!(headers instanceof Headers)) headers = new Headers(headers ?? void 0);
|
|
792
|
-
if (headers.has("set-cookie")) {
|
|
793
|
-
const cookies = [];
|
|
794
|
-
for (const [k, v] of headers) if (k === "set-cookie") cookies.push(v);
|
|
795
|
-
else res[k] = v;
|
|
796
|
-
if (cookies.length > 0) res["set-cookie"] = cookies;
|
|
797
|
-
} else for (const [k, v] of headers) res[k] = v;
|
|
798
|
-
if (defaultContentType) res["content-type"] ??= defaultContentType;
|
|
799
|
-
return res;
|
|
800
|
-
};
|
|
801
|
-
//#endregion
|
|
802
|
-
//#region ../../plugins/acryl-node-server/src/adapter/listener.ts
|
|
803
|
-
const outgoingEnded = Symbol("outgoingEnded");
|
|
804
|
-
const incomingDraining = Symbol("incomingDraining");
|
|
805
|
-
const DRAIN_TIMEOUT_MS = 500;
|
|
806
|
-
const MAX_DRAIN_BYTES = 64 * 1024 * 1024;
|
|
807
|
-
const drainIncoming = (incoming) => {
|
|
808
|
-
const incomingWithDrainState = incoming;
|
|
809
|
-
if (incoming.destroyed || incomingWithDrainState[incomingDraining]) return;
|
|
810
|
-
incomingWithDrainState[incomingDraining] = true;
|
|
811
|
-
if (incoming instanceof Http2ServerRequest) {
|
|
812
|
-
try {
|
|
813
|
-
incoming.stream?.close?.(constants.NGHTTP2_NO_ERROR);
|
|
814
|
-
} catch {}
|
|
815
|
-
return;
|
|
816
|
-
}
|
|
817
|
-
let bytesRead = 0;
|
|
818
|
-
const cleanup = () => {
|
|
819
|
-
clearTimeout(timer);
|
|
820
|
-
incoming.off("data", onData);
|
|
821
|
-
incoming.off("end", cleanup);
|
|
822
|
-
incoming.off("error", cleanup);
|
|
823
|
-
};
|
|
824
|
-
const forceClose = () => {
|
|
825
|
-
cleanup();
|
|
826
|
-
const socket = incoming.socket;
|
|
827
|
-
if (socket && !socket.destroyed) {
|
|
828
|
-
if (typeof socket.destroySoon === "function") socket.destroySoon();
|
|
829
|
-
else if (typeof socket.destroy === "function") socket.destroy();
|
|
830
|
-
}
|
|
831
|
-
};
|
|
832
|
-
const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);
|
|
833
|
-
timer.unref?.();
|
|
834
|
-
const onData = (chunk) => {
|
|
835
|
-
bytesRead += chunk.length;
|
|
836
|
-
if (bytesRead > MAX_DRAIN_BYTES) forceClose();
|
|
837
|
-
};
|
|
838
|
-
incoming.removeAllListeners("data");
|
|
839
|
-
incoming.on("data", onData);
|
|
840
|
-
incoming.on("end", cleanup);
|
|
841
|
-
incoming.on("error", cleanup);
|
|
842
|
-
incoming.resume();
|
|
843
|
-
};
|
|
844
|
-
const makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {
|
|
845
|
-
if (incoming.errored) {
|
|
846
|
-
recordBodyBufferedBeforeDisconnect(incoming);
|
|
847
|
-
req[abortRequest](incoming.errored.toString());
|
|
848
|
-
} else if (!outgoing.writableFinished || incoming instanceof Http2ServerRequest && incoming.aborted) {
|
|
849
|
-
recordBodyBufferedBeforeDisconnect(incoming);
|
|
850
|
-
req[abortRequest]("Client connection prematurely closed.");
|
|
851
|
-
}
|
|
852
|
-
if (needsBodyCleanup && !incoming.readableEnded) setTimeout(() => {
|
|
853
|
-
if (!incoming.readableEnded) setTimeout(() => {
|
|
854
|
-
drainIncoming(incoming);
|
|
855
|
-
});
|
|
856
|
-
});
|
|
857
|
-
};
|
|
858
|
-
const isImmediateCacheableResponse = (res) => {
|
|
859
|
-
if (!(cacheKey in res)) return false;
|
|
860
|
-
const body = res[cacheKey][1];
|
|
861
|
-
return body === null || typeof body === "string" || body instanceof Uint8Array;
|
|
862
|
-
};
|
|
863
|
-
const handleRequestError = () => new Response(null, { status: 400 });
|
|
864
|
-
const handleFetchError = (e) => new Response(null, { status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500 });
|
|
865
|
-
const handleResponseError = (e, outgoing) => {
|
|
866
|
-
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
|
867
|
-
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") console.info("The user aborted a request.");
|
|
868
|
-
else {
|
|
869
|
-
console.error(e);
|
|
870
|
-
if (!outgoing.headersSent) {
|
|
871
|
-
if (outgoing instanceof ServerResponse) outgoing._contentLength = null;
|
|
872
|
-
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
|
873
|
-
}
|
|
874
|
-
outgoing.end(`Error: ${err.message}`);
|
|
875
|
-
outgoing.destroy(err);
|
|
876
|
-
}
|
|
877
|
-
};
|
|
878
|
-
const flushHeaders = (outgoing) => {
|
|
879
|
-
if ("flushHeaders" in outgoing && outgoing.writable) outgoing.flushHeaders();
|
|
880
|
-
};
|
|
881
|
-
const trySetContentLength = (outgoing, status, length) => {
|
|
882
|
-
const http1 = outgoing;
|
|
883
|
-
if (http1._contentLength === null && http1._hasBody && http1.useChunkedEncodingByDefault && !http1._removedContLen && status >= 200 && status !== 204 && status !== 304 && !outgoing.hasHeader("content-length") && !outgoing.hasHeader("transfer-encoding") && !outgoing.hasHeader("trailer")) {
|
|
884
|
-
http1._contentLength = length;
|
|
885
|
-
return true;
|
|
886
|
-
}
|
|
887
|
-
return false;
|
|
888
|
-
};
|
|
889
|
-
const writeDefaultHeaders = (outgoing, status, length) => {
|
|
890
|
-
if (trySetContentLength(outgoing, status, length)) outgoing.writeHead(status, { "Content-Type": defaultContentType });
|
|
891
|
-
else outgoing.writeHead(status, {
|
|
892
|
-
"Content-Type": defaultContentType,
|
|
893
|
-
"Content-Length": length
|
|
894
|
-
});
|
|
895
|
-
};
|
|
896
|
-
const responseViaCache = async (res, outgoing) => {
|
|
897
|
-
let [status, body, header] = res[cacheKey];
|
|
898
|
-
if (!header) {
|
|
899
|
-
if (body === null) {
|
|
900
|
-
outgoing.writeHead(status);
|
|
901
|
-
outgoing.end();
|
|
902
|
-
} else if (typeof body === "string") {
|
|
903
|
-
writeDefaultHeaders(outgoing, status, Buffer.byteLength(body));
|
|
904
|
-
outgoing.end(body);
|
|
905
|
-
} else if (body instanceof Uint8Array) {
|
|
906
|
-
writeDefaultHeaders(outgoing, status, body.byteLength);
|
|
907
|
-
outgoing.end(body);
|
|
908
|
-
} else if (body instanceof Blob) {
|
|
909
|
-
writeDefaultHeaders(outgoing, status, body.size);
|
|
910
|
-
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
|
911
|
-
} else {
|
|
912
|
-
outgoing.writeHead(status, { "Content-Type": defaultContentType });
|
|
913
|
-
flushHeaders(outgoing);
|
|
914
|
-
await writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));
|
|
915
|
-
}
|
|
916
|
-
outgoing[outgoingEnded]?.();
|
|
917
|
-
return;
|
|
918
|
-
}
|
|
919
|
-
let hasContentLength = false;
|
|
920
|
-
let plainHeaders = false;
|
|
921
|
-
let canAutoLength = true;
|
|
922
|
-
if (header instanceof Headers) {
|
|
923
|
-
hasContentLength = header.has("content-length");
|
|
924
|
-
header = buildOutgoingHttpHeaders(header, body === null ? void 0 : defaultContentType);
|
|
925
|
-
} else if (Array.isArray(header)) {
|
|
926
|
-
const headerObj = new Headers(header);
|
|
927
|
-
hasContentLength = headerObj.has("content-length");
|
|
928
|
-
header = buildOutgoingHttpHeaders(headerObj, body === null ? void 0 : defaultContentType);
|
|
929
|
-
} else {
|
|
930
|
-
plainHeaders = true;
|
|
931
|
-
for (const key in header) {
|
|
932
|
-
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
|
933
|
-
hasContentLength = true;
|
|
934
|
-
break;
|
|
935
|
-
}
|
|
936
|
-
if (key.length === 17 && key.toLowerCase() === "transfer-encoding" || key.length === 7 && key.toLowerCase() === "trailer") canAutoLength = false;
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
if (!hasContentLength) {
|
|
940
|
-
let length;
|
|
941
|
-
if (typeof body === "string") length = Buffer.byteLength(body);
|
|
942
|
-
else if (body instanceof Uint8Array) length = body.byteLength;
|
|
943
|
-
else if (body instanceof Blob) length = body.size;
|
|
944
|
-
if (length !== void 0 && (!plainHeaders || !canAutoLength || !trySetContentLength(outgoing, status, length))) {
|
|
945
|
-
if (plainHeaders) header = { ...header };
|
|
946
|
-
header["Content-Length"] = length;
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
outgoing.writeHead(status, header);
|
|
950
|
-
if (body == null) outgoing.end();
|
|
951
|
-
else if (typeof body === "string" || body instanceof Uint8Array) outgoing.end(body);
|
|
952
|
-
else if (body instanceof Blob) outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
|
953
|
-
else {
|
|
954
|
-
flushHeaders(outgoing);
|
|
955
|
-
await writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));
|
|
956
|
-
}
|
|
957
|
-
outgoing[outgoingEnded]?.();
|
|
958
|
-
};
|
|
959
|
-
const isPromise = (res) => typeof res.then === "function";
|
|
960
|
-
const responseViaResponseObject = async (res, outgoing, options = {}) => {
|
|
961
|
-
if (isPromise(res)) if (options.errorHandler) try {
|
|
962
|
-
res = await res;
|
|
963
|
-
} catch (err) {
|
|
964
|
-
const errRes = await options.errorHandler(err);
|
|
965
|
-
if (!errRes) return;
|
|
966
|
-
res = errRes;
|
|
967
|
-
}
|
|
968
|
-
else res = await res.catch(handleFetchError);
|
|
969
|
-
if (cacheKey in res) return responseViaCache(res, outgoing);
|
|
970
|
-
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers, res.body === null ? void 0 : defaultContentType);
|
|
971
|
-
if (res.body) {
|
|
972
|
-
const reader = res.body.getReader();
|
|
973
|
-
const values = [];
|
|
974
|
-
let done = false;
|
|
975
|
-
let currentReadPromise = void 0;
|
|
976
|
-
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
|
977
|
-
let maxReadCount = 2;
|
|
978
|
-
for (let i = 0; i < maxReadCount; i++) {
|
|
979
|
-
currentReadPromise ||= reader.read();
|
|
980
|
-
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
|
981
|
-
console.error(e);
|
|
982
|
-
done = true;
|
|
983
|
-
});
|
|
984
|
-
if (!chunk) {
|
|
985
|
-
if (i === 1) {
|
|
986
|
-
await new Promise((resolve) => setTimeout(resolve));
|
|
987
|
-
maxReadCount = 3;
|
|
988
|
-
continue;
|
|
989
|
-
}
|
|
990
|
-
break;
|
|
991
|
-
}
|
|
992
|
-
currentReadPromise = void 0;
|
|
993
|
-
if (chunk.value) values.push(chunk.value);
|
|
994
|
-
if (chunk.done) {
|
|
995
|
-
done = true;
|
|
996
|
-
break;
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
if (done && !("content-length" in resHeaderRecord)) resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
|
1000
|
-
}
|
|
1001
|
-
outgoing.writeHead(res.status, resHeaderRecord);
|
|
1002
|
-
values.forEach((value) => {
|
|
1003
|
-
outgoing.write(value);
|
|
1004
|
-
});
|
|
1005
|
-
if (done) outgoing.end();
|
|
1006
|
-
else {
|
|
1007
|
-
if (values.length === 0) flushHeaders(outgoing);
|
|
1008
|
-
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
|
1009
|
-
}
|
|
1010
|
-
} else if (resHeaderRecord["x-acryl-already-sent"]) {} else {
|
|
1011
|
-
outgoing.writeHead(res.status, resHeaderRecord);
|
|
1012
|
-
outgoing.end();
|
|
1013
|
-
}
|
|
1014
|
-
outgoing[outgoingEnded]?.();
|
|
1015
|
-
};
|
|
1016
|
-
const getRequestListener = (fetchCallback, options = {}) => {
|
|
1017
|
-
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
|
1018
|
-
if (options.overrideGlobalObjects !== false && global.Request !== Request$1) {
|
|
1019
|
-
Object.defineProperty(global, "Request", { value: Request$1 });
|
|
1020
|
-
Object.defineProperty(global, "Response", { value: Response$1 });
|
|
1021
|
-
}
|
|
1022
|
-
return async (incoming, outgoing) => {
|
|
1023
|
-
let res, req;
|
|
1024
|
-
let needsBodyCleanup = false;
|
|
1025
|
-
let closeHandlerAttached = false;
|
|
1026
|
-
const ensureCloseHandler = () => {
|
|
1027
|
-
if (!req || closeHandlerAttached) return;
|
|
1028
|
-
closeHandlerAttached = true;
|
|
1029
|
-
outgoing.on("close", makeCloseHandler(req, incoming, outgoing, needsBodyCleanup));
|
|
1030
|
-
};
|
|
1031
|
-
try {
|
|
1032
|
-
req = newRequest(incoming, options.hostname);
|
|
1033
|
-
needsBodyCleanup = autoCleanupIncoming && !(incoming.method === "GET" || incoming.method === "HEAD");
|
|
1034
|
-
if (needsBodyCleanup) {
|
|
1035
|
-
incoming[wrapBodyStream] = true;
|
|
1036
|
-
if (incoming instanceof Http2ServerRequest) outgoing[outgoingEnded] = () => {
|
|
1037
|
-
if (!incoming.readableEnded) setTimeout(() => {
|
|
1038
|
-
if (!incoming.readableEnded) setTimeout(() => {
|
|
1039
|
-
incoming.destroy();
|
|
1040
|
-
outgoing.destroy();
|
|
1041
|
-
});
|
|
1042
|
-
});
|
|
1043
|
-
};
|
|
1044
|
-
}
|
|
1045
|
-
res = fetchCallback(req, {
|
|
1046
|
-
incoming,
|
|
1047
|
-
outgoing
|
|
1048
|
-
});
|
|
1049
|
-
if (!isPromise(res) && isImmediateCacheableResponse(res)) {
|
|
1050
|
-
if (needsBodyCleanup && !incoming.readableEnded) outgoing.once("finish", () => {
|
|
1051
|
-
if (!incoming.readableEnded) drainIncoming(incoming);
|
|
1052
|
-
});
|
|
1053
|
-
return responseViaCache(res, outgoing);
|
|
1054
|
-
}
|
|
1055
|
-
ensureCloseHandler();
|
|
1056
|
-
} catch (e) {
|
|
1057
|
-
if (!res) if (options.errorHandler) {
|
|
1058
|
-
ensureCloseHandler();
|
|
1059
|
-
res = await options.errorHandler(req ? e : toRequestError(e));
|
|
1060
|
-
if (!res) return;
|
|
1061
|
-
} else if (!req) res = handleRequestError();
|
|
1062
|
-
else res = handleFetchError(e);
|
|
1063
|
-
else return handleResponseError(e, outgoing);
|
|
1064
|
-
}
|
|
1065
|
-
try {
|
|
1066
|
-
return await responseViaResponseObject(res, outgoing, options);
|
|
1067
|
-
} catch (e) {
|
|
1068
|
-
return handleResponseError(e, outgoing);
|
|
1069
|
-
}
|
|
1070
|
-
};
|
|
1071
|
-
};
|
|
1072
|
-
//#endregion
|
|
1073
|
-
//#region ../../plugins/acryl-node-server/src/adapter/websocket.ts
|
|
1074
|
-
/**
|
|
1075
|
-
* @link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
|
|
1076
|
-
*/
|
|
1077
|
-
const CloseEvent = globalThis.CloseEvent ?? class extends Event {
|
|
1078
|
-
#eventInitDict;
|
|
1079
|
-
constructor(type, eventInitDict = {}) {
|
|
1080
|
-
super(type, eventInitDict);
|
|
1081
|
-
this.#eventInitDict = eventInitDict;
|
|
1082
|
-
}
|
|
1083
|
-
get wasClean() {
|
|
1084
|
-
return this.#eventInitDict.wasClean ?? false;
|
|
1085
|
-
}
|
|
1086
|
-
get code() {
|
|
1087
|
-
return this.#eventInitDict.code ?? 0;
|
|
1088
|
-
}
|
|
1089
|
-
get reason() {
|
|
1090
|
-
return this.#eventInitDict.reason ?? "";
|
|
1091
|
-
}
|
|
1092
|
-
};
|
|
1093
|
-
/**
|
|
1094
|
-
* Node.js has no global `ErrorEvent`, unlike `Event`/`MessageEvent`/`CloseEvent`.
|
|
1095
|
-
* @link https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent
|
|
1096
|
-
*/
|
|
1097
|
-
const ErrorEvent = globalThis.ErrorEvent ?? class extends Event {
|
|
1098
|
-
#eventInitDict;
|
|
1099
|
-
constructor(type, eventInitDict = {}) {
|
|
1100
|
-
super(type, eventInitDict);
|
|
1101
|
-
this.#eventInitDict = eventInitDict;
|
|
1102
|
-
}
|
|
1103
|
-
get message() {
|
|
1104
|
-
return this.#eventInitDict.message ?? "";
|
|
1105
|
-
}
|
|
1106
|
-
get filename() {
|
|
1107
|
-
return this.#eventInitDict.filename ?? "";
|
|
1108
|
-
}
|
|
1109
|
-
get lineno() {
|
|
1110
|
-
return this.#eventInitDict.lineno ?? 0;
|
|
1111
|
-
}
|
|
1112
|
-
get colno() {
|
|
1113
|
-
return this.#eventInitDict.colno ?? 0;
|
|
1114
|
-
}
|
|
1115
|
-
get error() {
|
|
1116
|
-
return this.#eventInitDict.error ?? null;
|
|
1117
|
-
}
|
|
1118
|
-
};
|
|
1119
|
-
const generateConnectionSymbol = () => Symbol("connection");
|
|
1120
|
-
const CONNECTION_SYMBOL_KEY = Symbol("CONNECTION_SYMBOL_KEY");
|
|
1121
|
-
const WAIT_FOR_WEBSOCKET_SYMBOL = Symbol("WAIT_FOR_WEBSOCKET_SYMBOL");
|
|
1122
|
-
const responseHeadersToSkip = /* @__PURE__ */ new Set([
|
|
1123
|
-
"connection",
|
|
1124
|
-
"content-length",
|
|
1125
|
-
"keep-alive",
|
|
1126
|
-
"proxy-authenticate",
|
|
1127
|
-
"proxy-authorization",
|
|
1128
|
-
"te",
|
|
1129
|
-
"trailer",
|
|
1130
|
-
"transfer-encoding",
|
|
1131
|
-
"upgrade",
|
|
1132
|
-
"sec-websocket-accept",
|
|
1133
|
-
"sec-websocket-extensions",
|
|
1134
|
-
"sec-websocket-protocol"
|
|
1135
|
-
]);
|
|
1136
|
-
const appendResponseHeaders = (headers, responseHeaders) => {
|
|
1137
|
-
if (!responseHeaders) return;
|
|
1138
|
-
responseHeaders.forEach((value, key) => {
|
|
1139
|
-
if (responseHeadersToSkip.has(key.toLowerCase())) return;
|
|
1140
|
-
headers.push(`${key}: ${value}`);
|
|
1141
|
-
});
|
|
1142
|
-
};
|
|
1143
|
-
const rejectUpgradeRequest = (socket, status, responseHeaders) => {
|
|
1144
|
-
const responseLines = ["Connection: close", "Content-Length: 0"];
|
|
1145
|
-
appendResponseHeaders(responseLines, responseHeaders);
|
|
1146
|
-
socket.end(`HTTP/1.1 ${status.toString()} ${STATUS_CODES[status] ?? ""}\r\n${responseLines.join("\r\n")}\r\n\r
|
|
1147
|
-
`);
|
|
1148
|
-
};
|
|
1149
|
-
const createUpgradeRequest = (request) => {
|
|
1150
|
-
const protocol = request.socket.encrypted ? "https" : "http";
|
|
1151
|
-
const url = new URL(request.url ?? "/", `${protocol}://${request.headers.host ?? "localhost"}`);
|
|
1152
|
-
const headers = new Headers();
|
|
1153
|
-
for (const key in request.headers) {
|
|
1154
|
-
const value = request.headers[key];
|
|
1155
|
-
if (!value) continue;
|
|
1156
|
-
headers.append(key, Array.isArray(value) ? value[0] : value);
|
|
1157
|
-
}
|
|
1158
|
-
return new Request(url, { headers });
|
|
1159
|
-
};
|
|
1160
|
-
const setupWebSocket = (options) => {
|
|
1161
|
-
const { server, fetchCallback, wss } = options;
|
|
1162
|
-
const waiterMap = /* @__PURE__ */ new Map();
|
|
1163
|
-
wss.on("connection", (ws, request) => {
|
|
1164
|
-
const waiter = waiterMap.get(request);
|
|
1165
|
-
if (waiter) {
|
|
1166
|
-
waiter.resolve(ws);
|
|
1167
|
-
waiterMap.delete(request);
|
|
1168
|
-
}
|
|
1169
|
-
});
|
|
1170
|
-
const rejectWaiter = (request) => {
|
|
1171
|
-
const waiter = waiterMap.get(request);
|
|
1172
|
-
if (waiter) {
|
|
1173
|
-
waiterMap.delete(request);
|
|
1174
|
-
waiter.reject(/* @__PURE__ */ new Error("WebSocket handshake aborted"));
|
|
1175
|
-
}
|
|
1176
|
-
};
|
|
1177
|
-
const waitForWebSocket = (request, connectionSymbol) => {
|
|
1178
|
-
return new Promise((resolve, reject) => {
|
|
1179
|
-
waiterMap.set(request, {
|
|
1180
|
-
resolve,
|
|
1181
|
-
reject,
|
|
1182
|
-
connectionSymbol
|
|
1183
|
-
});
|
|
1184
|
-
});
|
|
1185
|
-
};
|
|
1186
|
-
server.on("upgrade", async (request, socket, head) => {
|
|
1187
|
-
if (request.headers.upgrade?.toLowerCase() !== "websocket") return;
|
|
1188
|
-
const env = {
|
|
1189
|
-
incoming: request,
|
|
1190
|
-
outgoing: void 0,
|
|
1191
|
-
wss,
|
|
1192
|
-
[WAIT_FOR_WEBSOCKET_SYMBOL]: waitForWebSocket
|
|
1193
|
-
};
|
|
1194
|
-
let status = 400;
|
|
1195
|
-
let responseHeaders;
|
|
1196
|
-
try {
|
|
1197
|
-
const response = await fetchCallback(createUpgradeRequest(request), env);
|
|
1198
|
-
if (response instanceof Response) {
|
|
1199
|
-
status = response.status;
|
|
1200
|
-
responseHeaders = response.headers;
|
|
1201
|
-
}
|
|
1202
|
-
} catch {
|
|
1203
|
-
if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, 500);
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
|
-
const waiter = waiterMap.get(request);
|
|
1207
|
-
if (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {
|
|
1208
|
-
rejectWaiter(request);
|
|
1209
|
-
if (server.listenerCount("upgrade") === 1) rejectUpgradeRequest(socket, status, responseHeaders);
|
|
1210
|
-
return;
|
|
1211
|
-
}
|
|
1212
|
-
const addResponseHeaders = (headers) => {
|
|
1213
|
-
appendResponseHeaders(headers, responseHeaders);
|
|
1214
|
-
};
|
|
1215
|
-
const reclaimWaiterOnClose = () => rejectWaiter(request);
|
|
1216
|
-
socket.once("close", reclaimWaiterOnClose);
|
|
1217
|
-
wss.on("headers", addResponseHeaders);
|
|
1218
|
-
try {
|
|
1219
|
-
wss.handleUpgrade(request, socket, head, (ws) => {
|
|
1220
|
-
socket.off("close", reclaimWaiterOnClose);
|
|
1221
|
-
wss.emit("connection", ws, request);
|
|
1222
|
-
});
|
|
1223
|
-
} finally {
|
|
1224
|
-
wss.off("headers", addResponseHeaders);
|
|
1225
|
-
}
|
|
1226
|
-
});
|
|
1227
|
-
server.on("close", () => {
|
|
1228
|
-
wss.close();
|
|
1229
|
-
});
|
|
1230
|
-
};
|
|
1231
|
-
const upgradeWebSocket = defineWebSocketHelper(async (c, events, options) => {
|
|
1232
|
-
if (c.req.header("upgrade")?.toLowerCase() !== "websocket") return;
|
|
1233
|
-
const env = c.env;
|
|
1234
|
-
const waitForWebSocket = env[WAIT_FOR_WEBSOCKET_SYMBOL];
|
|
1235
|
-
if (!waitForWebSocket || !env.incoming) return new Response(null, { status: 500 });
|
|
1236
|
-
const connectionSymbol = generateConnectionSymbol();
|
|
1237
|
-
env[CONNECTION_SYMBOL_KEY] = connectionSymbol;
|
|
1238
|
-
(async () => {
|
|
1239
|
-
let ws;
|
|
1240
|
-
try {
|
|
1241
|
-
ws = await waitForWebSocket(env.incoming, connectionSymbol);
|
|
1242
|
-
} catch {
|
|
1243
|
-
return;
|
|
1244
|
-
}
|
|
1245
|
-
const messagesReceivedInStarting = [];
|
|
1246
|
-
const bufferMessage = (data, isBinary) => {
|
|
1247
|
-
messagesReceivedInStarting.push([data, isBinary]);
|
|
1248
|
-
};
|
|
1249
|
-
ws.on("message", bufferMessage);
|
|
1250
|
-
const ctx = {
|
|
1251
|
-
binaryType: "arraybuffer",
|
|
1252
|
-
close(code, reason) {
|
|
1253
|
-
ws.close(code, reason);
|
|
1254
|
-
},
|
|
1255
|
-
protocol: ws.protocol,
|
|
1256
|
-
raw: ws,
|
|
1257
|
-
get readyState() {
|
|
1258
|
-
return ws.readyState;
|
|
1259
|
-
},
|
|
1260
|
-
send(source, opts) {
|
|
1261
|
-
ws.send(source, { compress: opts?.compress });
|
|
1262
|
-
},
|
|
1263
|
-
url: new URL(c.req.url)
|
|
1264
|
-
};
|
|
1265
|
-
try {
|
|
1266
|
-
events?.onOpen?.(new Event("open"), ctx);
|
|
1267
|
-
} catch (e) {
|
|
1268
|
-
(options?.onError ?? console.error)(e);
|
|
1269
|
-
}
|
|
1270
|
-
const handleMessage = (data, isBinary) => {
|
|
1271
|
-
const datas = Array.isArray(data) ? data : [data];
|
|
1272
|
-
for (const data of datas) try {
|
|
1273
|
-
events?.onMessage?.(new MessageEvent("message", { data: isBinary ? data instanceof ArrayBuffer ? data : data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) : typeof data === "string" ? data : Buffer.from(data).toString("utf-8") }), ctx);
|
|
1274
|
-
} catch (e) {
|
|
1275
|
-
(options?.onError ?? console.error)(e);
|
|
1276
|
-
}
|
|
1277
|
-
};
|
|
1278
|
-
ws.off("message", bufferMessage);
|
|
1279
|
-
for (const message of messagesReceivedInStarting) handleMessage(...message);
|
|
1280
|
-
ws.on("message", (data, isBinary) => {
|
|
1281
|
-
handleMessage(data, isBinary);
|
|
1282
|
-
});
|
|
1283
|
-
ws.on("close", (code, reason) => {
|
|
1284
|
-
try {
|
|
1285
|
-
events?.onClose?.(new CloseEvent("close", {
|
|
1286
|
-
code,
|
|
1287
|
-
reason: reason.toString()
|
|
1288
|
-
}), ctx);
|
|
1289
|
-
} catch (e) {
|
|
1290
|
-
(options?.onError ?? console.error)(e);
|
|
1291
|
-
}
|
|
1292
|
-
});
|
|
1293
|
-
ws.on("error", (error) => {
|
|
1294
|
-
try {
|
|
1295
|
-
events?.onError?.(new ErrorEvent("error", { error }), ctx);
|
|
1296
|
-
} catch (e) {
|
|
1297
|
-
(options?.onError ?? console.error)(e);
|
|
1298
|
-
}
|
|
1299
|
-
});
|
|
1300
|
-
})();
|
|
1301
|
-
return new Response();
|
|
1302
|
-
});
|
|
1303
|
-
function createAdaptorServer(options) {
|
|
1304
|
-
const fetchCallback = options.fetch;
|
|
1305
|
-
const requestListener = getRequestListener(fetchCallback, {
|
|
1306
|
-
hostname: options.hostname,
|
|
1307
|
-
overrideGlobalObjects: options.overrideGlobalObjects,
|
|
1308
|
-
autoCleanupIncoming: options.autoCleanupIncoming
|
|
1309
|
-
});
|
|
1310
|
-
const server = (options.createServer || createServer)(options.serverOptions || {}, requestListener);
|
|
1311
|
-
if (options.websocket && options.websocket.server) {
|
|
1312
|
-
if (options.websocket.server.options.noServer !== true) throw new Error("WebSocket server must be created with { noServer: true } option");
|
|
1313
|
-
setupWebSocket({
|
|
1314
|
-
server,
|
|
1315
|
-
fetchCallback,
|
|
1316
|
-
wss: options.websocket.server
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
return server;
|
|
1320
|
-
}
|
|
1321
|
-
function serve(options, listeningListener) {
|
|
1322
|
-
const server = createAdaptorServer(options);
|
|
1323
|
-
server.listen(options?.port ?? 3e3, options.hostname ?? "127.0.0.1", () => {
|
|
1324
|
-
const serverInfo = server.address();
|
|
1325
|
-
listeningListener && listeningListener(serverInfo);
|
|
1326
|
-
});
|
|
1327
|
-
return server;
|
|
1328
|
-
}
|
|
1329
|
-
//#endregion
|
|
1330
|
-
//#region ../../plugins/acryl-node-server/src/client-modules.ts
|
|
1331
|
-
/**
|
|
1332
|
-
* Client components without a bundler. `clientModules({ root: 'src/client' })` is an app that serves the TypeScript and JSX modules of a
|
|
1333
|
-
* folder to the browser as ES modules: a `.tsx`/`.ts`/`.jsx` file compiled with the app's own `typescript` (JSX for `acrylblends/jsx/dom`),
|
|
1334
|
-
* a `.js`/`.mjs` file as it is. The framework's own browser imports (`acrylblends/jsx/dom` with its runtimes and `client`,
|
|
1335
|
-
* `acrylblends/client` and `acrylblends/read-sse`) are rewritten to three self-contained files the same app serves, at a URL relative to each module, so a page needs
|
|
1336
|
-
* one `<script type="module" src="/client/counter.tsx">` and no import map, under whatever path the app is routed at.
|
|
1337
|
-
*
|
|
1338
|
-
* Production runs without `typescript` (a deploy that leaves out devDependencies): `buildClientModules` writes the same compiled modules
|
|
1339
|
-
* and the three browser files into a folder, and with `NODE_ENV=production` and `compiled` set, only that folder is served.
|
|
1340
|
-
*/
|
|
1341
|
-
/** The folder the three browser files are served from, below the app's mount. A source folder of this name is not served. */
|
|
1342
|
-
const RUNTIME_DIR = "@acrylblends";
|
|
1343
|
-
/** The framework's browser imports and the browser file that provides each. */
|
|
1344
|
-
const BROWSER_IMPORTS = {
|
|
1345
|
-
"acrylblends/jsx/dom": "jsx-dom.js",
|
|
1346
|
-
"acrylblends/jsx/dom/jsx-runtime": "jsx-dom.js",
|
|
1347
|
-
"acrylblends/jsx/dom/jsx-dev-runtime": "jsx-dom.js",
|
|
1348
|
-
"acrylblends/jsx/dom/client": "jsx-dom.js",
|
|
1349
|
-
"acrylblends/client": "client.js",
|
|
1350
|
-
"acrylblends/read-sse": "read-sse.js"
|
|
1351
|
-
};
|
|
1352
|
-
const RUNTIME_FILES = [
|
|
1353
|
-
"jsx-dom.js",
|
|
1354
|
-
"client.js",
|
|
1355
|
-
"read-sse.js"
|
|
1356
|
-
];
|
|
1357
|
-
const COMPILED = /* @__PURE__ */ new Set([
|
|
1358
|
-
".ts",
|
|
1359
|
-
".tsx",
|
|
1360
|
-
".jsx",
|
|
1361
|
-
".mts"
|
|
1362
|
-
]);
|
|
1363
|
-
const SERVED = /* @__PURE__ */ new Set([
|
|
1364
|
-
...COMPILED,
|
|
1365
|
-
".js",
|
|
1366
|
-
".mjs"
|
|
1367
|
-
]);
|
|
1368
|
-
const JS_TYPE = "text/javascript; charset=utf-8";
|
|
1369
|
-
/** The cache bound when `cacheBytes` is not given. */
|
|
1370
|
-
const DEFAULT_CACHE_BYTES = 16 * 1024 * 1024;
|
|
1371
|
-
/** The framework's three browser files, next to the built module that contains this code. */
|
|
1372
|
-
const defaultRuntimeDir = () => fileURLToPath(new URL("./browser/", import.meta.url));
|
|
1373
|
-
/** A module path below the root (`widgets/counter.tsx`) with the URL prefix that reaches the browser files from it. */
|
|
1374
|
-
const runtimePrefix = (relativePath) => {
|
|
1375
|
-
const depth = relativePath.split("/").length - 1;
|
|
1376
|
-
return depth === 0 ? "./" : "../".repeat(depth);
|
|
1377
|
-
};
|
|
1378
|
-
/** One client module compiled for the browser: TypeScript and JSX compiled, the framework's imports pointed at its browser files. */
|
|
1379
|
-
function compileForBrowser(file, relativePath) {
|
|
1380
|
-
const prefix = runtimePrefix(relativePath);
|
|
1381
|
-
return compileModule(file, readFileSync(file, "utf8"), {
|
|
1382
|
-
importSource: "acrylblends/jsx/dom",
|
|
1383
|
-
defaultImportSource: "acrylblends/jsx/dom",
|
|
1384
|
-
what: "is a client module",
|
|
1385
|
-
rewrite: (specifier) => {
|
|
1386
|
-
const target = BROWSER_IMPORTS[specifier];
|
|
1387
|
-
return target === void 0 ? void 0 : `${prefix}${RUNTIME_DIR}/${target}`;
|
|
1388
|
-
}
|
|
1389
|
-
});
|
|
1390
|
-
}
|
|
1391
|
-
/**
|
|
1392
|
-
* The path below the root a request names, or `undefined` when it must not be served: a `..` or dot segment, a backslash or NUL, an
|
|
1393
|
-
* extension outside the served set, or a `.d.ts` file.
|
|
1394
|
-
*/
|
|
1395
|
-
function servedPath(requestPath) {
|
|
1396
|
-
let decoded;
|
|
1397
|
-
try {
|
|
1398
|
-
decoded = decodeURIComponent(requestPath);
|
|
1399
|
-
} catch {
|
|
1400
|
-
return;
|
|
1401
|
-
}
|
|
1402
|
-
const parts = decoded.split("/").filter((part) => part !== "");
|
|
1403
|
-
if (parts.length === 0 || parts.some((part) => part.startsWith(".") || part.includes("\\") || part.includes("\0"))) return void 0;
|
|
1404
|
-
const path = parts.join("/");
|
|
1405
|
-
if (!SERVED.has(extname(path)) || path.endsWith(".d.ts")) return void 0;
|
|
1406
|
-
return path;
|
|
1407
|
-
}
|
|
1408
|
-
/** A real file inside `root` (symbolic links followed), or `undefined`. */
|
|
1409
|
-
function fileInside(root, path) {
|
|
1410
|
-
try {
|
|
1411
|
-
const file = realpathSync(join(root, ...path.split("/")));
|
|
1412
|
-
return file.startsWith(root + sep) && statSync(file).isFile() ? file : void 0;
|
|
1413
|
-
} catch {
|
|
1414
|
-
return;
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
/** A file's validator: its size and modification time. */
|
|
1418
|
-
const etagOf = (stat) => `"${stat.size.toString(36)}-${Math.trunc(stat.mtimeMs).toString(36)}"`;
|
|
1419
|
-
/** Compiled modules, least recently served first, bounded by the UTF-8 bytes of their code. Exported for its tests. */
|
|
1420
|
-
var CompileCache = class {
|
|
1421
|
-
entries = /* @__PURE__ */ new Map();
|
|
1422
|
-
bytes = 0;
|
|
1423
|
-
limit;
|
|
1424
|
-
constructor(limit) {
|
|
1425
|
-
this.limit = limit;
|
|
1426
|
-
}
|
|
1427
|
-
get(file, mtimeMs, size) {
|
|
1428
|
-
const entry = this.entries.get(file);
|
|
1429
|
-
if (entry === void 0) return void 0;
|
|
1430
|
-
this.entries.delete(file);
|
|
1431
|
-
if (entry.mtimeMs !== mtimeMs || entry.size !== size) {
|
|
1432
|
-
this.bytes -= entry.bytes;
|
|
1433
|
-
return;
|
|
1434
|
-
}
|
|
1435
|
-
this.entries.set(file, entry);
|
|
1436
|
-
return entry;
|
|
1437
|
-
}
|
|
1438
|
-
set(file, stat, code) {
|
|
1439
|
-
const entry = {
|
|
1440
|
-
mtimeMs: stat.mtimeMs,
|
|
1441
|
-
size: stat.size,
|
|
1442
|
-
etag: etagOf(stat),
|
|
1443
|
-
code,
|
|
1444
|
-
bytes: Buffer.byteLength(code)
|
|
1445
|
-
};
|
|
1446
|
-
const previous = this.entries.get(file);
|
|
1447
|
-
if (previous !== void 0) {
|
|
1448
|
-
this.entries.delete(file);
|
|
1449
|
-
this.bytes -= previous.bytes;
|
|
1450
|
-
}
|
|
1451
|
-
if (entry.bytes > this.limit) return entry;
|
|
1452
|
-
this.entries.set(file, entry);
|
|
1453
|
-
this.bytes += entry.bytes;
|
|
1454
|
-
for (const [key, old] of this.entries) {
|
|
1455
|
-
if (this.bytes <= this.limit) break;
|
|
1456
|
-
this.entries.delete(key);
|
|
1457
|
-
this.bytes -= old.bytes;
|
|
1458
|
-
}
|
|
1459
|
-
return entry;
|
|
1460
|
-
}
|
|
1461
|
-
/** The UTF-8 bytes of code held now. */
|
|
1462
|
-
get heldBytes() {
|
|
1463
|
-
return this.bytes;
|
|
1464
|
-
}
|
|
1465
|
-
/** The files held now, least recently served first. */
|
|
1466
|
-
get files() {
|
|
1467
|
-
return [...this.entries.keys()];
|
|
1468
|
-
}
|
|
1469
|
-
};
|
|
1470
|
-
const absolute = (path) => isAbsolute(path) ? path : resolve(path);
|
|
1471
|
-
/** A folder's real path; one that does not exist (a production image that ships only the compiled folder) keeps its absolute path. */
|
|
1472
|
-
const realFolder = (path) => {
|
|
1473
|
-
try {
|
|
1474
|
-
return realpathSync(absolute(path));
|
|
1475
|
-
} catch {
|
|
1476
|
-
return absolute(path);
|
|
1477
|
-
}
|
|
1478
|
-
};
|
|
1479
|
-
/**
|
|
1480
|
-
* An app serving a folder of client modules to the browser. Route it where the page's script tags point: `app.route('/client',
|
|
1481
|
-
* clientModules({ root: 'src/client' }))` serves `src/client/counter.tsx` at `/client/counter.tsx`. Files are compiled on request and
|
|
1482
|
-
* cached until they change (bounded by `cacheBytes`); a response carries an ETag and `Cache-Control: no-cache`, so an edit shows on the
|
|
1483
|
-
* next reload. With `NODE_ENV=production` and `compiled` set, only the `compiled` folder is served and nothing is compiled.
|
|
1484
|
-
* @param options - the folder, the precompiled folder, and the cache bound.
|
|
1485
|
-
* @returns the app.
|
|
1486
|
-
*/
|
|
1487
|
-
function clientModules(options) {
|
|
1488
|
-
const root = realFolder(options.root);
|
|
1489
|
-
const runtimeDir = absolute(options.runtimeDir ?? defaultRuntimeDir());
|
|
1490
|
-
let compiled;
|
|
1491
|
-
if (process.env.NODE_ENV === "production" && options.compiled !== void 0) try {
|
|
1492
|
-
compiled = realpathSync(absolute(options.compiled));
|
|
1493
|
-
} catch {
|
|
1494
|
-
throw new Error(`acrylblends: the compiled client folder ${absolute(options.compiled)} does not exist; build it with buildClientModules before starting in production`);
|
|
1495
|
-
}
|
|
1496
|
-
const cache = new CompileCache(options.cacheBytes ?? DEFAULT_CACHE_BYTES);
|
|
1497
|
-
const app = new Acryl();
|
|
1498
|
-
app.get("/*", (c) => {
|
|
1499
|
-
const requestPath = c.req.path.slice(basePath(c).length);
|
|
1500
|
-
const runtime = /^\/@acrylblends\/([a-z-]+\.js)$/u.exec(requestPath)?.[1];
|
|
1501
|
-
const send = (code, etag) => {
|
|
1502
|
-
if (c.req.header("if-none-match") === etag) return c.body(null, 304, {
|
|
1503
|
-
etag,
|
|
1504
|
-
"cache-control": "no-cache"
|
|
1505
|
-
});
|
|
1506
|
-
return c.body(code, 200, {
|
|
1507
|
-
"content-type": JS_TYPE,
|
|
1508
|
-
etag,
|
|
1509
|
-
"cache-control": "no-cache"
|
|
1510
|
-
});
|
|
1511
|
-
};
|
|
1512
|
-
const serveFile = (file) => {
|
|
1513
|
-
const stat = statSync(file);
|
|
1514
|
-
return send(readFileSync(file, "utf8"), etagOf(stat));
|
|
1515
|
-
};
|
|
1516
|
-
if (runtime !== void 0) {
|
|
1517
|
-
if (!RUNTIME_FILES.includes(runtime)) return c.notFound();
|
|
1518
|
-
return serveFile(compiled === void 0 ? join(runtimeDir, runtime) : join(compiled, RUNTIME_DIR, runtime));
|
|
1519
|
-
}
|
|
1520
|
-
const path = servedPath(requestPath);
|
|
1521
|
-
if (path === void 0 || path.split("/")[0] === RUNTIME_DIR) return c.notFound();
|
|
1522
|
-
if (compiled !== void 0) {
|
|
1523
|
-
const file = fileInside(compiled, path);
|
|
1524
|
-
if (file !== void 0) return serveFile(file);
|
|
1525
|
-
if (fileInside(root, path) !== void 0) return c.text(`acrylblends: ${path} is not in ${relative(process.cwd(), compiled) || compiled}; build the client modules again (buildClientModules)`, 500);
|
|
1526
|
-
return c.notFound();
|
|
1527
|
-
}
|
|
1528
|
-
const file = fileInside(root, path);
|
|
1529
|
-
if (file === void 0) return c.notFound();
|
|
1530
|
-
if (!COMPILED.has(extname(file))) return serveFile(file);
|
|
1531
|
-
const stat = statSync(file);
|
|
1532
|
-
let entry = cache.get(file, stat.mtimeMs, stat.size);
|
|
1533
|
-
if (entry === void 0) {
|
|
1534
|
-
let code;
|
|
1535
|
-
try {
|
|
1536
|
-
code = compileForBrowser(file, path);
|
|
1537
|
-
} catch (error) {
|
|
1538
|
-
if (error instanceof MissingTypeScriptError) return c.text(error.message, 500);
|
|
1539
|
-
throw error;
|
|
1540
|
-
}
|
|
1541
|
-
entry = cache.set(file, stat, code);
|
|
1542
|
-
}
|
|
1543
|
-
return send(entry.code, entry.etag);
|
|
1544
|
-
});
|
|
1545
|
-
return app;
|
|
1546
|
-
}
|
|
1547
|
-
/** Every served file below `dir`, as paths below `root` with `/` separators; dot entries, `node_modules` and the runtime folder skipped. */
|
|
1548
|
-
function sourceFiles(root, dir = root) {
|
|
1549
|
-
const files = [];
|
|
1550
|
-
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1551
|
-
if (entry.name.startsWith(".") || entry.name === "node_modules" || dir === root && entry.name === RUNTIME_DIR) continue;
|
|
1552
|
-
const full = join(dir, entry.name);
|
|
1553
|
-
if (entry.isDirectory()) files.push(...sourceFiles(root, full));
|
|
1554
|
-
else if (entry.isFile() && SERVED.has(extname(entry.name)) && !entry.name.endsWith(".d.ts")) files.push(relative(root, full).split(sep).join("/"));
|
|
1555
|
-
}
|
|
1556
|
-
return files.sort();
|
|
1557
|
-
}
|
|
1558
|
-
/**
|
|
1559
|
-
* Compile a folder of client modules once, for a production that has no `typescript`: each module is written to `outDir` at the same
|
|
1560
|
-
* relative path and file name (so the page's URLs stay the same), compiled exactly as {@link clientModules} compiles it, and the three
|
|
1561
|
-
* browser files are copied to `outDir/@acrylblends/`. Files already in `outDir` that no source produces are left there.
|
|
1562
|
-
* @param options - the source folder and the output folder.
|
|
1563
|
-
* @returns the paths written, relative to `outDir`.
|
|
1564
|
-
* @throws MissingTypeScriptError when the app has no `typescript`; an error when `outDir` lies inside `root`.
|
|
1565
|
-
*/
|
|
1566
|
-
function buildClientModules(options) {
|
|
1567
|
-
const root = realpathSync(absolute(options.root));
|
|
1568
|
-
const outDir = absolute(options.outDir);
|
|
1569
|
-
const runtimeDir = absolute(options.runtimeDir ?? defaultRuntimeDir());
|
|
1570
|
-
if (outDir === root || outDir.startsWith(root + sep)) throw new Error(`acrylblends: the output folder ${outDir} lies inside the client folder ${root}`);
|
|
1571
|
-
const written = [];
|
|
1572
|
-
for (const path of sourceFiles(root)) {
|
|
1573
|
-
const source = join(root, ...path.split("/"));
|
|
1574
|
-
const target = join(outDir, ...path.split("/"));
|
|
1575
|
-
mkdirSync(dirname(target), { recursive: true });
|
|
1576
|
-
if (COMPILED.has(extname(path))) writeFileSync(target, compileForBrowser(source, path));
|
|
1577
|
-
else copyFileSync(source, target);
|
|
1578
|
-
written.push(path);
|
|
1579
|
-
}
|
|
1580
|
-
mkdirSync(join(outDir, RUNTIME_DIR), { recursive: true });
|
|
1581
|
-
for (const name of RUNTIME_FILES) {
|
|
1582
|
-
copyFileSync(join(runtimeDir, name), join(outDir, RUNTIME_DIR, name));
|
|
1583
|
-
written.push(`${RUNTIME_DIR}/${name}`);
|
|
1584
|
-
}
|
|
1585
|
-
return written;
|
|
1586
|
-
}
|
|
1587
|
-
//#endregion
|
|
4
|
+
import { n as clientModules, t as buildClientModules } from "./client-modules-CLvWOjbd.js";
|
|
1588
5
|
export { RequestError, buildClientModules, clientModules, createAdaptorServer, getConnInfo, getRequestListener, serve, serveStatic, upgradeWebSocket };
|