acrylblends 0.4.0 → 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/dist/index.js +56 -2
- 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/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 +140 -0
- 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/cordis/acryl-in-a-cordis-app.md +146 -0
- package/docs/framework/cordis/concepts.md +105 -0
- package/docs/framework/cordis/middleware.md +8 -0
- package/docs/framework/cordis/migration-from-0-3.md +111 -0
- package/docs/framework/cordis/migration-from-0-4.md +14 -0
- package/docs/framework/cordis/migration-from-dsh-webserver.md +103 -0
- package/docs/framework/cordis/mounting.md +85 -0
- package/docs/framework/cordis/node-server.md +75 -0
- package/docs/framework/cordis/plugin-lifecycle.md +111 -0
- package/docs/framework/cordis/surfaces.md +71 -0
- package/docs/framework/cordis/transport-and-cancellation.md +57 -0
- package/docs/framework/cordis/validation.md +135 -0
- 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 +9 -0
- 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 +315 -15
- package/plugins/acryl-inspect/src/report.ts +15 -10
- package/plugins/acryl-inspect/src/service.ts +2 -2
- package/plugins/acryl-inspect/tests/report.spec.ts +9 -3
- 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/middleware/index.ts +1 -1
- package/plugins/acryl-router/src/middleware/loopback-only.ts +34 -1
- package/plugins/acryl-router/src/service.ts +19 -13
- 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 +80 -0
- 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 +39 -22
- 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 +3 -3
- package/plugins/extensions/index.ts +4 -3
- package/plugins/extensions/resolve.ts +70 -10
- package/plugins/openai/prompt.ts +7 -7
- package/shared/AGENTS.core.md +61 -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 +2 -2
- package/templates/agent/test/model.test.ts +2 -2
- package/templates/agent/tsconfig.json +40 -0
- package/templates/blank/AGENTS.md +5 -0
- package/templates/blank/README.md +1 -1
- package/templates/blank/src/routes.ts +2 -2
- package/templates/todo/AGENTS.md +5 -0
- package/templates/todo/src/todo.ts +6 -4
- package/templates/todo/upstream.json +2 -2
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Route Helper
|
|
2
|
+
|
|
3
|
+
The Route Helper provides enhanced routing information for debugging and middleware development. It allows you to access detailed information about matched routes and the current route being processed.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Acryl } from 'acrylblends'
|
|
9
|
+
import {
|
|
10
|
+
matchedRoutes,
|
|
11
|
+
routePath,
|
|
12
|
+
baseRoutePath,
|
|
13
|
+
basePath,
|
|
14
|
+
} from 'acrylblends/route'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
### Basic route information
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
const app = new Acryl()
|
|
23
|
+
|
|
24
|
+
app.get('/posts/:id', (c) => {
|
|
25
|
+
const currentPath = routePath(c) // '/posts/:id'
|
|
26
|
+
const routes = matchedRoutes(c) // Array of matched routes
|
|
27
|
+
|
|
28
|
+
return c.json({
|
|
29
|
+
path: currentPath,
|
|
30
|
+
totalRoutes: routes.length,
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Working with sub-applications
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const app = new Acryl()
|
|
39
|
+
const apiApp = new Acryl()
|
|
40
|
+
|
|
41
|
+
apiApp.get('/posts/:id', (c) => {
|
|
42
|
+
return c.json({
|
|
43
|
+
routePath: routePath(c), // '/posts/:id'
|
|
44
|
+
baseRoutePath: baseRoutePath(c), // '/api'
|
|
45
|
+
basePath: basePath(c), // '/api' (with actual params)
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
app.route('/api', apiApp)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## `matchedRoutes()`
|
|
53
|
+
|
|
54
|
+
Returns an array of all routes that matched the current request, including middleware.
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
app.all('/api/*', (c, next) => {
|
|
58
|
+
console.log('API middleware')
|
|
59
|
+
return next()
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
app.get('/api/users/:id', (c) => {
|
|
63
|
+
const routes = matchedRoutes(c)
|
|
64
|
+
// Returns: [
|
|
65
|
+
// { method: 'ALL', path: '/api/*', handler: [Function] },
|
|
66
|
+
// { method: 'GET', path: '/api/users/:id', handler: [Function] }
|
|
67
|
+
// ]
|
|
68
|
+
return c.json({ routes: routes.length })
|
|
69
|
+
})
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## `routePath()`
|
|
73
|
+
|
|
74
|
+
Returns the route path pattern registered for the current handler.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
app.get('/posts/:id', (c) => {
|
|
78
|
+
console.log(routePath(c)) // '/posts/:id'
|
|
79
|
+
return c.text('Post details')
|
|
80
|
+
})
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Using with index parameter
|
|
84
|
+
|
|
85
|
+
You can optionally pass an index parameter to get the route path at a specific position, similar to `Array.prototype.at()`.
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
app.all('/api/*', (c, next) => {
|
|
89
|
+
return next()
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
app.get('/api/users/:id', (c) => {
|
|
93
|
+
console.log(routePath(c, 0)) // '/api/*' (first matched route)
|
|
94
|
+
console.log(routePath(c, -1)) // '/api/users/:id' (last matched route)
|
|
95
|
+
return c.text('User details')
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## `baseRoutePath()`
|
|
100
|
+
|
|
101
|
+
Returns the base path pattern of the current route as specified in routing.
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const subApp = new Acryl()
|
|
105
|
+
subApp.get('/posts/:id', (c) => {
|
|
106
|
+
return c.text(baseRoutePath(c)) // '/:sub'
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
app.route('/:sub', subApp)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Using with index parameter
|
|
113
|
+
|
|
114
|
+
You can optionally pass an index parameter to get the base route path at a specific
|
|
115
|
+
position, similar to `Array.prototype.at()`.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
app.all('/api/*', (c, next) => {
|
|
119
|
+
return next()
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
const subApp = new Acryl()
|
|
123
|
+
subApp.get('/users/:id', (c) => {
|
|
124
|
+
console.log(baseRoutePath(c, 0)) // '/' (first matched route)
|
|
125
|
+
console.log(baseRoutePath(c, -1)) // '/api' (last matched route)
|
|
126
|
+
return c.text('User details')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
app.route('/api', subApp)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## `basePath()`
|
|
133
|
+
|
|
134
|
+
Returns the base path with embedded parameters from the actual request.
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
const subApp = new Acryl()
|
|
138
|
+
subApp.get('/posts/:id', (c) => {
|
|
139
|
+
return c.text(basePath(c)) // '/api' (for request to '/api/posts/123')
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
app.route('/:sub', subApp)
|
|
143
|
+
```
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# SSG Helper
|
|
2
|
+
|
|
3
|
+
> **Not yet available.** Static site generation (`acrylblends/ssg`) is documented here so the page structure matches the rest of the framework, and is not part of acrylblends yet. The code on this page is not checked by the docs tests.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
SSG Helper generates a static site from your Acryl application. It will retrieve the contents of registered routes and save them as static files.
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
|
|
10
|
+
### Manual
|
|
11
|
+
|
|
12
|
+
If you have a simple Acryl application like the following:
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
// index.tsx
|
|
16
|
+
const app = new Acryl()
|
|
17
|
+
|
|
18
|
+
app.get('/', (c) => c.html('Hello, World!'))
|
|
19
|
+
|
|
20
|
+
app.use('/about', async (c, next) => {
|
|
21
|
+
c.setRenderer((content) => {
|
|
22
|
+
return c.html(
|
|
23
|
+
<html>
|
|
24
|
+
<head />
|
|
25
|
+
<body>
|
|
26
|
+
<p>{content}</p>
|
|
27
|
+
</body>
|
|
28
|
+
</html>
|
|
29
|
+
)
|
|
30
|
+
})
|
|
31
|
+
await next()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
app.get('/about', (c) => {
|
|
35
|
+
return c.render(
|
|
36
|
+
<>
|
|
37
|
+
<title>Acryl SSG Page</title>Hello!
|
|
38
|
+
</>
|
|
39
|
+
)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
export default app
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
For Node.js, create a build script like this:
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// build.ts
|
|
49
|
+
import app from './index'
|
|
50
|
+
import { toSSG } from 'acrylblends/ssg'
|
|
51
|
+
import fs from 'fs/promises'
|
|
52
|
+
|
|
53
|
+
toSSG(app, fs)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
By executing the script, the files will be output as follows:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
ls ./static
|
|
60
|
+
about.html index.html
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Vite Plugin
|
|
64
|
+
|
|
65
|
+
Using the `@acrylblends/vite-ssg` Vite Plugin, you can easily handle the process.
|
|
66
|
+
|
|
67
|
+
For more details, see here:
|
|
68
|
+
|
|
69
|
+
(not yet available)
|
|
70
|
+
|
|
71
|
+
## toSSG
|
|
72
|
+
|
|
73
|
+
`toSSG` is the main function for generating static sites, taking an application and a filesystem module as arguments. It is based on the following:
|
|
74
|
+
|
|
75
|
+
### Input
|
|
76
|
+
|
|
77
|
+
The arguments for toSSG are specified in ToSSGInterface.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
export interface ToSSGInterface {
|
|
81
|
+
(
|
|
82
|
+
app: Acryl,
|
|
83
|
+
fsModule: FileSystemModule,
|
|
84
|
+
options?: ToSSGOptions
|
|
85
|
+
): Promise<ToSSGResult>
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- `app` specifies `new Acryl()` with registered routes.
|
|
90
|
+
- `fs` specifies the following object, assuming `node:fs/promise`.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
export interface FileSystemModule {
|
|
94
|
+
writeFile(path: string, data: string | Uint8Array): Promise<void>
|
|
95
|
+
mkdir(
|
|
96
|
+
path: string,
|
|
97
|
+
options: { recursive: boolean }
|
|
98
|
+
): Promise<void | string>
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Using the adapter for Bun
|
|
103
|
+
|
|
104
|
+
On Bun, a `toSSG` function is provided by `acrylblends/bun` (not yet available).
|
|
105
|
+
|
|
106
|
+
### Options
|
|
107
|
+
|
|
108
|
+
Options are specified in the ToSSGOptions interface.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
export interface ToSSGOptions {
|
|
112
|
+
dir?: string
|
|
113
|
+
concurrency?: number
|
|
114
|
+
extensionMap?: Record<string, string>
|
|
115
|
+
plugins?: SSGPlugin[]
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- `dir` is the output destination for Static files. The default value is `./static`.
|
|
120
|
+
- `concurrency` is the concurrent number of files to be generated at the same time. The default value is `2`.
|
|
121
|
+
- `extensionMap` is a map containing the `Content-Type` as a key and the string of the extension as a value. This is used to determine the file extension of the output file.
|
|
122
|
+
- `plugins` is an array of SSG plugins that extend the functionality of the static site generation process.
|
|
123
|
+
|
|
124
|
+
### Output
|
|
125
|
+
|
|
126
|
+
`toSSG` returns the result in the following Result type.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
export interface ToSSGResult {
|
|
130
|
+
success: boolean
|
|
131
|
+
files: string[]
|
|
132
|
+
error?: Error
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Generate File
|
|
137
|
+
|
|
138
|
+
### Route and Filename
|
|
139
|
+
|
|
140
|
+
The following rules apply to the registered route information and the generated file name. The default `./static` behaves as follows:
|
|
141
|
+
|
|
142
|
+
- `/` -> `./static/index.html`
|
|
143
|
+
- `/path` -> `./static/path.html`
|
|
144
|
+
- `/path/` -> `./static/path/index.html`
|
|
145
|
+
|
|
146
|
+
### File Extension
|
|
147
|
+
|
|
148
|
+
The file extension depends on the `Content-Type` returned by each route. For example, responses from `c.html` are saved as `.html`.
|
|
149
|
+
|
|
150
|
+
If you want to customize the file extensions, set the `extensionMap` option.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { toSSG, defaultExtensionMap } from 'acrylblends/ssg'
|
|
154
|
+
|
|
155
|
+
// Save `application/x-html` content with `.html`
|
|
156
|
+
toSSG(app, fs, {
|
|
157
|
+
extensionMap: {
|
|
158
|
+
'application/x-html': 'html',
|
|
159
|
+
...defaultExtensionMap,
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Note that paths ending with a slash are saved as index.ext regardless of the extension.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
// save to ./static/html/index.html
|
|
168
|
+
app.get('/html/', (c) => c.html('html'))
|
|
169
|
+
|
|
170
|
+
// save to ./static/text/index.txt
|
|
171
|
+
app.get('/text/', (c) => c.text('text'))
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Middleware
|
|
175
|
+
|
|
176
|
+
Introducing built-in middleware that supports SSG.
|
|
177
|
+
|
|
178
|
+
### ssgParams
|
|
179
|
+
|
|
180
|
+
You can use an API like `generateStaticParams` of Next.js.
|
|
181
|
+
|
|
182
|
+
Example:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
app.get(
|
|
186
|
+
'/shops/:id',
|
|
187
|
+
ssgParams(async () => {
|
|
188
|
+
const shops = await getShops()
|
|
189
|
+
return shops.map((shop) => ({ id: shop.id }))
|
|
190
|
+
}),
|
|
191
|
+
async (c) => {
|
|
192
|
+
const shop = await getShop(c.req.param('id'))
|
|
193
|
+
if (!shop) {
|
|
194
|
+
return c.notFound()
|
|
195
|
+
}
|
|
196
|
+
return c.render(
|
|
197
|
+
<div>
|
|
198
|
+
<h1>{shop.name}</h1>
|
|
199
|
+
</div>
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### isSSGContext
|
|
206
|
+
|
|
207
|
+
`isSSGContext` is a helper function that returns `true` if the current application is running within the SSG context triggered by `toSSG`.
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
app.get('/page', (c) => {
|
|
211
|
+
if (isSSGContext(c)) {
|
|
212
|
+
return c.text('This is generated by SSG')
|
|
213
|
+
}
|
|
214
|
+
return c.text('This is served dynamically')
|
|
215
|
+
})
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### disableSSG
|
|
219
|
+
|
|
220
|
+
Routes with the `disableSSG` middleware set are excluded from static file generation by `toSSG`.
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
app.get('/api', disableSSG(), (c) => c.text('an-api'))
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
### onlySSG
|
|
227
|
+
|
|
228
|
+
Routes with the `onlySSG` middleware set will be overridden by `c.notFound()` after `toSSG` execution.
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
app.get('/static-page', onlySSG(), (c) => c.html(<h1>Welcome to my site</h1>))
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Plugins
|
|
235
|
+
|
|
236
|
+
Plugins allow you to extend the functionality of the static site generation process. They use hooks to customize the generation process at different stages.
|
|
237
|
+
|
|
238
|
+
### Default Plugin
|
|
239
|
+
|
|
240
|
+
By default, `toSSG` uses `defaultPlugin` which skips non-200 status responses (like redirects, errors, or 404s). This prevents generating files for unsuccessful responses.
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { toSSG, defaultPlugin } from 'acrylblends/ssg'
|
|
244
|
+
|
|
245
|
+
// defaultPlugin is automatically applied when no plugins specified
|
|
246
|
+
toSSG(app, fs)
|
|
247
|
+
|
|
248
|
+
// Equivalent to:
|
|
249
|
+
toSSG(app, fs, { plugins: [defaultPlugin] })
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
If you specify custom plugins, `defaultPlugin` is **not** automatically included. To keep the default behavior while adding custom plugins, explicitly include it:
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
toSSG(app, fs, {
|
|
256
|
+
plugins: [defaultPlugin, myCustomPlugin],
|
|
257
|
+
})
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Redirect Plugin
|
|
261
|
+
|
|
262
|
+
The `redirectPlugin` generates HTML redirect pages for routes that return HTTP redirect responses (301, 302, 303, 307, 308). The generated HTML includes a `<meta http-equiv="refresh">` tag and a canonical link.
|
|
263
|
+
|
|
264
|
+
```ts
|
|
265
|
+
import { toSSG, redirectPlugin, defaultPlugin } from 'acrylblends/ssg'
|
|
266
|
+
|
|
267
|
+
toSSG(app, fs, {
|
|
268
|
+
plugins: [redirectPlugin(), defaultPlugin()],
|
|
269
|
+
})
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
For example, if your app has:
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
app.get('/old', (c) => c.redirect('/new'))
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
The `redirectPlugin` will generate an HTML file at `/old.html` with a meta refresh redirect to `/new`.
|
|
279
|
+
|
|
280
|
+
> [!NOTE]
|
|
281
|
+
> When used with `defaultPlugin`, place `redirectPlugin` **before** `defaultPlugin`. Since `defaultPlugin` skips non-200 responses, placing it first would prevent `redirectPlugin` from processing redirect responses.
|
|
282
|
+
|
|
283
|
+
### Hook Types
|
|
284
|
+
|
|
285
|
+
Plugins can use the following hooks to customize the `toSSG` process:
|
|
286
|
+
|
|
287
|
+
```ts
|
|
288
|
+
export type BeforeRequestHook = (req: Request) => Request | false
|
|
289
|
+
export type AfterResponseHook = (res: Response) => Response | false
|
|
290
|
+
export type AfterGenerateHook = (
|
|
291
|
+
result: ToSSGResult
|
|
292
|
+
) => void | Promise<void>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
- **BeforeRequestHook**: Called before processing each request. Return `false` to skip the route.
|
|
296
|
+
- **AfterResponseHook**: Called after receiving each response. Return `false` to skip file generation.
|
|
297
|
+
- **AfterGenerateHook**: Called after the entire generation process completes.
|
|
298
|
+
|
|
299
|
+
### Plugin Interface
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
export interface SSGPlugin {
|
|
303
|
+
beforeRequestHook?: BeforeRequestHook | BeforeRequestHook[]
|
|
304
|
+
afterResponseHook?: AfterResponseHook | AfterResponseHook[]
|
|
305
|
+
afterGenerateHook?: AfterGenerateHook | AfterGenerateHook[]
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Basic Plugin Examples
|
|
310
|
+
|
|
311
|
+
Filter only GET requests:
|
|
312
|
+
|
|
313
|
+
```ts
|
|
314
|
+
const getOnlyPlugin: SSGPlugin = {
|
|
315
|
+
beforeRequestHook: (req) => {
|
|
316
|
+
if (req.method === 'GET') {
|
|
317
|
+
return req
|
|
318
|
+
}
|
|
319
|
+
return false
|
|
320
|
+
},
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Filter by status code:
|
|
325
|
+
|
|
326
|
+
```ts
|
|
327
|
+
const statusFilterPlugin: SSGPlugin = {
|
|
328
|
+
afterResponseHook: (res) => {
|
|
329
|
+
if (res.status === 200 || res.status === 500) {
|
|
330
|
+
return res
|
|
331
|
+
}
|
|
332
|
+
return false
|
|
333
|
+
},
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Log generated files:
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
const logFilesPlugin: SSGPlugin = {
|
|
341
|
+
afterGenerateHook: (result) => {
|
|
342
|
+
if (result.files) {
|
|
343
|
+
result.files.forEach((file) => console.log(file))
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Advanced Plugin Example
|
|
350
|
+
|
|
351
|
+
Here's an example of creating a sitemap plugin that generates a `sitemap.xml` file:
|
|
352
|
+
|
|
353
|
+
```ts
|
|
354
|
+
// plugins.ts
|
|
355
|
+
import fs from 'node:fs/promises'
|
|
356
|
+
import path from 'node:path'
|
|
357
|
+
import type { SSGPlugin } from 'acrylblends/ssg'
|
|
358
|
+
import { DEFAULT_OUTPUT_DIR } from 'acrylblends/ssg'
|
|
359
|
+
|
|
360
|
+
export const sitemapPlugin = (baseURL: string): SSGPlugin => {
|
|
361
|
+
return {
|
|
362
|
+
afterGenerateHook: (result, fsModule, options) => {
|
|
363
|
+
const outputDir = options?.dir ?? DEFAULT_OUTPUT_DIR
|
|
364
|
+
const filePath = path.join(outputDir, 'sitemap.xml')
|
|
365
|
+
const urls = result.files.map((file) =>
|
|
366
|
+
new URL(file, baseURL).toString()
|
|
367
|
+
)
|
|
368
|
+
const siteMapText = `<?xml version="1.0" encoding="UTF-8"?>
|
|
369
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
370
|
+
${urls.map((url) => `<url><loc>${url}</loc></url>`).join('\n')}
|
|
371
|
+
</urlset>`
|
|
372
|
+
fsModule.writeFile(filePath, siteMapText)
|
|
373
|
+
},
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Applying plugins:
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
import app from './index'
|
|
382
|
+
import { toSSG } from 'acrylblends/ssg'
|
|
383
|
+
import { sitemapPlugin } from './plugins'
|
|
384
|
+
|
|
385
|
+
toSSG(app, fs, {
|
|
386
|
+
plugins: [
|
|
387
|
+
getOnlyPlugin,
|
|
388
|
+
statusFilterPlugin,
|
|
389
|
+
logFilesPlugin,
|
|
390
|
+
sitemapPlugin('https://example.com'),
|
|
391
|
+
],
|
|
392
|
+
})
|
|
393
|
+
```
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Streaming Helper
|
|
2
|
+
|
|
3
|
+
The Streaming Helper provides methods for streaming responses.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { Acryl } from 'acrylblends'
|
|
9
|
+
import { stream, streamText, streamSSE } from 'acrylblends/streaming'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## `stream()`
|
|
13
|
+
|
|
14
|
+
It returns a simple streaming response as `Response` object.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
app.get('/stream', (c) => {
|
|
18
|
+
return stream(c, async (stream) => {
|
|
19
|
+
// Write a process to be executed when aborted.
|
|
20
|
+
stream.onAbort(() => {
|
|
21
|
+
console.log('Aborted!')
|
|
22
|
+
})
|
|
23
|
+
// Write a Uint8Array.
|
|
24
|
+
await stream.write(new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]))
|
|
25
|
+
// Pipe a readable stream.
|
|
26
|
+
await stream.pipe(anotherReadableStream)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## `streamText()`
|
|
32
|
+
|
|
33
|
+
It returns a streaming response with `Content-Type: text/plain`, `Transfer-Encoding: chunked`, and `X-Content-Type-Options: nosniff` headers.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
app.get('/streamText', (c) => {
|
|
37
|
+
return streamText(c, async (stream) => {
|
|
38
|
+
// Write a text with a new line ('\n').
|
|
39
|
+
await stream.writeln('Hello')
|
|
40
|
+
// Wait 1 second.
|
|
41
|
+
await stream.sleep(1000)
|
|
42
|
+
// Write a text without a new line.
|
|
43
|
+
await stream.write(`Acryl!`)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Warning.**
|
|
49
|
+
|
|
50
|
+
If you are developing an application for Cloudflare Workers, streaming may not work well on Wrangler. If so, add `Identity` for `Content-Encoding` header.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
app.get('/streamText', (c) => {
|
|
54
|
+
c.header('Content-Encoding', 'Identity')
|
|
55
|
+
return streamText(c, async (stream) => {
|
|
56
|
+
// ...
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## `streamSSE()`
|
|
62
|
+
|
|
63
|
+
It allows you to stream Server-Sent Events (SSE) seamlessly.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const app = new Acryl()
|
|
67
|
+
let id = 0
|
|
68
|
+
|
|
69
|
+
app.get('/sse', async (c) => {
|
|
70
|
+
return streamSSE(c, async (stream) => {
|
|
71
|
+
while (!stream.aborted) {
|
|
72
|
+
const message = `It is ${new Date().toISOString()}`
|
|
73
|
+
await stream.writeSSE({
|
|
74
|
+
data: message,
|
|
75
|
+
event: 'time-update',
|
|
76
|
+
id: String(id++),
|
|
77
|
+
})
|
|
78
|
+
await stream.sleep(1000)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Error Handling
|
|
85
|
+
|
|
86
|
+
The third argument of the streaming helper is an error handler.
|
|
87
|
+
This argument is optional, if you don't specify it, the error will be output as a console error.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
app.get('/stream', (c) => {
|
|
91
|
+
return stream(
|
|
92
|
+
c,
|
|
93
|
+
async (stream) => {
|
|
94
|
+
// Write a process to be executed when aborted.
|
|
95
|
+
stream.onAbort(() => {
|
|
96
|
+
console.log('Aborted!')
|
|
97
|
+
})
|
|
98
|
+
// Write a Uint8Array.
|
|
99
|
+
await stream.write(
|
|
100
|
+
new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f])
|
|
101
|
+
)
|
|
102
|
+
// Pipe a readable stream.
|
|
103
|
+
await stream.pipe(anotherReadableStream)
|
|
104
|
+
},
|
|
105
|
+
(err, stream) => {
|
|
106
|
+
stream.writeln('An error occurred!')
|
|
107
|
+
console.error(err)
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
})
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The stream will be automatically closed after the callbacks are executed.
|
|
114
|
+
|
|
115
|
+
> **Warning.**
|
|
116
|
+
> If the callback function of the streaming helper throws an error, the `onError` event of Acryl will not be triggered.
|
|
117
|
+
>
|
|
118
|
+
> `onError` is a hook to handle errors before the response is sent and overwrite the response. However, when the callback function is executed, the stream has already started, so it cannot be overwritten.
|
|
119
|
+
>
|