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,332 @@
|
|
|
1
|
+
import { t as compose } from "./compose-BuW2B6PZ.js";
|
|
2
|
+
import { i as getPathNoStrict, l as mergePath, r as getPath } from "./url-BPh4d6j-.js";
|
|
3
|
+
import { t as Context } from "./context-CkOh7Ygv.js";
|
|
4
|
+
import { n as METHODS } from "./router-Be_o6nFu.js";
|
|
5
|
+
import { t as COMPOSED_HANDLER } from "./constants-CBSEudrb.js";
|
|
6
|
+
//#region ../../plugins/acryl-router/src/core/app-base.ts
|
|
7
|
+
/**
|
|
8
|
+
* @module
|
|
9
|
+
* This module is the base module for the Acryl object.
|
|
10
|
+
*/
|
|
11
|
+
const notFoundHandler = (c) => {
|
|
12
|
+
return c.text("404 Not Found", 404);
|
|
13
|
+
};
|
|
14
|
+
const errorHandler = (err, c) => {
|
|
15
|
+
if ("getResponse" in err) {
|
|
16
|
+
const res = err.getResponse();
|
|
17
|
+
return c.newResponse(res.body, res);
|
|
18
|
+
}
|
|
19
|
+
console.error(err);
|
|
20
|
+
return c.text("Internal Server Error", 500);
|
|
21
|
+
};
|
|
22
|
+
var Acryl = class Acryl {
|
|
23
|
+
get;
|
|
24
|
+
post;
|
|
25
|
+
put;
|
|
26
|
+
delete;
|
|
27
|
+
options;
|
|
28
|
+
patch;
|
|
29
|
+
query;
|
|
30
|
+
all;
|
|
31
|
+
on;
|
|
32
|
+
use;
|
|
33
|
+
router;
|
|
34
|
+
getPath;
|
|
35
|
+
_basePath = "/";
|
|
36
|
+
#path = "/";
|
|
37
|
+
routes = [];
|
|
38
|
+
constructor(options = {}) {
|
|
39
|
+
[...METHODS, "all"].forEach((method) => {
|
|
40
|
+
this[method] = (args1, ...args) => {
|
|
41
|
+
const methodName = method.toUpperCase();
|
|
42
|
+
if (typeof args1 === "string") this.#path = args1;
|
|
43
|
+
else this.#addRoute(methodName, this.#path, args1);
|
|
44
|
+
args.forEach((handler) => {
|
|
45
|
+
this.#addRoute(methodName, this.#path, handler);
|
|
46
|
+
});
|
|
47
|
+
return this;
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
this.on = (method, path, ...handlers) => {
|
|
51
|
+
for (const p of [path].flat()) {
|
|
52
|
+
this.#path = p;
|
|
53
|
+
for (const m of [method].flat()) {
|
|
54
|
+
const methodName = m.toUpperCase();
|
|
55
|
+
for (const handler of handlers) this.#addRoute(methodName, this.#path, handler);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return this;
|
|
59
|
+
};
|
|
60
|
+
this.use = (arg1, ...handlers) => {
|
|
61
|
+
if (typeof arg1 === "string") this.#path = arg1;
|
|
62
|
+
else {
|
|
63
|
+
this.#path = "*";
|
|
64
|
+
handlers.unshift(arg1);
|
|
65
|
+
}
|
|
66
|
+
handlers.forEach((handler) => {
|
|
67
|
+
this.#addRoute("ALL", this.#path, handler);
|
|
68
|
+
});
|
|
69
|
+
return this;
|
|
70
|
+
};
|
|
71
|
+
const { strict, ...optionsWithoutStrict } = options;
|
|
72
|
+
Object.assign(this, optionsWithoutStrict);
|
|
73
|
+
this.getPath = strict ?? true ? options.getPath ?? getPath : getPathNoStrict;
|
|
74
|
+
}
|
|
75
|
+
#clone() {
|
|
76
|
+
const clone = new Acryl({
|
|
77
|
+
router: this.router,
|
|
78
|
+
getPath: this.getPath
|
|
79
|
+
});
|
|
80
|
+
clone.errorHandler = this.errorHandler;
|
|
81
|
+
clone.#notFoundHandler = this.#notFoundHandler;
|
|
82
|
+
clone.routes = this.routes;
|
|
83
|
+
return clone;
|
|
84
|
+
}
|
|
85
|
+
#notFoundHandler = notFoundHandler;
|
|
86
|
+
errorHandler = errorHandler;
|
|
87
|
+
/**
|
|
88
|
+
* `.route()` allows grouping other Acryl instance in routes.
|
|
89
|
+
*
|
|
90
|
+
*
|
|
91
|
+
* @param {string} path - base Path
|
|
92
|
+
* @param {Acryl} app - other Acryl instance
|
|
93
|
+
* @returns {Acryl} routed Acryl instance
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* const app = new Acryl()
|
|
98
|
+
* const app2 = new Acryl()
|
|
99
|
+
*
|
|
100
|
+
* app2.get("/user", (c) => c.text("user"))
|
|
101
|
+
* app.route("/api", app2) // GET /api/user
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
route(path, app) {
|
|
105
|
+
const subApp = this.basePath(path);
|
|
106
|
+
app.routes.map((r) => {
|
|
107
|
+
let handler;
|
|
108
|
+
if (app.errorHandler === errorHandler) handler = r.handler;
|
|
109
|
+
else {
|
|
110
|
+
handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
|
|
111
|
+
handler[COMPOSED_HANDLER] = r.handler;
|
|
112
|
+
}
|
|
113
|
+
subApp.#addRoute(r.method, r.path, handler, r.basePath);
|
|
114
|
+
});
|
|
115
|
+
return this;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* `.basePath()` allows base paths to be specified.
|
|
119
|
+
*
|
|
120
|
+
*
|
|
121
|
+
* @param {string} path - base Path
|
|
122
|
+
* @returns {Acryl} changed Acryl instance
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* const api = new Acryl().basePath('/api')
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
basePath(path) {
|
|
130
|
+
const subApp = this.#clone();
|
|
131
|
+
subApp._basePath = mergePath(this._basePath, path);
|
|
132
|
+
return subApp;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* `.onError()` handles an error and returns a customized Response.
|
|
136
|
+
*
|
|
137
|
+
*
|
|
138
|
+
* @param {ErrorHandler} handler - request Handler for error
|
|
139
|
+
* @returns {Acryl} changed Acryl instance
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* app.onError((err, c) => {
|
|
144
|
+
* console.error(`${err}`)
|
|
145
|
+
* return c.text('Custom Error Message', 500)
|
|
146
|
+
* })
|
|
147
|
+
* ```
|
|
148
|
+
*/
|
|
149
|
+
onError = (handler) => {
|
|
150
|
+
this.errorHandler = handler;
|
|
151
|
+
return this;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* `.notFound()` allows you to customize a Not Found Response.
|
|
155
|
+
*
|
|
156
|
+
*
|
|
157
|
+
* @param {NotFoundHandler} handler - request handler for not-found
|
|
158
|
+
* @returns {Acryl} changed Acryl instance
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* app.notFound((c) => {
|
|
163
|
+
* return c.text('Custom 404 Message', 404)
|
|
164
|
+
* })
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
notFound = (handler) => {
|
|
168
|
+
this.#notFoundHandler = handler;
|
|
169
|
+
return this;
|
|
170
|
+
};
|
|
171
|
+
/**
|
|
172
|
+
* `.mount()` allows you to mount applications built with other frameworks into your Acryl application.
|
|
173
|
+
*
|
|
174
|
+
* @deprecated Use `mount()` from `acryl-router/mount` instead. `.mount()` will be removed in v5.
|
|
175
|
+
*
|
|
176
|
+
*
|
|
177
|
+
* @param {string} path - base Path
|
|
178
|
+
* @param {Function} applicationHandler - other Request Handler
|
|
179
|
+
* @param {MountOptions} [options] - options of `.mount()`
|
|
180
|
+
* @returns {Acryl} mounted Acryl instance
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```ts
|
|
184
|
+
* import { Router as IttyRouter } from 'itty-router'
|
|
185
|
+
* import { Acryl } from 'acrylblends'
|
|
186
|
+
* // Create itty-router application
|
|
187
|
+
* const ittyRouter = IttyRouter()
|
|
188
|
+
* // GET /itty-router/hello
|
|
189
|
+
* ittyRouter.get('/hello', () => new Response('Hello from itty-router'))
|
|
190
|
+
*
|
|
191
|
+
* const app = new Acryl()
|
|
192
|
+
* app.mount('/itty-router', ittyRouter.handle)
|
|
193
|
+
* ```
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```ts
|
|
197
|
+
* const app = new Acryl()
|
|
198
|
+
* // Send the request to another application without modification.
|
|
199
|
+
* app.mount('/app', anotherApp, {
|
|
200
|
+
* replaceRequest: (req) => req,
|
|
201
|
+
* })
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
mount(path, applicationHandler, options) {
|
|
205
|
+
let replaceRequest;
|
|
206
|
+
let optionHandler;
|
|
207
|
+
if (options) if (typeof options === "function") optionHandler = options;
|
|
208
|
+
else {
|
|
209
|
+
optionHandler = options.optionHandler;
|
|
210
|
+
if (options.replaceRequest === false) replaceRequest = (request) => request;
|
|
211
|
+
else replaceRequest = options.replaceRequest;
|
|
212
|
+
}
|
|
213
|
+
const getOptions = optionHandler ? (c) => {
|
|
214
|
+
const options = optionHandler(c);
|
|
215
|
+
return Array.isArray(options) ? options : [options];
|
|
216
|
+
} : (c) => {
|
|
217
|
+
let executionContext = void 0;
|
|
218
|
+
try {
|
|
219
|
+
executionContext = c.executionCtx;
|
|
220
|
+
} catch {}
|
|
221
|
+
return [c.env, executionContext];
|
|
222
|
+
};
|
|
223
|
+
replaceRequest ||= (() => {
|
|
224
|
+
const mergedPath = mergePath(this._basePath, path);
|
|
225
|
+
const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
|
|
226
|
+
return (request) => {
|
|
227
|
+
const url = new URL(request.url);
|
|
228
|
+
url.pathname = this.getPath(request).slice(pathPrefixLength) || "/";
|
|
229
|
+
return new Request(url, request);
|
|
230
|
+
};
|
|
231
|
+
})();
|
|
232
|
+
const handler = async (c, next) => {
|
|
233
|
+
const res = await applicationHandler(replaceRequest(c.req.raw), ...getOptions(c));
|
|
234
|
+
if (res) return res;
|
|
235
|
+
await next();
|
|
236
|
+
};
|
|
237
|
+
this.#addRoute("ALL", mergePath(path, "*"), handler);
|
|
238
|
+
return this;
|
|
239
|
+
}
|
|
240
|
+
#addRoute(method, path, handler, baseRoutePath) {
|
|
241
|
+
path = mergePath(this._basePath, path);
|
|
242
|
+
const r = {
|
|
243
|
+
basePath: baseRoutePath !== void 0 ? mergePath(this._basePath, baseRoutePath) : this._basePath,
|
|
244
|
+
path,
|
|
245
|
+
method,
|
|
246
|
+
handler
|
|
247
|
+
};
|
|
248
|
+
this.router.add(method, path, [handler, r]);
|
|
249
|
+
this.routes.push(r);
|
|
250
|
+
}
|
|
251
|
+
#handleError(err, c) {
|
|
252
|
+
if (err instanceof Error) return this.errorHandler(err, c);
|
|
253
|
+
throw err;
|
|
254
|
+
}
|
|
255
|
+
#dispatch(request, executionCtx, env, method) {
|
|
256
|
+
if (method === "HEAD") return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
|
|
257
|
+
const path = this.getPath(request, { env });
|
|
258
|
+
const matchResult = this.router.match(method, path);
|
|
259
|
+
const c = new Context(request, {
|
|
260
|
+
path,
|
|
261
|
+
matchResult,
|
|
262
|
+
env,
|
|
263
|
+
executionCtx,
|
|
264
|
+
notFoundHandler: this.#notFoundHandler
|
|
265
|
+
});
|
|
266
|
+
if (matchResult[0].length === 1) {
|
|
267
|
+
let res;
|
|
268
|
+
try {
|
|
269
|
+
res = matchResult[0][0][0][0](c, async () => {
|
|
270
|
+
c.res = await this.#notFoundHandler(c);
|
|
271
|
+
});
|
|
272
|
+
} catch (err) {
|
|
273
|
+
return this.#handleError(err, c);
|
|
274
|
+
}
|
|
275
|
+
return res instanceof Promise ? res.then((resolved) => resolved || (c.finalized ? c.res : this.#notFoundHandler(c))).catch((err) => this.#handleError(err, c)) : res ?? this.#notFoundHandler(c);
|
|
276
|
+
}
|
|
277
|
+
const composed = compose(matchResult[0], this.errorHandler, this.#notFoundHandler);
|
|
278
|
+
return (async () => {
|
|
279
|
+
try {
|
|
280
|
+
const context = await composed(c);
|
|
281
|
+
if (!context.finalized) throw new Error("Context is not finalized. Did you forget to return a Response object or `await next()`?");
|
|
282
|
+
return context.res;
|
|
283
|
+
} catch (err) {
|
|
284
|
+
return this.#handleError(err, c);
|
|
285
|
+
}
|
|
286
|
+
})();
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* `.fetch()` will be entry point of your app.
|
|
290
|
+
*
|
|
291
|
+
*
|
|
292
|
+
* @param {Request} request - request Object of request
|
|
293
|
+
* @param {Env} env - env Object
|
|
294
|
+
* @param {ExecutionContext} executionCtx - context of execution
|
|
295
|
+
* @returns {Response | Promise<Response>} response of request
|
|
296
|
+
*
|
|
297
|
+
*/
|
|
298
|
+
fetch = (request, ...rest) => {
|
|
299
|
+
return this.#dispatch(request, rest[1], rest[0], request.method);
|
|
300
|
+
};
|
|
301
|
+
/**
|
|
302
|
+
* `.request()` is a useful method for testing.
|
|
303
|
+
* You can pass a URL or pathname to send a GET request.
|
|
304
|
+
* app will return a Response object.
|
|
305
|
+
* ```ts
|
|
306
|
+
* test('GET /hello is ok', async () => {
|
|
307
|
+
* const res = await app.request('/hello')
|
|
308
|
+
* expect(res.status).toBe(200)
|
|
309
|
+
* })
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
request = (input, requestInit, Env, executionCtx) => {
|
|
313
|
+
if (input instanceof Request) return this.fetch(requestInit ? new Request(input, requestInit) : input, Env, executionCtx);
|
|
314
|
+
input = input.toString();
|
|
315
|
+
return this.fetch(new Request(/^https?:\/\//.test(input) ? input : `http://localhost${mergePath("/", input)}`, requestInit), Env, executionCtx);
|
|
316
|
+
};
|
|
317
|
+
/**
|
|
318
|
+
* `.fire()` automatically adds a global fetch event listener.
|
|
319
|
+
* This can be useful for environments that adhere to the Service Worker API, such as non-ES module Cloudflare Workers.
|
|
320
|
+
* @deprecated
|
|
321
|
+
* ACRYL ships no service-worker adapter: mount the app with `ctx.router.route(path, app)` and serve it through an ACRYL adapter instead.
|
|
322
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API
|
|
323
|
+
* @see https://developers.cloudflare.com/workers/reference/migrate-to-module-workers/
|
|
324
|
+
*/
|
|
325
|
+
fire = () => {
|
|
326
|
+
addEventListener("fetch", (event) => {
|
|
327
|
+
event.respondWith(this.#dispatch(event.request, event, void 0, event.request.method));
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
//#endregion
|
|
332
|
+
export { Acryl as t };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as
|
|
1
|
+
import { _ as UiRequest, n as AuditEntry, r as ChannelToHost, v as UiResult } from "./protocol-C37gPePD.js";
|
|
2
2
|
|
|
3
3
|
//#region ../../plugins/acryl-door/src/host/channel.d.ts
|
|
4
4
|
/** The slice of a page's stream the channel needs, so tests can supply their own. */
|
|
@@ -12,6 +12,8 @@ declare class UiChannel {
|
|
|
12
12
|
private nextId;
|
|
13
13
|
private clock;
|
|
14
14
|
private closed;
|
|
15
|
+
/** Callers waiting for a page to (re)connect: each is told once, by the next stream that attaches. */
|
|
16
|
+
private readonly attachWaiters;
|
|
15
17
|
/**
|
|
16
18
|
* Register a page's stream. A stream already open for the same window is closed first, and its calls settle as `disconnected`.
|
|
17
19
|
* @returns the function to call when this stream ends.
|
|
@@ -34,6 +36,17 @@ declare class UiChannel {
|
|
|
34
36
|
signal?: AbortSignal;
|
|
35
37
|
timeoutMs?: number;
|
|
36
38
|
}): Promise<UiResult>;
|
|
39
|
+
/**
|
|
40
|
+
* A promise for the next time a page connects (a page that reloaded or moved opens a new stream). Ask for it BEFORE the call that makes the page leave, or a fast page is missed.
|
|
41
|
+
* @returns whether a page connected within `timeoutMs`.
|
|
42
|
+
*/
|
|
43
|
+
expectAttach(timeoutMs: number, count?: number): Promise<boolean>;
|
|
44
|
+
/**
|
|
45
|
+
* Ask every connected page to reload (the app just changed under them) and wait, up to `timeoutMs`, for them to come back. Best effort: a page that does not come back
|
|
46
|
+
* (it was closed, or it moved to a page without the door) is not an error here.
|
|
47
|
+
* @returns how many pages were asked.
|
|
48
|
+
*/
|
|
49
|
+
reloadAll(timeoutMs?: number): Promise<number>;
|
|
37
50
|
/** Close every page's stream and settle every pending call as `unloaded`. */
|
|
38
51
|
close(): void;
|
|
39
52
|
private byRecency;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as resolveCallbackSync, n as escapeToBuffer, o as stringBufferToString, r as raw } from "./html-DGExBFNg.js";
|
|
2
2
|
import { i as DOM_RENDERER, n as DOM_INTERNAL_TAG, o as PERMALINK, r as DOM_MEMO, t as DOM_ERROR_HANDLER } from "./constants-BR9jM9BC.js";
|
|
3
3
|
import "node:module";
|
|
4
4
|
//#region \0rolldown/runtime.js
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { t as decodeBase64 } from "./encode-BhbNLrjp.js";
|
|
2
|
+
//#region ../../plugins/acryl-router/src/core/utils/basic-auth.ts
|
|
3
|
+
const CREDENTIALS_REGEXP = /^ *(?:[Bb][Aa][Ss][Ii][Cc]) +([A-Za-z0-9._~+/-]+=*) *$/;
|
|
4
|
+
const USER_PASS_REGEXP = /^([^:]*):(.*)$/;
|
|
5
|
+
const utf8Decoder = new TextDecoder();
|
|
6
|
+
const auth = (req) => {
|
|
7
|
+
const match = CREDENTIALS_REGEXP.exec(req.headers.get("Authorization") || "");
|
|
8
|
+
if (!match) return;
|
|
9
|
+
let userPass = void 0;
|
|
10
|
+
try {
|
|
11
|
+
userPass = USER_PASS_REGEXP.exec(utf8Decoder.decode(decodeBase64(match[1])));
|
|
12
|
+
} catch {}
|
|
13
|
+
if (!userPass) return;
|
|
14
|
+
return {
|
|
15
|
+
username: userPass[1],
|
|
16
|
+
password: userPass[2]
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
20
|
+
export { auth as t };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { t as HTTPException } from "./http-exception-MjWkT89V.js";
|
|
2
|
+
import { i as timingSafeEqual } from "./buffer-CkEOJCcY.js";
|
|
3
|
+
import { t as auth } from "./basic-auth-C0HTRpXh.js";
|
|
4
|
+
//#region ../../plugins/acryl-router/src/core/middleware/basic-auth/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Basic Auth Middleware for Acryl.
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* @param {BasicAuthOptions} options - The options for the basic authentication middleware.
|
|
10
|
+
* @param {string} options.username - The username for authentication.
|
|
11
|
+
* @param {string} options.password - The password for authentication.
|
|
12
|
+
* @param {string} [options.realm="Secure Area"] - The realm attribute for the WWW-Authenticate header.
|
|
13
|
+
* @param {Function} [options.hashFunction] - The hash function used for secure comparison.
|
|
14
|
+
* @param {Function} [options.verifyUser] - The function to verify user credentials.
|
|
15
|
+
* @param {string | object | MessageFunction} [options.invalidUserMessage="Unauthorized"] - The invalid user message.
|
|
16
|
+
* @param {Function} [options.onAuthSuccess] - Callback function called on successful authentication.
|
|
17
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
18
|
+
* @throws {HTTPException} If neither "username and password" nor "verifyUser" options are provided.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```ts
|
|
22
|
+
* const app = new Acryl()
|
|
23
|
+
*
|
|
24
|
+
* app.use(
|
|
25
|
+
* '/auth/*',
|
|
26
|
+
* basicAuth({
|
|
27
|
+
* username: process.env.BASIC_AUTH_USERNAME,
|
|
28
|
+
* password: process.env.BASIC_AUTH_PASSWORD,
|
|
29
|
+
* })
|
|
30
|
+
* )
|
|
31
|
+
*
|
|
32
|
+
* app.get('/auth/page', (c) => {
|
|
33
|
+
* return c.text('You are authorized')
|
|
34
|
+
* })
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* // With onAuthSuccess callback
|
|
40
|
+
* app.use(
|
|
41
|
+
* '/auth/*',
|
|
42
|
+
* basicAuth({
|
|
43
|
+
* username: process.env.BASIC_AUTH_USERNAME,
|
|
44
|
+
* password: process.env.BASIC_AUTH_PASSWORD,
|
|
45
|
+
* onAuthSuccess: (c, username) => {
|
|
46
|
+
* c.set('user', { name: username, role: 'admin' })
|
|
47
|
+
* console.log(`User ${username} authenticated`)
|
|
48
|
+
* },
|
|
49
|
+
* })
|
|
50
|
+
* )
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
const basicAuth = (options, ...users) => {
|
|
54
|
+
const usernamePasswordInOptions = "username" in options && "password" in options;
|
|
55
|
+
const verifyUserInOptions = "verifyUser" in options;
|
|
56
|
+
if (!(usernamePasswordInOptions || verifyUserInOptions)) throw new Error("basic auth middleware requires options for \"username and password\" or \"verifyUser\"");
|
|
57
|
+
if (!options.realm) options.realm = "Secure Area";
|
|
58
|
+
if (!options.invalidUserMessage) options.invalidUserMessage = "Unauthorized";
|
|
59
|
+
if (usernamePasswordInOptions) users.unshift({
|
|
60
|
+
username: options.username,
|
|
61
|
+
password: options.password
|
|
62
|
+
});
|
|
63
|
+
return async function basicAuth(ctx, next) {
|
|
64
|
+
const requestUser = auth(ctx.req.raw);
|
|
65
|
+
if (requestUser) if (verifyUserInOptions) {
|
|
66
|
+
if (await options.verifyUser(requestUser.username, requestUser.password, ctx)) {
|
|
67
|
+
if (options.onAuthSuccess) await options.onAuthSuccess(ctx, requestUser.username);
|
|
68
|
+
await next();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
} else for (const user of users) {
|
|
72
|
+
const [usernameEqual, passwordEqual] = await Promise.all([timingSafeEqual(user.username, requestUser.username, options.hashFunction), timingSafeEqual(user.password, requestUser.password, options.hashFunction)]);
|
|
73
|
+
if (usernameEqual && passwordEqual) {
|
|
74
|
+
if (options.onAuthSuccess) await options.onAuthSuccess(ctx, requestUser.username);
|
|
75
|
+
await next();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const status = 401;
|
|
80
|
+
const headers = { "WWW-Authenticate": "Basic realm=\"" + options.realm?.replace(/"/g, "\\\"") + "\"" };
|
|
81
|
+
const responseMessage = typeof options.invalidUserMessage === "function" ? await options.invalidUserMessage(ctx) : options.invalidUserMessage;
|
|
82
|
+
throw new HTTPException(status, { res: typeof responseMessage === "string" ? new Response(responseMessage, {
|
|
83
|
+
status,
|
|
84
|
+
headers
|
|
85
|
+
}) : new Response(JSON.stringify(responseMessage), {
|
|
86
|
+
status,
|
|
87
|
+
headers: {
|
|
88
|
+
...headers,
|
|
89
|
+
"content-type": "application/json"
|
|
90
|
+
}
|
|
91
|
+
}) });
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
//#endregion
|
|
95
|
+
export { basicAuth as t };
|
package/lib/basic-auth.js
CHANGED
|
@@ -1,95 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { timingSafeEqual } from "./utils/buffer.js";
|
|
3
|
-
import { auth } from "./utils/basic-auth.js";
|
|
4
|
-
//#region ../../plugins/acryl-router/src/core/middleware/basic-auth/index.ts
|
|
5
|
-
/**
|
|
6
|
-
* Basic Auth Middleware for Acryl.
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* @param {BasicAuthOptions} options - The options for the basic authentication middleware.
|
|
10
|
-
* @param {string} options.username - The username for authentication.
|
|
11
|
-
* @param {string} options.password - The password for authentication.
|
|
12
|
-
* @param {string} [options.realm="Secure Area"] - The realm attribute for the WWW-Authenticate header.
|
|
13
|
-
* @param {Function} [options.hashFunction] - The hash function used for secure comparison.
|
|
14
|
-
* @param {Function} [options.verifyUser] - The function to verify user credentials.
|
|
15
|
-
* @param {string | object | MessageFunction} [options.invalidUserMessage="Unauthorized"] - The invalid user message.
|
|
16
|
-
* @param {Function} [options.onAuthSuccess] - Callback function called on successful authentication.
|
|
17
|
-
* @returns {MiddlewareHandler} The middleware handler function.
|
|
18
|
-
* @throws {HTTPException} If neither "username and password" nor "verifyUser" options are provided.
|
|
19
|
-
*
|
|
20
|
-
* @example
|
|
21
|
-
* ```ts
|
|
22
|
-
* const app = new Acryl()
|
|
23
|
-
*
|
|
24
|
-
* app.use(
|
|
25
|
-
* '/auth/*',
|
|
26
|
-
* basicAuth({
|
|
27
|
-
* username: process.env.BASIC_AUTH_USERNAME,
|
|
28
|
-
* password: process.env.BASIC_AUTH_PASSWORD,
|
|
29
|
-
* })
|
|
30
|
-
* )
|
|
31
|
-
*
|
|
32
|
-
* app.get('/auth/page', (c) => {
|
|
33
|
-
* return c.text('You are authorized')
|
|
34
|
-
* })
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* ```ts
|
|
39
|
-
* // With onAuthSuccess callback
|
|
40
|
-
* app.use(
|
|
41
|
-
* '/auth/*',
|
|
42
|
-
* basicAuth({
|
|
43
|
-
* username: process.env.BASIC_AUTH_USERNAME,
|
|
44
|
-
* password: process.env.BASIC_AUTH_PASSWORD,
|
|
45
|
-
* onAuthSuccess: (c, username) => {
|
|
46
|
-
* c.set('user', { name: username, role: 'admin' })
|
|
47
|
-
* console.log(`User ${username} authenticated`)
|
|
48
|
-
* },
|
|
49
|
-
* })
|
|
50
|
-
* )
|
|
51
|
-
* ```
|
|
52
|
-
*/
|
|
53
|
-
const basicAuth = (options, ...users) => {
|
|
54
|
-
const usernamePasswordInOptions = "username" in options && "password" in options;
|
|
55
|
-
const verifyUserInOptions = "verifyUser" in options;
|
|
56
|
-
if (!(usernamePasswordInOptions || verifyUserInOptions)) throw new Error("basic auth middleware requires options for \"username and password\" or \"verifyUser\"");
|
|
57
|
-
if (!options.realm) options.realm = "Secure Area";
|
|
58
|
-
if (!options.invalidUserMessage) options.invalidUserMessage = "Unauthorized";
|
|
59
|
-
if (usernamePasswordInOptions) users.unshift({
|
|
60
|
-
username: options.username,
|
|
61
|
-
password: options.password
|
|
62
|
-
});
|
|
63
|
-
return async function basicAuth(ctx, next) {
|
|
64
|
-
const requestUser = auth(ctx.req.raw);
|
|
65
|
-
if (requestUser) if (verifyUserInOptions) {
|
|
66
|
-
if (await options.verifyUser(requestUser.username, requestUser.password, ctx)) {
|
|
67
|
-
if (options.onAuthSuccess) await options.onAuthSuccess(ctx, requestUser.username);
|
|
68
|
-
await next();
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
} else for (const user of users) {
|
|
72
|
-
const [usernameEqual, passwordEqual] = await Promise.all([timingSafeEqual(user.username, requestUser.username, options.hashFunction), timingSafeEqual(user.password, requestUser.password, options.hashFunction)]);
|
|
73
|
-
if (usernameEqual && passwordEqual) {
|
|
74
|
-
if (options.onAuthSuccess) await options.onAuthSuccess(ctx, requestUser.username);
|
|
75
|
-
await next();
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
const status = 401;
|
|
80
|
-
const headers = { "WWW-Authenticate": "Basic realm=\"" + options.realm?.replace(/"/g, "\\\"") + "\"" };
|
|
81
|
-
const responseMessage = typeof options.invalidUserMessage === "function" ? await options.invalidUserMessage(ctx) : options.invalidUserMessage;
|
|
82
|
-
throw new HTTPException(status, { res: typeof responseMessage === "string" ? new Response(responseMessage, {
|
|
83
|
-
status,
|
|
84
|
-
headers
|
|
85
|
-
}) : new Response(JSON.stringify(responseMessage), {
|
|
86
|
-
status,
|
|
87
|
-
headers: {
|
|
88
|
-
...headers,
|
|
89
|
-
"content-type": "application/json"
|
|
90
|
-
}
|
|
91
|
-
}) });
|
|
92
|
-
};
|
|
93
|
-
};
|
|
94
|
-
//#endregion
|
|
1
|
+
import { t as basicAuth } from "./basic-auth-DFLflXNe.js";
|
|
95
2
|
export { basicAuth };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { t as HTTPException } from "./http-exception-MjWkT89V.js";
|
|
2
|
+
import { i as timingSafeEqual } from "./buffer-CkEOJCcY.js";
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/middleware/bearer-auth/index.ts
|
|
4
|
+
const TOKEN_STRINGS = "[A-Za-z0-9._~+/-]+=*";
|
|
5
|
+
const PREFIX = "Bearer";
|
|
6
|
+
const HEADER = "Authorization";
|
|
7
|
+
/**
|
|
8
|
+
* Bearer Auth Middleware for Acryl.
|
|
9
|
+
*
|
|
10
|
+
*
|
|
11
|
+
* @template E - The environment type.
|
|
12
|
+
* @param {BearerAuthOptions} options - The options for the bearer authentication middleware.
|
|
13
|
+
* @param {string | string[]} [options.token] - The string or array of strings to validate the incoming bearer token against.
|
|
14
|
+
* @param {Function} [options.verifyToken] - The function to verify the token.
|
|
15
|
+
* @param {string} [options.realm=""] - The domain name of the realm, as part of the returned WWW-Authenticate challenge header.
|
|
16
|
+
* @param {string} [options.prefix="Bearer"] - The prefix (or known as `schema`) for the Authorization header value. If set to the empty string, no prefix is expected.
|
|
17
|
+
* @param {string} [options.headerName=Authorization] - The header name.
|
|
18
|
+
* @param {Function} [options.hashFunction] - A function to handle hashing for safe comparison of authentication tokens.
|
|
19
|
+
* @param {string | object | MessageFunction} [options.noAuthenticationHeader.message="Unauthorized"] - The no authentication header message.
|
|
20
|
+
* @param {string | object | MessageFunction} [options.noAuthenticationHeader.wwwAuthenticateHeader="Bearer realm=\"\""] - The response header value for the WWW-Authenticate header when no authentication header is provided.
|
|
21
|
+
* @param {string | object | MessageFunction} [options.invalidAuthenticationHeader.message="Bad Request"] - The invalid authentication header message.
|
|
22
|
+
* @param {string | object | MessageFunction} [options.invalidAuthenticationHeader.wwwAuthenticateHeader="Bearer error=\"invalid_request\""] - The response header value for the WWW-Authenticate header when authentication header is invalid.
|
|
23
|
+
* @param {string | object | MessageFunction} [options.invalidToken.message="Unauthorized"] - The invalid token message.
|
|
24
|
+
* @param {string | object | MessageFunction} [options.invalidToken.wwwAuthenticateHeader="Bearer error=\"invalid_token\""] - The response header value for the WWW-Authenticate header when token is invalid.
|
|
25
|
+
* @returns {MiddlewareHandler<E>} The middleware handler function.
|
|
26
|
+
* @throws {Error} If neither "token" nor "verifyToken" options are provided.
|
|
27
|
+
* @throws {HTTPException} If authentication fails, with 401 status code for missing or invalid token, or 400 status code for invalid request.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* const app = new Acryl()
|
|
32
|
+
*
|
|
33
|
+
* const token = process.env.API_TOKEN // never a literal in source
|
|
34
|
+
*
|
|
35
|
+
* app.use('/api/*', bearerAuth({ token }))
|
|
36
|
+
*
|
|
37
|
+
* app.get('/api/page', (c) => {
|
|
38
|
+
* return c.json({ message: 'You are authorized' })
|
|
39
|
+
* })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
const bearerAuth = (options) => {
|
|
43
|
+
if (!("token" in options || "verifyToken" in options)) throw new Error("bearer auth middleware requires options for \"token\" or \"verifyToken\"");
|
|
44
|
+
if (!options.realm) options.realm = "";
|
|
45
|
+
if (options.prefix === void 0) options.prefix = PREFIX;
|
|
46
|
+
const realm = options.realm?.replace(/"/g, "\\\"");
|
|
47
|
+
const prefix = options.prefix;
|
|
48
|
+
const tokenRegexp = new RegExp(`^${TOKEN_STRINGS}$`);
|
|
49
|
+
const wwwAuthenticatePrefix = prefix === "" ? "" : `${prefix} `;
|
|
50
|
+
const throwHTTPException = async (c, status, wwwAuthenticateHeader, messageOption) => {
|
|
51
|
+
const wwwAuthenticateHeaderValue = typeof wwwAuthenticateHeader === "function" ? await wwwAuthenticateHeader(c) : wwwAuthenticateHeader;
|
|
52
|
+
const headers = { "WWW-Authenticate": typeof wwwAuthenticateHeaderValue === "string" ? wwwAuthenticateHeaderValue : `${wwwAuthenticatePrefix}${Object.entries(wwwAuthenticateHeaderValue).map(([key, value]) => `${key}="${value}"`).join(",")}` };
|
|
53
|
+
const responseMessage = typeof messageOption === "function" ? await messageOption(c) : messageOption;
|
|
54
|
+
throw new HTTPException(status, { res: typeof responseMessage === "string" ? new Response(responseMessage, {
|
|
55
|
+
status,
|
|
56
|
+
headers
|
|
57
|
+
}) : new Response(JSON.stringify(responseMessage), {
|
|
58
|
+
status,
|
|
59
|
+
headers: {
|
|
60
|
+
...headers,
|
|
61
|
+
"content-type": "application/json"
|
|
62
|
+
}
|
|
63
|
+
}) });
|
|
64
|
+
};
|
|
65
|
+
return async function bearerAuth(c, next) {
|
|
66
|
+
const headerToken = c.req.header(options.headerName || HEADER);
|
|
67
|
+
if (!headerToken) await throwHTTPException(c, 401, options.noAuthenticationHeader?.wwwAuthenticateHeader || `${wwwAuthenticatePrefix}realm="${realm}"`, options.noAuthenticationHeader?.message || options.noAuthenticationHeaderMessage || "Unauthorized");
|
|
68
|
+
else {
|
|
69
|
+
let tokenValue;
|
|
70
|
+
if (prefix === "") tokenValue = headerToken;
|
|
71
|
+
else {
|
|
72
|
+
const headerLower = headerToken.toLowerCase();
|
|
73
|
+
const prefixLower = prefix.toLowerCase();
|
|
74
|
+
if (headerLower.startsWith(prefixLower) && headerToken[prefix.length] === " ") tokenValue = headerToken.slice(prefix.length).trimStart();
|
|
75
|
+
}
|
|
76
|
+
if (!tokenValue || !tokenRegexp.test(tokenValue)) await throwHTTPException(c, 400, options.invalidAuthenticationHeader?.wwwAuthenticateHeader || `${wwwAuthenticatePrefix}error="invalid_request"`, options.invalidAuthenticationHeader?.message || options.invalidAuthenticationHeaderMessage || "Bad Request");
|
|
77
|
+
else {
|
|
78
|
+
let equal = false;
|
|
79
|
+
if ("verifyToken" in options) equal = await options.verifyToken(tokenValue, c);
|
|
80
|
+
else if (typeof options.token === "string") equal = await timingSafeEqual(options.token, tokenValue, options.hashFunction);
|
|
81
|
+
else if (Array.isArray(options.token) && options.token.length > 0) {
|
|
82
|
+
for (const token of options.token) if (await timingSafeEqual(token, tokenValue, options.hashFunction)) {
|
|
83
|
+
equal = true;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (!equal) await throwHTTPException(c, 401, options.invalidToken?.wwwAuthenticateHeader || `${wwwAuthenticatePrefix}error="invalid_token"`, options.invalidToken?.message || options.invalidTokenMessage || "Unauthorized");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
await next();
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
//#endregion
|
|
94
|
+
export { bearerAuth as t };
|