acrylblends 1.0.3 → 1.0.5
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/docs/framework/agents/index.md +6 -4
- package/docs/framework/workshop/README.md +3 -3
- package/docs/framework/workshop/facilitator.md +1 -0
- package/lib/accept-CNNHu4Cf.js +193 -0
- package/lib/{accepts-XBuZPVRI.js → accepts-Btq83xPd.js} +1 -1
- package/lib/accepts.js +1 -1
- package/lib/acryl-base.js +1 -331
- package/lib/adapter-CaZ6FZUU.js +37 -0
- package/lib/adapter.js +1 -36
- package/lib/{app-BM0rTCp7.js → app-CQcGWjrk.js} +4 -4
- package/lib/app-base-CpRMZL4v.js +332 -0
- package/lib/{audit-BXnYsLge.d.ts → audit-D5z9uwOP.d.ts} +14 -1
- package/lib/{base-NSN_SNv-.js → base-D_6kfOr-.js} +1 -1
- package/lib/basic-auth-C0HTRpXh.js +20 -0
- package/lib/basic-auth-DFLflXNe.js +95 -0
- package/lib/basic-auth.js +1 -94
- package/lib/bearer-auth-Cwxt-vgS.js +94 -0
- package/lib/bearer-auth.js +1 -93
- package/lib/body-D7f4e7w_.js +94 -0
- package/lib/body-limit-WmIjWRLt.js +66 -0
- package/lib/body-limit.js +1 -65
- package/lib/buffer-CkEOJCcY.js +51 -0
- package/lib/bun.js +3 -3
- package/lib/cache-B0bHH7s5.js +169 -0
- package/lib/cache.js +1 -168
- package/lib/{client-DDLXwhBo.js → client-BrMFnMEd.js} +1 -1
- package/lib/{client-modules-CLvWOjbd.js → client-modules-drj4mjhj.js} +4 -4
- package/lib/client.js +1 -1
- package/lib/color-COa3DplO.js +37 -0
- package/lib/combine-TWuGdcbC.js +137 -0
- package/lib/combine.js +1 -136
- package/lib/{components-cEW3ovK0.js → components-B2ka9Ax1.js} +4 -4
- package/lib/{components-JXVm45kK.js → components-PVXwaOaC.js} +2 -2
- package/lib/compress-BzWqsHF1.js +79 -0
- package/lib/compress-C-9vK4B2.d.ts +11 -0
- package/lib/compress-DCyrrQ5D.js +11 -0
- package/lib/compress.d.ts +1 -1
- package/lib/compress.js +2 -78
- package/lib/concurrent-DrF3d2c-.js +30 -0
- package/lib/conninfo-BCROmdnf.d.ts +11 -0
- package/lib/conninfo-CWJwieh4.js +19 -0
- package/lib/constants-CBSEudrb.js +7 -0
- package/lib/{context-DDO0cfuP.js → context-CkOh7Ygv.js} +2 -2
- package/lib/context-storage-iuPoI_CR.js +52 -0
- package/lib/context-storage.js +1 -51
- package/lib/cookie-B1LlkzOe.js +125 -0
- package/lib/cookie-BHIduy2T.js +82 -0
- package/lib/cookie.js +1 -81
- package/lib/cordis/db-sqlite.d.ts +1 -1
- package/lib/cordis/door.d.ts +17 -3
- package/lib/cordis/door.js +123 -16
- package/lib/cordis/inspect.js +4 -4
- package/lib/cordis/kv-db.d.ts +1 -1
- package/lib/cordis/kv-db.js +1 -1
- package/lib/cordis/kv-json.d.ts +1 -1
- package/lib/cordis/kv-json.js +1 -1
- package/lib/cordis/node-server.d.ts +1 -1
- package/lib/cordis/node-server.js +3 -116
- package/lib/cordis/router-http.d.ts +1 -1
- package/lib/cordis/router-http.js +2 -2
- package/lib/cordis/router.d.ts +1 -1
- package/lib/cordis/router.js +4 -4
- package/lib/cordis/state.js +7 -7
- package/lib/{core-CaY8XDZ6.js → core-BOu1jYua.js} +1 -1
- package/lib/cors-CbAQ-8qU.js +106 -0
- package/lib/cors.js +1 -105
- package/lib/crypto-iVP-N-tS.js +34 -0
- package/lib/csrf-DqqOZtgy.js +101 -0
- package/lib/csrf.js +1 -100
- package/lib/css-C5CPVMvM.js +134 -0
- package/lib/css.js +2 -133
- package/lib/db/sqlite.d.ts +1 -25
- package/lib/dev-CLgu-JRe.js +50 -0
- package/lib/dev.js +1 -49
- package/lib/dom-YjND9Jt3.js +74 -0
- package/lib/door/host.d.ts +2 -2
- package/lib/door/host.js +1 -1
- package/lib/door/page.d.ts +12 -1
- package/lib/door/page.js +22 -1
- package/lib/door/protocol.d.ts +2 -2
- package/lib/door/protocol.js +2 -197
- package/lib/encode-BhbNLrjp.js +33 -0
- package/lib/factory-CLdSf-xS.js +30 -0
- package/lib/factory.js +1 -29
- package/lib/handler-C0wZ0KwO.js +12 -0
- package/lib/helpers-BEjcdbgw.js +5 -0
- package/lib/{hooks-w72iLeFR.js → hooks-CfC07ri0.js} +1 -1
- package/lib/html-CgNa89xw.js +31 -0
- package/lib/html-DGExBFNg.js +103 -0
- package/lib/html.d.ts +2 -5
- package/lib/html.js +2 -30
- package/lib/http-exception-MjWkT89V.js +54 -0
- package/lib/http-exception.js +1 -53
- package/lib/{index-D4nVR3wu.d.ts → index-DMOtA-NJ.d.ts} +7 -1
- package/lib/index-dAzQsJG9.d.ts +6 -0
- package/lib/index.js +3 -3
- package/lib/ip-restriction-jKtKCRM_.js +166 -0
- package/lib/ip-restriction.js +1 -165
- package/lib/ipaddr-DCoIo528.js +238 -0
- package/lib/jsx/dom/client.js +1 -1
- package/lib/jsx/dom/jsx-dev-runtime.js +1 -1
- package/lib/jsx/dom/jsx-runtime.js +2 -1
- package/lib/jsx/dom/server.js +3 -3
- package/lib/jsx/dom.js +5 -73
- package/lib/jsx/jsx-dev-runtime.d.ts +2 -5
- package/lib/jsx/jsx-dev-runtime.js +2 -13
- package/lib/jsx/jsx-runtime.d.ts +2 -2
- package/lib/jsx/jsx-runtime.js +4 -4
- package/lib/jsx/streaming.js +1 -1
- package/lib/jsx-CUQgttxU.js +47 -0
- package/lib/jsx-dev-runtime-B4WTyq8r.js +14 -0
- package/lib/{jsx-dev-runtime-CWLRA2F3.js → jsx-dev-runtime-BLfA-EhI.js} +2 -2
- package/lib/jsx-dev-runtime-CGt4kNYr.d.ts +6 -0
- package/lib/jsx-renderer-CfifM4hT.js +99 -0
- package/lib/jsx-renderer.js +1 -98
- package/lib/jsx-runtime-COCRWBJ9.js +2 -0
- package/lib/jsx.js +5 -46
- package/lib/{jwk-LkzeoaU8.js → jwk-CDPpYQpD.js} +3 -3
- package/lib/jwk.js +1 -1
- package/lib/{jwt-BGJBw5AF.js → jwt-BXoIA2fQ.js} +2 -2
- package/lib/{jwt-CskdhEW9.js → jwt-lyS4Q3mT.js} +3 -3
- package/lib/jwt.js +2 -2
- package/lib/kv/db.d.ts +1 -10
- package/lib/kv/db.js +1 -56
- package/lib/kv/json.d.ts +1 -9
- package/lib/kv/json.js +1 -223
- package/lib/{language-D9a4zqvn.js → language-DeGRtLJt.js} +2 -2
- package/lib/language.js +1 -1
- package/lib/{linear-router-C3FPib6h.js → linear-router-CmZn_JLV.js} +2 -2
- package/lib/logger-Ckxu8diz.js +54 -0
- package/lib/logger.js +1 -53
- package/lib/loopback-only-BbasoF7R.js +90 -0
- package/lib/loopback-only.js +1 -89
- package/lib/method-not-allowed-TO2_hnfl.js +82 -0
- package/lib/method-not-allowed.js +1 -81
- package/lib/method-override-DnZKfJbV.js +103 -0
- package/lib/method-override.js +1 -102
- package/lib/middleware-BfG_fp8P.js +12 -0
- package/lib/mime-BnScXkQn.js +77 -0
- package/lib/mount-QkK_3NtJ.js +67 -0
- package/lib/mount.js +1 -66
- package/lib/node-server/conninfo.d.ts +1 -10
- package/lib/node-server/conninfo.js +1 -18
- package/lib/node-server/register.js +25 -2
- package/lib/node-server/serve-static.d.ts +1 -17
- package/lib/node-server/serve-static.js +1 -1
- package/lib/node-server.d.ts +2 -2
- package/lib/node-server.js +4 -4
- package/lib/open-BqK4D2Wn.d.ts +11 -0
- package/lib/open-But9E2rL.js +57 -0
- package/lib/open-CULVJgOc.d.ts +12 -0
- package/lib/open-Dp4sxspc.js +224 -0
- package/lib/open-T7kgbO2O.d.ts +27 -0
- package/lib/{pattern-router-HZxjDGEQ.js → pattern-router-CJBecJBd.js} +1 -1
- package/lib/powered-by-CXQNjNIX.js +24 -0
- package/lib/powered-by.js +1 -23
- package/lib/pretty-json-CeC1yvYt.js +39 -0
- package/lib/pretty-json.js +1 -38
- package/lib/{protocol-BizVt4J6.d.ts → protocol-C37gPePD.d.ts} +9 -2
- package/lib/protocol-Dt0AZBOz.js +213 -0
- package/lib/proxy-C2w_mH7k.js +121 -0
- package/lib/proxy.js +1 -120
- package/lib/quick.js +4 -4
- package/lib/{reg-exp-router-DC1R3qoY.js → reg-exp-router-C_WV84eV.js} +2 -2
- package/lib/request-DvMgGtlW.js +323 -0
- package/lib/request.js +1 -322
- package/lib/route-D8m-a2I1.js +126 -0
- package/lib/route.js +1 -125
- package/lib/router/linear-router.js +1 -1
- package/lib/router/pattern-router.js +1 -1
- package/lib/router/reg-exp-router.js +1 -1
- package/lib/router/smart-router.js +1 -1
- package/lib/router/trie-router.js +1 -1
- package/lib/router-Be_o6nFu.js +35 -0
- package/lib/router.js +1 -34
- package/lib/schema-validator-EK3cUUCt.js +22 -0
- package/lib/schema-validator.js +1 -21
- package/lib/{secure-headers-mP3j6Hm6.js → secure-headers-C5ZOcXqk.js} +1 -1
- package/lib/secure-headers.js +1 -1
- package/lib/serve-static-B7sqnftW.d.ts +18 -0
- package/lib/{serve-static-3uo_9rjF.js → serve-static-C1Nkj_xB.js} +2 -2
- package/lib/{serve-static-Cp5adzGo.js → serve-static-EiJf1zkO.js} +4 -4
- package/lib/serve-static.js +1 -1
- package/lib/{smart-router-C5CZ5XSM.js → smart-router-BjxkDQCE.js} +1 -1
- package/lib/{snapshot-text-DmE0YfeZ.js → snapshot-text-Bbx43mN0.js} +57 -9
- package/lib/{src-2Z4mJg0x.js → src-BTBm4OPD.js} +22 -6
- package/lib/src-LX0E4ec4.js +117 -0
- package/lib/{ssg-BwjcA-Ge.js → ssg-BEl7MHqg.js} +5 -5
- package/lib/ssg.js +1 -1
- package/lib/stream-CzM_SHkq.js +88 -0
- package/lib/{streaming-DHST3Scg.js → streaming-BlDaph8U.js} +3 -3
- package/lib/streaming.js +1 -1
- package/lib/{test-websocket-D8WWqE5G.js → test-websocket-BLeEvybj.js} +2 -2
- package/lib/testing-BQx5T_UX.js +17 -0
- package/lib/testing.js +1 -16
- package/lib/timeout-FeqZ9A-0.js +42 -0
- package/lib/timeout.js +1 -41
- package/lib/tiny.js +2 -2
- package/lib/trailing-slash-DwTx-1sk.js +85 -0
- package/lib/trailing-slash.js +1 -84
- package/lib/{trie-router-CfFbapzL.js → trie-router-JydLKUa2.js} +2 -2
- package/lib/url-BPh4d6j-.js +197 -0
- package/lib/utils/accept.js +1 -192
- package/lib/utils/basic-auth.js +1 -19
- package/lib/utils/body.js +1 -93
- package/lib/utils/buffer.js +1 -50
- package/lib/utils/color.js +1 -36
- package/lib/utils/compress.d.ts +1 -10
- package/lib/utils/compress.js +1 -10
- package/lib/utils/concurrent.js +1 -29
- package/lib/utils/constants.js +1 -6
- package/lib/utils/cookie.js +1 -124
- package/lib/utils/crypto.js +1 -33
- package/lib/utils/encode.js +1 -32
- package/lib/utils/handler.js +1 -11
- package/lib/utils/html.js +1 -102
- package/lib/utils/ipaddr.js +1 -237
- package/lib/utils/jwt.js +1 -1
- package/lib/utils/mime.js +1 -76
- package/lib/utils/stream.js +1 -87
- package/lib/utils/url.js +1 -196
- package/lib/{validator-D84mq-dO.js → validator-Btiyt5VJ.js} +3 -3
- package/lib/validator.js +1 -1
- package/lib/websocket-DsyBIKVA.js +56 -0
- package/lib/ws.js +1 -55
- package/package.json +1 -1
- package/plugins/acryl-door/src/cli/acryl.ts +5 -3
- package/plugins/acryl-door/src/host/channel.ts +36 -0
- package/plugins/acryl-door/src/host/chat-tools.ts +2 -0
- package/plugins/acryl-door/src/host/door.ts +44 -5
- package/plugins/acryl-door/src/host/shim.ts +23 -0
- package/plugins/acryl-door/src/host/verbs.ts +4 -3
- package/plugins/acryl-door/src/index.ts +39 -3
- package/plugins/acryl-door/src/page/driver/driver.ts +22 -1
- package/plugins/acryl-door/src/page/protocol.ts +13 -2
- package/plugins/acryl-node-server/src/register.ts +29 -2
- package/plugins/acryl-router/src/service.ts +19 -1
- package/plugins/agent/model.ts +6 -1
- package/plugins/agent/tools.ts +12 -2
- package/plugins/agent-panel/client/describe.ts +44 -0
- package/plugins/agent-panel/client/main.ts +67 -35
- package/plugins/agent-panel/index.ts +137 -35
- package/plugins/desktop/attach.ts +72 -0
- package/plugins/desktop/main.ts +17 -4
- package/plugins/extensions/index.ts +3 -4
- package/plugins/extensions/stage.ts +33 -5
- package/plugins/openai/index.ts +1 -1
- package/shared/DEFAULTS.md +4 -0
- package/templates/agent/AGENTS.md +2 -0
- package/templates/agent/blend.yaml +4 -1
- package/templates/agent/src/app.ts +2 -0
- package/templates/agent/src/routes.ts +1 -1
- package/templates/agent/template.json +1 -0
- package/templates/agent/test/builder.test.ts +26 -21
- package/lib/helpers-CvTauQT5.js +0 -5
- package/lib/middleware-CPQ8himN.js +0 -12
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
//#region ../../plugins/acryl-router/src/core/utils/html.ts
|
|
2
|
+
/**
|
|
3
|
+
* @module
|
|
4
|
+
* HTML utility.
|
|
5
|
+
*/
|
|
6
|
+
const HtmlEscapedCallbackPhase = {
|
|
7
|
+
Stringify: 1,
|
|
8
|
+
BeforeStream: 2,
|
|
9
|
+
Stream: 3
|
|
10
|
+
};
|
|
11
|
+
const raw = (value, callbacks) => {
|
|
12
|
+
const escapedString = new String(value);
|
|
13
|
+
escapedString.isEscaped = true;
|
|
14
|
+
escapedString.callbacks = callbacks;
|
|
15
|
+
return escapedString;
|
|
16
|
+
};
|
|
17
|
+
const escapeRe = /[&<>'"]/;
|
|
18
|
+
const stringBufferToString = async (buffer, callbacks) => {
|
|
19
|
+
let str = "";
|
|
20
|
+
callbacks ||= [];
|
|
21
|
+
const resolvedBuffer = await Promise.all(buffer);
|
|
22
|
+
for (let i = resolvedBuffer.length - 1;; i--) {
|
|
23
|
+
str += resolvedBuffer[i];
|
|
24
|
+
i--;
|
|
25
|
+
if (i < 0) break;
|
|
26
|
+
let r = resolvedBuffer[i];
|
|
27
|
+
if (typeof r === "object") callbacks.push(...r.callbacks || []);
|
|
28
|
+
const isEscaped = r.isEscaped;
|
|
29
|
+
r = await (typeof r === "object" ? r.toString() : r);
|
|
30
|
+
if (typeof r === "object") callbacks.push(...r.callbacks || []);
|
|
31
|
+
if (r.isEscaped ?? isEscaped) str += r;
|
|
32
|
+
else {
|
|
33
|
+
const buf = [str];
|
|
34
|
+
escapeToBuffer(r, buf);
|
|
35
|
+
str = buf[0];
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return raw(str, callbacks);
|
|
39
|
+
};
|
|
40
|
+
const escapeToBuffer = (str, buffer) => {
|
|
41
|
+
const match = str.search(escapeRe);
|
|
42
|
+
if (match === -1) {
|
|
43
|
+
buffer[0] += str;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
let escape;
|
|
47
|
+
let index;
|
|
48
|
+
let lastIndex = 0;
|
|
49
|
+
for (index = match; index < str.length; index++) {
|
|
50
|
+
switch (str.charCodeAt(index)) {
|
|
51
|
+
case 34:
|
|
52
|
+
escape = """;
|
|
53
|
+
break;
|
|
54
|
+
case 39:
|
|
55
|
+
escape = "'";
|
|
56
|
+
break;
|
|
57
|
+
case 38:
|
|
58
|
+
escape = "&";
|
|
59
|
+
break;
|
|
60
|
+
case 60:
|
|
61
|
+
escape = "<";
|
|
62
|
+
break;
|
|
63
|
+
case 62:
|
|
64
|
+
escape = ">";
|
|
65
|
+
break;
|
|
66
|
+
default: continue;
|
|
67
|
+
}
|
|
68
|
+
buffer[0] += str.substring(lastIndex, index) + escape;
|
|
69
|
+
lastIndex = index + 1;
|
|
70
|
+
}
|
|
71
|
+
buffer[0] += str.substring(lastIndex, index);
|
|
72
|
+
};
|
|
73
|
+
const resolveCallbackSync = (str) => {
|
|
74
|
+
const callbacks = str.callbacks;
|
|
75
|
+
if (!callbacks?.length) return str;
|
|
76
|
+
const buffer = [str];
|
|
77
|
+
const context = {};
|
|
78
|
+
callbacks.forEach((c) => c({
|
|
79
|
+
phase: HtmlEscapedCallbackPhase.Stringify,
|
|
80
|
+
buffer,
|
|
81
|
+
context
|
|
82
|
+
}));
|
|
83
|
+
return buffer[0];
|
|
84
|
+
};
|
|
85
|
+
const resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
86
|
+
if (typeof str === "object" && !(str instanceof String)) {
|
|
87
|
+
if (!(str instanceof Promise)) str = str.toString();
|
|
88
|
+
if (str instanceof Promise) str = await str;
|
|
89
|
+
}
|
|
90
|
+
const callbacks = str.callbacks;
|
|
91
|
+
if (!callbacks?.length) return Promise.resolve(str);
|
|
92
|
+
if (buffer) buffer[0] += str;
|
|
93
|
+
else buffer = [str];
|
|
94
|
+
const resStr = Promise.all(callbacks.map((c) => c({
|
|
95
|
+
phase,
|
|
96
|
+
buffer,
|
|
97
|
+
context
|
|
98
|
+
}))).then((res) => Promise.all(res.filter(Boolean).map((str) => resolveCallback(str, phase, false, context, buffer))).then(() => buffer[0]));
|
|
99
|
+
if (preserveCallbacks) return raw(await resStr, callbacks);
|
|
100
|
+
else return resStr;
|
|
101
|
+
};
|
|
102
|
+
//#endregion
|
|
103
|
+
export { resolveCallbackSync as a, resolveCallback as i, escapeToBuffer as n, stringBufferToString as o, raw as r, HtmlEscapedCallbackPhase as t };
|
package/lib/html.d.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { c as raw
|
|
2
|
-
|
|
3
|
-
//#region ../../plugins/acryl-router/src/core/helper/html/index.d.ts
|
|
4
|
-
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => HtmlEscapedString | Promise<HtmlEscapedString>;
|
|
5
|
-
//#endregion
|
|
1
|
+
import { c as raw } from "./html-SllAe0YT.js";
|
|
2
|
+
import { t as html } from "./index-dAzQsJG9.js";
|
|
6
3
|
export { html, raw };
|
package/lib/html.js
CHANGED
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @module
|
|
5
|
-
* html Helper for Acryl.
|
|
6
|
-
*/
|
|
7
|
-
const html = (strings, ...values) => {
|
|
8
|
-
const buffer = [""];
|
|
9
|
-
for (let i = 0, len = strings.length - 1; i < len; i++) {
|
|
10
|
-
buffer[0] += strings[i];
|
|
11
|
-
const children = Array.isArray(values[i]) ? values[i].flat(Infinity) : [values[i]];
|
|
12
|
-
for (let i = 0, len = children.length; i < len; i++) {
|
|
13
|
-
const child = children[i];
|
|
14
|
-
if (typeof child === "string") escapeToBuffer(child, buffer);
|
|
15
|
-
else if (typeof child === "number") buffer[0] += child;
|
|
16
|
-
else if (typeof child === "boolean" || child === null || child === void 0) continue;
|
|
17
|
-
else if (typeof child === "object" && child.isEscaped) if (child.callbacks) buffer.unshift("", child);
|
|
18
|
-
else {
|
|
19
|
-
const tmp = child.toString();
|
|
20
|
-
if (tmp instanceof Promise) buffer.unshift("", tmp);
|
|
21
|
-
else buffer[0] += tmp;
|
|
22
|
-
}
|
|
23
|
-
else if (child instanceof Promise) buffer.unshift("", child);
|
|
24
|
-
else escapeToBuffer(child.toString(), buffer);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
buffer[0] += strings.at(-1);
|
|
28
|
-
return buffer.length === 1 ? "callbacks" in buffer ? raw(resolveCallbackSync(raw(buffer[0], buffer.callbacks))) : raw(buffer[0]) : stringBufferToString(buffer, buffer.callbacks);
|
|
29
|
-
};
|
|
30
|
-
//#endregion
|
|
1
|
+
import { r as raw } from "./html-DGExBFNg.js";
|
|
2
|
+
import { t as html } from "./html-CgNa89xw.js";
|
|
31
3
|
export { html, raw };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//#region ../../plugins/acryl-router/src/core/http-exception.ts
|
|
2
|
+
/**
|
|
3
|
+
* `HTTPException` must be used when a fatal error such as authentication failure occurs.
|
|
4
|
+
*
|
|
5
|
+
*
|
|
6
|
+
* @param {StatusCode} status - status code of HTTPException
|
|
7
|
+
* @param {HTTPExceptionOptions} options - options of HTTPException
|
|
8
|
+
* @param {HTTPExceptionOptions["res"]} options.res - response of options of HTTPException
|
|
9
|
+
* @param {HTTPExceptionOptions["message"]} options.message - message of options of HTTPException
|
|
10
|
+
* @param {HTTPExceptionOptions["cause"]} options.cause - cause of options of HTTPException
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { HTTPException } from 'acrylblends/http-exception'
|
|
15
|
+
*
|
|
16
|
+
* // ...
|
|
17
|
+
*
|
|
18
|
+
* app.post('/auth', async (c, next) => {
|
|
19
|
+
* // authentication
|
|
20
|
+
* if (authorized === false) {
|
|
21
|
+
* throw new HTTPException(401, { message: 'Custom error message' })
|
|
22
|
+
* }
|
|
23
|
+
* await next()
|
|
24
|
+
* })
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
var HTTPException = class extends Error {
|
|
28
|
+
res;
|
|
29
|
+
status;
|
|
30
|
+
/**
|
|
31
|
+
* Creates an instance of `HTTPException`.
|
|
32
|
+
* @param status - HTTP status code for the exception. Defaults to 500.
|
|
33
|
+
* @param options - Additional options for the exception.
|
|
34
|
+
*/
|
|
35
|
+
constructor(status = 500, options) {
|
|
36
|
+
super(options?.message, { cause: options?.cause });
|
|
37
|
+
this.res = options?.res;
|
|
38
|
+
this.status = status;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Returns the response object associated with the exception.
|
|
42
|
+
* If a response object is not provided, a new response is created with the error message and status code.
|
|
43
|
+
* @returns The response object.
|
|
44
|
+
*/
|
|
45
|
+
getResponse() {
|
|
46
|
+
if (this.res) return new Response(this.res.body, {
|
|
47
|
+
status: this.status,
|
|
48
|
+
headers: this.res.headers
|
|
49
|
+
});
|
|
50
|
+
return new Response(this.message, { status: this.status });
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { HTTPException as t };
|
package/lib/http-exception.js
CHANGED
|
@@ -1,54 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* `HTTPException` must be used when a fatal error such as authentication failure occurs.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @param {StatusCode} status - status code of HTTPException
|
|
7
|
-
* @param {HTTPExceptionOptions} options - options of HTTPException
|
|
8
|
-
* @param {HTTPExceptionOptions["res"]} options.res - response of options of HTTPException
|
|
9
|
-
* @param {HTTPExceptionOptions["message"]} options.message - message of options of HTTPException
|
|
10
|
-
* @param {HTTPExceptionOptions["cause"]} options.cause - cause of options of HTTPException
|
|
11
|
-
*
|
|
12
|
-
* @example
|
|
13
|
-
* ```ts
|
|
14
|
-
* import { HTTPException } from 'acrylblends/http-exception'
|
|
15
|
-
*
|
|
16
|
-
* // ...
|
|
17
|
-
*
|
|
18
|
-
* app.post('/auth', async (c, next) => {
|
|
19
|
-
* // authentication
|
|
20
|
-
* if (authorized === false) {
|
|
21
|
-
* throw new HTTPException(401, { message: 'Custom error message' })
|
|
22
|
-
* }
|
|
23
|
-
* await next()
|
|
24
|
-
* })
|
|
25
|
-
* ```
|
|
26
|
-
*/
|
|
27
|
-
var HTTPException = class extends Error {
|
|
28
|
-
res;
|
|
29
|
-
status;
|
|
30
|
-
/**
|
|
31
|
-
* Creates an instance of `HTTPException`.
|
|
32
|
-
* @param status - HTTP status code for the exception. Defaults to 500.
|
|
33
|
-
* @param options - Additional options for the exception.
|
|
34
|
-
*/
|
|
35
|
-
constructor(status = 500, options) {
|
|
36
|
-
super(options?.message, { cause: options?.cause });
|
|
37
|
-
this.res = options?.res;
|
|
38
|
-
this.status = status;
|
|
39
|
-
}
|
|
40
|
-
/**
|
|
41
|
-
* Returns the response object associated with the exception.
|
|
42
|
-
* If a response object is not provided, a new response is created with the error message and status code.
|
|
43
|
-
* @returns The response object.
|
|
44
|
-
*/
|
|
45
|
-
getResponse() {
|
|
46
|
-
if (this.res) return new Response(this.res.body, {
|
|
47
|
-
status: this.status,
|
|
48
|
-
headers: this.res.headers
|
|
49
|
-
});
|
|
50
|
-
return new Response(this.message, { status: this.status });
|
|
51
|
-
}
|
|
52
|
-
};
|
|
53
|
-
//#endregion
|
|
1
|
+
import { t as HTTPException } from "./http-exception-MjWkT89V.js";
|
|
54
2
|
export { HTTPException };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { B as NotFoundHandler, y as ErrorHandler } from "./context-DS3fYyG-.js";
|
|
1
|
+
import { B as NotFoundHandler, E as H, y as ErrorHandler } from "./context-DS3fYyG-.js";
|
|
2
2
|
import { t as ConnectionInfo } from "./connection-ZLEso7XL.js";
|
|
3
3
|
import { n as UpgradeWebSocket } from "./index-C-SklY6u.js";
|
|
4
4
|
import { Context, Service } from "@deepseek-ai/cordis";
|
|
@@ -77,6 +77,12 @@ declare class Router extends Service {
|
|
|
77
77
|
* are copied now: one the app registers after this call is not served (mount again, or finish the app first).
|
|
78
78
|
*/
|
|
79
79
|
route(path: string, app: MountableApp): () => void;
|
|
80
|
+
/**
|
|
81
|
+
* Run `middleware` around every request the router serves, whenever the plugin that asks was mounted: a middleware in a plain mount wraps only the routes mounted after it,
|
|
82
|
+
* which is the wrong tool for a plugin that must see every page (the door adds its script to each HTML response, the pages of a plugin that loaded earlier included). It goes
|
|
83
|
+
* outside all mounts, in the order wrappers were added, and goes away when the calling plugin unloads or when the returned function is called.
|
|
84
|
+
*/
|
|
85
|
+
wrap(middleware: H): () => void;
|
|
80
86
|
/**
|
|
81
87
|
* The mount's own copy of `app`'s routes as they are now (like the core's `app.route`), each handler wrapped so the router knows which
|
|
82
88
|
* mount's code a request is in. The core's `app.route` runs first so a sub-app's own `onError` still applies to its routes.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { i as HtmlEscapedString } from "./html-SllAe0YT.js";
|
|
2
|
+
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/helper/html/index.d.ts
|
|
4
|
+
declare const html: (strings: TemplateStringsArray, ...values: unknown[]) => HtmlEscapedString | Promise<HtmlEscapedString>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { html as t };
|
package/lib/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as Context } from "./context-
|
|
2
|
-
import { t as Acryl } from "./app-
|
|
3
|
-
import "./core-
|
|
1
|
+
import { t as Context } from "./context-CkOh7Ygv.js";
|
|
2
|
+
import { t as Acryl } from "./app-CQcGWjrk.js";
|
|
3
|
+
import "./core-BOu1jYua.js";
|
|
4
4
|
export { Acryl, Context };
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { t as HTTPException } from "./http-exception-MjWkT89V.js";
|
|
2
|
+
import { a as convertIPv6BinaryToString, i as convertIPv4ToBinary, l as isIPv4MappedIPv6, o as convertIPv6ToBinary, r as convertIPv4MappedIPv6ToIPv4, s as distinctRemoteAddr } from "./ipaddr-DCoIo528.js";
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/middleware/ip-restriction/index.ts
|
|
4
|
+
const IS_CIDR_NOTATION_REGEX = /\/[^/]*$/;
|
|
5
|
+
const parseCidrPrefix = (rule, prefix, max) => {
|
|
6
|
+
if (!/^[0-9]{1,3}$/.test(prefix)) throw new TypeError(`Invalid rule: ${rule}`);
|
|
7
|
+
const parsedPrefix = parseInt(prefix);
|
|
8
|
+
if (parsedPrefix > max) throw new TypeError(`Invalid rule: ${rule}`);
|
|
9
|
+
return parsedPrefix;
|
|
10
|
+
};
|
|
11
|
+
const buildMatcher = (rules) => {
|
|
12
|
+
const functionRules = [];
|
|
13
|
+
const staticRules = /* @__PURE__ */ new Set();
|
|
14
|
+
const staticIPv4Rules = /* @__PURE__ */ new Set();
|
|
15
|
+
const staticIPv6Rules = /* @__PURE__ */ new Set();
|
|
16
|
+
const cidrRules = [];
|
|
17
|
+
const registerStaticRule = (rule) => {
|
|
18
|
+
const type = distinctRemoteAddr(rule);
|
|
19
|
+
if (type === void 0) throw new TypeError(`Invalid rule: ${rule}`);
|
|
20
|
+
if (type === "IPv4") {
|
|
21
|
+
const ipv4binary = convertIPv4ToBinary(rule);
|
|
22
|
+
staticRules.add(rule);
|
|
23
|
+
staticRules.add(`::ffff:${rule}`);
|
|
24
|
+
staticIPv4Rules.add(ipv4binary);
|
|
25
|
+
staticIPv6Rules.add(65535n << 32n | ipv4binary);
|
|
26
|
+
} else {
|
|
27
|
+
const ipv6binary = convertIPv6ToBinary(rule);
|
|
28
|
+
const ipv6Addr = convertIPv6BinaryToString(ipv6binary);
|
|
29
|
+
staticRules.add(ipv6Addr);
|
|
30
|
+
staticIPv6Rules.add(ipv6binary);
|
|
31
|
+
if (isIPv4MappedIPv6(ipv6binary)) {
|
|
32
|
+
staticRules.add(ipv6Addr.substring(7));
|
|
33
|
+
staticIPv4Rules.add(convertIPv4MappedIPv6ToIPv4(ipv6binary));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
for (let rule of rules) if (rule === "*") return () => true;
|
|
38
|
+
else if (typeof rule === "function") functionRules.push(rule);
|
|
39
|
+
else {
|
|
40
|
+
if (IS_CIDR_NOTATION_REGEX.test(rule)) {
|
|
41
|
+
const separatedRule = rule.split("/");
|
|
42
|
+
const addrStr = separatedRule[0];
|
|
43
|
+
const type = distinctRemoteAddr(addrStr);
|
|
44
|
+
if (type === void 0) throw new TypeError(`Invalid rule: ${rule}`);
|
|
45
|
+
let isIPv4 = type === "IPv4";
|
|
46
|
+
let prefix = parseCidrPrefix(rule, separatedRule[1], isIPv4 ? 32 : 128);
|
|
47
|
+
if (isIPv4 ? prefix === 32 : prefix === 128) rule = addrStr;
|
|
48
|
+
else {
|
|
49
|
+
let addr = (isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(addrStr);
|
|
50
|
+
if (type === "IPv6" && isIPv4MappedIPv6(addr) && prefix >= 96) {
|
|
51
|
+
isIPv4 = true;
|
|
52
|
+
addr = convertIPv4MappedIPv6ToIPv4(addr);
|
|
53
|
+
prefix -= 96;
|
|
54
|
+
}
|
|
55
|
+
const mask = (1n << BigInt(prefix)) - 1n << BigInt((isIPv4 ? 32 : 128) - prefix);
|
|
56
|
+
cidrRules.push([
|
|
57
|
+
isIPv4,
|
|
58
|
+
addr & mask,
|
|
59
|
+
mask
|
|
60
|
+
]);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
registerStaticRule(rule);
|
|
65
|
+
}
|
|
66
|
+
return (remote) => {
|
|
67
|
+
if (staticRules.has(remote.addr)) return true;
|
|
68
|
+
const remoteAddr = remote.binaryAddr ||= (remote.isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(remote.addr);
|
|
69
|
+
const remoteIPv4Addr = remote.isIPv4 || isIPv4MappedIPv6(remoteAddr) ? remote.isIPv4 ? remoteAddr : convertIPv4MappedIPv6ToIPv4(remoteAddr) : void 0;
|
|
70
|
+
if ((remote.isIPv4 ? staticIPv4Rules : staticIPv6Rules).has(remoteAddr)) return true;
|
|
71
|
+
for (const [isIPv4, addr, mask] of cidrRules) {
|
|
72
|
+
if (isIPv4) {
|
|
73
|
+
if (remoteIPv4Addr === void 0) continue;
|
|
74
|
+
if ((remoteIPv4Addr & mask) === addr) return true;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (remote.isIPv4) continue;
|
|
78
|
+
if ((remoteAddr & mask) === addr) return true;
|
|
79
|
+
}
|
|
80
|
+
for (const rule of functionRules) if (rule({
|
|
81
|
+
addr: remote.addr,
|
|
82
|
+
type: remote.type
|
|
83
|
+
})) return true;
|
|
84
|
+
return false;
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
/**
|
|
88
|
+
* IP Restriction Middleware for Acryl.
|
|
89
|
+
*
|
|
90
|
+
*
|
|
91
|
+
* @param {GetConnInfo | ((c: Context) => string)} getIP - A function to retrieve the client IP address. Use `getConnInfo` from the appropriate runtime adapter.
|
|
92
|
+
* @param {IPRestrictionRules} rules - An object with optional `denyList` and `allowList` arrays of IP rules. Each rule can be a static IP, a CIDR range, or a custom function.
|
|
93
|
+
* @param {(remote: { addr: string; type: AddressType }, c: Context) => Response | Promise<Response>} [onError] - Optional custom handler invoked when a request is blocked. Defaults to returning a 403 Forbidden response.
|
|
94
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* import { Acryl } from 'acrylblends'
|
|
99
|
+
* import { ipRestriction } from 'acrylblends/ip-restriction'
|
|
100
|
+
* import { getConnInfo } from 'acrylblends/cloudflare-workers'
|
|
101
|
+
*
|
|
102
|
+
* const app = new Acryl()
|
|
103
|
+
*
|
|
104
|
+
* app.use(
|
|
105
|
+
* '*',
|
|
106
|
+
* ipRestriction(getConnInfo, {
|
|
107
|
+
* // Block a specific IP and an entire subnet
|
|
108
|
+
* denyList: ['192.168.0.5', '10.0.0.0/8'],
|
|
109
|
+
* // Only allow requests from localhost and a private range
|
|
110
|
+
* allowList: ['127.0.0.1', '::1', '192.168.1.0/24'],
|
|
111
|
+
* })
|
|
112
|
+
* )
|
|
113
|
+
*
|
|
114
|
+
* // With a custom error handler
|
|
115
|
+
* app.use(
|
|
116
|
+
* '/admin/*',
|
|
117
|
+
* ipRestriction(
|
|
118
|
+
* getConnInfo,
|
|
119
|
+
* { allowList: ['203.0.113.0/24'] },
|
|
120
|
+
* (remote, c) => c.text(`Access denied for ${remote.addr}`, 403)
|
|
121
|
+
* )
|
|
122
|
+
* )
|
|
123
|
+
*
|
|
124
|
+
* app.get('/', (c) => c.text('Hello!'))
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
const ipRestriction = (getIP, { denyList = [], allowList = [] }, onError) => {
|
|
128
|
+
const allowLength = allowList.length;
|
|
129
|
+
const denyMatcher = buildMatcher(denyList);
|
|
130
|
+
const allowMatcher = buildMatcher(allowList);
|
|
131
|
+
const blockError = (c) => new HTTPException(403, { res: c.text("Forbidden", { status: 403 }) });
|
|
132
|
+
return async function ipRestriction(c, next) {
|
|
133
|
+
const connInfo = getIP(c);
|
|
134
|
+
const addr = typeof connInfo === "string" ? connInfo : connInfo.remote.address;
|
|
135
|
+
if (!addr) throw blockError(c);
|
|
136
|
+
const type = typeof connInfo !== "string" && connInfo.remote.addressType || distinctRemoteAddr(addr);
|
|
137
|
+
const remoteData = {
|
|
138
|
+
addr,
|
|
139
|
+
type,
|
|
140
|
+
isIPv4: type === "IPv4"
|
|
141
|
+
};
|
|
142
|
+
try {
|
|
143
|
+
if (denyMatcher(remoteData)) {
|
|
144
|
+
if (onError) return onError({
|
|
145
|
+
addr,
|
|
146
|
+
type
|
|
147
|
+
}, c);
|
|
148
|
+
throw blockError(c);
|
|
149
|
+
}
|
|
150
|
+
if (allowMatcher(remoteData)) return await next();
|
|
151
|
+
} catch (e) {
|
|
152
|
+
if (e instanceof TypeError && e.code === "ERR_INVALID_IP_ADDRESS") throw blockError(c);
|
|
153
|
+
throw e;
|
|
154
|
+
}
|
|
155
|
+
if (allowLength === 0) return await next();
|
|
156
|
+
else {
|
|
157
|
+
if (onError) return await onError({
|
|
158
|
+
addr,
|
|
159
|
+
type
|
|
160
|
+
}, c);
|
|
161
|
+
throw blockError(c);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
//#endregion
|
|
166
|
+
export { ipRestriction as t };
|
package/lib/ip-restriction.js
CHANGED
|
@@ -1,166 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { convertIPv4MappedIPv6ToIPv4, convertIPv4ToBinary, convertIPv6BinaryToString, convertIPv6ToBinary, distinctRemoteAddr, isIPv4MappedIPv6 } from "./utils/ipaddr.js";
|
|
3
|
-
//#region ../../plugins/acryl-router/src/core/middleware/ip-restriction/index.ts
|
|
4
|
-
const IS_CIDR_NOTATION_REGEX = /\/[^/]*$/;
|
|
5
|
-
const parseCidrPrefix = (rule, prefix, max) => {
|
|
6
|
-
if (!/^[0-9]{1,3}$/.test(prefix)) throw new TypeError(`Invalid rule: ${rule}`);
|
|
7
|
-
const parsedPrefix = parseInt(prefix);
|
|
8
|
-
if (parsedPrefix > max) throw new TypeError(`Invalid rule: ${rule}`);
|
|
9
|
-
return parsedPrefix;
|
|
10
|
-
};
|
|
11
|
-
const buildMatcher = (rules) => {
|
|
12
|
-
const functionRules = [];
|
|
13
|
-
const staticRules = /* @__PURE__ */ new Set();
|
|
14
|
-
const staticIPv4Rules = /* @__PURE__ */ new Set();
|
|
15
|
-
const staticIPv6Rules = /* @__PURE__ */ new Set();
|
|
16
|
-
const cidrRules = [];
|
|
17
|
-
const registerStaticRule = (rule) => {
|
|
18
|
-
const type = distinctRemoteAddr(rule);
|
|
19
|
-
if (type === void 0) throw new TypeError(`Invalid rule: ${rule}`);
|
|
20
|
-
if (type === "IPv4") {
|
|
21
|
-
const ipv4binary = convertIPv4ToBinary(rule);
|
|
22
|
-
staticRules.add(rule);
|
|
23
|
-
staticRules.add(`::ffff:${rule}`);
|
|
24
|
-
staticIPv4Rules.add(ipv4binary);
|
|
25
|
-
staticIPv6Rules.add(65535n << 32n | ipv4binary);
|
|
26
|
-
} else {
|
|
27
|
-
const ipv6binary = convertIPv6ToBinary(rule);
|
|
28
|
-
const ipv6Addr = convertIPv6BinaryToString(ipv6binary);
|
|
29
|
-
staticRules.add(ipv6Addr);
|
|
30
|
-
staticIPv6Rules.add(ipv6binary);
|
|
31
|
-
if (isIPv4MappedIPv6(ipv6binary)) {
|
|
32
|
-
staticRules.add(ipv6Addr.substring(7));
|
|
33
|
-
staticIPv4Rules.add(convertIPv4MappedIPv6ToIPv4(ipv6binary));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
for (let rule of rules) if (rule === "*") return () => true;
|
|
38
|
-
else if (typeof rule === "function") functionRules.push(rule);
|
|
39
|
-
else {
|
|
40
|
-
if (IS_CIDR_NOTATION_REGEX.test(rule)) {
|
|
41
|
-
const separatedRule = rule.split("/");
|
|
42
|
-
const addrStr = separatedRule[0];
|
|
43
|
-
const type = distinctRemoteAddr(addrStr);
|
|
44
|
-
if (type === void 0) throw new TypeError(`Invalid rule: ${rule}`);
|
|
45
|
-
let isIPv4 = type === "IPv4";
|
|
46
|
-
let prefix = parseCidrPrefix(rule, separatedRule[1], isIPv4 ? 32 : 128);
|
|
47
|
-
if (isIPv4 ? prefix === 32 : prefix === 128) rule = addrStr;
|
|
48
|
-
else {
|
|
49
|
-
let addr = (isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(addrStr);
|
|
50
|
-
if (type === "IPv6" && isIPv4MappedIPv6(addr) && prefix >= 96) {
|
|
51
|
-
isIPv4 = true;
|
|
52
|
-
addr = convertIPv4MappedIPv6ToIPv4(addr);
|
|
53
|
-
prefix -= 96;
|
|
54
|
-
}
|
|
55
|
-
const mask = (1n << BigInt(prefix)) - 1n << BigInt((isIPv4 ? 32 : 128) - prefix);
|
|
56
|
-
cidrRules.push([
|
|
57
|
-
isIPv4,
|
|
58
|
-
addr & mask,
|
|
59
|
-
mask
|
|
60
|
-
]);
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
registerStaticRule(rule);
|
|
65
|
-
}
|
|
66
|
-
return (remote) => {
|
|
67
|
-
if (staticRules.has(remote.addr)) return true;
|
|
68
|
-
const remoteAddr = remote.binaryAddr ||= (remote.isIPv4 ? convertIPv4ToBinary : convertIPv6ToBinary)(remote.addr);
|
|
69
|
-
const remoteIPv4Addr = remote.isIPv4 || isIPv4MappedIPv6(remoteAddr) ? remote.isIPv4 ? remoteAddr : convertIPv4MappedIPv6ToIPv4(remoteAddr) : void 0;
|
|
70
|
-
if ((remote.isIPv4 ? staticIPv4Rules : staticIPv6Rules).has(remoteAddr)) return true;
|
|
71
|
-
for (const [isIPv4, addr, mask] of cidrRules) {
|
|
72
|
-
if (isIPv4) {
|
|
73
|
-
if (remoteIPv4Addr === void 0) continue;
|
|
74
|
-
if ((remoteIPv4Addr & mask) === addr) return true;
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (remote.isIPv4) continue;
|
|
78
|
-
if ((remoteAddr & mask) === addr) return true;
|
|
79
|
-
}
|
|
80
|
-
for (const rule of functionRules) if (rule({
|
|
81
|
-
addr: remote.addr,
|
|
82
|
-
type: remote.type
|
|
83
|
-
})) return true;
|
|
84
|
-
return false;
|
|
85
|
-
};
|
|
86
|
-
};
|
|
87
|
-
/**
|
|
88
|
-
* IP Restriction Middleware for Acryl.
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* @param {GetConnInfo | ((c: Context) => string)} getIP - A function to retrieve the client IP address. Use `getConnInfo` from the appropriate runtime adapter.
|
|
92
|
-
* @param {IPRestrictionRules} rules - An object with optional `denyList` and `allowList` arrays of IP rules. Each rule can be a static IP, a CIDR range, or a custom function.
|
|
93
|
-
* @param {(remote: { addr: string; type: AddressType }, c: Context) => Response | Promise<Response>} [onError] - Optional custom handler invoked when a request is blocked. Defaults to returning a 403 Forbidden response.
|
|
94
|
-
* @returns {MiddlewareHandler} The middleware handler function.
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* ```ts
|
|
98
|
-
* import { Acryl } from 'acrylblends'
|
|
99
|
-
* import { ipRestriction } from 'acrylblends/ip-restriction'
|
|
100
|
-
* import { getConnInfo } from 'acrylblends/cloudflare-workers'
|
|
101
|
-
*
|
|
102
|
-
* const app = new Acryl()
|
|
103
|
-
*
|
|
104
|
-
* app.use(
|
|
105
|
-
* '*',
|
|
106
|
-
* ipRestriction(getConnInfo, {
|
|
107
|
-
* // Block a specific IP and an entire subnet
|
|
108
|
-
* denyList: ['192.168.0.5', '10.0.0.0/8'],
|
|
109
|
-
* // Only allow requests from localhost and a private range
|
|
110
|
-
* allowList: ['127.0.0.1', '::1', '192.168.1.0/24'],
|
|
111
|
-
* })
|
|
112
|
-
* )
|
|
113
|
-
*
|
|
114
|
-
* // With a custom error handler
|
|
115
|
-
* app.use(
|
|
116
|
-
* '/admin/*',
|
|
117
|
-
* ipRestriction(
|
|
118
|
-
* getConnInfo,
|
|
119
|
-
* { allowList: ['203.0.113.0/24'] },
|
|
120
|
-
* (remote, c) => c.text(`Access denied for ${remote.addr}`, 403)
|
|
121
|
-
* )
|
|
122
|
-
* )
|
|
123
|
-
*
|
|
124
|
-
* app.get('/', (c) => c.text('Hello!'))
|
|
125
|
-
* ```
|
|
126
|
-
*/
|
|
127
|
-
const ipRestriction = (getIP, { denyList = [], allowList = [] }, onError) => {
|
|
128
|
-
const allowLength = allowList.length;
|
|
129
|
-
const denyMatcher = buildMatcher(denyList);
|
|
130
|
-
const allowMatcher = buildMatcher(allowList);
|
|
131
|
-
const blockError = (c) => new HTTPException(403, { res: c.text("Forbidden", { status: 403 }) });
|
|
132
|
-
return async function ipRestriction(c, next) {
|
|
133
|
-
const connInfo = getIP(c);
|
|
134
|
-
const addr = typeof connInfo === "string" ? connInfo : connInfo.remote.address;
|
|
135
|
-
if (!addr) throw blockError(c);
|
|
136
|
-
const type = typeof connInfo !== "string" && connInfo.remote.addressType || distinctRemoteAddr(addr);
|
|
137
|
-
const remoteData = {
|
|
138
|
-
addr,
|
|
139
|
-
type,
|
|
140
|
-
isIPv4: type === "IPv4"
|
|
141
|
-
};
|
|
142
|
-
try {
|
|
143
|
-
if (denyMatcher(remoteData)) {
|
|
144
|
-
if (onError) return onError({
|
|
145
|
-
addr,
|
|
146
|
-
type
|
|
147
|
-
}, c);
|
|
148
|
-
throw blockError(c);
|
|
149
|
-
}
|
|
150
|
-
if (allowMatcher(remoteData)) return await next();
|
|
151
|
-
} catch (e) {
|
|
152
|
-
if (e instanceof TypeError && e.code === "ERR_INVALID_IP_ADDRESS") throw blockError(c);
|
|
153
|
-
throw e;
|
|
154
|
-
}
|
|
155
|
-
if (allowLength === 0) return await next();
|
|
156
|
-
else {
|
|
157
|
-
if (onError) return await onError({
|
|
158
|
-
addr,
|
|
159
|
-
type
|
|
160
|
-
}, c);
|
|
161
|
-
throw blockError(c);
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
};
|
|
165
|
-
//#endregion
|
|
1
|
+
import { t as ipRestriction } from "./ip-restriction-jKtKCRM_.js";
|
|
166
2
|
export { ipRestriction };
|