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/jwk.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { HTTPException } from "./http-exception.js";
|
|
2
|
+
import { getCookie, getSignedCookie } from "./cookie.js";
|
|
3
|
+
import { t as Jwt } from "./jwt-BGJBw5AF.js";
|
|
4
|
+
//#region ../../plugins/acryl-router/src/core/middleware/jwk/jwk.ts
|
|
5
|
+
/**
|
|
6
|
+
* JWK Auth Middleware for Acryl.
|
|
7
|
+
*
|
|
8
|
+
*
|
|
9
|
+
* @param {object} options - The options for the JWK middleware.
|
|
10
|
+
* @param {AcrylJsonWebKey[] | ((ctx: Context) => Promise<AcrylJsonWebKey[]> | AcrylJsonWebKey[])} [options.keys] - The public keys used for JWK verification, or a function that returns them.
|
|
11
|
+
* @param {string | ((ctx: Context) => Promise<string> | string)} [options.jwks_uri] - If set to a URI string or a function that returns a URI string, attempt to fetch JWKs from it. The response must be a JSON object containing a `keys` array, which will be merged with the `keys` option.
|
|
12
|
+
* @param {boolean} [options.allow_anon] - If set to `true`, the middleware allows requests without a token to proceed without authentication.
|
|
13
|
+
* @param {string} [options.cookie] - If set, the middleware attempts to retrieve the token from a cookie with these options (optionally signed) only if no token is found in the header.
|
|
14
|
+
* @param {string} [options.headerName='Authorization'] - The name of the header to look for the JWT token. Default is 'Authorization'.
|
|
15
|
+
* @param {string} [options.realm] - The protection space described by the `realm` parameter of the returned `WWW-Authenticate` challenge header. Defaults to the request URL.
|
|
16
|
+
* @param {AsymmetricAlgorithm[]} options.alg - An array of allowed asymmetric algorithms for JWT verification. Only tokens signed with these algorithms will be accepted.
|
|
17
|
+
* @param {RequestInit} [init] - Optional init options for the `fetch` request when retrieving JWKS from a URI.
|
|
18
|
+
* @param {VerifyOptions} [options.verification] - Additional options for JWK payload verification.
|
|
19
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const app = new Acryl()
|
|
24
|
+
*
|
|
25
|
+
* app.use("/auth/*", jwk({
|
|
26
|
+
* jwks_uri: (c) => `https://${c.env.authServer}/.well-known/jwks.json`,
|
|
27
|
+
* headerName: 'x-custom-auth-header', // Optional, default is 'Authorization'
|
|
28
|
+
* }))
|
|
29
|
+
*
|
|
30
|
+
* app.get('/auth/page', (c) => {
|
|
31
|
+
* return c.text('You are authorized')
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
const jwk = (options, init) => {
|
|
36
|
+
const verifyOpts = options.verification || {};
|
|
37
|
+
if (!options || !(options.keys || options.jwks_uri)) throw new Error("JWK auth middleware requires options for either \"keys\" or \"jwks_uri\" or both");
|
|
38
|
+
if (!crypto.subtle || !crypto.subtle.importKey) throw new Error("`crypto.subtle.importKey` is undefined. JWK auth middleware requires it.");
|
|
39
|
+
return async function jwk(ctx, next) {
|
|
40
|
+
const headerName = options.headerName || "Authorization";
|
|
41
|
+
const credentials = ctx.req.raw.headers.get(headerName);
|
|
42
|
+
let token;
|
|
43
|
+
if (credentials) {
|
|
44
|
+
const parts = credentials.split(/\s+/);
|
|
45
|
+
if (parts.length !== 2 || parts[0].toLowerCase() !== "bearer") {
|
|
46
|
+
const errDescription = "invalid credentials structure";
|
|
47
|
+
throw new HTTPException(401, {
|
|
48
|
+
message: errDescription,
|
|
49
|
+
res: unauthorizedResponse({
|
|
50
|
+
ctx,
|
|
51
|
+
error: "invalid_request",
|
|
52
|
+
errDescription,
|
|
53
|
+
realm: options.realm
|
|
54
|
+
})
|
|
55
|
+
});
|
|
56
|
+
} else token = parts[1];
|
|
57
|
+
} else if (options.cookie) if (typeof options.cookie == "string") token = getCookie(ctx, options.cookie);
|
|
58
|
+
else if (options.cookie.secret) if (options.cookie.prefixOptions) token = await getSignedCookie(ctx, options.cookie.secret, options.cookie.key, options.cookie.prefixOptions);
|
|
59
|
+
else token = await getSignedCookie(ctx, options.cookie.secret, options.cookie.key);
|
|
60
|
+
else if (options.cookie.prefixOptions) token = getCookie(ctx, options.cookie.key, options.cookie.prefixOptions);
|
|
61
|
+
else token = getCookie(ctx, options.cookie.key);
|
|
62
|
+
if (!token) {
|
|
63
|
+
if (options.allow_anon) return next();
|
|
64
|
+
const errDescription = "no authorization included in request";
|
|
65
|
+
throw new HTTPException(401, {
|
|
66
|
+
message: errDescription,
|
|
67
|
+
res: unauthorizedResponse({
|
|
68
|
+
ctx,
|
|
69
|
+
error: "invalid_request",
|
|
70
|
+
errDescription,
|
|
71
|
+
realm: options.realm
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
let payload;
|
|
76
|
+
let cause;
|
|
77
|
+
try {
|
|
78
|
+
const keys = typeof options.keys === "function" ? await options.keys(ctx) : options.keys;
|
|
79
|
+
const jwks_uri = typeof options.jwks_uri === "function" ? await options.jwks_uri(ctx) : options.jwks_uri;
|
|
80
|
+
payload = await Jwt.verifyWithJwks(token, {
|
|
81
|
+
keys,
|
|
82
|
+
jwks_uri,
|
|
83
|
+
verification: verifyOpts,
|
|
84
|
+
allowedAlgorithms: options.alg
|
|
85
|
+
}, init);
|
|
86
|
+
} catch (e) {
|
|
87
|
+
cause = e;
|
|
88
|
+
}
|
|
89
|
+
if (!payload) {
|
|
90
|
+
if (cause instanceof Error && cause.constructor === Error) throw cause;
|
|
91
|
+
throw new HTTPException(401, {
|
|
92
|
+
message: "Unauthorized",
|
|
93
|
+
res: unauthorizedResponse({
|
|
94
|
+
ctx,
|
|
95
|
+
error: "invalid_token",
|
|
96
|
+
statusText: "Unauthorized",
|
|
97
|
+
errDescription: "token verification failure",
|
|
98
|
+
realm: options.realm
|
|
99
|
+
}),
|
|
100
|
+
cause
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
ctx.set("jwtPayload", payload);
|
|
104
|
+
await next();
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
function unauthorizedResponse(opts) {
|
|
108
|
+
const realm = (opts.realm ?? opts.ctx.req.url).replace(/"/g, "\\\"");
|
|
109
|
+
const errDescription = opts.errDescription.replace(/"/g, "\\\"");
|
|
110
|
+
return new Response("Unauthorized", {
|
|
111
|
+
status: 401,
|
|
112
|
+
statusText: opts.statusText,
|
|
113
|
+
headers: { "WWW-Authenticate": `Bearer realm="${realm}",error="${opts.error}",error_description="${errDescription}"` }
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//#endregion
|
|
117
|
+
export { jwk };
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { decodeBase64, decodeBase64Url, encodeBase64Url } from "./utils/encode.js";
|
|
2
|
+
import { getRuntimeKey } from "./adapter.js";
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/jwa.ts
|
|
4
|
+
/**
|
|
5
|
+
* @module
|
|
6
|
+
* JSON Web Algorithms (JWA)
|
|
7
|
+
* https://datatracker.ietf.org/doc/html/rfc7518
|
|
8
|
+
*/
|
|
9
|
+
const AlgorithmTypes = {
|
|
10
|
+
HS256: "HS256",
|
|
11
|
+
HS384: "HS384",
|
|
12
|
+
HS512: "HS512",
|
|
13
|
+
RS256: "RS256",
|
|
14
|
+
RS384: "RS384",
|
|
15
|
+
RS512: "RS512",
|
|
16
|
+
PS256: "PS256",
|
|
17
|
+
PS384: "PS384",
|
|
18
|
+
PS512: "PS512",
|
|
19
|
+
ES256: "ES256",
|
|
20
|
+
ES384: "ES384",
|
|
21
|
+
ES512: "ES512",
|
|
22
|
+
EdDSA: "EdDSA"
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/types.ts
|
|
26
|
+
/**
|
|
27
|
+
* @module
|
|
28
|
+
* Type definitions for JWT utilities.
|
|
29
|
+
*/
|
|
30
|
+
var JwtAlgorithmNotImplemented = class extends Error {
|
|
31
|
+
constructor(alg) {
|
|
32
|
+
super(`${alg} is not an implemented algorithm`);
|
|
33
|
+
this.name = "JwtAlgorithmNotImplemented";
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
var JwtAlgorithmRequired = class extends Error {
|
|
37
|
+
constructor() {
|
|
38
|
+
super("JWT verification requires \"alg\" option to be specified");
|
|
39
|
+
this.name = "JwtAlgorithmRequired";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
var JwtAlgorithmMismatch = class extends Error {
|
|
43
|
+
constructor(expected, actual) {
|
|
44
|
+
super(`JWT algorithm mismatch: expected "${expected}", got "${actual}"`);
|
|
45
|
+
this.name = "JwtAlgorithmMismatch";
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
var JwtTokenInvalid = class extends Error {
|
|
49
|
+
constructor(token) {
|
|
50
|
+
super(`invalid JWT token: ${token}`);
|
|
51
|
+
this.name = "JwtTokenInvalid";
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var JwtTokenNotBefore = class extends Error {
|
|
55
|
+
constructor(token) {
|
|
56
|
+
super(`token (${token}) is being used before it's valid`);
|
|
57
|
+
this.name = "JwtTokenNotBefore";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var JwtTokenExpired = class extends Error {
|
|
61
|
+
constructor(token) {
|
|
62
|
+
super(`token (${token}) expired`);
|
|
63
|
+
this.name = "JwtTokenExpired";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var JwtTokenIssuedAt = class extends Error {
|
|
67
|
+
constructor(currentTimestamp, iat) {
|
|
68
|
+
super(`Invalid "iat" claim, must be a valid number lower than "${currentTimestamp}" (iat: "${iat}")`);
|
|
69
|
+
this.name = "JwtTokenIssuedAt";
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
var JwtTokenIssuer = class extends Error {
|
|
73
|
+
constructor(expected, iss) {
|
|
74
|
+
super(`expected issuer "${expected}", got ${iss ? `"${iss}"` : "none"} `);
|
|
75
|
+
this.name = "JwtTokenIssuer";
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
var JwtHeaderInvalid = class extends Error {
|
|
79
|
+
constructor(header) {
|
|
80
|
+
super(`jwt header is invalid: ${JSON.stringify(header)}`);
|
|
81
|
+
this.name = "JwtHeaderInvalid";
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var JwtHeaderRequiresKid = class extends Error {
|
|
85
|
+
constructor(header) {
|
|
86
|
+
super(`required "kid" in jwt header: ${JSON.stringify(header)}`);
|
|
87
|
+
this.name = "JwtHeaderRequiresKid";
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
var JwtSymmetricAlgorithmNotAllowed = class extends Error {
|
|
91
|
+
constructor(alg) {
|
|
92
|
+
super(`symmetric algorithm "${alg}" is not allowed for JWK verification`);
|
|
93
|
+
this.name = "JwtSymmetricAlgorithmNotAllowed";
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
var JwtAlgorithmNotAllowed = class extends Error {
|
|
97
|
+
constructor(alg, allowedAlgorithms) {
|
|
98
|
+
super(`algorithm "${alg}" is not in the allowed list: [${allowedAlgorithms.join(", ")}]`);
|
|
99
|
+
this.name = "JwtAlgorithmNotAllowed";
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
var JwtTokenSignatureMismatched = class extends Error {
|
|
103
|
+
constructor(token) {
|
|
104
|
+
super(`token(${token}) signature mismatched`);
|
|
105
|
+
this.name = "JwtTokenSignatureMismatched";
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
var JwtPayloadRequiresAud = class extends Error {
|
|
109
|
+
constructor(payload) {
|
|
110
|
+
super(`required "aud" in jwt payload: ${JSON.stringify(payload)}`);
|
|
111
|
+
this.name = "JwtPayloadRequiresAud";
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
var JwtTokenAudience = class extends Error {
|
|
115
|
+
constructor(expected, aud) {
|
|
116
|
+
super(`expected audience "${Array.isArray(expected) ? expected.join(", ") : expected}", got "${aud}"`);
|
|
117
|
+
this.name = "JwtTokenAudience";
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const CryptoKeyUsage = {
|
|
121
|
+
Encrypt: "encrypt",
|
|
122
|
+
Decrypt: "decrypt",
|
|
123
|
+
Sign: "sign",
|
|
124
|
+
Verify: "verify",
|
|
125
|
+
DeriveKey: "deriveKey",
|
|
126
|
+
DeriveBits: "deriveBits",
|
|
127
|
+
WrapKey: "wrapKey",
|
|
128
|
+
UnwrapKey: "unwrapKey"
|
|
129
|
+
};
|
|
130
|
+
//#endregion
|
|
131
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/utf8.ts
|
|
132
|
+
/**
|
|
133
|
+
* @module
|
|
134
|
+
* Functions for encoding/decoding UTF8.
|
|
135
|
+
*/
|
|
136
|
+
const utf8Encoder = new TextEncoder();
|
|
137
|
+
const utf8Decoder = new TextDecoder();
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/jws.ts
|
|
140
|
+
/**
|
|
141
|
+
* @module
|
|
142
|
+
* JSON Web Signature (JWS)
|
|
143
|
+
* https://datatracker.ietf.org/doc/html/rfc7515
|
|
144
|
+
*/
|
|
145
|
+
async function signing(privateKey, alg, data) {
|
|
146
|
+
const algorithm = getKeyAlgorithm(alg);
|
|
147
|
+
const cryptoKey = await importPrivateKey(privateKey, algorithm);
|
|
148
|
+
return await crypto.subtle.sign(algorithm, cryptoKey, data);
|
|
149
|
+
}
|
|
150
|
+
async function verifying(publicKey, alg, signature, data) {
|
|
151
|
+
const algorithm = getKeyAlgorithm(alg);
|
|
152
|
+
const cryptoKey = await importPublicKey(publicKey, algorithm);
|
|
153
|
+
return await crypto.subtle.verify(algorithm, cryptoKey, signature, data);
|
|
154
|
+
}
|
|
155
|
+
function pemToBinary(pem) {
|
|
156
|
+
return decodeBase64(pem.replace(/-+(BEGIN|END).*?-+/g, "").replace(/\s/g, ""));
|
|
157
|
+
}
|
|
158
|
+
async function importPrivateKey(key, alg) {
|
|
159
|
+
if (!crypto.subtle || !crypto.subtle.importKey) throw new Error("`crypto.subtle.importKey` is undefined. JWT auth middleware requires it.");
|
|
160
|
+
if (isCryptoKey(key)) {
|
|
161
|
+
if (key.type !== "private" && key.type !== "secret") throw new Error(`unexpected key type: CryptoKey.type is ${key.type}, expected private or secret`);
|
|
162
|
+
return key;
|
|
163
|
+
}
|
|
164
|
+
const usages = [CryptoKeyUsage.Sign];
|
|
165
|
+
if (typeof key === "object") return await crypto.subtle.importKey("jwk", key, alg, false, usages);
|
|
166
|
+
if (key.includes("PRIVATE")) return await crypto.subtle.importKey("pkcs8", pemToBinary(key), alg, false, usages);
|
|
167
|
+
return await crypto.subtle.importKey("raw", utf8Encoder.encode(key), alg, false, usages);
|
|
168
|
+
}
|
|
169
|
+
async function importPublicKey(key, alg) {
|
|
170
|
+
if (!crypto.subtle || !crypto.subtle.importKey) throw new Error("`crypto.subtle.importKey` is undefined. JWT auth middleware requires it.");
|
|
171
|
+
if (isCryptoKey(key)) {
|
|
172
|
+
if (key.type === "public" || key.type === "secret") return key;
|
|
173
|
+
key = await exportPublicJwkFrom(key);
|
|
174
|
+
}
|
|
175
|
+
if (typeof key === "string" && key.includes("PRIVATE")) key = await exportPublicJwkFrom(await crypto.subtle.importKey("pkcs8", pemToBinary(key), alg, true, [CryptoKeyUsage.Sign]));
|
|
176
|
+
const usages = [CryptoKeyUsage.Verify];
|
|
177
|
+
if (typeof key === "object") return await crypto.subtle.importKey("jwk", key, alg, false, usages);
|
|
178
|
+
if (key.includes("PUBLIC")) return await crypto.subtle.importKey("spki", pemToBinary(key), alg, false, usages);
|
|
179
|
+
return await crypto.subtle.importKey("raw", utf8Encoder.encode(key), alg, false, usages);
|
|
180
|
+
}
|
|
181
|
+
async function exportPublicJwkFrom(privateKey) {
|
|
182
|
+
if (privateKey.type !== "private") throw new Error(`unexpected key type: ${privateKey.type}`);
|
|
183
|
+
if (!privateKey.extractable) throw new Error("unexpected private key is unextractable");
|
|
184
|
+
const jwk = await crypto.subtle.exportKey("jwk", privateKey);
|
|
185
|
+
const { kty } = jwk;
|
|
186
|
+
const { alg, e, n } = jwk;
|
|
187
|
+
const { crv, x, y } = jwk;
|
|
188
|
+
return {
|
|
189
|
+
kty,
|
|
190
|
+
alg,
|
|
191
|
+
e,
|
|
192
|
+
n,
|
|
193
|
+
crv,
|
|
194
|
+
x,
|
|
195
|
+
y,
|
|
196
|
+
key_ops: [CryptoKeyUsage.Verify]
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function getKeyAlgorithm(name) {
|
|
200
|
+
switch (name) {
|
|
201
|
+
case "HS256": return {
|
|
202
|
+
name: "HMAC",
|
|
203
|
+
hash: { name: "SHA-256" }
|
|
204
|
+
};
|
|
205
|
+
case "HS384": return {
|
|
206
|
+
name: "HMAC",
|
|
207
|
+
hash: { name: "SHA-384" }
|
|
208
|
+
};
|
|
209
|
+
case "HS512": return {
|
|
210
|
+
name: "HMAC",
|
|
211
|
+
hash: { name: "SHA-512" }
|
|
212
|
+
};
|
|
213
|
+
case "RS256": return {
|
|
214
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
215
|
+
hash: { name: "SHA-256" }
|
|
216
|
+
};
|
|
217
|
+
case "RS384": return {
|
|
218
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
219
|
+
hash: { name: "SHA-384" }
|
|
220
|
+
};
|
|
221
|
+
case "RS512": return {
|
|
222
|
+
name: "RSASSA-PKCS1-v1_5",
|
|
223
|
+
hash: { name: "SHA-512" }
|
|
224
|
+
};
|
|
225
|
+
case "PS256": return {
|
|
226
|
+
name: "RSA-PSS",
|
|
227
|
+
hash: { name: "SHA-256" },
|
|
228
|
+
saltLength: 32
|
|
229
|
+
};
|
|
230
|
+
case "PS384": return {
|
|
231
|
+
name: "RSA-PSS",
|
|
232
|
+
hash: { name: "SHA-384" },
|
|
233
|
+
saltLength: 48
|
|
234
|
+
};
|
|
235
|
+
case "PS512": return {
|
|
236
|
+
name: "RSA-PSS",
|
|
237
|
+
hash: { name: "SHA-512" },
|
|
238
|
+
saltLength: 64
|
|
239
|
+
};
|
|
240
|
+
case "ES256": return {
|
|
241
|
+
name: "ECDSA",
|
|
242
|
+
hash: { name: "SHA-256" },
|
|
243
|
+
namedCurve: "P-256"
|
|
244
|
+
};
|
|
245
|
+
case "ES384": return {
|
|
246
|
+
name: "ECDSA",
|
|
247
|
+
hash: { name: "SHA-384" },
|
|
248
|
+
namedCurve: "P-384"
|
|
249
|
+
};
|
|
250
|
+
case "ES512": return {
|
|
251
|
+
name: "ECDSA",
|
|
252
|
+
hash: { name: "SHA-512" },
|
|
253
|
+
namedCurve: "P-521"
|
|
254
|
+
};
|
|
255
|
+
case "EdDSA": return {
|
|
256
|
+
name: "Ed25519",
|
|
257
|
+
namedCurve: "Ed25519"
|
|
258
|
+
};
|
|
259
|
+
default: throw new JwtAlgorithmNotImplemented(name);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function isCryptoKey(key) {
|
|
263
|
+
if (getRuntimeKey() === "node" && !!crypto.webcrypto) return key instanceof crypto.webcrypto.CryptoKey;
|
|
264
|
+
return key instanceof CryptoKey;
|
|
265
|
+
}
|
|
266
|
+
//#endregion
|
|
267
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/jwt.ts
|
|
268
|
+
/**
|
|
269
|
+
* @module
|
|
270
|
+
* JSON Web Token (JWT)
|
|
271
|
+
* https://datatracker.ietf.org/doc/html/rfc7519
|
|
272
|
+
*/
|
|
273
|
+
const encodeJwtPart = (part) => encodeBase64Url(utf8Encoder.encode(JSON.stringify(part)).buffer).replace(/=/g, "");
|
|
274
|
+
const encodeSignaturePart = (buf) => encodeBase64Url(buf).replace(/=/g, "");
|
|
275
|
+
const decodeJwtPart = (part) => JSON.parse(utf8Decoder.decode(decodeBase64Url(part)));
|
|
276
|
+
function isTokenHeader(obj) {
|
|
277
|
+
if (typeof obj === "object" && obj !== null) {
|
|
278
|
+
const objWithAlg = obj;
|
|
279
|
+
return "alg" in objWithAlg && Object.values(AlgorithmTypes).includes(objWithAlg.alg) && (!("typ" in objWithAlg) || objWithAlg.typ === "JWT");
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
const sign = async (payload, privateKey, alg = "HS256") => {
|
|
284
|
+
const encodedPayload = encodeJwtPart(payload);
|
|
285
|
+
let encodedHeader;
|
|
286
|
+
if (typeof privateKey === "object" && "alg" in privateKey) {
|
|
287
|
+
alg = privateKey.alg;
|
|
288
|
+
encodedHeader = encodeJwtPart({
|
|
289
|
+
alg,
|
|
290
|
+
typ: "JWT",
|
|
291
|
+
kid: privateKey.kid
|
|
292
|
+
});
|
|
293
|
+
} else encodedHeader = encodeJwtPart({
|
|
294
|
+
alg,
|
|
295
|
+
typ: "JWT"
|
|
296
|
+
});
|
|
297
|
+
const partialToken = `${encodedHeader}.${encodedPayload}`;
|
|
298
|
+
const signaturePart = await signing(privateKey, alg, utf8Encoder.encode(partialToken));
|
|
299
|
+
return `${partialToken}.${encodeSignaturePart(signaturePart)}`;
|
|
300
|
+
};
|
|
301
|
+
const verify = async (token, publicKey, algOrOptions) => {
|
|
302
|
+
if (!algOrOptions) throw new JwtAlgorithmRequired();
|
|
303
|
+
const { alg, iss, nbf = true, exp = true, iat = true, aud } = typeof algOrOptions === "string" ? { alg: algOrOptions } : algOrOptions;
|
|
304
|
+
if (!alg) throw new JwtAlgorithmRequired();
|
|
305
|
+
const tokenParts = token.split(".");
|
|
306
|
+
if (tokenParts.length !== 3) throw new JwtTokenInvalid(token);
|
|
307
|
+
const { header, payload } = decode(token);
|
|
308
|
+
if (!isTokenHeader(header)) throw new JwtHeaderInvalid(header);
|
|
309
|
+
if (header.alg !== alg) throw new JwtAlgorithmMismatch(alg, header.alg);
|
|
310
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
311
|
+
if (nbf && payload.nbf !== void 0) {
|
|
312
|
+
if (typeof payload.nbf !== "number" || !Number.isFinite(payload.nbf) || payload.nbf > now) throw new JwtTokenNotBefore(token);
|
|
313
|
+
}
|
|
314
|
+
if (exp && payload.exp !== void 0) {
|
|
315
|
+
if (typeof payload.exp !== "number" || !Number.isFinite(payload.exp) || payload.exp <= now) throw new JwtTokenExpired(token);
|
|
316
|
+
}
|
|
317
|
+
if (iat && payload.iat !== void 0) {
|
|
318
|
+
if (typeof payload.iat !== "number" || !Number.isFinite(payload.iat) || now < payload.iat) throw new JwtTokenIssuedAt(now, payload.iat);
|
|
319
|
+
}
|
|
320
|
+
if (iss) {
|
|
321
|
+
if (!payload.iss) throw new JwtTokenIssuer(iss, null);
|
|
322
|
+
if (typeof iss === "string" && payload.iss !== iss) throw new JwtTokenIssuer(iss, payload.iss);
|
|
323
|
+
if (iss instanceof RegExp && !iss.test(payload.iss)) throw new JwtTokenIssuer(iss, payload.iss);
|
|
324
|
+
}
|
|
325
|
+
if (aud) {
|
|
326
|
+
if (!payload.aud) throw new JwtPayloadRequiresAud(payload);
|
|
327
|
+
if (!(Array.isArray(payload.aud) ? payload.aud : [payload.aud]).some((payloadAud) => aud instanceof RegExp ? aud.test(payloadAud) : typeof aud === "string" ? payloadAud === aud : Array.isArray(aud) && aud.includes(payloadAud))) throw new JwtTokenAudience(aud, payload.aud);
|
|
328
|
+
}
|
|
329
|
+
const headerPayload = token.substring(0, token.lastIndexOf("."));
|
|
330
|
+
let signature;
|
|
331
|
+
try {
|
|
332
|
+
signature = decodeBase64Url(tokenParts[2]);
|
|
333
|
+
} catch {
|
|
334
|
+
throw new JwtTokenInvalid(token);
|
|
335
|
+
}
|
|
336
|
+
if (!await verifying(publicKey, alg, signature, utf8Encoder.encode(headerPayload))) throw new JwtTokenSignatureMismatched(token);
|
|
337
|
+
return payload;
|
|
338
|
+
};
|
|
339
|
+
const symmetricAlgorithms = [
|
|
340
|
+
AlgorithmTypes.HS256,
|
|
341
|
+
AlgorithmTypes.HS384,
|
|
342
|
+
AlgorithmTypes.HS512
|
|
343
|
+
];
|
|
344
|
+
const verifyWithJwks = async (token, options, init) => {
|
|
345
|
+
const verifyOpts = options.verification || {};
|
|
346
|
+
const header = decodeHeader(token);
|
|
347
|
+
if (!isTokenHeader(header)) throw new JwtHeaderInvalid(header);
|
|
348
|
+
if (!header.kid) throw new JwtHeaderRequiresKid(header);
|
|
349
|
+
if (symmetricAlgorithms.includes(header.alg)) throw new JwtSymmetricAlgorithmNotAllowed(header.alg);
|
|
350
|
+
if (!options.allowedAlgorithms.includes(header.alg)) throw new JwtAlgorithmNotAllowed(header.alg, options.allowedAlgorithms);
|
|
351
|
+
let verifyKeys = options.keys ? [...options.keys] : void 0;
|
|
352
|
+
if (options.jwks_uri) {
|
|
353
|
+
const response = await fetch(options.jwks_uri, init);
|
|
354
|
+
if (!response.ok) throw new Error(`failed to fetch JWKS from ${options.jwks_uri}`);
|
|
355
|
+
const data = await response.json();
|
|
356
|
+
if (!data.keys) throw new Error("invalid JWKS response. \"keys\" field is missing");
|
|
357
|
+
if (!Array.isArray(data.keys)) throw new Error("invalid JWKS response. \"keys\" field is not an array");
|
|
358
|
+
verifyKeys ??= [];
|
|
359
|
+
verifyKeys.push(...data.keys);
|
|
360
|
+
} else if (!verifyKeys) throw new Error("verifyWithJwks requires options for either \"keys\" or \"jwks_uri\" or both");
|
|
361
|
+
const matchingKey = verifyKeys.find((key) => key.kid === header.kid);
|
|
362
|
+
if (!matchingKey) throw new JwtTokenInvalid(token);
|
|
363
|
+
if (matchingKey.alg && matchingKey.alg !== header.alg) throw new JwtAlgorithmMismatch(matchingKey.alg, header.alg);
|
|
364
|
+
return await verify(token, matchingKey, {
|
|
365
|
+
alg: header.alg,
|
|
366
|
+
...verifyOpts
|
|
367
|
+
});
|
|
368
|
+
};
|
|
369
|
+
const decode = (token) => {
|
|
370
|
+
const parts = token.split(".");
|
|
371
|
+
if (parts.length !== 3) throw new JwtTokenInvalid(token);
|
|
372
|
+
try {
|
|
373
|
+
return {
|
|
374
|
+
header: decodeJwtPart(parts[0]),
|
|
375
|
+
payload: decodeJwtPart(parts[1])
|
|
376
|
+
};
|
|
377
|
+
} catch {
|
|
378
|
+
throw new JwtTokenInvalid(token);
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
const decodeHeader = (token) => {
|
|
382
|
+
const parts = token.split(".");
|
|
383
|
+
if (parts.length !== 3) throw new JwtTokenInvalid(token);
|
|
384
|
+
try {
|
|
385
|
+
return decodeJwtPart(parts[0]);
|
|
386
|
+
} catch {
|
|
387
|
+
throw new JwtTokenInvalid(token);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
//#endregion
|
|
391
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/index.ts
|
|
392
|
+
/**
|
|
393
|
+
* @module
|
|
394
|
+
* JWT utility.
|
|
395
|
+
*/
|
|
396
|
+
const Jwt = {
|
|
397
|
+
sign,
|
|
398
|
+
verify,
|
|
399
|
+
decode,
|
|
400
|
+
verifyWithJwks
|
|
401
|
+
};
|
|
402
|
+
//#endregion
|
|
403
|
+
export { AlgorithmTypes as n, Jwt as t };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { _ as JsonWebKey, i as CryptoKey } from "./types-CwrQjlaM.js";
|
|
2
|
+
|
|
3
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/jwa.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* @module
|
|
6
|
+
* JSON Web Algorithms (JWA)
|
|
7
|
+
* https://datatracker.ietf.org/doc/html/rfc7518
|
|
8
|
+
*/
|
|
9
|
+
declare const AlgorithmTypes: {
|
|
10
|
+
readonly HS256: "HS256";
|
|
11
|
+
readonly HS384: "HS384";
|
|
12
|
+
readonly HS512: "HS512";
|
|
13
|
+
readonly RS256: "RS256";
|
|
14
|
+
readonly RS384: "RS384";
|
|
15
|
+
readonly RS512: "RS512";
|
|
16
|
+
readonly PS256: "PS256";
|
|
17
|
+
readonly PS384: "PS384";
|
|
18
|
+
readonly PS512: "PS512";
|
|
19
|
+
readonly ES256: "ES256";
|
|
20
|
+
readonly ES384: "ES384";
|
|
21
|
+
readonly ES512: "ES512";
|
|
22
|
+
readonly EdDSA: "EdDSA";
|
|
23
|
+
};
|
|
24
|
+
type AlgorithmTypes = (typeof AlgorithmTypes)[keyof typeof AlgorithmTypes];
|
|
25
|
+
type SignatureAlgorithm = keyof typeof AlgorithmTypes;
|
|
26
|
+
type AsymmetricAlgorithm = 'RS256' | 'RS384' | 'RS512' | 'PS256' | 'PS384' | 'PS512' | 'ES256' | 'ES384' | 'ES512' | 'EdDSA';
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/jws.d.ts
|
|
29
|
+
interface AcrylJsonWebKey extends JsonWebKey {
|
|
30
|
+
kid?: string;
|
|
31
|
+
}
|
|
32
|
+
type SignatureKey = string | AcrylJsonWebKey | CryptoKey;
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region ../../plugins/acryl-router/src/core/utils/jwt/jwt.d.ts
|
|
35
|
+
interface TokenHeader {
|
|
36
|
+
alg: SignatureAlgorithm;
|
|
37
|
+
typ?: 'JWT';
|
|
38
|
+
kid?: string;
|
|
39
|
+
}
|
|
40
|
+
type VerifyOptions = {
|
|
41
|
+
/** The expected issuer used for verifying the token */iss?: string | RegExp; /** Verify the `nbf` claim (default: `true`) */
|
|
42
|
+
nbf?: boolean; /** Verify the `exp` claim (default: `true`) */
|
|
43
|
+
exp?: boolean; /** Verify the `iat` claim (default: `true`) */
|
|
44
|
+
iat?: boolean; /** Acceptable audience(s) for the token */
|
|
45
|
+
aud?: string | string[] | RegExp;
|
|
46
|
+
};
|
|
47
|
+
type VerifyOptionsWithAlg = {
|
|
48
|
+
/** The algorithm used for decoding the token */alg: SignatureAlgorithm;
|
|
49
|
+
} & VerifyOptions;
|
|
50
|
+
//#endregion
|
|
51
|
+
export { SignatureKey as a, SignatureAlgorithm as c, AcrylJsonWebKey as i, VerifyOptions as n, AlgorithmTypes as o, VerifyOptionsWithAlg as r, AsymmetricAlgorithm as s, TokenHeader as t };
|
package/lib/jwt.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { I as MiddlewareHandler } from "./context-Bm7rI-oK.js";
|
|
2
|
+
import { n as BufferSource } from "./types-CwrQjlaM.js";
|
|
3
|
+
import { i as CookiePrefixOptions } from "./cookie-ClMaKDQf.js";
|
|
4
|
+
import { a as SignatureKey, c as SignatureAlgorithm, i as AcrylJsonWebKey, n as VerifyOptions, o as AlgorithmTypes, r as VerifyOptionsWithAlg, s as AsymmetricAlgorithm, t as TokenHeader } from "./jwt-Dg493Tai.js";
|
|
5
|
+
import { t as JWTPayload } from "./types-DR95J00T.js";
|
|
6
|
+
|
|
7
|
+
//#region ../../plugins/acryl-router/src/core/middleware/jwt/jwt.d.ts
|
|
8
|
+
type JwtVariables<T = any> = {
|
|
9
|
+
jwtPayload: T;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* JWT Auth Middleware for Acryl.
|
|
13
|
+
*
|
|
14
|
+
*
|
|
15
|
+
* @param {object} options - The options for the JWT middleware.
|
|
16
|
+
* @param {SignatureKey} options.secret - A value of your secret key.
|
|
17
|
+
* @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.
|
|
18
|
+
* @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`.
|
|
19
|
+
* @param {string} [options.headerName='Authorization'] - The name of the header to look for the JWT token. Default is 'Authorization'.
|
|
20
|
+
* @param {string} [options.realm] - The protection space described by the `realm` parameter of the returned `WWW-Authenticate` challenge header. Defaults to the request URL.
|
|
21
|
+
* @param {VerifyOptions} [options.verification] - Additional options for JWT payload verification.
|
|
22
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* const app = new Acryl()
|
|
27
|
+
*
|
|
28
|
+
* app.use(
|
|
29
|
+
* '/auth/*',
|
|
30
|
+
* jwt({
|
|
31
|
+
* secret: process.env.JWT_SECRET, // never a literal in source
|
|
32
|
+
* alg: 'HS256',
|
|
33
|
+
* headerName: 'x-custom-auth-header', // Optional, default is 'Authorization'
|
|
34
|
+
* })
|
|
35
|
+
* )
|
|
36
|
+
*
|
|
37
|
+
* app.get('/auth/page', (c) => {
|
|
38
|
+
* return c.text('You are authorized')
|
|
39
|
+
* })
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare const jwt: (options: {
|
|
43
|
+
secret: SignatureKey;
|
|
44
|
+
cookie?: string | {
|
|
45
|
+
key: string;
|
|
46
|
+
secret?: string | BufferSource;
|
|
47
|
+
prefixOptions?: CookiePrefixOptions;
|
|
48
|
+
};
|
|
49
|
+
alg: SignatureAlgorithm;
|
|
50
|
+
headerName?: string;
|
|
51
|
+
realm?: string;
|
|
52
|
+
verification?: VerifyOptions;
|
|
53
|
+
}) => MiddlewareHandler;
|
|
54
|
+
declare const verifyWithJwks: (token: string, options: {
|
|
55
|
+
keys?: AcrylJsonWebKey[];
|
|
56
|
+
jwks_uri?: string;
|
|
57
|
+
verification?: VerifyOptions;
|
|
58
|
+
allowedAlgorithms: readonly AsymmetricAlgorithm[];
|
|
59
|
+
}, init?: RequestInit) => Promise<JWTPayload>;
|
|
60
|
+
declare const verify: (token: string, publicKey: SignatureKey, algOrOptions: SignatureAlgorithm | VerifyOptionsWithAlg) => Promise<JWTPayload>;
|
|
61
|
+
declare const decode: (token: string) => {
|
|
62
|
+
header: TokenHeader;
|
|
63
|
+
payload: JWTPayload;
|
|
64
|
+
};
|
|
65
|
+
declare const sign: (payload: JWTPayload, privateKey: SignatureKey, alg?: SignatureAlgorithm) => Promise<string>;
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region ../../plugins/acryl-router/src/core/middleware/jwt/index.d.ts
|
|
68
|
+
declare module '../../context.ts' {
|
|
69
|
+
interface ContextVariableMap extends JwtVariables<unknown> {}
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { AlgorithmTypes, type JwtVariables, decode, jwt, sign, verify, verifyWithJwks };
|