acrylblends 0.4.1 → 0.5.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/LICENSE +73 -0
- package/docs/framework/README.md +51 -51
- package/docs/framework/UPSTREAM.md +1 -1
- package/docs/framework/agents/index.md +24 -0
- package/docs/framework/api/acryl.md +259 -0
- package/docs/framework/api/context.md +527 -0
- package/docs/framework/api/exception.md +80 -0
- package/docs/framework/api/index.md +12 -0
- package/docs/framework/api/presets.md +65 -0
- package/docs/framework/api/request.md +396 -0
- package/docs/framework/api/routing.md +303 -0
- package/docs/framework/{api-summary.md → api/summary.md} +19 -17
- package/docs/framework/concepts/benchmarks.md +26 -0
- package/docs/framework/concepts/developer-experience.md +5 -0
- package/docs/framework/concepts/middleware.md +21 -0
- package/docs/framework/concepts/motivation.md +14 -0
- package/docs/framework/concepts/routers.md +63 -0
- package/docs/framework/concepts/stacks.md +235 -0
- package/docs/framework/concepts/web-standard.md +37 -0
- package/docs/framework/{getting-started.md → cordis/acryl-in-a-cordis-app.md} +16 -16
- package/docs/framework/{concepts.md → cordis/concepts.md} +2 -2
- package/docs/framework/cordis/middleware.md +8 -0
- package/docs/framework/{migration-from-0-3.md → cordis/migration-from-0-3.md} +16 -13
- package/docs/framework/cordis/migration-from-0-4.md +14 -0
- package/docs/framework/{migration-from-dsh-webserver.md → cordis/migration-from-dsh-webserver.md} +7 -7
- package/docs/framework/{routing.md → cordis/mounting.md} +5 -108
- package/docs/framework/{node-server.md → cordis/node-server.md} +4 -4
- package/docs/framework/{surfaces.md → cordis/surfaces.md} +2 -2
- package/docs/framework/cordis/transport-and-cancellation.md +57 -0
- package/docs/framework/{validation.md → cordis/validation.md} +9 -9
- package/docs/framework/getting-started/basic.md +196 -0
- package/docs/framework/getting-started/bun.md +221 -0
- package/docs/framework/getting-started/nodejs.md +344 -0
- package/docs/framework/getting-started/other-runtimes.md +23 -0
- package/docs/framework/guides/best-practices.md +231 -0
- package/docs/framework/guides/create-acrylblends.md +79 -0
- package/docs/framework/guides/examples.md +3 -0
- package/docs/framework/guides/faq.md +19 -0
- package/docs/framework/guides/helpers.md +33 -0
- package/docs/framework/guides/jsx-dom.md +299 -0
- package/docs/framework/guides/jsx.md +440 -0
- package/docs/framework/guides/middleware.md +253 -0
- package/docs/framework/guides/rpc.md +886 -0
- package/docs/framework/guides/testing.md +133 -0
- package/docs/framework/guides/validation.md +383 -0
- package/docs/framework/helpers/accepts.md +60 -0
- package/docs/framework/helpers/adapter.md +87 -0
- package/docs/framework/helpers/conninfo.md +112 -0
- package/docs/framework/helpers/cookie.md +232 -0
- package/docs/framework/helpers/css.md +285 -0
- package/docs/framework/helpers/dev.md +67 -0
- package/docs/framework/helpers/factory.md +180 -0
- package/docs/framework/helpers/html.md +123 -0
- package/docs/framework/helpers/jwt.md +184 -0
- package/docs/framework/helpers/proxy.md +118 -0
- package/docs/framework/helpers/route.md +143 -0
- package/docs/framework/helpers/ssg.md +393 -0
- package/docs/framework/helpers/streaming.md +119 -0
- package/docs/framework/helpers/testing.md +101 -0
- package/docs/framework/helpers/websocket.md +215 -0
- package/docs/framework/middleware/builtin/basic-auth.md +165 -0
- package/docs/framework/middleware/builtin/bearer-auth.md +138 -0
- package/docs/framework/middleware/builtin/body-limit.md +71 -0
- package/docs/framework/middleware/builtin/cache.md +122 -0
- package/docs/framework/middleware/builtin/combine.md +94 -0
- package/docs/framework/middleware/builtin/compress.md +59 -0
- package/docs/framework/middleware/builtin/context-storage.md +78 -0
- package/docs/framework/middleware/builtin/cors.md +135 -0
- package/docs/framework/middleware/builtin/csrf.md +105 -0
- package/docs/framework/middleware/builtin/etag.md +54 -0
- package/docs/framework/middleware/builtin/ip-restriction.md +69 -0
- package/docs/framework/middleware/builtin/jsx-renderer.md +286 -0
- package/docs/framework/middleware/builtin/jwk.md +192 -0
- package/docs/framework/middleware/builtin/jwt.md +145 -0
- package/docs/framework/middleware/builtin/language.md +232 -0
- package/docs/framework/middleware/builtin/logger.md +74 -0
- package/docs/framework/middleware/builtin/loopback-only.md +31 -0
- package/docs/framework/middleware/builtin/method-not-allowed.md +48 -0
- package/docs/framework/middleware/builtin/method-override.md +80 -0
- package/docs/framework/middleware/builtin/mount.md +106 -0
- package/docs/framework/middleware/builtin/pretty-json.md +53 -0
- package/docs/framework/middleware/builtin/request-id.md +94 -0
- package/docs/framework/middleware/builtin/secure-headers.md +247 -0
- package/docs/framework/middleware/builtin/timeout.md +98 -0
- package/docs/framework/middleware/builtin/timing.md +101 -0
- package/docs/framework/middleware/builtin/trailing-slash.md +74 -0
- package/docs/framework/middleware/third-party.md +4 -0
- package/docs/framework/upstream.json +3 -3
- package/lib/accepts-XBuZPVRI.js +52 -0
- package/lib/accepts.d.ts +33 -0
- package/lib/accepts.js +2 -0
- package/lib/acryl-base.d.ts +2 -0
- package/lib/acryl-base.js +332 -0
- package/lib/adapter.d.ts +12 -0
- package/lib/adapter.js +37 -0
- package/lib/app-BM0rTCp7.js +26 -0
- package/lib/app-CmAYW1Al.d.ts +21 -0
- package/lib/basic-auth.d.ts +72 -0
- package/lib/basic-auth.js +95 -0
- package/lib/bearer-auth.d.ts +89 -0
- package/lib/bearer-auth.js +94 -0
- package/lib/body-limit.d.ts +42 -0
- package/lib/body-limit.js +66 -0
- package/lib/client-BHTr318g.js +266 -0
- package/lib/client.d.ts +3 -0
- package/lib/client.js +2 -0
- package/lib/combine.d.ts +85 -0
- package/lib/combine.js +137 -0
- package/lib/compose-BuW2B6PZ.js +50 -0
- package/lib/compress.d.ts +38 -0
- package/lib/compress.js +79 -0
- package/lib/connection-C7xgP1hP.js +24 -0
- package/lib/conninfo.d.ts +25 -0
- package/lib/conninfo.js +2 -0
- package/lib/constants-Dy7ZvN1H.js +4 -0
- package/lib/context-Bm7rI-oK.d.ts +1234 -0
- package/lib/context-DDO0cfuP.js +365 -0
- package/lib/context-storage.d.ts +38 -0
- package/lib/context-storage.js +52 -0
- package/lib/cookie-ClMaKDQf.d.ts +40 -0
- package/lib/cookie.d.ts +24 -0
- package/lib/cookie.js +82 -0
- package/lib/cors.d.ts +52 -0
- package/lib/cors.js +106 -0
- package/lib/csrf.d.ts +75 -0
- package/lib/csrf.js +101 -0
- package/lib/etag.d.ts +40 -0
- package/lib/etag.js +135 -0
- package/lib/factory.d.ts +35 -0
- package/lib/factory.js +30 -0
- package/lib/headers-tu2YYN8T.d.ts +11 -0
- package/lib/html.d.ts +6 -0
- package/lib/html.js +31 -0
- package/lib/http-exception.d.ts +57 -0
- package/lib/http-exception.js +54 -0
- package/lib/http-status-DaAwGAFL.d.ts +35 -0
- package/lib/index-B-3F4wt2.d.ts +12 -0
- package/lib/index-UTBmM3GX.d.ts +68 -0
- package/lib/index-oOClm_Xk.d.ts +45 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.js +28 -0
- package/lib/ip-restriction.d.ts +68 -0
- package/lib/ip-restriction.js +166 -0
- package/lib/jwk.d.ts +52 -0
- package/lib/jwk.js +117 -0
- package/lib/jwt-BGJBw5AF.js +403 -0
- package/lib/jwt-Dg493Tai.d.ts +51 -0
- package/lib/jwt.d.ts +72 -0
- package/lib/jwt.js +115 -0
- package/lib/language.d.ts +88 -0
- package/lib/language.js +198 -0
- package/lib/logger.d.ts +22 -0
- package/lib/logger.js +54 -0
- package/lib/loopback-only.d.ts +45 -0
- package/lib/loopback-only.js +90 -0
- package/lib/method-not-allowed.d.ts +47 -0
- package/lib/method-not-allowed.js +82 -0
- package/lib/method-override.d.ts +46 -0
- package/lib/method-override.js +103 -0
- package/lib/mime-BQOYHl-l.d.ts +72 -0
- package/lib/node-server/conninfo.d.ts +11 -0
- package/lib/node-server/conninfo.js +19 -0
- package/lib/node-server/serve-static.d.ts +19 -0
- package/lib/node-server/serve-static.js +2 -0
- package/lib/node-server.d.ts +103 -0
- package/lib/node-server.js +1325 -0
- package/lib/powered-by.d.ts +28 -0
- package/lib/powered-by.js +24 -0
- package/lib/pretty-json.d.ts +40 -0
- package/lib/pretty-json.js +39 -0
- package/lib/reg-exp-router-DC1R3qoY.js +363 -0
- package/lib/request-id.d.ts +45 -0
- package/lib/request-id.js +34 -0
- package/lib/request.d.ts +2 -0
- package/lib/request.js +323 -0
- package/lib/route.d.ts +78 -0
- package/lib/route.js +126 -0
- package/lib/router/linear-router.d.ts +11 -0
- package/lib/router/linear-router.js +96 -0
- package/lib/router/pattern-router.d.ts +11 -0
- package/lib/router/pattern-router.js +41 -0
- package/lib/router/reg-exp-router.d.ts +35 -0
- package/lib/router/reg-exp-router.js +2 -0
- package/lib/router/smart-router.d.ts +15 -0
- package/lib/router/smart-router.js +2 -0
- package/lib/router/trie-router.d.ts +11 -0
- package/lib/router/trie-router.js +2 -0
- package/lib/router-CvUxUTOq.d.ts +99 -0
- package/lib/router.d.ts +2 -0
- package/lib/router.js +35 -0
- package/lib/schema-validator.d.ts +28 -0
- package/lib/schema-validator.js +22 -0
- package/lib/secure-headers.d.ts +125 -0
- package/lib/secure-headers.js +163 -0
- package/lib/serve-static-Dw_m6KxR.js +213 -0
- package/lib/serve-static.d.ts +31 -0
- package/lib/serve-static.js +77 -0
- package/lib/smart-router-C5CZ5XSM.js +49 -0
- package/lib/stream-CPdqZ0Fp.d.ts +34 -0
- package/lib/streaming-DHST3Scg.js +96 -0
- package/lib/streaming.d.ts +23 -0
- package/lib/streaming.js +2 -0
- package/lib/testing.d.ts +10 -0
- package/lib/testing.js +17 -0
- package/lib/timeout.d.ts +30 -0
- package/lib/timeout.js +42 -0
- package/lib/timing.d.ts +130 -0
- package/lib/timing.js +183 -0
- package/lib/trailing-slash.d.ts +91 -0
- package/lib/trailing-slash.js +85 -0
- package/lib/trie-router-CfFbapzL.js +146 -0
- package/lib/types-CDO6I3B0.d.ts +40 -0
- package/lib/types-CHesD1KG.d.ts +195 -0
- package/lib/types-CwrQjlaM.d.ts +105 -0
- package/lib/types-DR95J00T.d.ts +29 -0
- package/lib/types.d.ts +2 -0
- package/lib/types.js +4 -0
- package/lib/utils/accept.d.ts +9 -0
- package/lib/utils/accept.js +193 -0
- package/lib/utils/basic-auth.d.ts +8 -0
- package/lib/utils/basic-auth.js +20 -0
- package/lib/utils/body.d.ts +2 -0
- package/lib/utils/body.js +94 -0
- package/lib/utils/buffer.d.ts +19 -0
- package/lib/utils/buffer.js +51 -0
- package/lib/utils/color.d.ts +24 -0
- package/lib/utils/color.js +37 -0
- package/lib/utils/compress.d.ts +11 -0
- package/lib/utils/compress.js +11 -0
- package/lib/utils/concurrent.d.ts +17 -0
- package/lib/utils/concurrent.js +30 -0
- package/lib/utils/constants.d.ts +7 -0
- package/lib/utils/constants.js +7 -0
- package/lib/utils/cookie.d.ts +2 -0
- package/lib/utils/cookie.js +125 -0
- package/lib/utils/crypto.d.ts +14 -0
- package/lib/utils/crypto.js +34 -0
- package/lib/utils/encode.d.ts +11 -0
- package/lib/utils/encode.js +33 -0
- package/lib/utils/filepath.d.ts +14 -0
- package/lib/utils/filepath.js +25 -0
- package/lib/utils/handler.d.ts +9 -0
- package/lib/utils/handler.js +12 -0
- package/lib/utils/headers.d.ts +2 -0
- package/lib/utils/headers.js +1 -0
- package/lib/utils/html.d.ts +46 -0
- package/lib/utils/html.js +103 -0
- package/lib/utils/http-status.d.ts +2 -0
- package/lib/utils/http-status.js +1 -0
- package/lib/utils/ipaddr.d.ts +56 -0
- package/lib/utils/ipaddr.js +238 -0
- package/lib/utils/jwt.d.ts +24 -0
- package/lib/utils/jwt.js +2 -0
- package/lib/utils/mime.d.ts +2 -0
- package/lib/utils/mime.js +77 -0
- package/lib/utils/stream.d.ts +2 -0
- package/lib/utils/stream.js +88 -0
- package/lib/utils/types.d.ts +2 -0
- package/lib/utils/types.js +1 -0
- package/lib/utils/url.d.ts +46 -0
- package/lib/utils/url.js +197 -0
- package/lib/utils-dw8lxqjL.js +4 -0
- package/lib/validator-D84mq-dO.js +65 -0
- package/lib/validator.d.ts +42 -0
- package/lib/validator.js +2 -0
- package/lib/ws.d.ts +2 -0
- package/lib/ws.js +53 -0
- package/package.json +312 -14
- package/plugins/acryl-inspect/src/service.ts +2 -2
- package/plugins/acryl-inspect/tests/service.spec.ts +3 -3
- package/plugins/acryl-inspect/upstream.json +2 -2
- package/plugins/acryl-node-server/tests/adapter/app.ts +2 -2
- package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -1
- package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -1
- package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +2 -2
- package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +4 -4
- package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +5 -5
- package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +2 -2
- package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +20 -20
- package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +2 -2
- package/plugins/acryl-node-server/tests/adapter/server.test.ts +50 -50
- package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +4 -4
- package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +9 -9
- package/plugins/acryl-node-server/tests/server.spec.ts +6 -6
- package/plugins/acryl-node-server/upstream.json +2 -2
- package/plugins/acryl-router/src/client.ts +1 -1
- package/plugins/acryl-router/src/connection.ts +2 -2
- package/plugins/acryl-router/src/core/app-base.ts +29 -29
- package/plugins/acryl-router/src/core/app.test.ts +175 -175
- package/plugins/acryl-router/src/core/app.ts +8 -8
- package/plugins/acryl-router/src/core/client/client.test.ts +76 -76
- package/plugins/acryl-router/src/core/client/client.ts +2 -2
- package/plugins/acryl-router/src/core/client/fetch-result-please.ts +1 -1
- package/plugins/acryl-router/src/core/client/index.ts +1 -1
- package/plugins/acryl-router/src/core/client/types.test.ts +6 -6
- package/plugins/acryl-router/src/core/client/types.ts +16 -16
- package/plugins/acryl-router/src/core/client/utils.test.ts +2 -2
- package/plugins/acryl-router/src/core/context.test.ts +4 -4
- package/plugins/acryl-router/src/core/context.ts +6 -6
- package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +3 -3
- package/plugins/acryl-router/src/core/helper/accepts/index.ts +1 -1
- package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +6 -6
- package/plugins/acryl-router/src/core/helper/adapter/index.ts +1 -1
- package/plugins/acryl-router/src/core/helper/conninfo/index.ts +1 -1
- package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +8 -8
- package/plugins/acryl-router/src/core/helper/cookie/index.ts +1 -1
- package/plugins/acryl-router/src/core/helper/factory/index.test.ts +9 -9
- package/plugins/acryl-router/src/core/helper/factory/index.ts +10 -10
- package/plugins/acryl-router/src/core/helper/html/index.test.ts +4 -4
- package/plugins/acryl-router/src/core/helper/html/index.ts +1 -1
- package/plugins/acryl-router/src/core/helper/route/index.test.ts +7 -7
- package/plugins/acryl-router/src/core/helper/route/index.ts +8 -8
- package/plugins/acryl-router/src/core/helper/streaming/index.ts +1 -1
- package/plugins/acryl-router/src/core/helper/testing/index.test.ts +6 -6
- package/plugins/acryl-router/src/core/helper/testing/index.ts +4 -4
- package/plugins/acryl-router/src/core/helper/websocket/index.ts +2 -1
- package/plugins/acryl-router/src/core/http-exception.ts +1 -1
- package/plugins/acryl-router/src/core/index.ts +9 -9
- package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +6 -6
- package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +5 -5
- package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +6 -6
- package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +9 -9
- package/plugins/acryl-router/src/core/middleware/combine/index.ts +7 -7
- package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +9 -9
- package/plugins/acryl-router/src/core/middleware/compress/index.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +5 -5
- package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +4 -4
- package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +7 -7
- package/plugins/acryl-router/src/core/middleware/cors/index.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +10 -10
- package/plugins/acryl-router/src/core/middleware/csrf/index.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +42 -42
- package/plugins/acryl-router/src/core/middleware/etag/index.ts +4 -4
- package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +4 -4
- package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +6 -6
- package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +16 -16
- package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +7 -6
- package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +16 -16
- package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +4 -3
- package/plugins/acryl-router/src/core/middleware/language/index.test.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/language/language.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +5 -5
- package/plugins/acryl-router/src/core/middleware/logger/index.ts +4 -4
- package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +24 -24
- package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +8 -8
- package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +5 -5
- package/plugins/acryl-router/src/core/middleware/method-override/index.ts +6 -6
- package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +4 -4
- package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +6 -6
- package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +30 -30
- package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +4 -4
- package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +15 -15
- package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +35 -35
- package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +23 -23
- package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +1 -1
- package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +2 -2
- package/plugins/acryl-router/src/core/middleware/timeout/index.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +14 -14
- package/plugins/acryl-router/src/core/middleware/timing/timing.ts +3 -3
- package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +7 -7
- package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +7 -7
- package/plugins/acryl-router/src/core/request.test.ts +42 -42
- package/plugins/acryl-router/src/core/request.ts +6 -6
- package/plugins/acryl-router/src/core/router/linear-router/index.ts +1 -1
- package/plugins/acryl-router/src/core/router/pattern-router/index.ts +1 -1
- package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +1 -1
- package/plugins/acryl-router/src/core/router/smart-router/index.ts +1 -1
- package/plugins/acryl-router/src/core/router/trie-router/index.ts +1 -1
- package/plugins/acryl-router/src/core/types.test.ts +115 -115
- package/plugins/acryl-router/src/core/types.ts +72 -72
- package/plugins/acryl-router/src/core/utils/body.ts +8 -8
- package/plugins/acryl-router/src/core/utils/html.ts +1 -1
- package/plugins/acryl-router/src/core/utils/jwt/jws.ts +3 -3
- package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +2 -2
- package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +3 -3
- package/plugins/acryl-router/src/core/utils/jwt/types.ts +1 -1
- package/plugins/acryl-router/src/core/utils/types.ts +42 -0
- package/plugins/acryl-router/src/core/utils/url.test.ts +2 -2
- package/plugins/acryl-router/src/core/validator/index.ts +1 -1
- package/plugins/acryl-router/src/core/validator/validator.test.ts +28 -28
- package/plugins/acryl-router/src/deprecated.ts +15 -0
- package/plugins/acryl-router/src/index.ts +3 -2
- package/plugins/acryl-router/src/service.ts +10 -10
- package/plugins/acryl-router/tests/docs-examples.spec.ts +11 -11
- package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
- package/plugins/acryl-router/tests/loader.spec.ts +3 -3
- package/plugins/acryl-router/tests/loopback-only.spec.ts +4 -4
- package/plugins/acryl-router/tests/no-dom/consumer.ts +11 -0
- package/plugins/acryl-router/tests/no-dom/tsconfig.json +13 -0
- package/plugins/acryl-router/tests/service.spec.ts +23 -23
- package/plugins/acryl-router/upstream.json +3 -3
- package/plugins/acryl-router-http/tests/adapter.spec.ts +3 -3
- package/plugins/acryl-router-http/tests/surfaces.spec.ts +2 -2
- package/plugins/acryl-router-http/upstream.json +2 -2
- package/plugins/acryl-state/src/service.ts +2 -2
- package/plugins/acryl-state/upstream.json +2 -2
- package/plugins/builder/script.ts +2 -2
- package/plugins/extensions/resolve.ts +70 -10
- package/plugins/openai/prompt.ts +5 -5
- package/shared/AGENTS.core.md +16 -9
- package/templates/agent/src/routes.ts +2 -2
- package/templates/agent/test/model.test.ts +2 -2
- package/templates/agent/tsconfig.json +40 -0
- package/templates/blank/src/routes.ts +2 -2
- package/templates/todo/src/todo.ts +2 -2
- package/templates/todo/upstream.json +2 -2
- package/docs/framework/context.md +0 -129
- package/docs/framework/helpers.md +0 -118
- package/docs/framework/middleware.md +0 -154
- package/docs/framework/request.md +0 -106
- /package/docs/framework/{plugin-lifecycle.md → cordis/plugin-lifecycle.md} +0 -0
package/lib/jwt.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { HTTPException } from "./http-exception.js";
|
|
2
|
+
import { getCookie, getSignedCookie } from "./cookie.js";
|
|
3
|
+
import { n as AlgorithmTypes, t as Jwt } from "./jwt-BGJBw5AF.js";
|
|
4
|
+
//#region ../../plugins/acryl-router/src/core/middleware/jwt/jwt.ts
|
|
5
|
+
/**
|
|
6
|
+
* JWT Auth Middleware for Acryl.
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* @param {object} options - The options for the JWT middleware.
|
|
10
|
+
* @param {SignatureKey} options.secret - A value of your secret key.
|
|
11
|
+
* @param {string} [options.cookie] - If this value is set, then the value is retrieved from the cookie header using that value as a key, which is then validated as a token.
|
|
12
|
+
* @param {SignatureAlgorithm} options.alg - An algorithm type that is used for verifying (required). Available types are `HS256` | `HS384` | `HS512` | `RS256` | `RS384` | `RS512` | `PS256` | `PS384` | `PS512` | `ES256` | `ES384` | `ES512` | `EdDSA`.
|
|
13
|
+
* @param {string} [options.headerName='Authorization'] - The name of the header to look for the JWT token. Default is 'Authorization'.
|
|
14
|
+
* @param {string} [options.realm] - The protection space described by the `realm` parameter of the returned `WWW-Authenticate` challenge header. Defaults to the request URL.
|
|
15
|
+
* @param {VerifyOptions} [options.verification] - Additional options for JWT payload verification.
|
|
16
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const app = new Acryl()
|
|
21
|
+
*
|
|
22
|
+
* app.use(
|
|
23
|
+
* '/auth/*',
|
|
24
|
+
* jwt({
|
|
25
|
+
* secret: process.env.JWT_SECRET, // never a literal in source
|
|
26
|
+
* alg: 'HS256',
|
|
27
|
+
* headerName: 'x-custom-auth-header', // Optional, default is 'Authorization'
|
|
28
|
+
* })
|
|
29
|
+
* )
|
|
30
|
+
*
|
|
31
|
+
* app.get('/auth/page', (c) => {
|
|
32
|
+
* return c.text('You are authorized')
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
const jwt = (options) => {
|
|
37
|
+
const verifyOpts = options.verification || {};
|
|
38
|
+
if (!options || !options.secret) throw new Error("JWT auth middleware requires options for \"secret\"");
|
|
39
|
+
if (!options.alg) throw new Error("JWT auth middleware requires options for \"alg\"");
|
|
40
|
+
if (!crypto.subtle || !crypto.subtle.importKey) throw new Error("`crypto.subtle.importKey` is undefined. JWT auth middleware requires it.");
|
|
41
|
+
return async function jwt(ctx, next) {
|
|
42
|
+
const headerName = options.headerName || "Authorization";
|
|
43
|
+
const credentials = ctx.req.raw.headers.get(headerName);
|
|
44
|
+
let token;
|
|
45
|
+
if (credentials) {
|
|
46
|
+
const parts = credentials.split(/\s+/);
|
|
47
|
+
if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer") {
|
|
48
|
+
const errDescription = "invalid credentials structure";
|
|
49
|
+
throw new HTTPException(401, {
|
|
50
|
+
message: errDescription,
|
|
51
|
+
res: unauthorizedResponse({
|
|
52
|
+
ctx,
|
|
53
|
+
error: "invalid_request",
|
|
54
|
+
errDescription,
|
|
55
|
+
realm: options.realm
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
} else token = parts[1];
|
|
59
|
+
} else if (options.cookie) if (typeof options.cookie == "string") token = getCookie(ctx, options.cookie);
|
|
60
|
+
else if (options.cookie.secret) if (options.cookie.prefixOptions) token = await getSignedCookie(ctx, options.cookie.secret, options.cookie.key, options.cookie.prefixOptions);
|
|
61
|
+
else token = await getSignedCookie(ctx, options.cookie.secret, options.cookie.key);
|
|
62
|
+
else if (options.cookie.prefixOptions) token = getCookie(ctx, options.cookie.key, options.cookie.prefixOptions);
|
|
63
|
+
else token = getCookie(ctx, options.cookie.key);
|
|
64
|
+
if (!token) {
|
|
65
|
+
const errDescription = "no authorization included in request";
|
|
66
|
+
throw new HTTPException(401, {
|
|
67
|
+
message: errDescription,
|
|
68
|
+
res: unauthorizedResponse({
|
|
69
|
+
ctx,
|
|
70
|
+
error: "invalid_request",
|
|
71
|
+
errDescription,
|
|
72
|
+
realm: options.realm
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
let payload;
|
|
77
|
+
let cause;
|
|
78
|
+
try {
|
|
79
|
+
payload = await Jwt.verify(token, options.secret, {
|
|
80
|
+
alg: options.alg,
|
|
81
|
+
...verifyOpts
|
|
82
|
+
});
|
|
83
|
+
} catch (e) {
|
|
84
|
+
cause = e;
|
|
85
|
+
}
|
|
86
|
+
if (!payload) throw new HTTPException(401, {
|
|
87
|
+
message: "Unauthorized",
|
|
88
|
+
res: unauthorizedResponse({
|
|
89
|
+
ctx,
|
|
90
|
+
error: "invalid_token",
|
|
91
|
+
statusText: "Unauthorized",
|
|
92
|
+
errDescription: "token verification failure",
|
|
93
|
+
realm: options.realm
|
|
94
|
+
}),
|
|
95
|
+
cause
|
|
96
|
+
});
|
|
97
|
+
ctx.set("jwtPayload", payload);
|
|
98
|
+
await next();
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
function unauthorizedResponse(opts) {
|
|
102
|
+
const realm = (opts.realm ?? opts.ctx.req.url).replace(/"/g, "\\\"");
|
|
103
|
+
const errDescription = opts.errDescription.replace(/"/g, "\\\"");
|
|
104
|
+
return new Response("Unauthorized", {
|
|
105
|
+
status: 401,
|
|
106
|
+
statusText: opts.statusText,
|
|
107
|
+
headers: { "WWW-Authenticate": `Bearer realm="${realm}",error="${opts.error}",error_description="${errDescription}"` }
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const verifyWithJwks = Jwt.verifyWithJwks;
|
|
111
|
+
const verify = Jwt.verify;
|
|
112
|
+
const decode = Jwt.decode;
|
|
113
|
+
const sign = Jwt.sign;
|
|
114
|
+
//#endregion
|
|
115
|
+
export { AlgorithmTypes, decode, jwt, sign, verify, verifyWithJwks };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { I as MiddlewareHandler, t as Context } from "./context-Bm7rI-oK.js";
|
|
2
|
+
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/middleware/language/language.d.ts
|
|
4
|
+
type DetectorType = 'path' | 'querystring' | 'cookie' | 'header';
|
|
5
|
+
type CacheType = 'cookie';
|
|
6
|
+
interface DetectorOptions {
|
|
7
|
+
/** Order of language detection strategies */
|
|
8
|
+
order: DetectorType[];
|
|
9
|
+
/** Query parameter name for language */
|
|
10
|
+
lookupQueryString: string;
|
|
11
|
+
/** Cookie name for language */
|
|
12
|
+
lookupCookie: string;
|
|
13
|
+
/** Index in URL path where language code appears */
|
|
14
|
+
lookupFromPathIndex: number;
|
|
15
|
+
/** Header key for language detection */
|
|
16
|
+
lookupFromHeaderKey: string;
|
|
17
|
+
/** Caching strategies */
|
|
18
|
+
caches: CacheType[] | false;
|
|
19
|
+
/** Cookie configuration options */
|
|
20
|
+
cookieOptions?: {
|
|
21
|
+
domain?: string;
|
|
22
|
+
path?: string;
|
|
23
|
+
sameSite?: 'Strict' | 'Lax' | 'None';
|
|
24
|
+
secure?: boolean;
|
|
25
|
+
maxAge?: number;
|
|
26
|
+
httpOnly?: boolean;
|
|
27
|
+
};
|
|
28
|
+
/** Whether to ignore case in language codes */
|
|
29
|
+
ignoreCase: boolean;
|
|
30
|
+
/** Default language if none detected */
|
|
31
|
+
fallbackLanguage: string;
|
|
32
|
+
/** List of supported language codes */
|
|
33
|
+
supportedLanguages: string[];
|
|
34
|
+
/** Optional function to transform detected language codes */
|
|
35
|
+
convertDetectedLanguage?: (lang: string) => string;
|
|
36
|
+
/** Enable debug logging */
|
|
37
|
+
debug?: boolean;
|
|
38
|
+
}
|
|
39
|
+
interface LanguageVariables {
|
|
40
|
+
language: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Detects language from query parameter
|
|
44
|
+
*/
|
|
45
|
+
declare const detectFromQuery: (c: Context, options: DetectorOptions) => string | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Detects language from cookie
|
|
48
|
+
*/
|
|
49
|
+
declare const detectFromCookie: (c: Context, options: DetectorOptions) => string | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Detects language from Accept-Language header
|
|
52
|
+
*/
|
|
53
|
+
declare function detectFromHeader(c: Context, options: DetectorOptions): string | undefined;
|
|
54
|
+
/**
|
|
55
|
+
* Detects language from URL path
|
|
56
|
+
*/
|
|
57
|
+
declare function detectFromPath(c: Context, options: DetectorOptions): string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Language detector middleware factory
|
|
60
|
+
* @param userOptions Configuration options for the language detector
|
|
61
|
+
* @returns Acryl middleware function
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* type Variables = LanguageVariables
|
|
66
|
+
* const app = new Acryl<{ Variables: Variables }>()
|
|
67
|
+
*
|
|
68
|
+
* app.use(
|
|
69
|
+
* languageDetector({
|
|
70
|
+
* supportedLanguages: ['en', 'ja'], // Must include fallback
|
|
71
|
+
* fallbackLanguage: 'en', // Required
|
|
72
|
+
* })
|
|
73
|
+
* )
|
|
74
|
+
*
|
|
75
|
+
* app.get('/', (c) => {
|
|
76
|
+
* const lang = c.get('language')
|
|
77
|
+
* return c.text(`Current language: ${lang}`)
|
|
78
|
+
* })
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
declare const languageDetector: (userOptions: Partial<DetectorOptions>) => MiddlewareHandler;
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region ../../plugins/acryl-router/src/core/middleware/language/index.d.ts
|
|
84
|
+
declare module '../../context.ts' {
|
|
85
|
+
interface ContextVariableMap extends LanguageVariables {}
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export { type CacheType, type DetectorOptions, type DetectorType, type LanguageVariables, detectFromCookie, detectFromHeader, detectFromPath, detectFromQuery, languageDetector };
|
package/lib/language.js
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { parseAccept } from "./utils/accept.js";
|
|
2
|
+
import { getCookie, setCookie } from "./cookie.js";
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/middleware/language/language.ts
|
|
4
|
+
const DEFAULT_OPTIONS = {
|
|
5
|
+
order: [
|
|
6
|
+
"querystring",
|
|
7
|
+
"cookie",
|
|
8
|
+
"header"
|
|
9
|
+
],
|
|
10
|
+
lookupQueryString: "lang",
|
|
11
|
+
lookupCookie: "language",
|
|
12
|
+
lookupFromHeaderKey: "accept-language",
|
|
13
|
+
lookupFromPathIndex: 0,
|
|
14
|
+
caches: ["cookie"],
|
|
15
|
+
ignoreCase: true,
|
|
16
|
+
fallbackLanguage: "en",
|
|
17
|
+
supportedLanguages: ["en"],
|
|
18
|
+
cookieOptions: {
|
|
19
|
+
sameSite: "Strict",
|
|
20
|
+
secure: true,
|
|
21
|
+
maxAge: 365 * 24 * 60 * 60,
|
|
22
|
+
httpOnly: true
|
|
23
|
+
},
|
|
24
|
+
debug: false
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Parse Accept-Language header values with quality scores
|
|
28
|
+
* @param header Accept-Language header string
|
|
29
|
+
* @returns Array of parsed languages with quality scores
|
|
30
|
+
*/
|
|
31
|
+
function parseAcceptLanguage(header) {
|
|
32
|
+
return parseAccept(header).map(({ type, q }) => ({
|
|
33
|
+
lang: type,
|
|
34
|
+
q
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Validate and normalize language codes
|
|
39
|
+
* @param lang Language code to normalize
|
|
40
|
+
* @param options Detector options
|
|
41
|
+
* @returns Normalized language code or undefined
|
|
42
|
+
*/
|
|
43
|
+
const normalizeLanguage = (lang, options) => {
|
|
44
|
+
if (!lang) return;
|
|
45
|
+
try {
|
|
46
|
+
let normalizedLang = lang.trim();
|
|
47
|
+
if (options.convertDetectedLanguage) normalizedLang = options.convertDetectedLanguage(normalizedLang);
|
|
48
|
+
const compLang = options.ignoreCase ? normalizedLang.toLowerCase() : normalizedLang;
|
|
49
|
+
const compSupported = options.supportedLanguages.map((l) => options.ignoreCase ? l.toLowerCase() : l);
|
|
50
|
+
const exactIndex = compSupported.indexOf(compLang);
|
|
51
|
+
if (exactIndex !== -1) return options.supportedLanguages[exactIndex];
|
|
52
|
+
let longestMatchIndex = -1;
|
|
53
|
+
let longestMatchLength = -1;
|
|
54
|
+
for (let i = 0; i < compSupported.length; i++) {
|
|
55
|
+
const candidate = compSupported[i];
|
|
56
|
+
if (candidate.length < compLang.length && candidate.length > longestMatchLength && compLang.startsWith(candidate) && compLang[candidate.length] === "-") {
|
|
57
|
+
longestMatchIndex = i;
|
|
58
|
+
longestMatchLength = candidate.length;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (longestMatchIndex !== -1) return options.supportedLanguages[longestMatchIndex];
|
|
62
|
+
return;
|
|
63
|
+
} catch {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Detects language from query parameter
|
|
69
|
+
*/
|
|
70
|
+
const detectFromQuery = (c, options) => {
|
|
71
|
+
const query = c.req.query(options.lookupQueryString);
|
|
72
|
+
return normalizeLanguage(query, options);
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Detects language from cookie
|
|
76
|
+
*/
|
|
77
|
+
const detectFromCookie = (c, options) => {
|
|
78
|
+
const cookie = getCookie(c, options.lookupCookie);
|
|
79
|
+
return normalizeLanguage(cookie, options);
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Detects language from Accept-Language header
|
|
83
|
+
*/
|
|
84
|
+
function detectFromHeader(c, options) {
|
|
85
|
+
try {
|
|
86
|
+
const acceptLanguage = c.req.header(options.lookupFromHeaderKey);
|
|
87
|
+
if (!acceptLanguage) return;
|
|
88
|
+
const languages = parseAcceptLanguage(acceptLanguage);
|
|
89
|
+
for (const { lang, q } of languages) {
|
|
90
|
+
if (q === 0) continue;
|
|
91
|
+
const normalizedLang = normalizeLanguage(lang, options);
|
|
92
|
+
if (normalizedLang) return normalizedLang;
|
|
93
|
+
}
|
|
94
|
+
return;
|
|
95
|
+
} catch {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Detects language from URL path
|
|
101
|
+
*/
|
|
102
|
+
function detectFromPath(c, options) {
|
|
103
|
+
const langSegment = new URL(c.req.url).pathname.split("/").filter(Boolean)[options.lookupFromPathIndex];
|
|
104
|
+
return normalizeLanguage(langSegment, options);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Collection of all language detection strategies
|
|
108
|
+
*/
|
|
109
|
+
const detectors = {
|
|
110
|
+
querystring: detectFromQuery,
|
|
111
|
+
cookie: detectFromCookie,
|
|
112
|
+
header: detectFromHeader,
|
|
113
|
+
path: detectFromPath
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Validate detector options
|
|
117
|
+
* @param options Detector options to validate
|
|
118
|
+
* @throws Error if options are invalid
|
|
119
|
+
*/
|
|
120
|
+
function validateOptions(options) {
|
|
121
|
+
if (!options.supportedLanguages.includes(options.fallbackLanguage)) throw new Error("Fallback language must be included in supported languages");
|
|
122
|
+
if (options.lookupFromPathIndex < 0) throw new Error("Path index must be non-negative");
|
|
123
|
+
if (!options.order.every((detector) => Object.keys(detectors).includes(detector))) throw new Error("Invalid detector type in order array");
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Cache detected language
|
|
127
|
+
*/
|
|
128
|
+
function cacheLanguage(c, language, options) {
|
|
129
|
+
if (!Array.isArray(options.caches) || !options.caches.includes("cookie")) return;
|
|
130
|
+
try {
|
|
131
|
+
setCookie(c, options.lookupCookie, language, options.cookieOptions);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
if (options.debug) console.error("Failed to cache language:", error);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Detect language from request
|
|
138
|
+
*/
|
|
139
|
+
const detectLanguage = (c, options) => {
|
|
140
|
+
let detectedLang;
|
|
141
|
+
for (const detectorName of options.order) {
|
|
142
|
+
const detector = detectors[detectorName];
|
|
143
|
+
try {
|
|
144
|
+
detectedLang = detector(c, options);
|
|
145
|
+
if (detectedLang) {
|
|
146
|
+
if (options.debug) console.log(`Language detected from ${detectorName}: ${detectedLang}`);
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
} catch (error) {
|
|
150
|
+
if (options.debug) console.error(`Error in ${detectorName} detector:`, error);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const finalLang = detectedLang || options.fallbackLanguage;
|
|
155
|
+
if (detectedLang && options.caches) cacheLanguage(c, finalLang, options);
|
|
156
|
+
return finalLang;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Language detector middleware factory
|
|
160
|
+
* @param userOptions Configuration options for the language detector
|
|
161
|
+
* @returns Acryl middleware function
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```ts
|
|
165
|
+
* type Variables = LanguageVariables
|
|
166
|
+
* const app = new Acryl<{ Variables: Variables }>()
|
|
167
|
+
*
|
|
168
|
+
* app.use(
|
|
169
|
+
* languageDetector({
|
|
170
|
+
* supportedLanguages: ['en', 'ja'], // Must include fallback
|
|
171
|
+
* fallbackLanguage: 'en', // Required
|
|
172
|
+
* })
|
|
173
|
+
* )
|
|
174
|
+
*
|
|
175
|
+
* app.get('/', (c) => {
|
|
176
|
+
* const lang = c.get('language')
|
|
177
|
+
* return c.text(`Current language: ${lang}`)
|
|
178
|
+
* })
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
const languageDetector = (userOptions) => {
|
|
182
|
+
const options = {
|
|
183
|
+
...DEFAULT_OPTIONS,
|
|
184
|
+
...userOptions,
|
|
185
|
+
cookieOptions: {
|
|
186
|
+
...DEFAULT_OPTIONS.cookieOptions,
|
|
187
|
+
...userOptions.cookieOptions
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
validateOptions(options);
|
|
191
|
+
return async function languageDetector(ctx, next) {
|
|
192
|
+
const lang = detectLanguage(ctx, options);
|
|
193
|
+
ctx.set("language", lang);
|
|
194
|
+
await next();
|
|
195
|
+
};
|
|
196
|
+
};
|
|
197
|
+
//#endregion
|
|
198
|
+
export { detectFromCookie, detectFromHeader, detectFromPath, detectFromQuery, languageDetector };
|
package/lib/logger.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { I as MiddlewareHandler } from "./context-Bm7rI-oK.js";
|
|
2
|
+
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/middleware/logger/index.d.ts
|
|
4
|
+
type PrintFunc = (str: string, ...rest: string[]) => void;
|
|
5
|
+
/**
|
|
6
|
+
* Logger Middleware for Acryl.
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* @param {PrintFunc} [fn=console.log] - Optional function for customized logging behavior.
|
|
10
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const app = new Acryl()
|
|
15
|
+
*
|
|
16
|
+
* app.use(logger())
|
|
17
|
+
* app.get('/', (c) => c.text('Hello Acryl!'))
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare const logger: (fn?: PrintFunc) => MiddlewareHandler;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { logger };
|
package/lib/logger.js
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getColorEnabledAsync } from "./utils/color.js";
|
|
2
|
+
//#region ../../plugins/acryl-router/src/core/middleware/logger/index.ts
|
|
3
|
+
const LogPrefix = {
|
|
4
|
+
Outgoing: "-->",
|
|
5
|
+
Incoming: "<--",
|
|
6
|
+
Error: "xxx"
|
|
7
|
+
};
|
|
8
|
+
const humanize = (times) => {
|
|
9
|
+
const [delimiter, separator] = [",", "."];
|
|
10
|
+
return times.map((v) => v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter)).join(separator);
|
|
11
|
+
};
|
|
12
|
+
const time = (start) => {
|
|
13
|
+
const delta = Date.now() - start;
|
|
14
|
+
return humanize([delta < 1e3 ? delta + "ms" : Math.round(delta / 1e3) + "s"]);
|
|
15
|
+
};
|
|
16
|
+
const colorStatus = async (status) => {
|
|
17
|
+
if (await getColorEnabledAsync()) switch (status / 100 | 0) {
|
|
18
|
+
case 5: return `\x1b[31m${status}\x1b[0m`;
|
|
19
|
+
case 4: return `\x1b[33m${status}\x1b[0m`;
|
|
20
|
+
case 3: return `\x1b[36m${status}\x1b[0m`;
|
|
21
|
+
case 2: return `\x1b[32m${status}\x1b[0m`;
|
|
22
|
+
}
|
|
23
|
+
return `${status}`;
|
|
24
|
+
};
|
|
25
|
+
async function log(fn, prefix, method, path, status = 0, elapsed) {
|
|
26
|
+
fn(prefix === LogPrefix.Incoming ? `${prefix} ${method} ${path}` : `${prefix} ${method} ${path} ${await colorStatus(status)} ${elapsed}`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Logger Middleware for Acryl.
|
|
30
|
+
*
|
|
31
|
+
*
|
|
32
|
+
* @param {PrintFunc} [fn=console.log] - Optional function for customized logging behavior.
|
|
33
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const app = new Acryl()
|
|
38
|
+
*
|
|
39
|
+
* app.use(logger())
|
|
40
|
+
* app.get('/', (c) => c.text('Hello Acryl!'))
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
const logger = (fn = console.log) => {
|
|
44
|
+
return async function logger(c, next) {
|
|
45
|
+
const { method, url } = c.req;
|
|
46
|
+
const path = url.slice(url.indexOf("/", 8));
|
|
47
|
+
await log(fn, LogPrefix.Incoming, method, path);
|
|
48
|
+
const start = Date.now();
|
|
49
|
+
await next();
|
|
50
|
+
await log(fn, LogPrefix.Outgoing, method, path, c.res.status, time(start));
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { logger };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { I as MiddlewareHandler, t as Context } from "./context-Bm7rI-oK.js";
|
|
2
|
+
|
|
3
|
+
//#region ../../plugins/acryl-router/src/middleware/loopback-only.d.ts
|
|
4
|
+
interface LoopbackOptions {
|
|
5
|
+
/** Hostnames a `Host` header may name. Default: the loopback names `127.0.0.1`, `localhost` and `[::1]`. */
|
|
6
|
+
readonly hostnames?: readonly string[];
|
|
7
|
+
/**
|
|
8
|
+
* What a request that changes things (not GET, HEAD or OPTIONS) must show: `same-origin` (default) refuses an `Origin` header that is not this same
|
|
9
|
+
* authority (including `null`), which stops another web page from driving a local app. A browser always sends `Origin` on a cross-origin change, so a
|
|
10
|
+
* request with no `Origin` (curl, a script) is allowed: the `Host` it names is already checked to be a loopback address with this server's port, which
|
|
11
|
+
* is what stops DNS rebinding. `none` checks only the peer and the `Host`.
|
|
12
|
+
*/
|
|
13
|
+
readonly mutations?: 'same-origin' | 'none';
|
|
14
|
+
/**
|
|
15
|
+
* A call made inside the process (the terminal UI, a test) has no socket, so no peer to check. `deny` (default) refuses it, the safe choice for a route
|
|
16
|
+
* that guards something; `allow` lets it through for routes whose in-process caller is the host's own code. A request that came over a socket is always
|
|
17
|
+
* checked in full: only a call with no connection facts at all counts as in process.
|
|
18
|
+
*/
|
|
19
|
+
readonly inProcess?: 'deny' | 'allow';
|
|
20
|
+
/**
|
|
21
|
+
* Who may call. `local` (default): any program on this machine, a browser page only as `mutations` allows. `own-page`: only this app's own page,
|
|
22
|
+
* for private routes a script on the machine must not drive or read either. A request then shows an `Origin` that is exactly this authority (with
|
|
23
|
+
* `Sec-Fetch-Site` absent or `same-origin`), or, for a read (GET, HEAD, OPTIONS), which browsers often send without `Origin`, `Sec-Fetch-Site:
|
|
24
|
+
* same-origin` and a `Referer` from this authority. `mutations` is not consulted: every request is held to that rule.
|
|
25
|
+
*/
|
|
26
|
+
readonly callers?: 'local' | 'own-page';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The authority a loopback request addressed: the `Host` header as a URL, or `undefined` when the request does not come from a loopback peer to the
|
|
30
|
+
* real local port, names another host, or is marked cross-site by the browser. The peer and the port come from the transport (`connectionOf(c)`), never
|
|
31
|
+
* from a header; an in-process call has neither and is refused.
|
|
32
|
+
*/
|
|
33
|
+
declare const LOOPBACK_HOSTNAMES: readonly string[];
|
|
34
|
+
declare function loopbackAuthority(c: Context, hostnames?: readonly string[]): URL | undefined;
|
|
35
|
+
/** Whether a changing request is acceptable by its `Origin`: absent (not a browser cross-origin change) or naming this same authority. `null` and any other origin are not. */
|
|
36
|
+
declare function sameOrigin(c: Context, authority: URL): boolean;
|
|
37
|
+
/** Whether the request comes from a page served by this authority itself: the `own-page` rule of {@link LoopbackOptions.callers}. */
|
|
38
|
+
declare function fromOwnPage(c: Context, authority: URL): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Only requests from this machine to this app: loopback peer, the real port, an allowed `Host`, and for mutations a matching `Origin` (with
|
|
41
|
+
* `callers: 'own-page'`, every request from this app's own page). Everything else gets a 403.
|
|
42
|
+
*/
|
|
43
|
+
declare function loopbackOnly(options?: LoopbackOptions): MiddlewareHandler;
|
|
44
|
+
//#endregion
|
|
45
|
+
export { LOOPBACK_HOSTNAMES, LoopbackOptions, fromOwnPage, loopbackAuthority, loopbackOnly, sameOrigin };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { t as connectionOf } from "./connection-C7xgP1hP.js";
|
|
2
|
+
import { BlockList, isIP } from "node:net";
|
|
3
|
+
//#region ../../plugins/acryl-router/src/middleware/loopback-only.ts
|
|
4
|
+
const loopback = new BlockList();
|
|
5
|
+
loopback.addSubnet("127.0.0.0", 8, "ipv4");
|
|
6
|
+
loopback.addSubnet("::1", 128, "ipv6");
|
|
7
|
+
const SAFE_METHODS = /* @__PURE__ */ new Set([
|
|
8
|
+
"GET",
|
|
9
|
+
"HEAD",
|
|
10
|
+
"OPTIONS"
|
|
11
|
+
]);
|
|
12
|
+
/**
|
|
13
|
+
* The authority a loopback request addressed: the `Host` header as a URL, or `undefined` when the request does not come from a loopback peer to the
|
|
14
|
+
* real local port, names another host, or is marked cross-site by the browser. The peer and the port come from the transport (`connectionOf(c)`), never
|
|
15
|
+
* from a header; an in-process call has neither and is refused.
|
|
16
|
+
*/
|
|
17
|
+
const LOOPBACK_HOSTNAMES = [
|
|
18
|
+
"127.0.0.1",
|
|
19
|
+
"localhost",
|
|
20
|
+
"[::1]"
|
|
21
|
+
];
|
|
22
|
+
function loopbackAuthority(c, hostnames = LOOPBACK_HOSTNAMES) {
|
|
23
|
+
const { remoteAddress, localPort } = connectionOf(c);
|
|
24
|
+
const host = c.req.header("host");
|
|
25
|
+
if (remoteAddress === void 0 || localPort === void 0 || host === void 0) return void 0;
|
|
26
|
+
const address = (remoteAddress.replace(/^\[|\]$/gu, "").split("%", 1)[0] ?? "").replace(/^::ffff:/iu, "");
|
|
27
|
+
const family = isIP(address);
|
|
28
|
+
if (family === 0 || !loopback.check(address, family === 4 ? "ipv4" : "ipv6")) return void 0;
|
|
29
|
+
let authority;
|
|
30
|
+
try {
|
|
31
|
+
authority = new URL(`http://${host}`);
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (authority.protocol !== "http:" || Number(authority.port || "80") !== localPort || !hostnames.includes(authority.hostname) || c.req.header("sec-fetch-site") === "cross-site") return void 0;
|
|
36
|
+
return authority;
|
|
37
|
+
}
|
|
38
|
+
/** Whether a changing request is acceptable by its `Origin`: absent (not a browser cross-origin change) or naming this same authority. `null` and any other origin are not. */
|
|
39
|
+
function sameOrigin(c, authority) {
|
|
40
|
+
const origin = c.req.header("origin");
|
|
41
|
+
if (origin === void 0) return true;
|
|
42
|
+
try {
|
|
43
|
+
const parsed = new URL(origin);
|
|
44
|
+
return parsed.protocol === "http:" && parsed.host === authority.host && parsed.pathname === "/";
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function originOf(value) {
|
|
50
|
+
if (value === void 0) return void 0;
|
|
51
|
+
try {
|
|
52
|
+
return new URL(value).origin;
|
|
53
|
+
} catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Whether the request comes from a page served by this authority itself: the `own-page` rule of {@link LoopbackOptions.callers}. */
|
|
58
|
+
function fromOwnPage(c, authority) {
|
|
59
|
+
const origin = c.req.header("origin");
|
|
60
|
+
const fetchSite = c.req.header("sec-fetch-site");
|
|
61
|
+
if (origin !== void 0 && originOf(origin) === origin && origin === authority.origin) return fetchSite === void 0 || fetchSite === "same-origin";
|
|
62
|
+
return SAFE_METHODS.has(c.req.method) && fetchSite === "same-origin" && originOf(c.req.header("referer")) === authority.origin;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Only requests from this machine to this app: loopback peer, the real port, an allowed `Host`, and for mutations a matching `Origin` (with
|
|
66
|
+
* `callers: 'own-page'`, every request from this app's own page). Everything else gets a 403.
|
|
67
|
+
*/
|
|
68
|
+
function loopbackOnly(options = {}) {
|
|
69
|
+
const mutations = options.mutations ?? "same-origin";
|
|
70
|
+
const inProcess = options.inProcess ?? "deny";
|
|
71
|
+
const ownPage = options.callers === "own-page";
|
|
72
|
+
return async (c, next) => {
|
|
73
|
+
const connection = connectionOf(c);
|
|
74
|
+
if (inProcess === "allow" && connection.remoteAddress === void 0 && connection.localPort === void 0) {
|
|
75
|
+
await next();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const authority = loopbackAuthority(c, options.hostnames);
|
|
79
|
+
if (authority === void 0) return c.json({ error: "request authority rejected" }, 403);
|
|
80
|
+
if (ownPage) {
|
|
81
|
+
if (!fromOwnPage(c, authority)) return c.json({ error: "only this app's own page may call this" }, 403);
|
|
82
|
+
await next();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (mutations === "same-origin" && !SAFE_METHODS.has(c.req.method) && !sameOrigin(c, authority)) return c.json({ error: "a change must come from this app's own origin" }, 403);
|
|
86
|
+
await next();
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { LOOPBACK_HOSTNAMES, fromOwnPage, loopbackAuthority, loopbackOnly, sameOrigin };
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { I as MiddlewareHandler, _ as Env, t as Context } from "./context-Bm7rI-oK.js";
|
|
2
|
+
import { t as Acryl } from "./app-CmAYW1Al.js";
|
|
3
|
+
|
|
4
|
+
//#region ../../plugins/acryl-router/src/core/middleware/method-not-allowed/index.d.ts
|
|
5
|
+
type MethodNotAllowedHandler<E extends Env> = (c: Context<E>, allowedMethods: string[]) => Response | Promise<Response>;
|
|
6
|
+
type MethodNotAllowedOptions<E extends Env> = {
|
|
7
|
+
app: Acryl<E, any, any>;
|
|
8
|
+
onMethodNotAllowed?: MethodNotAllowedHandler<E>;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Method Not Allowed Middleware for Acryl.
|
|
12
|
+
*
|
|
13
|
+
* Returns a `405 Method Not Allowed` response with an `Allow` header when the request path
|
|
14
|
+
* matches a registered route but the request method is not supported.
|
|
15
|
+
*
|
|
16
|
+
* @param {MethodNotAllowedOptions} options - The options for the middleware.
|
|
17
|
+
* @param {Acryl} options.app - The Acryl instance used by the application.
|
|
18
|
+
* @param {MethodNotAllowedHandler} [options.onMethodNotAllowed] - Generates the response, including its `Allow` header.
|
|
19
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const app = new Acryl()
|
|
24
|
+
*
|
|
25
|
+
* app.use(methodNotAllowed({ app }))
|
|
26
|
+
*
|
|
27
|
+
* app.get('/hello', (c) => c.text('Hello!'))
|
|
28
|
+
* app.post('/hello', (c) => c.text('Posted!'))
|
|
29
|
+
*
|
|
30
|
+
* // PUT /hello -> 405 Method Not Allowed
|
|
31
|
+
* // Allow: GET, HEAD, POST
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* app.use(
|
|
37
|
+
* methodNotAllowed({
|
|
38
|
+
* app,
|
|
39
|
+
* onMethodNotAllowed: (c, methods) =>
|
|
40
|
+
* c.json({ error: 'Method Not Allowed' }, 405, { Allow: methods.join(', ') }),
|
|
41
|
+
* })
|
|
42
|
+
* )
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
declare const methodNotAllowed: <E extends Env = Env>(options: MethodNotAllowedOptions<E>) => MiddlewareHandler<E>;
|
|
46
|
+
//#endregion
|
|
47
|
+
export { methodNotAllowed };
|