acrylblends 0.4.1 → 0.5.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/LICENSE +73 -0
- package/README.md +325 -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} +13 -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 +60 -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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2024",
|
|
4
|
+
"lib": ["ES2024"],
|
|
5
|
+
"module": "NodeNext",
|
|
6
|
+
"moduleResolution": "NodeNext",
|
|
7
|
+
"strict": true,
|
|
8
|
+
"exactOptionalPropertyTypes": true,
|
|
9
|
+
"noEmit": true,
|
|
10
|
+
"types": ["node"]
|
|
11
|
+
},
|
|
12
|
+
"files": ["consumer.ts"]
|
|
13
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { Context, type FiberState } from '@deepseek-ai/cordis'
|
|
8
8
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
9
9
|
import { streamSSE } from '../src/helpers/index.ts'
|
|
10
|
-
import { apply,
|
|
10
|
+
import { apply, Acryl, Config, connectionOf, HTTPException, name, type Router } from '../src/index.ts'
|
|
11
11
|
|
|
12
12
|
const PENDING = 0 as FiberState.PENDING
|
|
13
13
|
const ACTIVE = 2 as FiberState.ACTIVE
|
|
@@ -42,7 +42,7 @@ function consumer(path: string, label: string) {
|
|
|
42
42
|
name: `consumer${label}`,
|
|
43
43
|
inject: ['router'],
|
|
44
44
|
apply(ctx: Context): void {
|
|
45
|
-
ctx.router.route('/', new
|
|
45
|
+
ctx.router.route('/', new Acryl().get(path, c => c.text(label)))
|
|
46
46
|
},
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -52,7 +52,7 @@ const get = (router: Router, path: string): Promise<Response> => router.fetch(ne
|
|
|
52
52
|
describe('acryl-router mounts', () => {
|
|
53
53
|
it('serves a mounted app under its path, with the app\'s own routes, middleware and error handler', async () => {
|
|
54
54
|
const { router } = await mountRouter()
|
|
55
|
-
const api = new
|
|
55
|
+
const api = new Acryl()
|
|
56
56
|
.use(async (c, next) => { await next(); c.header('x-api', 'yes') })
|
|
57
57
|
.get('/items/:id', c => c.json({ id: c.req.param('id') }))
|
|
58
58
|
.get('/boom', () => { throw new Error('boom') })
|
|
@@ -70,28 +70,28 @@ describe('acryl-router mounts', () => {
|
|
|
70
70
|
|
|
71
71
|
it('removes a mount with its remover, idempotently, and keeps the others', async () => {
|
|
72
72
|
const { router } = await mountRouter()
|
|
73
|
-
const removeA = router.route('/', new
|
|
74
|
-
router.route('/', new
|
|
73
|
+
const removeA = router.route('/', new Acryl().get('/a', c => c.text('a')))
|
|
74
|
+
router.route('/', new Acryl().get('/b', c => c.text('b')))
|
|
75
75
|
expect((await get(router, '/a')).status).toBe(200)
|
|
76
76
|
removeA()
|
|
77
77
|
removeA()
|
|
78
78
|
expect((await get(router, '/a')).status).toBe(404)
|
|
79
79
|
expect(await (await get(router, '/b')).text()).toBe('b')
|
|
80
|
-
router.route('/', new
|
|
80
|
+
router.route('/', new Acryl().get('/a', c => c.text('a2')))
|
|
81
81
|
expect(await (await get(router, '/a')).text()).toBe('a2')
|
|
82
82
|
})
|
|
83
83
|
|
|
84
84
|
it('runs mounts in the order they were made, so an earlier mount\'s middleware wraps a later mount\'s routes', async () => {
|
|
85
85
|
const { router } = await mountRouter()
|
|
86
|
-
router.route('/', new
|
|
87
|
-
router.route('/', new
|
|
86
|
+
router.route('/', new Acryl().use('/guarded/*', async c => c.text('denied', 401)))
|
|
87
|
+
router.route('/', new Acryl().get('/guarded/x', c => c.text('secret')).get('/open', c => c.text('open')))
|
|
88
88
|
expect((await get(router, '/guarded/x')).status).toBe(401)
|
|
89
89
|
expect(await (await get(router, '/open')).text()).toBe('open')
|
|
90
90
|
})
|
|
91
91
|
|
|
92
92
|
it('takes one router-wide error handler and one not-found handler, owned by the caller', async () => {
|
|
93
93
|
const { router } = await mountRouter()
|
|
94
|
-
router.route('/', new
|
|
94
|
+
router.route('/', new Acryl().get('/boom', () => { throw new Error('boom') }).get('/teapot', () => { throw new HTTPException(418, { message: 'short' }) }))
|
|
95
95
|
expect((await get(router, '/boom')).status).toBe(500)
|
|
96
96
|
expect((await get(router, '/teapot')).status).toBe(418)
|
|
97
97
|
|
|
@@ -109,13 +109,13 @@ describe('acryl-router mounts', () => {
|
|
|
109
109
|
const ctx = root()
|
|
110
110
|
ctx.plugin(provider, { trailingSlash: 'ignore', disposeGraceMs: 2000 })
|
|
111
111
|
await settle()
|
|
112
|
-
ctx.router.route('/', new
|
|
112
|
+
ctx.router.route('/', new Acryl().get('/a', c => c.text('a')))
|
|
113
113
|
expect((await get(ctx.router, '/a/')).status).toBe(200)
|
|
114
114
|
})
|
|
115
115
|
|
|
116
116
|
it('hands the transport\'s connection info to the handler and gives an in-process call an empty one', async () => {
|
|
117
117
|
const { router } = await mountRouter()
|
|
118
|
-
router.route('/', new
|
|
118
|
+
router.route('/', new Acryl().get('/who', c => c.json({ remote: connectionOf(c).remoteAddress ?? null, port: connectionOf(c).localPort ?? null })))
|
|
119
119
|
const over = await router.fetch(new Request('http://acryl.test/who'), { remoteAddress: '127.0.0.1', localPort: 4000 })
|
|
120
120
|
expect(await over.json()).toEqual({ remote: '127.0.0.1', port: 4000 })
|
|
121
121
|
const inProcess = await router.request('/who')
|
|
@@ -154,7 +154,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
154
154
|
|
|
155
155
|
it('labels a mount by its path with one child per route, so no label grows with the app (an inspector caps label length)', async () => {
|
|
156
156
|
const { ctx, router } = await mountRouter()
|
|
157
|
-
const big = new
|
|
157
|
+
const big = new Acryl().use('/api/*', async (_c, next) => { await next() })
|
|
158
158
|
for (let i = 0; i < 60; i += 1) big.get(`/api/a-fairly-long-resource-name-${String(i)}`, c => c.text('ok'))
|
|
159
159
|
const fiber = ctx.plugin({ name: 'big', inject: ['router'], apply: (inner: Context) => { inner.router.route('/', big) } })
|
|
160
160
|
await settle()
|
|
@@ -192,7 +192,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
192
192
|
|
|
193
193
|
it('serves the routes an app had when it was mounted, whatever else changes later', async () => {
|
|
194
194
|
const { ctx, router } = await mountRouter()
|
|
195
|
-
const app = new
|
|
195
|
+
const app = new Acryl().get('/early', c => c.text('early'))
|
|
196
196
|
router.route('/', app)
|
|
197
197
|
app.get('/late', c => c.text('late'))
|
|
198
198
|
expect((await get(router, '/early')).status).toBe(200)
|
|
@@ -223,7 +223,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
223
223
|
name: 'counting',
|
|
224
224
|
inject: ['router'],
|
|
225
225
|
apply(inner: Context): void {
|
|
226
|
-
inner.router.route('/', new
|
|
226
|
+
inner.router.route('/', new Acryl().use(async (_c, next) => { calls += 1; await next() }).get('/count', c => c.text(String(calls))))
|
|
227
227
|
},
|
|
228
228
|
}
|
|
229
229
|
for (let round = 0; round < 10; round += 1) {
|
|
@@ -261,7 +261,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
261
261
|
await settle()
|
|
262
262
|
const router = ctx.router
|
|
263
263
|
let aborted = false
|
|
264
|
-
router.route('/', new
|
|
264
|
+
router.route('/', new Acryl().get('/slow', async c => {
|
|
265
265
|
await new Promise<void>((_resolve, reject) => { c.req.raw.signal.addEventListener('abort', () => { aborted = true; reject(new Error('aborted')) }, { once: true }) })
|
|
266
266
|
return c.text('late')
|
|
267
267
|
}))
|
|
@@ -278,7 +278,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
278
278
|
it('forwards the caller\'s own abort to the handler signal', async () => {
|
|
279
279
|
const { router } = await mountRouter()
|
|
280
280
|
let seen = false
|
|
281
|
-
router.route('/', new
|
|
281
|
+
router.route('/', new Acryl().get('/slow', async c => {
|
|
282
282
|
await new Promise<void>((_resolve, reject) => { c.req.raw.signal.addEventListener('abort', () => { seen = true; reject(new Error('aborted')) }, { once: true }) })
|
|
283
283
|
return c.text('x')
|
|
284
284
|
}))
|
|
@@ -295,7 +295,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
295
295
|
const fiber = ctx.plugin(provider, config)
|
|
296
296
|
await settle()
|
|
297
297
|
let cleaned = false
|
|
298
|
-
ctx.router.route('/', new
|
|
298
|
+
ctx.router.route('/', new Acryl().get('/events', c => streamSSE(c, async stream => {
|
|
299
299
|
stream.onAbort(() => { cleaned = true })
|
|
300
300
|
await stream.writeSSE({ data: 'first' })
|
|
301
301
|
while (!stream.aborted) await stream.sleep(10)
|
|
@@ -319,7 +319,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
319
319
|
name: 'streaming',
|
|
320
320
|
inject: ['router'],
|
|
321
321
|
apply(inner: Context): void {
|
|
322
|
-
inner.router.route('/', new
|
|
322
|
+
inner.router.route('/', new Acryl().get('/events', c => streamSSE(c, async stream => {
|
|
323
323
|
stream.onAbort(() => { cleaned = true })
|
|
324
324
|
await stream.writeSSE({ data: 'first' })
|
|
325
325
|
while (!stream.aborted) await stream.sleep(10)
|
|
@@ -330,7 +330,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
330
330
|
name: 'other',
|
|
331
331
|
inject: ['router'],
|
|
332
332
|
apply(inner: Context): void {
|
|
333
|
-
inner.router.route('/', new
|
|
333
|
+
inner.router.route('/', new Acryl().get('/slow', async c => {
|
|
334
334
|
c.req.raw.signal.addEventListener('abort', () => { otherAborted = true }, { once: true })
|
|
335
335
|
await new Promise<void>(resolve => { release = resolve })
|
|
336
336
|
return c.text('done')
|
|
@@ -361,7 +361,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
361
361
|
name: 'guard',
|
|
362
362
|
inject: ['router'],
|
|
363
363
|
apply(inner: Context): void {
|
|
364
|
-
inner.router.route('/', new
|
|
364
|
+
inner.router.route('/', new Acryl()
|
|
365
365
|
.use('/held/*', async (c, next) => {
|
|
366
366
|
c.req.raw.signal.addEventListener('abort', () => { guardAborted = true }, { once: true })
|
|
367
367
|
await new Promise<void>((_resolve, reject) => { c.req.raw.signal.addEventListener('abort', () => { reject(new Error('aborted')) }, { once: true }) })
|
|
@@ -374,7 +374,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
374
374
|
name: 'handler',
|
|
375
375
|
inject: ['router'],
|
|
376
376
|
apply(inner: Context): void {
|
|
377
|
-
inner.router.route('/', new
|
|
377
|
+
inner.router.route('/', new Acryl()
|
|
378
378
|
.get('/held/x', c => c.text('held'))
|
|
379
379
|
.get('/passed/x', c => streamSSE(c, async stream => {
|
|
380
380
|
stream.onAbort(() => { handlerAborted = true })
|
|
@@ -402,7 +402,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
402
402
|
const fiber = ctx.plugin(provider, config)
|
|
403
403
|
await settle()
|
|
404
404
|
let finished = false
|
|
405
|
-
ctx.router.route('/', new
|
|
405
|
+
ctx.router.route('/', new Acryl().get('/later', c => {
|
|
406
406
|
c.executionCtx.waitUntil(new Promise<void>(resolve => { setTimeout(() => { finished = true; resolve() }, 30) }))
|
|
407
407
|
return c.text('now')
|
|
408
408
|
}))
|
|
@@ -416,7 +416,7 @@ describe('acryl-router lifecycle through Cordis', () => {
|
|
|
416
416
|
const ctx = root()
|
|
417
417
|
const fiber = ctx.plugin(provider, { trailingSlash: 'strict', disposeGraceMs: 30 })
|
|
418
418
|
await settle()
|
|
419
|
-
ctx.router.route('/', new
|
|
419
|
+
ctx.router.route('/', new Acryl().get('/stuck', c => { c.executionCtx.waitUntil(new Promise(() => undefined)); return c.text('x') }))
|
|
420
420
|
await get(ctx.router, '/stuck')
|
|
421
421
|
const started = Date.now()
|
|
422
422
|
await fiber.dispose()
|
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
"source": {
|
|
3
3
|
"repo": "acryldev/acryl",
|
|
4
4
|
"path": "plugins/acryl-router",
|
|
5
|
-
"commit": "
|
|
5
|
+
"commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
|
|
6
6
|
},
|
|
7
7
|
"vendored": [
|
|
8
8
|
"src",
|
|
9
9
|
"tests",
|
|
10
10
|
"LICENSE"
|
|
11
11
|
],
|
|
12
|
-
"rewrittenSpecifiers":
|
|
13
|
-
"digest": "sha256:
|
|
12
|
+
"rewrittenSpecifiers": 4,
|
|
13
|
+
"digest": "sha256:543a5ca99518eea1fe2e319b7708d62af34a6c24ab3daeb17dde48d67d319d6a",
|
|
14
14
|
"testsNotRun": {
|
|
15
15
|
"tests/loader.spec.ts": "loads the built lib/ entry through the real Loader; the library ships source and has no build"
|
|
16
16
|
},
|
|
@@ -8,7 +8,7 @@ import { Context, type FiberState } from '@deepseek-ai/cordis'
|
|
|
8
8
|
import WebServer from '@deepseek-ai/dsh-host-webserver'
|
|
9
9
|
import { apply as routerApply, name as routerName } from '../../acryl-router/src/index.ts'
|
|
10
10
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
11
|
-
import {
|
|
11
|
+
import { Acryl, connectionOf, type RouterHttpService } from '../../acryl-router/src/index.ts'
|
|
12
12
|
import { methodNotAllowed } from '../../acryl-router/src/middleware/index.ts'
|
|
13
13
|
import { apply, inject, name } from '../src/index.ts'
|
|
14
14
|
|
|
@@ -40,13 +40,13 @@ async function stack(): Promise<{ ctx: Context, base: () => string }> {
|
|
|
40
40
|
return { ctx, base: () => `http://127.0.0.1:${String((ctx as unknown as { webServer: { port: number } }).webServer.port)}` }
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
function demo(prefix: string, extra?: (app:
|
|
43
|
+
function demo(prefix: string, extra?: (app: Acryl) => void) {
|
|
44
44
|
return {
|
|
45
45
|
name: `demo${prefix.replaceAll('/', '-')}`,
|
|
46
46
|
inject: ['router', 'routerHttp'],
|
|
47
47
|
apply(ctx: Context): void {
|
|
48
48
|
ctx.routerHttp.mount(prefix)
|
|
49
|
-
const app = new
|
|
49
|
+
const app = new Acryl()
|
|
50
50
|
app.use(methodNotAllowed({ app }))
|
|
51
51
|
app.get('/hello/:who', c => c.json({ hello: c.req.param('who'), q: c.req.query('q') ?? null, host: c.req.header('host') !== undefined }))
|
|
52
52
|
app.post('/echo', async c => c.json({ got: await c.req.text(), type: c.req.header('content-type') ?? null }, 201))
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Context } from '@deepseek-ai/cordis'
|
|
9
9
|
import WebServer from '@deepseek-ai/dsh-host-webserver'
|
|
10
|
-
import {
|
|
10
|
+
import { Acryl, apply as routerApply, name as routerName } from '../../acryl-router/src/index.ts'
|
|
11
11
|
import { afterEach, describe, expect, it } from 'vitest'
|
|
12
12
|
import { apply as httpApply, inject as httpInject, name as httpName } from '../src/index.ts'
|
|
13
13
|
|
|
@@ -28,7 +28,7 @@ const notes = {
|
|
|
28
28
|
inject: ['router'],
|
|
29
29
|
apply(ctx: Context): void {
|
|
30
30
|
const store = new Map<string, string>()
|
|
31
|
-
const app = new
|
|
31
|
+
const app = new Acryl()
|
|
32
32
|
.post('/:id', async c => {
|
|
33
33
|
const text = await c.req.text()
|
|
34
34
|
store.set(c.req.param('id'), text)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"source": {
|
|
3
3
|
"repo": "acryldev/acryl",
|
|
4
4
|
"path": "plugins/acryl-router-http",
|
|
5
|
-
"commit": "
|
|
5
|
+
"commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
|
|
6
6
|
},
|
|
7
7
|
"vendored": [
|
|
8
8
|
"src",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"LICENSE"
|
|
11
11
|
],
|
|
12
12
|
"rewrittenSpecifiers": 7,
|
|
13
|
-
"digest": "sha256:
|
|
13
|
+
"digest": "sha256:394994528a104c8f788e2d911f8f940ff9f74e9c5a72835ea3ea751651aa9fbd",
|
|
14
14
|
"testsNotRun": {
|
|
15
15
|
"tests/adapter.spec.ts": "needs @deepseek-ai/dsh-host-webserver (the DSH web server); acryl-node-server has its own tests",
|
|
16
16
|
"tests/stream.spec.ts": "needs @deepseek-ai/dsh-host-webserver (the DSH web server)",
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { Context, Service } from '@deepseek-ai/cordis'
|
|
9
|
-
import {
|
|
9
|
+
import { Acryl, type Context as RequestContext } from '../../acryl-router/src/index.ts'
|
|
10
10
|
import { streamSSE } from '../../acryl-router/src/helpers/index.ts'
|
|
11
11
|
import { loopbackOnly, methodNotAllowed } from '../../acryl-router/src/middleware/index.ts'
|
|
12
12
|
import { createCell, createDerived, type Cell, type ReadonlyCell } from './cell.ts'
|
|
@@ -104,7 +104,7 @@ export function apply(ctx: Context): void {
|
|
|
104
104
|
// The same cells on the router, read-only, for any surface; present only where a router is. A request over a socket must come from this machine to this
|
|
105
105
|
// app; the terminal calls the router in process and is the host's own code.
|
|
106
106
|
ctx.inject(['router'], inner => {
|
|
107
|
-
const api = new
|
|
107
|
+
const api = new Acryl()
|
|
108
108
|
api.use(loopbackOnly({ inProcess: 'allow' }), methodNotAllowed({ app: api }))
|
|
109
109
|
.get('/', c => c.json({ keys: state.keys() }))
|
|
110
110
|
.get('/:key', c => {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"source": {
|
|
3
3
|
"repo": "acryldev/acryl",
|
|
4
4
|
"path": "plugins/acryl-state",
|
|
5
|
-
"commit": "
|
|
5
|
+
"commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
|
|
6
6
|
},
|
|
7
7
|
"vendored": [
|
|
8
8
|
"src",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"NOTICE"
|
|
12
12
|
],
|
|
13
13
|
"rewrittenSpecifiers": 4,
|
|
14
|
-
"digest": "sha256:
|
|
14
|
+
"digest": "sha256:18df69d338a1928fc0f7497c14c245afb98f0c39d4fe6a24bda62bb845d96030",
|
|
15
15
|
"testsNotRun": {
|
|
16
16
|
"tests/react.spec.ts": "needs react and @testing-library/react, which generated apps do not install"
|
|
17
17
|
},
|
|
@@ -18,7 +18,7 @@ const PATH = /^\/[a-z0-9/-]*$/
|
|
|
18
18
|
|
|
19
19
|
export function routeSource(name: string, path: string, text: string): string {
|
|
20
20
|
return `import type { Context } from '@deepseek-ai/cordis'
|
|
21
|
-
import {
|
|
21
|
+
import { Acryl } from 'acrylblends'
|
|
22
22
|
|
|
23
23
|
/** Written by the builder: answers GET ${path}, and checks that it does before the install counts. */
|
|
24
24
|
export const name = '${name}'
|
|
@@ -26,7 +26,7 @@ export const inject = ['router']
|
|
|
26
26
|
|
|
27
27
|
export function apply(ctx: Context) {
|
|
28
28
|
// The app is mounted through this plugin's context, so the route is removed when the plugin is unloaded.
|
|
29
|
-
ctx.router.route('/', new
|
|
29
|
+
ctx.router.route('/', new Acryl().get(${JSON.stringify(path)}, (c) => c.json({ text: ${JSON.stringify(text)} })))
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export async function check(ctx: Context) {
|
|
@@ -12,21 +12,81 @@ import { registerHooks } from 'node:module'
|
|
|
12
12
|
import { join } from 'node:path'
|
|
13
13
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
14
14
|
|
|
15
|
+
const PACKAGE = 'acrylblends'
|
|
16
|
+
|
|
15
17
|
const isBare = (specifier: string) => !/^[./]/.test(specifier) && !specifier.includes(':')
|
|
16
18
|
|
|
17
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* The framework's specifiers, as files of the vendored router plugin that sits beside this one. A plugin written while the app runs (by the agent, from the docs in the app)
|
|
21
|
+
* imports `acrylblends` and `acrylblends/<subpath>` as the docs write them; the old `acryl-router` names keep working. Empty when the app has no router.
|
|
22
|
+
*/
|
|
23
|
+
const MIDDLEWARE = [
|
|
24
|
+
'basic-auth',
|
|
25
|
+
'bearer-auth',
|
|
26
|
+
'body-limit',
|
|
27
|
+
'combine',
|
|
28
|
+
'compress',
|
|
29
|
+
'context-storage',
|
|
30
|
+
'cors',
|
|
31
|
+
'csrf',
|
|
32
|
+
'etag',
|
|
33
|
+
'ip-restriction',
|
|
34
|
+
'jwk',
|
|
35
|
+
'jwt',
|
|
36
|
+
'language',
|
|
37
|
+
'logger',
|
|
38
|
+
'loopback-only',
|
|
39
|
+
'method-not-allowed',
|
|
40
|
+
'method-override',
|
|
41
|
+
'powered-by',
|
|
42
|
+
'pretty-json',
|
|
43
|
+
'request-id',
|
|
44
|
+
'secure-headers',
|
|
45
|
+
'serve-static',
|
|
46
|
+
'timeout',
|
|
47
|
+
'timing',
|
|
48
|
+
'trailing-slash',
|
|
49
|
+
]
|
|
50
|
+
const HELPERS = [
|
|
51
|
+
'accepts',
|
|
52
|
+
'cookie',
|
|
53
|
+
'factory',
|
|
54
|
+
'html',
|
|
55
|
+
'route',
|
|
56
|
+
'schema-validator',
|
|
57
|
+
'streaming',
|
|
58
|
+
'testing',
|
|
59
|
+
'validator',
|
|
60
|
+
'ws',
|
|
61
|
+
]
|
|
62
|
+
|
|
63
|
+
/** The `acrylblends/...` names a plugin installed live may import, with the file each resolves to under `acryl-router/src`. */
|
|
64
|
+
export function frameworkSpecifiers(): Record<string, string> {
|
|
65
|
+
const map: Record<string, string> = {
|
|
66
|
+
'': 'index.ts',
|
|
67
|
+
conninfo: 'index.ts',
|
|
68
|
+
'http-exception': 'index.ts',
|
|
69
|
+
types: 'index.ts',
|
|
70
|
+
client: 'client.ts',
|
|
71
|
+
}
|
|
72
|
+
for (const name of MIDDLEWARE) map[name] = 'middleware/index.ts'
|
|
73
|
+
for (const name of HELPERS) map[name] = 'helpers/index.ts'
|
|
74
|
+
return map
|
|
75
|
+
}
|
|
76
|
+
|
|
18
77
|
export function routerAliases(): Record<string, string> {
|
|
19
78
|
const src = new URL('../acryl-router/src/', import.meta.url)
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
79
|
+
const aliases: Record<string, string> = {}
|
|
80
|
+
const add = (specifier: string, file: string) => {
|
|
81
|
+
const path = fileURLToPath(new URL(file, src))
|
|
82
|
+
if (existsSync(path)) aliases[specifier] = path
|
|
24
83
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
)
|
|
84
|
+
for (const [sub, file] of Object.entries(frameworkSpecifiers()))
|
|
85
|
+
add(sub === '' ? PACKAGE : `${PACKAGE}/${sub}`, file)
|
|
86
|
+
add('acryl-router', 'index.ts')
|
|
87
|
+
add('acryl-router/middleware', 'middleware/index.ts')
|
|
88
|
+
add('acryl-router/helpers', 'helpers/index.ts')
|
|
89
|
+
return aliases
|
|
30
90
|
}
|
|
31
91
|
|
|
32
92
|
export function resolveFromApp(
|
package/plugins/openai/prompt.ts
CHANGED
|
@@ -10,20 +10,20 @@ To add a capability:
|
|
|
10
10
|
A plugin's index.ts is TypeScript that Node runs directly (erasable syntax only: no enums, no parameter properties):
|
|
11
11
|
|
|
12
12
|
import type { Context } from '@deepseek-ai/cordis'
|
|
13
|
-
import {
|
|
13
|
+
import { Acryl } from 'acrylblends'
|
|
14
14
|
export const name = 'hello' // must equal the folder name
|
|
15
15
|
export const inject = ['router'] // services it needs; it waits (pending) until they exist
|
|
16
16
|
export function apply(ctx: Context) {
|
|
17
|
-
ctx.router.route('/', new
|
|
17
|
+
ctx.router.route('/', new Acryl().get('/hello', (c) => c.json({ text: 'Hello' }))) // removed when the plugin is unloaded
|
|
18
18
|
}
|
|
19
19
|
export async function check(ctx: Context) { // optional: must pass, or the install is rolled back
|
|
20
20
|
const reply = await ctx.router.request('/hello')
|
|
21
21
|
if (!reply.ok) throw new Error('GET /hello failed')
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
The router: build an
|
|
24
|
+
The router: build an Acryl app (import { Acryl } from 'acrylblends'), register routes on it with app.get/post/put/patch/delete(path, handler) and mount it with
|
|
25
25
|
ctx.router.route(prefix, app). A path parameter is :id and is read with c.req.param('id'); c.json(body, status) answers JSON, c.text(...) answers text,
|
|
26
|
-
await c.req.json() reads a JSON body, throw new HTTPException(404, { message }) (also from '
|
|
26
|
+
await c.req.json() reads a JSON body, throw new HTTPException(404, { message }) (also from 'acrylblends') answers an error. Routes added to an app
|
|
27
27
|
after route() are not served: build the whole app first. ctx.router.request('/path', { method: 'POST', body: ... }) calls a route in process (use it in
|
|
28
28
|
check). The mount goes away when the plugin is unloaded.
|
|
29
29
|
|
|
@@ -32,6 +32,6 @@ host: it runs in a separate process that can read only its own folder. Files: in
|
|
|
32
32
|
{ "description": "what it does and its input", "examples": [ { "input": {...}, "output": {...} } ] }
|
|
33
33
|
The examples are run in the sandbox at install and must match exactly, or the install is refused. Use write_plugin and install_plugin for tools too.
|
|
34
34
|
|
|
35
|
-
Rules: import only relative files, node: built-ins, @deepseek-ai/cordis and
|
|
35
|
+
Rules: import only relative files, node: built-ins, @deepseek-ai/cordis and acrylblends (and its subpaths such as acrylblends/cors, whose docs are in docs/framework). Provide services with ctx.provide(name, value) and
|
|
36
36
|
use others with ctx.get(name). Put timers, listeners and routes inside ctx.effect(() => cleanup). Use list_plugins and
|
|
37
37
|
read_plugin to see what exists. When you are done, answer in one or two plain sentences saying what you built.`
|
package/shared/AGENTS.core.md
CHANGED
|
@@ -5,26 +5,33 @@ parameter properties). Every part of it is a Cordis plugin.
|
|
|
5
5
|
|
|
6
6
|
## The framework's API is in `docs/framework/`
|
|
7
7
|
|
|
8
|
-
Start at `docs/framework/README.md`; `api
|
|
9
|
-
`validation.md`, `helpers.md` (`streamSSE`), `middleware.md`, `plugin-lifecycle.md` (what a plugin
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
Start at `docs/framework/README.md`; `api/summary.md` is the one-page summary. Read before you write routes: `api/routing.md` (the `Acryl` app), `api/request.md` (`c.req`),
|
|
9
|
+
`api/context.md` (`c`), `cordis/validation.md` and `guides/validation.md`, `guides/helpers.md` (`streamSSE`), `concepts/middleware.md`, `cordis/plugin-lifecycle.md` (what a plugin
|
|
10
|
+
owns and when it is unloaded), `cordis/mounting.md` and `cordis/node-server.md`. Pages marked "not yet available" describe parts that are not in this app.
|
|
11
|
+
|
|
12
|
+
The docs write `import { Acryl } from 'acrylblends'` and `from 'acrylblends/<subpath>'`. In this app the framework is the vendored plugin source in `src/plugins/acryl-router/src`
|
|
13
|
+
(read it, do not edit it: a change belongs in ACRYL, upstream), so from a file in `src/` import:
|
|
14
|
+
|
|
15
|
+
- `./plugins/acryl-router/src/index.ts` for `Acryl`, `Context`, `HTTPException`, `connectionOf`, `getConnInfo` and the types;
|
|
16
|
+
- `./plugins/acryl-router/src/middleware/index.ts` for every middleware (`cors`, `bodyLimit`, `trimTrailingSlash`, `loopbackOnly`, ...);
|
|
17
|
+
- `./plugins/acryl-router/src/helpers/index.ts` for the helpers and validators (`streamSSE`, `schemaValidator`, `validator`, cookies, `testClient`, ...).
|
|
18
|
+
|
|
19
|
+
A plugin written into `extensions/` while the app runs may use the docs' own names instead: `acrylblends` and `acrylblends/<subpath>` resolve to the same files. `App` is the
|
|
20
|
+
deprecated name of `Acryl`.
|
|
14
21
|
|
|
15
22
|
## How a feature is built
|
|
16
23
|
|
|
17
|
-
Routes are an ordinary `
|
|
24
|
+
Routes are an ordinary `Acryl` app that a plugin mounts once with `ctx.router.route(prefix, app)`. The mount belongs to the plugin and goes away when it unloads.
|
|
18
25
|
|
|
19
26
|
```ts
|
|
20
27
|
import type { Context } from '@deepseek-ai/cordis'
|
|
21
|
-
import {
|
|
28
|
+
import { Acryl, HTTPException } from './plugins/acryl-router/src/index.ts'
|
|
22
29
|
import { schemaValidator, type StandardSchema } from './plugins/acryl-router/src/helpers/index.ts'
|
|
23
30
|
|
|
24
31
|
export const name = 'notes' // a plugin's name; blend.yaml refers to it
|
|
25
32
|
export const inject = ['router'] // services it needs
|
|
26
33
|
export function apply(ctx: Context) {
|
|
27
|
-
const app = new
|
|
34
|
+
const app = new Acryl()
|
|
28
35
|
.get('/', (c) => c.json({ ok: true }))
|
|
29
36
|
.get('/:id', (c) => c.json({ id: c.req.param('id') }))
|
|
30
37
|
.post('/', schemaValidator('json', NewNote), (c) => c.json(c.req.valid('json'), 201)) // NewNote is a Standard Schema
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis'
|
|
2
|
-
import {
|
|
2
|
+
import { Acryl } from './plugins/acryl-router/src/index.ts'
|
|
3
3
|
import { bodyLimit } from './plugins/acryl-router/src/middleware/index.ts'
|
|
4
4
|
import type {} from './plugins/agent/index.ts'
|
|
5
5
|
import type {} from './plugins/extensions/index.ts'
|
|
@@ -23,7 +23,7 @@ export const routes = {
|
|
|
23
23
|
const body = await c.req.json().catch(() => undefined)
|
|
24
24
|
return typeof body === 'object' && body !== null ? (body as Record<string, unknown>) : {}
|
|
25
25
|
}
|
|
26
|
-
const app = new
|
|
26
|
+
const app = new Acryl()
|
|
27
27
|
.use(bodyLimit({ maxSize: 64 * 1024 }))
|
|
28
28
|
.get('/', (c) => c.json({ app: APP_NAME, ok: true }))
|
|
29
29
|
.get('/health', (c) => c.json({ ok: true }))
|
|
@@ -10,12 +10,12 @@ import { pinnedInstance, withPort } from '../src/plugins/instance/index.ts'
|
|
|
10
10
|
|
|
11
11
|
/** A plugin no scripted command knows: the model writes it from scratch. */
|
|
12
12
|
const COUNTER = `import type { Context } from '@deepseek-ai/cordis'
|
|
13
|
-
import {
|
|
13
|
+
import { Acryl } from 'acrylblends'
|
|
14
14
|
export const name = 'counter'
|
|
15
15
|
export const inject = ['router']
|
|
16
16
|
export function apply(ctx: Context) {
|
|
17
17
|
let count = 0
|
|
18
|
-
ctx.router.route('/', new
|
|
18
|
+
ctx.router.route('/', new Acryl().get('/count', (c) => c.json({ count: ++count })))
|
|
19
19
|
}
|
|
20
20
|
`
|
|
21
21
|
|
|
@@ -13,6 +13,46 @@
|
|
|
13
13
|
"skipLibCheck": true,
|
|
14
14
|
"types": ["node"],
|
|
15
15
|
"paths": {
|
|
16
|
+
"acrylblends": ["./src/plugins/acryl-router/src/index.ts"],
|
|
17
|
+
"acrylblends/conninfo": ["./src/plugins/acryl-router/src/index.ts"],
|
|
18
|
+
"acrylblends/http-exception": ["./src/plugins/acryl-router/src/index.ts"],
|
|
19
|
+
"acrylblends/types": ["./src/plugins/acryl-router/src/index.ts"],
|
|
20
|
+
"acrylblends/client": ["./src/plugins/acryl-router/src/client.ts"],
|
|
21
|
+
"acrylblends/basic-auth": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
22
|
+
"acrylblends/bearer-auth": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
23
|
+
"acrylblends/body-limit": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
24
|
+
"acrylblends/combine": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
25
|
+
"acrylblends/compress": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
26
|
+
"acrylblends/context-storage": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
27
|
+
"acrylblends/cors": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
28
|
+
"acrylblends/csrf": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
29
|
+
"acrylblends/etag": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
30
|
+
"acrylblends/ip-restriction": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
31
|
+
"acrylblends/jwk": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
32
|
+
"acrylblends/jwt": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
33
|
+
"acrylblends/language": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
34
|
+
"acrylblends/logger": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
35
|
+
"acrylblends/loopback-only": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
36
|
+
"acrylblends/method-not-allowed": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
37
|
+
"acrylblends/method-override": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
38
|
+
"acrylblends/powered-by": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
39
|
+
"acrylblends/pretty-json": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
40
|
+
"acrylblends/request-id": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
41
|
+
"acrylblends/secure-headers": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
42
|
+
"acrylblends/serve-static": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
43
|
+
"acrylblends/timeout": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
44
|
+
"acrylblends/timing": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
45
|
+
"acrylblends/trailing-slash": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
46
|
+
"acrylblends/accepts": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
47
|
+
"acrylblends/cookie": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
48
|
+
"acrylblends/factory": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
49
|
+
"acrylblends/html": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
50
|
+
"acrylblends/route": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
51
|
+
"acrylblends/schema-validator": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
52
|
+
"acrylblends/streaming": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
53
|
+
"acrylblends/testing": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
54
|
+
"acrylblends/validator": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
55
|
+
"acrylblends/ws": ["./src/plugins/acryl-router/src/helpers/index.ts"],
|
|
16
56
|
"acryl-router": ["./src/plugins/acryl-router/src/index.ts"],
|
|
17
57
|
"acryl-router/middleware": ["./src/plugins/acryl-router/src/middleware/index.ts"],
|
|
18
58
|
"acryl-router/helpers": ["./src/plugins/acryl-router/src/helpers/index.ts"]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Context } from '@deepseek-ai/cordis'
|
|
2
|
-
import {
|
|
2
|
+
import { Acryl } from './plugins/acryl-router/src/index.ts'
|
|
3
3
|
|
|
4
4
|
export const APP_NAME = '__APP_NAME__'
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ export const routes = {
|
|
|
8
8
|
name: 'routes',
|
|
9
9
|
inject: ['router'],
|
|
10
10
|
apply(ctx: Context) {
|
|
11
|
-
const app = new
|
|
11
|
+
const app = new Acryl()
|
|
12
12
|
.get('/', (c) => c.json({ app: APP_NAME, ok: true }))
|
|
13
13
|
.get('/health', (c) => c.json({ ok: true }))
|
|
14
14
|
ctx.router.route('/', app)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs'
|
|
7
7
|
import { dirname } from 'node:path'
|
|
8
8
|
import type { Context } from '@deepseek-ai/cordis'
|
|
9
|
-
import {
|
|
9
|
+
import { Acryl, HTTPException } from './plugins/acryl-router/src/index.ts'
|
|
10
10
|
import { bodyLimit, loopbackOnly, trimTrailingSlash } from './plugins/acryl-router/src/middleware/index.ts'
|
|
11
11
|
import { schemaValidator, streamSSE, type StandardSchema } from './plugins/acryl-router/src/helpers/index.ts'
|
|
12
12
|
import type {} from './plugins/acryl-state/src/index.ts'
|
|
@@ -86,7 +86,7 @@ export function apply(ctx: Context, config: Config = {}): void {
|
|
|
86
86
|
|
|
87
87
|
// `/todo/` is what people type: trimTrailingSlash answers a GET for an unknown path ending in `/` with a 301 to the path without it,
|
|
88
88
|
// so the page is found either way while each route keeps one canonical path (the router itself treats `/a` and `/a/` as different).
|
|
89
|
-
const api = new
|
|
89
|
+
const api = new Acryl()
|
|
90
90
|
.use(loopbackOnly({ inProcess: 'allow' }), bodyLimit({ maxSize: MAX_BODY_BYTES }), trimTrailingSlash())
|
|
91
91
|
.get('/', c => c.html(PAGE))
|
|
92
92
|
.get('/api', c => c.json(todos.get()))
|