acrylblends 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -1
- package/dist/index.js +84 -5
- package/dist/index.js.map +1 -1
- package/docs/framework/LICENSE +23 -0
- package/docs/framework/README.md +63 -0
- package/docs/framework/UPSTREAM.md +3 -0
- package/docs/framework/api-summary.md +138 -0
- package/docs/framework/concepts.md +105 -0
- package/docs/framework/context.md +129 -0
- package/docs/framework/getting-started.md +146 -0
- package/docs/framework/helpers.md +118 -0
- package/docs/framework/middleware.md +154 -0
- package/docs/framework/migration-from-0-3.md +108 -0
- package/docs/framework/migration-from-dsh-webserver.md +103 -0
- package/docs/framework/node-server.md +75 -0
- package/docs/framework/plugin-lifecycle.md +111 -0
- package/docs/framework/request.md +106 -0
- package/docs/framework/routing.md +188 -0
- package/docs/framework/surfaces.md +71 -0
- package/docs/framework/upstream.json +9 -0
- package/docs/framework/validation.md +135 -0
- package/package.json +4 -2
- package/plugins/acryl-inspect/plugin.json +2 -1
- package/plugins/acryl-inspect/src/report.ts +21 -13
- package/plugins/acryl-inspect/src/service.ts +9 -7
- package/plugins/acryl-inspect/tests/report.spec.ts +13 -8
- package/plugins/acryl-inspect/tests/service.spec.ts +11 -10
- package/plugins/acryl-inspect/upstream.json +2 -2
- package/plugins/acryl-node-server/LICENSE +26 -0
- package/plugins/acryl-node-server/plugin.json +2 -1
- package/plugins/acryl-node-server/src/adapter/conninfo.ts +23 -0
- package/plugins/acryl-node-server/src/adapter/early-hints.ts +55 -0
- package/plugins/acryl-node-server/src/adapter/error.ts +11 -0
- package/plugins/acryl-node-server/src/adapter/headers.ts +249 -0
- package/plugins/acryl-node-server/src/adapter/index.ts +6 -0
- package/plugins/acryl-node-server/src/adapter/listener.ts +540 -0
- package/plugins/acryl-node-server/src/adapter/request.ts +797 -0
- package/plugins/acryl-node-server/src/adapter/response.ts +186 -0
- package/plugins/acryl-node-server/src/adapter/serve-static.ts +238 -0
- package/plugins/acryl-node-server/src/adapter/server.ts +36 -0
- package/plugins/acryl-node-server/src/adapter/types.ts +82 -0
- package/plugins/acryl-node-server/src/adapter/url.ts +42 -0
- package/plugins/acryl-node-server/src/adapter/utils/response/constants.ts +1 -0
- package/plugins/acryl-node-server/src/adapter/utils/response.ts +4 -0
- package/plugins/acryl-node-server/src/adapter/utils/stream.ts +88 -0
- package/plugins/acryl-node-server/src/adapter/utils.ts +96 -0
- package/plugins/acryl-node-server/src/adapter/websocket-types.ts +45 -0
- package/plugins/acryl-node-server/src/adapter/websocket.ts +375 -0
- package/plugins/acryl-node-server/src/index.ts +19 -6
- package/plugins/acryl-node-server/tests/adapter/app.ts +76 -0
- package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
- package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +5 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +1 -0
- package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +1 -0
- package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +34 -0
- package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +248 -0
- package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +457 -0
- package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +23 -0
- package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +27 -0
- package/plugins/acryl-node-server/tests/adapter/headers.test.ts +252 -0
- package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +190 -0
- package/plugins/acryl-node-server/tests/adapter/listener.test.ts +727 -0
- package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +189 -0
- package/plugins/acryl-node-server/tests/adapter/request.test.ts +1230 -0
- package/plugins/acryl-node-server/tests/adapter/response.test.ts +285 -0
- package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +849 -0
- package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +790 -0
- package/plugins/acryl-node-server/tests/adapter/server.test.ts +1302 -0
- package/plugins/acryl-node-server/tests/adapter/setup.ts +16 -0
- package/plugins/acryl-node-server/tests/adapter/url.test.ts +76 -0
- package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +23 -0
- package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +75 -0
- package/plugins/acryl-node-server/tests/adapter/utils.test.ts +235 -0
- package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +260 -0
- package/plugins/acryl-node-server/tests/server.spec.ts +44 -8
- package/plugins/acryl-node-server/upstream.json +3 -3
- package/plugins/acryl-router/LICENSE +26 -0
- package/plugins/acryl-router/plugin.json +2 -1
- package/plugins/acryl-router/src/client.ts +2 -0
- package/plugins/acryl-router/src/connection.ts +42 -0
- package/plugins/acryl-router/src/core/app-base.ts +544 -0
- package/plugins/acryl-router/src/core/app.test.ts +3833 -0
- package/plugins/acryl-router/src/core/app.ts +34 -0
- package/plugins/acryl-router/src/core/client/client.test.ts +2313 -0
- package/plugins/acryl-router/src/core/client/client.ts +249 -0
- package/plugins/acryl-router/src/core/client/fetch-result-please.ts +95 -0
- package/plugins/acryl-router/src/core/client/index.ts +17 -0
- package/plugins/acryl-router/src/core/client/types.test.ts +149 -0
- package/plugins/acryl-router/src/core/client/types.ts +393 -0
- package/plugins/acryl-router/src/core/client/utils.test.ts +405 -0
- package/plugins/acryl-router/src/core/client/utils.ts +117 -0
- package/plugins/acryl-router/src/core/compose.test.ts +751 -0
- package/plugins/acryl-router/src/core/compose.ts +73 -0
- package/plugins/acryl-router/src/core/context.test.ts +629 -0
- package/plugins/acryl-router/src/core/context.ts +781 -0
- package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +344 -0
- package/plugins/acryl-router/src/core/helper/accepts/accepts.ts +96 -0
- package/plugins/acryl-router/src/core/helper/accepts/index.ts +6 -0
- package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +55 -0
- package/plugins/acryl-router/src/core/helper/adapter/index.ts +90 -0
- package/plugins/acryl-router/src/core/helper/conninfo/index.ts +6 -0
- package/plugins/acryl-router/src/core/helper/conninfo/types.ts +45 -0
- package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +510 -0
- package/plugins/acryl-router/src/core/helper/cookie/index.ts +146 -0
- package/plugins/acryl-router/src/core/helper/factory/index.test.ts +434 -0
- package/plugins/acryl-router/src/core/helper/factory/index.ts +375 -0
- package/plugins/acryl-router/src/core/helper/html/index.test.ts +78 -0
- package/plugins/acryl-router/src/core/helper/html/index.ts +57 -0
- package/plugins/acryl-router/src/core/helper/route/index.test.ts +259 -0
- package/plugins/acryl-router/src/core/helper/route/index.ts +144 -0
- package/plugins/acryl-router/src/core/helper/streaming/index.ts +9 -0
- package/plugins/acryl-router/src/core/helper/streaming/sse.ts +101 -0
- package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +128 -0
- package/plugins/acryl-router/src/core/helper/streaming/stream.ts +45 -0
- package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +34 -0
- package/plugins/acryl-router/src/core/helper/streaming/text.ts +15 -0
- package/plugins/acryl-router/src/core/helper/streaming/utils.ts +11 -0
- package/plugins/acryl-router/src/core/helper/testing/index.test.ts +42 -0
- package/plugins/acryl-router/src/core/helper/testing/index.ts +28 -0
- package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +124 -0
- package/plugins/acryl-router/src/core/helper/websocket/index.ts +140 -0
- package/plugins/acryl-router/src/core/http-exception.test.ts +45 -0
- package/plugins/acryl-router/src/core/http-exception.ts +77 -0
- package/plugins/acryl-router/src/core/index.ts +53 -0
- package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +434 -0
- package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +152 -0
- package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +1018 -0
- package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +220 -0
- package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +273 -0
- package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +110 -0
- package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +355 -0
- package/plugins/acryl-router/src/core/middleware/combine/index.ts +171 -0
- package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +535 -0
- package/plugins/acryl-router/src/core/middleware/compress/index.ts +142 -0
- package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +43 -0
- package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +58 -0
- package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +532 -0
- package/plugins/acryl-router/src/core/middleware/cors/index.ts +163 -0
- package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +534 -0
- package/plugins/acryl-router/src/core/middleware/csrf/index.ts +150 -0
- package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +21 -0
- package/plugins/acryl-router/src/core/middleware/etag/digest.ts +95 -0
- package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +503 -0
- package/plugins/acryl-router/src/core/middleware/etag/index.ts +135 -0
- package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +217 -0
- package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +278 -0
- package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +1135 -0
- package/plugins/acryl-router/src/core/middleware/jwk/index.ts +1 -0
- package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +195 -0
- package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +48 -0
- package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +802 -0
- package/plugins/acryl-router/src/core/middleware/jwt/index.ts +9 -0
- package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +189 -0
- package/plugins/acryl-router/src/core/middleware/language/index.test.ts +552 -0
- package/plugins/acryl-router/src/core/middleware/language/index.ts +12 -0
- package/plugins/acryl-router/src/core/middleware/language/language.ts +314 -0
- package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +204 -0
- package/plugins/acryl-router/src/core/middleware/logger/index.ts +95 -0
- package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +292 -0
- package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +141 -0
- package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +221 -0
- package/plugins/acryl-router/src/core/middleware/method-override/index.ts +147 -0
- package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +37 -0
- package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +35 -0
- package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +218 -0
- package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +67 -0
- package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +168 -0
- package/plugins/acryl-router/src/core/middleware/request-id/index.ts +7 -0
- package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +59 -0
- package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +671 -0
- package/plugins/acryl-router/src/core/middleware/secure-headers/index.ts +8 -0
- package/plugins/acryl-router/src/core/middleware/secure-headers/permissions-policy.ts +101 -0
- package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +340 -0
- package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +450 -0
- package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +135 -0
- package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +50 -0
- package/plugins/acryl-router/src/core/middleware/serve-static/path.ts +25 -0
- package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +70 -0
- package/plugins/acryl-router/src/core/middleware/timeout/index.ts +58 -0
- package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +310 -0
- package/plugins/acryl-router/src/core/middleware/timing/index.ts +8 -0
- package/plugins/acryl-router/src/core/middleware/timing/timing.ts +256 -0
- package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +381 -0
- package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +156 -0
- package/plugins/acryl-router/src/core/request/constants.ts +1 -0
- package/plugins/acryl-router/src/core/request.test.ts +751 -0
- package/plugins/acryl-router/src/core/request.ts +502 -0
- package/plugins/acryl-router/src/core/router/common.case.test.ts +1132 -0
- package/plugins/acryl-router/src/core/router/linear-router/index.ts +6 -0
- package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +80 -0
- package/plugins/acryl-router/src/core/router/linear-router/router.ts +152 -0
- package/plugins/acryl-router/src/core/router/pattern-router/index.ts +6 -0
- package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +46 -0
- package/plugins/acryl-router/src/core/router/pattern-router/router.ts +54 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +7 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/matcher.ts +33 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/node.ts +170 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +154 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.ts +165 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +265 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/router.ts +174 -0
- package/plugins/acryl-router/src/core/router/reg-exp-router/trie.ts +84 -0
- package/plugins/acryl-router/src/core/router/smart-router/index.ts +6 -0
- package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +13 -0
- package/plugins/acryl-router/src/core/router/smart-router/router.ts +70 -0
- package/plugins/acryl-router/src/core/router/trie-router/index.ts +6 -0
- package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +896 -0
- package/plugins/acryl-router/src/core/router/trie-router/node.ts +221 -0
- package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +8 -0
- package/plugins/acryl-router/src/core/router/trie-router/router.ts +18 -0
- package/plugins/acryl-router/src/core/router/utils.ts +1 -0
- package/plugins/acryl-router/src/core/router.ts +103 -0
- package/plugins/acryl-router/src/core/types.test.ts +4134 -0
- package/plugins/acryl-router/src/core/types.ts +2782 -0
- package/plugins/acryl-router/src/core/utils/accept.test.ts +299 -0
- package/plugins/acryl-router/src/core/utils/accept.ts +268 -0
- package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +56 -0
- package/plugins/acryl-router/src/core/utils/basic-auth.ts +26 -0
- package/plugins/acryl-router/src/core/utils/body.test.ts +496 -0
- package/plugins/acryl-router/src/core/utils/body.ts +263 -0
- package/plugins/acryl-router/src/core/utils/buffer.test.ts +147 -0
- package/plugins/acryl-router/src/core/utils/buffer.ts +117 -0
- package/plugins/acryl-router/src/core/utils/color.test.ts +23 -0
- package/plugins/acryl-router/src/core/utils/color.ts +56 -0
- package/plugins/acryl-router/src/core/utils/compress.ts +10 -0
- package/plugins/acryl-router/src/core/utils/concurrent.test.ts +69 -0
- package/plugins/acryl-router/src/core/utils/concurrent.ts +55 -0
- package/plugins/acryl-router/src/core/utils/constants.ts +4 -0
- package/plugins/acryl-router/src/core/utils/cookie.test.ts +460 -0
- package/plugins/acryl-router/src/core/utils/cookie.ts +281 -0
- package/plugins/acryl-router/src/core/utils/crypto.test.ts +43 -0
- package/plugins/acryl-router/src/core/utils/crypto.ts +58 -0
- package/plugins/acryl-router/src/core/utils/encode.test.ts +61 -0
- package/plugins/acryl-router/src/core/utils/encode.ts +34 -0
- package/plugins/acryl-router/src/core/utils/filepath.test.ts +78 -0
- package/plugins/acryl-router/src/core/utils/filepath.ts +60 -0
- package/plugins/acryl-router/src/core/utils/handler.ts +15 -0
- package/plugins/acryl-router/src/core/utils/headers.ts +355 -0
- package/plugins/acryl-router/src/core/utils/html.test.ts +16 -0
- package/plugins/acryl-router/src/core/utils/html.ts +182 -0
- package/plugins/acryl-router/src/core/utils/http-status.ts +72 -0
- package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +149 -0
- package/plugins/acryl-router/src/core/utils/ipaddr.ts +374 -0
- package/plugins/acryl-router/src/core/utils/jwt/index.ts +7 -0
- package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +86 -0
- package/plugins/acryl-router/src/core/utils/jwt/jwa.ts +38 -0
- package/plugins/acryl-router/src/core/utils/jwt/jws.ts +235 -0
- package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +1788 -0
- package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +292 -0
- package/plugins/acryl-router/src/core/utils/jwt/types.ts +157 -0
- package/plugins/acryl-router/src/core/utils/jwt/utf8.ts +7 -0
- package/plugins/acryl-router/src/core/utils/mime.test.ts +64 -0
- package/plugins/acryl-router/src/core/utils/mime.ts +94 -0
- package/plugins/acryl-router/src/core/utils/stream.test.ts +212 -0
- package/plugins/acryl-router/src/core/utils/stream.ts +107 -0
- package/plugins/acryl-router/src/core/utils/types.test.ts +295 -0
- package/plugins/acryl-router/src/core/utils/types.ts +123 -0
- package/plugins/acryl-router/src/core/utils/url.test.ts +384 -0
- package/plugins/acryl-router/src/core/utils/url.ts +337 -0
- package/plugins/acryl-router/src/core/validator/index.ts +8 -0
- package/plugins/acryl-router/src/core/validator/utils.test.ts +82 -0
- package/plugins/acryl-router/src/core/validator/utils.ts +69 -0
- package/plugins/acryl-router/src/core/validator/validator.test.ts +1488 -0
- package/plugins/acryl-router/src/core/validator/validator.ts +185 -0
- package/plugins/acryl-router/src/helpers/index.ts +13 -3
- package/plugins/acryl-router/src/helpers/schema-validator.ts +35 -0
- package/plugins/acryl-router/src/index.ts +6 -6
- package/plugins/acryl-router/src/middleware/index.ts +25 -6
- package/plugins/acryl-router/src/middleware/loopback-only.ts +53 -14
- package/plugins/acryl-router/src/service.ts +262 -64
- package/plugins/acryl-router/tests/docs-examples.spec.ts +152 -0
- package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
- package/plugins/acryl-router/tests/loader.spec.ts +3 -2
- package/plugins/acryl-router/tests/loopback-only.spec.ts +80 -0
- package/plugins/acryl-router/tests/service.spec.ts +281 -66
- package/plugins/acryl-router/tests/shadow-state.spec.ts +79 -0
- package/plugins/acryl-router/upstream.json +2 -2
- package/plugins/acryl-router-http/plugin.json +2 -1
- package/plugins/acryl-router-http/src/bridge.ts +3 -1
- package/plugins/acryl-router-http/tests/adapter.spec.ts +16 -12
- package/plugins/acryl-router-http/tests/surfaces.spec.ts +12 -10
- package/plugins/acryl-router-http/upstream.json +3 -3
- package/plugins/acryl-state/NOTICE +30 -0
- package/plugins/acryl-state/plugin.json +1 -1
- package/plugins/acryl-state/src/cell.ts +1 -1
- package/plugins/acryl-state/src/service.ts +33 -15
- package/plugins/acryl-state/upstream.json +6 -4
- package/plugins/builder/script.ts +4 -7
- package/plugins/extensions/index.ts +6 -5
- package/plugins/extensions/resolve.ts +28 -3
- package/plugins/openai/prompt.ts +9 -7
- package/plugins/tsconfig.json +5 -4
- package/shared/AGENTS.core.md +54 -0
- package/templates/agent/AGENTS.md +6 -0
- package/templates/agent/README.md +2 -2
- package/templates/agent/blend.yaml +1 -1
- package/templates/agent/src/routes.ts +37 -27
- package/templates/agent/test/model.test.ts +2 -1
- package/templates/agent/tsconfig.json +8 -5
- package/templates/blank/AGENTS.md +5 -0
- package/templates/blank/README.md +1 -1
- package/templates/blank/src/routes.ts +6 -4
- package/templates/blank/tsconfig.json +2 -4
- package/templates/todo/AGENTS.md +5 -0
- package/templates/todo/src/page.ts +1 -1
- package/templates/todo/src/todo.ts +58 -29
- package/templates/todo/tsconfig.json +2 -4
- package/templates/todo/upstream.json +2 -2
- package/plugins/acryl-router/src/compose.ts +0 -21
- package/plugins/acryl-router/src/context.ts +0 -59
- package/plugins/acryl-router/src/helpers/read-body.ts +0 -59
- package/plugins/acryl-router/src/helpers/sse.ts +0 -83
- package/plugins/acryl-router/src/helpers/validate.ts +0 -44
- package/plugins/acryl-router/src/http-error.ts +0 -21
- package/plugins/acryl-router/src/middleware/body-limit.ts +0 -25
- package/plugins/acryl-router/src/middleware/cors.ts +0 -46
- package/plugins/acryl-router/src/middleware/logger.ts +0 -21
- package/plugins/acryl-router/src/middleware/request-id.ts +0 -24
- package/plugins/acryl-router/src/middleware/secure-headers.ts +0 -23
- package/plugins/acryl-router/src/pattern.ts +0 -89
- package/plugins/acryl-router/src/registrar.ts +0 -90
- package/plugins/acryl-router/src/table.ts +0 -156
- package/plugins/acryl-router/src/types.ts +0 -73
- package/plugins/acryl-router/src/util.ts +0 -23
- package/plugins/acryl-router/tests/api.spec.ts +0 -223
- package/plugins/acryl-router/tests/conformance.ts +0 -170
- package/plugins/acryl-router/tests/helpers.spec.ts +0 -172
- package/plugins/acryl-router/tests/middleware.spec.ts +0 -183
- package/plugins/acryl-router/tests/table.spec.ts +0 -47
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { every, except, some } from './index.ts'
|
|
2
|
+
import { App } from '../../app.ts'
|
|
3
|
+
import type { MiddlewareHandler } from '../../types.ts'
|
|
4
|
+
|
|
5
|
+
const nextMiddleware: MiddlewareHandler = async (_, next) => await next()
|
|
6
|
+
|
|
7
|
+
describe('some', () => {
|
|
8
|
+
let app: App
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
app = new App()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
it('Should call only the first middleware', async () => {
|
|
15
|
+
const middleware1 = vi.fn(nextMiddleware)
|
|
16
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
17
|
+
|
|
18
|
+
app.use('/', some(middleware1, middleware2))
|
|
19
|
+
app.get('/', (c) => {
|
|
20
|
+
return c.text('Hello World')
|
|
21
|
+
})
|
|
22
|
+
const res = await app.request('http://localhost/')
|
|
23
|
+
|
|
24
|
+
expect(middleware1).toBeCalled()
|
|
25
|
+
expect(middleware2).not.toBeCalled()
|
|
26
|
+
expect(await res.text()).toBe('Hello World')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('Should try to call the second middleware if the first one throws an error', async () => {
|
|
30
|
+
const middleware1 = () => {
|
|
31
|
+
throw new Error('Error')
|
|
32
|
+
}
|
|
33
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
34
|
+
|
|
35
|
+
app.use('/', some(middleware1, middleware2))
|
|
36
|
+
app.get('/', (c) => {
|
|
37
|
+
return c.text('Hello World')
|
|
38
|
+
})
|
|
39
|
+
const res = await app.request('http://localhost/')
|
|
40
|
+
|
|
41
|
+
expect(middleware2).toBeCalled()
|
|
42
|
+
expect(await res.text()).toBe('Hello World')
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it('Should try to call the second middleware if the first one returns false', async () => {
|
|
46
|
+
const middleware1 = () => false
|
|
47
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
48
|
+
|
|
49
|
+
app.use('/', some(middleware1, middleware2))
|
|
50
|
+
app.get('/', (c) => {
|
|
51
|
+
return c.text('Hello World')
|
|
52
|
+
})
|
|
53
|
+
const res = await app.request('http://localhost/')
|
|
54
|
+
|
|
55
|
+
expect(middleware2).toBeCalled()
|
|
56
|
+
expect(await res.text()).toBe('Hello World')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
it('Should throw last error if all middleware throw an error', async () => {
|
|
60
|
+
const middleware1 = () => {
|
|
61
|
+
throw new Error('Error1')
|
|
62
|
+
}
|
|
63
|
+
const middleware2 = () => {
|
|
64
|
+
throw new Error('Error2')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
app.use('/', some(middleware1, middleware2))
|
|
68
|
+
app.get('/', (c) => {
|
|
69
|
+
return c.text('Hello World')
|
|
70
|
+
})
|
|
71
|
+
app.onError((error, c) => {
|
|
72
|
+
return c.text(error.message)
|
|
73
|
+
})
|
|
74
|
+
const res = await app.request('http://localhost/')
|
|
75
|
+
|
|
76
|
+
expect(await res.text()).toBe('Error2')
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it('Should throw error if all middleware return false', async () => {
|
|
80
|
+
const middleware1 = () => false
|
|
81
|
+
const middleware2 = () => false
|
|
82
|
+
|
|
83
|
+
app.use('/', some(middleware1, middleware2))
|
|
84
|
+
app.get('/', (c) => {
|
|
85
|
+
return c.text('Hello World')
|
|
86
|
+
})
|
|
87
|
+
app.onError((_, c) => {
|
|
88
|
+
return c.text('oops')
|
|
89
|
+
})
|
|
90
|
+
const res = await app.request('http://localhost/')
|
|
91
|
+
|
|
92
|
+
expect(await res.text()).toBe('oops')
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it('Should not call skipped middleware even if an error is thrown', async () => {
|
|
96
|
+
const middleware1: MiddlewareHandler = async (_c, next) => {
|
|
97
|
+
await next()
|
|
98
|
+
}
|
|
99
|
+
const middleware2 = vi.fn(() => true)
|
|
100
|
+
|
|
101
|
+
app.use(
|
|
102
|
+
'/',
|
|
103
|
+
every(some(middleware1, middleware2), () => {
|
|
104
|
+
throw new Error('Error')
|
|
105
|
+
})
|
|
106
|
+
)
|
|
107
|
+
app.get('/', (c) => c.text('OK'))
|
|
108
|
+
app.onError((_, c) => {
|
|
109
|
+
return c.text('oops')
|
|
110
|
+
})
|
|
111
|
+
const res = await app.request('http://localhost/')
|
|
112
|
+
|
|
113
|
+
expect(middleware2).not.toBeCalled()
|
|
114
|
+
expect(await res.text()).toBe('oops')
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('Should not call skipped middleware even if an error is thrown with returning truthy value middleware', async () => {
|
|
118
|
+
const middleware1 = () => true
|
|
119
|
+
const middleware2 = vi.fn(() => true)
|
|
120
|
+
|
|
121
|
+
app.use(
|
|
122
|
+
'/',
|
|
123
|
+
every(some(middleware1, middleware2), () => {
|
|
124
|
+
throw new Error('Error')
|
|
125
|
+
})
|
|
126
|
+
)
|
|
127
|
+
app.get('/', (c) => c.text('OK'))
|
|
128
|
+
app.onError((_, c) => {
|
|
129
|
+
return c.text('oops')
|
|
130
|
+
})
|
|
131
|
+
const res = await app.request('http://localhost/')
|
|
132
|
+
|
|
133
|
+
expect(middleware2).not.toBeCalled()
|
|
134
|
+
expect(await res.text()).toBe('oops')
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('Should return a Response from a middleware that short-circuits', async () => {
|
|
138
|
+
const shortCircuit: MiddlewareHandler = async (c) => c.json({ error: 'bad request' }, 400)
|
|
139
|
+
const next = vi.fn(async (_c, n) => {
|
|
140
|
+
await n()
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
const app = new App()
|
|
144
|
+
app.use('/', some(shortCircuit, next))
|
|
145
|
+
app.get('/', (c) => c.text('handler'))
|
|
146
|
+
|
|
147
|
+
const res = await app.request('http://localhost/')
|
|
148
|
+
|
|
149
|
+
expect(res.status).toBe(400)
|
|
150
|
+
expect(await res.json()).toEqual({ error: 'bad request' })
|
|
151
|
+
expect(next).not.toBeCalled()
|
|
152
|
+
})
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
describe('every', () => {
|
|
156
|
+
let app: App
|
|
157
|
+
|
|
158
|
+
beforeEach(() => {
|
|
159
|
+
app = new App()
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
it('Should call all middleware', async () => {
|
|
163
|
+
const middleware1 = vi.fn(nextMiddleware)
|
|
164
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
165
|
+
|
|
166
|
+
app.use('/', every(middleware1, middleware2))
|
|
167
|
+
app.get('/', (c) => {
|
|
168
|
+
return c.text('Hello World')
|
|
169
|
+
})
|
|
170
|
+
const res = await app.request('http://localhost/')
|
|
171
|
+
|
|
172
|
+
expect(middleware1).toBeCalled()
|
|
173
|
+
expect(middleware2).toBeCalled()
|
|
174
|
+
expect(await res.text()).toBe('Hello World')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('Should throw error if any middleware throws an error', async () => {
|
|
178
|
+
const middleware1 = () => {
|
|
179
|
+
throw new Error('Error1')
|
|
180
|
+
}
|
|
181
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
182
|
+
|
|
183
|
+
app.use('/', every(middleware1, middleware2))
|
|
184
|
+
app.get('/', (c) => {
|
|
185
|
+
return c.text('Hello World')
|
|
186
|
+
})
|
|
187
|
+
app.onError((error, c) => {
|
|
188
|
+
return c.text(error.message)
|
|
189
|
+
})
|
|
190
|
+
const res = await app.request('http://localhost/')
|
|
191
|
+
|
|
192
|
+
expect(await res.text()).toBe('Error1')
|
|
193
|
+
expect(middleware2).not.toBeCalled()
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
it('Should throw error if any middleware returns false', async () => {
|
|
197
|
+
const middleware1 = () => false
|
|
198
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
199
|
+
|
|
200
|
+
app.use('/', every(middleware1, middleware2))
|
|
201
|
+
app.get('/', (c) => {
|
|
202
|
+
return c.text('Hello World')
|
|
203
|
+
})
|
|
204
|
+
app.onError((_, c) => {
|
|
205
|
+
return c.text('oops')
|
|
206
|
+
})
|
|
207
|
+
const res = await app.request('http://localhost/')
|
|
208
|
+
|
|
209
|
+
expect(await res.text()).toBe('oops')
|
|
210
|
+
expect(middleware2).not.toBeCalled()
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
it('Should return the same response a middleware returns if it short-circuits the chain', async () => {
|
|
214
|
+
const middleware1: MiddlewareHandler = async (c) => {
|
|
215
|
+
return c.text('Hello Middleware 1')
|
|
216
|
+
}
|
|
217
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
218
|
+
|
|
219
|
+
app.use('/', every(middleware1, middleware2))
|
|
220
|
+
app.get('/', (c) => {
|
|
221
|
+
return c.text('Hello World')
|
|
222
|
+
})
|
|
223
|
+
const res = await app.request('http://localhost/')
|
|
224
|
+
|
|
225
|
+
expect(await res.text()).toBe('Hello Middleware 1')
|
|
226
|
+
expect(middleware2).not.toBeCalled()
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
it('Should pass the path params to middlewares', async () => {
|
|
230
|
+
const app = new App()
|
|
231
|
+
app.use('*', nextMiddleware)
|
|
232
|
+
const paramMiddleware: MiddlewareHandler = async (c) => {
|
|
233
|
+
return c.json(c.req.param(), 200)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
app.use('/:id', every(paramMiddleware))
|
|
237
|
+
app.get('/:id', (c) => {
|
|
238
|
+
return c.text('Hello World')
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
const res = await app.request('http://localhost/123')
|
|
242
|
+
expect(await res.json()).toEqual({ id: '123' })
|
|
243
|
+
})
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
describe('except', () => {
|
|
247
|
+
let app: App
|
|
248
|
+
|
|
249
|
+
beforeEach(() => {
|
|
250
|
+
app = new App()
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
it('Should call all middleware, except the one that matches the condition', async () => {
|
|
254
|
+
const middleware1 = vi.fn(nextMiddleware)
|
|
255
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
256
|
+
|
|
257
|
+
app.use('*', except('/maintenance', middleware1, middleware2))
|
|
258
|
+
app.get('/maintenance', (c) => {
|
|
259
|
+
return c.text('Hello Maintenance')
|
|
260
|
+
})
|
|
261
|
+
app.get('*', (c) => {
|
|
262
|
+
return c.redirect('/maintenance')
|
|
263
|
+
})
|
|
264
|
+
let res = await app.request('http://localhost/')
|
|
265
|
+
|
|
266
|
+
expect(middleware1).toBeCalled()
|
|
267
|
+
expect(middleware2).toBeCalled()
|
|
268
|
+
expect(res.headers.get('location')).toBe('/maintenance')
|
|
269
|
+
|
|
270
|
+
middleware1.mockClear()
|
|
271
|
+
middleware2.mockClear()
|
|
272
|
+
res = await app.request('http://localhost/maintenance')
|
|
273
|
+
|
|
274
|
+
expect(middleware1).not.toBeCalled()
|
|
275
|
+
expect(middleware2).not.toBeCalled()
|
|
276
|
+
expect(await res.text()).toBe('Hello Maintenance')
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
it('Should call all middleware, except the one that matches some of the conditions', async () => {
|
|
280
|
+
const middleware1 = vi.fn(nextMiddleware)
|
|
281
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
282
|
+
|
|
283
|
+
app.use('*', except(['/maintenance', '/public/users/:id'], middleware1, middleware2))
|
|
284
|
+
app.get('/maintenance', (c) => {
|
|
285
|
+
return c.text('Hello Maintenance')
|
|
286
|
+
})
|
|
287
|
+
app.get('/public/users/:id', (c) => {
|
|
288
|
+
return c.text(`Hello Public User ${c.req.param('id')}`)
|
|
289
|
+
})
|
|
290
|
+
app.get('/secret', (c) => {
|
|
291
|
+
return c.text('Hello Secret')
|
|
292
|
+
})
|
|
293
|
+
let res = await app.request('http://localhost/secret')
|
|
294
|
+
|
|
295
|
+
expect(middleware1).toBeCalled()
|
|
296
|
+
expect(middleware2).toBeCalled()
|
|
297
|
+
expect(await res.text()).toBe('Hello Secret')
|
|
298
|
+
|
|
299
|
+
middleware1.mockClear()
|
|
300
|
+
middleware2.mockClear()
|
|
301
|
+
res = await app.request('http://localhost/maintenance')
|
|
302
|
+
|
|
303
|
+
expect(middleware1).not.toBeCalled()
|
|
304
|
+
expect(middleware2).not.toBeCalled()
|
|
305
|
+
expect(await res.text()).toBe('Hello Maintenance')
|
|
306
|
+
|
|
307
|
+
middleware1.mockClear()
|
|
308
|
+
middleware2.mockClear()
|
|
309
|
+
res = await app.request('http://localhost/public/users/123')
|
|
310
|
+
|
|
311
|
+
expect(middleware1).not.toBeCalled()
|
|
312
|
+
expect(middleware2).not.toBeCalled()
|
|
313
|
+
expect(await res.text()).toBe('Hello Public User 123')
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
it('Should call all middleware, except the one that matches some of the condition function', async () => {
|
|
317
|
+
const middleware1 = vi.fn(nextMiddleware)
|
|
318
|
+
const middleware2 = vi.fn(nextMiddleware)
|
|
319
|
+
|
|
320
|
+
app.use(
|
|
321
|
+
'*',
|
|
322
|
+
except(['/maintenance', (c) => !!c.req.path.match(/public/)], middleware1, middleware2)
|
|
323
|
+
)
|
|
324
|
+
app.get('/maintenance', (c) => {
|
|
325
|
+
return c.text('Hello Maintenance')
|
|
326
|
+
})
|
|
327
|
+
app.get('/public/users/:id', (c) => {
|
|
328
|
+
return c.text(`Hello Public User ${c.req.param('id')}`)
|
|
329
|
+
})
|
|
330
|
+
app.get('/secret', (c) => {
|
|
331
|
+
return c.text('Hello Secret')
|
|
332
|
+
})
|
|
333
|
+
let res = await app.request('http://localhost/secret')
|
|
334
|
+
|
|
335
|
+
expect(middleware1).toBeCalled()
|
|
336
|
+
expect(middleware2).toBeCalled()
|
|
337
|
+
expect(await res.text()).toBe('Hello Secret')
|
|
338
|
+
|
|
339
|
+
middleware1.mockClear()
|
|
340
|
+
middleware2.mockClear()
|
|
341
|
+
res = await app.request('http://localhost/maintenance')
|
|
342
|
+
|
|
343
|
+
expect(middleware1).not.toBeCalled()
|
|
344
|
+
expect(middleware2).not.toBeCalled()
|
|
345
|
+
expect(await res.text()).toBe('Hello Maintenance')
|
|
346
|
+
|
|
347
|
+
middleware1.mockClear()
|
|
348
|
+
middleware2.mockClear()
|
|
349
|
+
res = await app.request('http://localhost/public/users/123')
|
|
350
|
+
|
|
351
|
+
expect(middleware1).not.toBeCalled()
|
|
352
|
+
expect(middleware2).not.toBeCalled()
|
|
353
|
+
expect(await res.text()).toBe('Hello Public User 123')
|
|
354
|
+
})
|
|
355
|
+
})
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* Combine Middleware for App.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { compose } from '../../compose.ts'
|
|
7
|
+
import type { Context } from '../../context.ts'
|
|
8
|
+
import { METHOD_NAME_ALL } from '../../router.ts'
|
|
9
|
+
import { TrieRouter } from '../../router/trie-router/index.ts'
|
|
10
|
+
import type { MiddlewareHandler, Next } from '../../types.ts'
|
|
11
|
+
|
|
12
|
+
type Condition = (c: Context) => boolean
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create a composed middleware that runs the first middleware that returns true.
|
|
16
|
+
*
|
|
17
|
+
* @param middleware - An array of MiddlewareHandler or Condition functions.
|
|
18
|
+
* Middleware is applied in the order it is passed, and if any middleware exits without returning
|
|
19
|
+
* an exception first, subsequent middleware will not be executed.
|
|
20
|
+
* You can also pass a condition function that returns a boolean value. If returns true
|
|
21
|
+
* the evaluation will be halted, and rest of the middleware will not be executed.
|
|
22
|
+
* @returns A composed middleware.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { some } from 'acryl-router/middleware'
|
|
27
|
+
* import { bearerAuth } from 'acryl-router/middleware'
|
|
28
|
+
* import { myRateLimit } from '@/rate-limit'
|
|
29
|
+
*
|
|
30
|
+
* // If client has a valid token, then skip rate limiting.
|
|
31
|
+
* // Otherwise, apply rate limiting.
|
|
32
|
+
* app.use('/api/*', some(
|
|
33
|
+
* bearerAuth({ token }),
|
|
34
|
+
* myRateLimit({ limit: 100 }),
|
|
35
|
+
* ));
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export const some = (...middleware: (MiddlewareHandler | Condition)[]): MiddlewareHandler => {
|
|
39
|
+
return async function some(c, next) {
|
|
40
|
+
let isNextCalled = false
|
|
41
|
+
const wrappedNext = () => {
|
|
42
|
+
isNextCalled = true
|
|
43
|
+
return next()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let lastError: unknown
|
|
47
|
+
let response: Response | undefined
|
|
48
|
+
for (const handler of middleware) {
|
|
49
|
+
try {
|
|
50
|
+
const result = await handler(c, wrappedNext)
|
|
51
|
+
if (result === true && !c.finalized) {
|
|
52
|
+
await wrappedNext()
|
|
53
|
+
} else if (result === false) {
|
|
54
|
+
lastError = new Error('No successful middleware found')
|
|
55
|
+
continue
|
|
56
|
+
} else if (result && result !== true) {
|
|
57
|
+
response = result
|
|
58
|
+
}
|
|
59
|
+
lastError = undefined
|
|
60
|
+
break
|
|
61
|
+
} catch (error) {
|
|
62
|
+
lastError = error
|
|
63
|
+
if (isNextCalled) {
|
|
64
|
+
break
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (lastError) {
|
|
69
|
+
throw lastError
|
|
70
|
+
}
|
|
71
|
+
return response
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create a composed middleware that runs all middleware and throws an error if any of them fail.
|
|
77
|
+
*
|
|
78
|
+
* @param middleware - An array of MiddlewareHandler or Condition functions.
|
|
79
|
+
* Middleware is applied in the order it is passed, and if any middleware throws an error,
|
|
80
|
+
* subsequent middleware will not be executed.
|
|
81
|
+
* You can also pass a condition function that returns a boolean value. If returns false
|
|
82
|
+
* the evaluation will be halted, and rest of the middleware will not be executed.
|
|
83
|
+
* @returns A composed middleware.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* import { some, every } from 'acryl-router/middleware'
|
|
88
|
+
* import { bearerAuth } from 'acryl-router/middleware'
|
|
89
|
+
* import { myCheckLocalNetwork } from '@/check-local-network'
|
|
90
|
+
* import { myRateLimit } from '@/rate-limit'
|
|
91
|
+
*
|
|
92
|
+
* // If client is in local network, then skip authentication and rate limiting.
|
|
93
|
+
* // Otherwise, apply authentication and rate limiting.
|
|
94
|
+
* app.use('/api/*', some(
|
|
95
|
+
* myCheckLocalNetwork(),
|
|
96
|
+
* every(
|
|
97
|
+
* bearerAuth({ token }),
|
|
98
|
+
* myRateLimit({ limit: 100 }),
|
|
99
|
+
* ),
|
|
100
|
+
* ));
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export const every = (...middleware: (MiddlewareHandler | Condition)[]): MiddlewareHandler => {
|
|
104
|
+
return async function every(c, next) {
|
|
105
|
+
const currentRouteIndex = c.req.routeIndex
|
|
106
|
+
await compose(
|
|
107
|
+
middleware.map((m) => [
|
|
108
|
+
[
|
|
109
|
+
async (c: Context, next: Next) => {
|
|
110
|
+
c.req.routeIndex = currentRouteIndex // should be unchanged in this context
|
|
111
|
+
const res = await m(c, next)
|
|
112
|
+
if (res === false) {
|
|
113
|
+
throw new Error('Unmet condition')
|
|
114
|
+
}
|
|
115
|
+
return res
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
])
|
|
119
|
+
)(c, next)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Create a composed middleware that runs all middleware except when the condition is met.
|
|
125
|
+
*
|
|
126
|
+
* @param condition - A string or Condition function.
|
|
127
|
+
* If there are multiple targets to match any of them, they can be passed as an array.
|
|
128
|
+
* If a string is passed, it will be treated as a path pattern to match.
|
|
129
|
+
* If a Condition function is passed, it will be evaluated against the request context.
|
|
130
|
+
* @param middleware - Middleware to run when the condition is not met.
|
|
131
|
+
* Multiple middleware can be passed, and they are applied in the order they are passed.
|
|
132
|
+
* @returns A composed middleware.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* import { except } from 'acryl-router/middleware'
|
|
137
|
+
* import { bearerAuth } from 'acryl-router/middleware'
|
|
138
|
+
*
|
|
139
|
+
* // If client is accessing public API, then skip authentication.
|
|
140
|
+
* // Otherwise, require a valid token.
|
|
141
|
+
* app.use('/api/*', except(
|
|
142
|
+
* '/api/public/*',
|
|
143
|
+
* bearerAuth({ token }),
|
|
144
|
+
* ));
|
|
145
|
+
* ```
|
|
146
|
+
*/
|
|
147
|
+
export const except = (
|
|
148
|
+
condition: string | Condition | (string | Condition)[],
|
|
149
|
+
...middleware: MiddlewareHandler[]
|
|
150
|
+
): MiddlewareHandler => {
|
|
151
|
+
let router: TrieRouter<true> | undefined = undefined
|
|
152
|
+
const conditions = (Array.isArray(condition) ? condition : [condition])
|
|
153
|
+
.map((condition) => {
|
|
154
|
+
if (typeof condition === 'string') {
|
|
155
|
+
router ||= new TrieRouter()
|
|
156
|
+
router.add(METHOD_NAME_ALL, condition, true)
|
|
157
|
+
} else {
|
|
158
|
+
return condition
|
|
159
|
+
}
|
|
160
|
+
})
|
|
161
|
+
.filter(Boolean) as Condition[]
|
|
162
|
+
|
|
163
|
+
if (router) {
|
|
164
|
+
conditions.unshift((c: Context) => !!router?.match(METHOD_NAME_ALL, c.req.path)?.[0]?.[0]?.[0])
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const handler = some((c: Context) => conditions.some((cond) => cond(c)), every(...middleware))
|
|
168
|
+
return async function except(c, next) {
|
|
169
|
+
await handler(c, next)
|
|
170
|
+
}
|
|
171
|
+
}
|