acrylblends 1.0.4 → 1.0.6
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/docs/framework/agents/index.md +7 -5
- package/lib/accept-CNNHu4Cf.js +193 -0
- package/lib/{accepts-XBuZPVRI.js → accepts-Btq83xPd.js} +1 -1
- package/lib/accepts.js +1 -1
- package/lib/acryl-base.js +1 -331
- package/lib/adapter-CaZ6FZUU.js +37 -0
- package/lib/adapter.js +1 -36
- package/lib/{app-BM0rTCp7.js → app-CQcGWjrk.js} +4 -4
- package/lib/app-base-CpRMZL4v.js +332 -0
- package/lib/{audit-D5z9uwOP.d.ts → audit-GcLtvNLV.d.ts} +4 -2
- package/lib/{base-NSN_SNv-.js → base-D_6kfOr-.js} +1 -1
- package/lib/basic-auth-C0HTRpXh.js +20 -0
- package/lib/basic-auth-DFLflXNe.js +95 -0
- package/lib/basic-auth.js +1 -94
- package/lib/bearer-auth-Cwxt-vgS.js +94 -0
- package/lib/bearer-auth.js +1 -93
- package/lib/body-D7f4e7w_.js +94 -0
- package/lib/body-limit-WmIjWRLt.js +66 -0
- package/lib/body-limit.js +1 -65
- package/lib/buffer-CkEOJCcY.js +51 -0
- package/lib/bun.js +3 -3
- package/lib/cache-B0bHH7s5.js +169 -0
- package/lib/cache.js +1 -168
- package/lib/{client-DDLXwhBo.js → client-BrMFnMEd.js} +1 -1
- package/lib/{client-modules-CLvWOjbd.js → client-modules-drj4mjhj.js} +4 -4
- package/lib/client.js +1 -1
- package/lib/color-COa3DplO.js +37 -0
- package/lib/combine-TWuGdcbC.js +137 -0
- package/lib/combine.js +1 -136
- package/lib/{components-cEW3ovK0.js → components-B2ka9Ax1.js} +4 -4
- package/lib/{components-JXVm45kK.js → components-PVXwaOaC.js} +2 -2
- package/lib/compress-BzWqsHF1.js +79 -0
- package/lib/compress-C-9vK4B2.d.ts +11 -0
- package/lib/compress-DCyrrQ5D.js +11 -0
- package/lib/compress.d.ts +1 -1
- package/lib/compress.js +2 -78
- package/lib/concurrent-DrF3d2c-.js +30 -0
- package/lib/conninfo-BCROmdnf.d.ts +11 -0
- package/lib/conninfo-CWJwieh4.js +19 -0
- package/lib/constants-CBSEudrb.js +7 -0
- package/lib/{context-DDO0cfuP.js → context-CkOh7Ygv.js} +2 -2
- package/lib/context-storage-iuPoI_CR.js +52 -0
- package/lib/context-storage.js +1 -51
- package/lib/cookie-B1LlkzOe.js +125 -0
- package/lib/cookie-BHIduy2T.js +82 -0
- package/lib/cookie.js +1 -81
- package/lib/cordis/db-sqlite.d.ts +1 -1
- package/lib/cordis/door.d.ts +99 -5
- package/lib/cordis/door.js +562 -20
- package/lib/cordis/inspect.js +4 -4
- package/lib/cordis/kv-db.d.ts +1 -1
- package/lib/cordis/kv-db.js +1 -1
- package/lib/cordis/kv-json.d.ts +1 -1
- package/lib/cordis/kv-json.js +1 -1
- package/lib/cordis/node-server.d.ts +1 -1
- package/lib/cordis/node-server.js +3 -116
- package/lib/cordis/router-http.js +2 -2
- package/lib/cordis/router.js +4 -4
- package/lib/cordis/state.js +7 -7
- package/lib/{core-CaY8XDZ6.js → core-BOu1jYua.js} +1 -1
- package/lib/cors-CbAQ-8qU.js +106 -0
- package/lib/cors.js +1 -105
- package/lib/crypto-iVP-N-tS.js +34 -0
- package/lib/csrf-DqqOZtgy.js +101 -0
- package/lib/csrf.js +1 -100
- package/lib/css-C5CPVMvM.js +134 -0
- package/lib/css.js +2 -133
- package/lib/db/sqlite.d.ts +1 -25
- package/lib/dev-CLgu-JRe.js +50 -0
- package/lib/dev.js +1 -49
- package/lib/dom-YjND9Jt3.js +74 -0
- package/lib/door/host.d.ts +2 -2
- package/lib/door/host.js +1 -1
- package/lib/door/page.d.ts +3 -1
- package/lib/door/page.js +2 -2
- package/lib/door/protocol.d.ts +1 -1
- package/lib/door/protocol.js +1 -212
- package/lib/encode-BhbNLrjp.js +33 -0
- package/lib/factory-CLdSf-xS.js +30 -0
- package/lib/factory.js +1 -29
- package/lib/handler-C0wZ0KwO.js +12 -0
- package/lib/helpers-BEjcdbgw.js +5 -0
- package/lib/{hooks-w72iLeFR.js → hooks-CfC07ri0.js} +1 -1
- package/lib/html-CgNa89xw.js +31 -0
- package/lib/html-DGExBFNg.js +103 -0
- package/lib/html.d.ts +2 -5
- package/lib/html.js +2 -30
- package/lib/http-exception-MjWkT89V.js +54 -0
- package/lib/http-exception.js +1 -53
- package/lib/index-dAzQsJG9.d.ts +6 -0
- package/lib/index.js +3 -3
- package/lib/ip-restriction-jKtKCRM_.js +166 -0
- package/lib/ip-restriction.js +1 -165
- package/lib/ipaddr-DCoIo528.js +238 -0
- package/lib/jsx/dom/client.js +1 -1
- package/lib/jsx/dom/jsx-dev-runtime.js +1 -1
- package/lib/jsx/dom/jsx-runtime.js +2 -1
- package/lib/jsx/dom/server.js +3 -3
- package/lib/jsx/dom.js +5 -73
- package/lib/jsx/jsx-dev-runtime.d.ts +2 -5
- package/lib/jsx/jsx-dev-runtime.js +2 -13
- package/lib/jsx/jsx-runtime.d.ts +2 -2
- package/lib/jsx/jsx-runtime.js +4 -4
- package/lib/jsx/streaming.js +1 -1
- package/lib/jsx-CUQgttxU.js +47 -0
- package/lib/jsx-dev-runtime-B4WTyq8r.js +14 -0
- package/lib/{jsx-dev-runtime-CWLRA2F3.js → jsx-dev-runtime-BLfA-EhI.js} +2 -2
- package/lib/jsx-dev-runtime-CGt4kNYr.d.ts +6 -0
- package/lib/jsx-renderer-CfifM4hT.js +99 -0
- package/lib/jsx-renderer.js +1 -98
- package/lib/jsx-runtime-COCRWBJ9.js +2 -0
- package/lib/jsx.js +5 -46
- package/lib/{jwk-LkzeoaU8.js → jwk-CDPpYQpD.js} +3 -3
- package/lib/jwk.js +1 -1
- package/lib/{jwt-BGJBw5AF.js → jwt-BXoIA2fQ.js} +2 -2
- package/lib/{jwt-CskdhEW9.js → jwt-lyS4Q3mT.js} +3 -3
- package/lib/jwt.js +2 -2
- package/lib/kv/db.d.ts +1 -10
- package/lib/kv/db.js +1 -56
- package/lib/kv/json.d.ts +1 -9
- package/lib/kv/json.js +1 -223
- package/lib/{language-D9a4zqvn.js → language-DeGRtLJt.js} +2 -2
- package/lib/language.js +1 -1
- package/lib/{linear-router-C3FPib6h.js → linear-router-CmZn_JLV.js} +2 -2
- package/lib/logger-Ckxu8diz.js +54 -0
- package/lib/logger.js +1 -53
- package/lib/loopback-only-BbasoF7R.js +90 -0
- package/lib/loopback-only.js +1 -89
- package/lib/method-not-allowed-TO2_hnfl.js +82 -0
- package/lib/method-not-allowed.js +1 -81
- package/lib/method-override-DnZKfJbV.js +103 -0
- package/lib/method-override.js +1 -102
- package/lib/middleware-BfG_fp8P.js +12 -0
- package/lib/mime-BnScXkQn.js +77 -0
- package/lib/mount-QkK_3NtJ.js +67 -0
- package/lib/mount.js +1 -66
- package/lib/node-server/conninfo.d.ts +1 -10
- package/lib/node-server/conninfo.js +1 -18
- package/lib/node-server/register.js +25 -2
- package/lib/node-server/serve-static.d.ts +1 -17
- package/lib/node-server/serve-static.js +1 -1
- package/lib/node-server.d.ts +2 -2
- package/lib/node-server.js +4 -4
- package/lib/open-BqK4D2Wn.d.ts +11 -0
- package/lib/open-But9E2rL.js +57 -0
- package/lib/open-CULVJgOc.d.ts +12 -0
- package/lib/open-Dp4sxspc.js +224 -0
- package/lib/open-T7kgbO2O.d.ts +27 -0
- package/lib/{pattern-router-HZxjDGEQ.js → pattern-router-CJBecJBd.js} +1 -1
- package/lib/powered-by-CXQNjNIX.js +24 -0
- package/lib/powered-by.js +1 -23
- package/lib/pretty-json-CeC1yvYt.js +39 -0
- package/lib/pretty-json.js +1 -38
- package/lib/{protocol-C37gPePD.d.ts → protocol-CR31M7K_.d.ts} +2 -0
- package/lib/protocol-Dt0AZBOz.js +213 -0
- package/lib/proxy-C2w_mH7k.js +121 -0
- package/lib/proxy.js +1 -120
- package/lib/quick.js +4 -4
- package/lib/{reg-exp-router-DC1R3qoY.js → reg-exp-router-C_WV84eV.js} +2 -2
- package/lib/request-DvMgGtlW.js +323 -0
- package/lib/request.js +1 -322
- package/lib/route-D8m-a2I1.js +126 -0
- package/lib/route.js +1 -125
- package/lib/router/linear-router.js +1 -1
- package/lib/router/pattern-router.js +1 -1
- package/lib/router/reg-exp-router.js +1 -1
- package/lib/router/smart-router.js +1 -1
- package/lib/router/trie-router.js +1 -1
- package/lib/router-Be_o6nFu.js +35 -0
- package/lib/router.js +1 -34
- package/lib/schema-validator-EK3cUUCt.js +22 -0
- package/lib/schema-validator.js +1 -21
- package/lib/{secure-headers-mP3j6Hm6.js → secure-headers-C5ZOcXqk.js} +1 -1
- package/lib/secure-headers.js +1 -1
- package/lib/serve-static-B7sqnftW.d.ts +18 -0
- package/lib/{serve-static-3uo_9rjF.js → serve-static-C1Nkj_xB.js} +2 -2
- package/lib/{serve-static-Cp5adzGo.js → serve-static-EiJf1zkO.js} +4 -4
- package/lib/serve-static.js +1 -1
- package/lib/{smart-router-C5CZ5XSM.js → smart-router-BjxkDQCE.js} +1 -1
- package/lib/{snapshot-text-BLz8nlSc.js → snapshot-text-CtQm3n8n.js} +23 -14
- package/lib/{src-dy3Fk9tA.js → src-BTBm4OPD.js} +6 -6
- package/lib/src-LX0E4ec4.js +117 -0
- package/lib/{ssg-BwjcA-Ge.js → ssg-BEl7MHqg.js} +5 -5
- package/lib/ssg.js +1 -1
- package/lib/stream-CzM_SHkq.js +88 -0
- package/lib/{streaming-DHST3Scg.js → streaming-BlDaph8U.js} +3 -3
- package/lib/streaming.js +1 -1
- package/lib/{test-websocket-D8WWqE5G.js → test-websocket-BLeEvybj.js} +2 -2
- package/lib/testing-BQx5T_UX.js +17 -0
- package/lib/testing.js +1 -16
- package/lib/timeout-FeqZ9A-0.js +42 -0
- package/lib/timeout.js +1 -41
- package/lib/tiny.js +2 -2
- package/lib/trailing-slash-DwTx-1sk.js +85 -0
- package/lib/trailing-slash.js +1 -84
- package/lib/{trie-router-CfFbapzL.js → trie-router-JydLKUa2.js} +2 -2
- package/lib/url-BPh4d6j-.js +197 -0
- package/lib/utils/accept.js +1 -192
- package/lib/utils/basic-auth.js +1 -19
- package/lib/utils/body.js +1 -93
- package/lib/utils/buffer.js +1 -50
- package/lib/utils/color.js +1 -36
- package/lib/utils/compress.d.ts +1 -10
- package/lib/utils/compress.js +1 -10
- package/lib/utils/concurrent.js +1 -29
- package/lib/utils/constants.js +1 -6
- package/lib/utils/cookie.js +1 -124
- package/lib/utils/crypto.js +1 -33
- package/lib/utils/encode.js +1 -32
- package/lib/utils/handler.js +1 -11
- package/lib/utils/html.js +1 -102
- package/lib/utils/ipaddr.js +1 -237
- package/lib/utils/jwt.js +1 -1
- package/lib/utils/mime.js +1 -76
- package/lib/utils/stream.js +1 -87
- package/lib/utils/url.js +1 -196
- package/lib/{validator-D84mq-dO.js → validator-Btiyt5VJ.js} +3 -3
- package/lib/validator.js +1 -1
- package/lib/websocket-DsyBIKVA.js +56 -0
- package/lib/ws.js +1 -55
- package/package.json +1 -1
- package/plugins/acryl-door/src/cli/acryl.ts +36 -5
- package/plugins/acryl-door/src/host/channel.ts +14 -6
- package/plugins/acryl-door/src/host/chat-tools.ts +2 -0
- package/plugins/acryl-door/src/host/door.ts +97 -12
- package/plugins/acryl-door/src/host/page-routes.ts +3 -1
- package/plugins/acryl-door/src/host/shell.ts +147 -0
- package/plugins/acryl-door/src/host/shim.ts +39 -3
- package/plugins/acryl-door/src/host/verbs.ts +39 -2
- package/plugins/acryl-door/src/index.ts +22 -3
- package/plugins/acryl-door/src/page/channel.ts +3 -1
- package/plugins/acryl-door/src/page/index.ts +2 -1
- package/plugins/acryl-door/src/page/protocol.ts +2 -0
- package/plugins/acryl-door/src/shell/protocol.ts +130 -0
- package/plugins/acryl-node-server/src/register.ts +29 -2
- package/plugins/agent/model.ts +6 -1
- package/plugins/agent/tools.ts +12 -2
- package/plugins/agent-panel/client/describe.ts +44 -0
- package/plugins/agent-panel/client/main.ts +4 -1
- package/plugins/agent-panel/headless.ts +29 -8
- package/plugins/agent-panel/index.ts +22 -10
- package/plugins/agent-panel/launch.ts +67 -0
- package/plugins/desktop/attach.ts +72 -0
- package/plugins/desktop/door-shell.ts +379 -0
- package/plugins/desktop/main.ts +82 -15
- package/plugins/extensions/index.ts +3 -4
- package/plugins/extensions/stage.ts +33 -5
- package/plugins/openai/index.ts +1 -1
- package/templates/agent/AGENTS.md +4 -0
- package/templates/agent/blend.yaml +4 -1
- package/templates/agent/src/app.ts +2 -0
- package/templates/agent/src/routes.ts +1 -1
- package/templates/agent/template.json +1 -0
- package/templates/agent/test/builder.test.ts +26 -21
- package/lib/helpers-CvTauQT5.js +0 -5
- package/lib/middleware-CPQ8himN.js +0 -12
- package/plugins/acryl-router/src/connection.d.ts +0 -25
- package/plugins/acryl-router/src/core/app-base.d.ts +0 -215
- package/plugins/acryl-router/src/core/app.d.ts +0 -19
- package/plugins/acryl-router/src/core/client/client.d.ts +0 -4
- package/plugins/acryl-router/src/core/client/fetch-result-please.d.ts +0 -35
- package/plugins/acryl-router/src/core/client/index.d.ts +0 -7
- package/plugins/acryl-router/src/core/client/types.d.ts +0 -229
- package/plugins/acryl-router/src/core/client/utils.d.ts +0 -18
- package/plugins/acryl-router/src/core/compose.d.ts +0 -14
- package/plugins/acryl-router/src/core/context.d.ts +0 -443
- package/plugins/acryl-router/src/core/helper/accepts/accepts.d.ts +0 -30
- package/plugins/acryl-router/src/core/helper/accepts/index.d.ts +0 -5
- package/plugins/acryl-router/src/core/helper/conninfo/index.d.ts +0 -5
- package/plugins/acryl-router/src/core/helper/conninfo/types.d.ts +0 -36
- package/plugins/acryl-router/src/core/helper/cookie/index.d.ts +0 -25
- package/plugins/acryl-router/src/core/helper/css/common.d.ts +0 -59
- package/plugins/acryl-router/src/core/helper/css/index.d.ts +0 -80
- package/plugins/acryl-router/src/core/helper/dev/index.d.ts +0 -20
- package/plugins/acryl-router/src/core/helper/factory/index.d.ts +0 -82
- package/plugins/acryl-router/src/core/helper/html/index.d.ts +0 -8
- package/plugins/acryl-router/src/core/helper/proxy/index.d.ts +0 -73
- package/plugins/acryl-router/src/core/helper/route/index.d.ts +0 -75
- package/plugins/acryl-router/src/core/helper/ssg/index.d.ts +0 -7
- package/plugins/acryl-router/src/core/helper/ssg/middleware.d.ts +0 -44
- package/plugins/acryl-router/src/core/helper/ssg/plugins.d.ts +0 -27
- package/plugins/acryl-router/src/core/helper/ssg/ssg.d.ts +0 -91
- package/plugins/acryl-router/src/core/helper/ssg/utils.d.ts +0 -16
- package/plugins/acryl-router/src/core/helper/streaming/index.d.ts +0 -8
- package/plugins/acryl-router/src/core/helper/streaming/sse.d.ts +0 -13
- package/plugins/acryl-router/src/core/helper/streaming/stream.d.ts +0 -3
- package/plugins/acryl-router/src/core/helper/streaming/text.d.ts +0 -3
- package/plugins/acryl-router/src/core/helper/streaming/utils.d.ts +0 -1
- package/plugins/acryl-router/src/core/helper/testing/index.d.ts +0 -13
- package/plugins/acryl-router/src/core/helper/websocket/index.d.ts +0 -70
- package/plugins/acryl-router/src/core/http-exception.d.ts +0 -58
- package/plugins/acryl-router/src/core/index.d.ts +0 -37
- package/plugins/acryl-router/src/core/jsx/base.d.ts +0 -61
- package/plugins/acryl-router/src/core/jsx/children.d.ts +0 -9
- package/plugins/acryl-router/src/core/jsx/components.d.ts +0 -15
- package/plugins/acryl-router/src/core/jsx/constants.d.ts +0 -6
- package/plugins/acryl-router/src/core/jsx/context.d.ts +0 -51
- package/plugins/acryl-router/src/core/jsx/dom/components.d.ts +0 -10
- package/plugins/acryl-router/src/core/jsx/dom/context.d.ts +0 -3
- package/plugins/acryl-router/src/core/jsx/dom/css.d.ts +0 -83
- package/plugins/acryl-router/src/core/jsx/dom/hooks/index.d.ts +0 -39
- package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.d.ts +0 -16
- package/plugins/acryl-router/src/core/jsx/dom/jsx-dev-runtime.d.ts +0 -8
- package/plugins/acryl-router/src/core/jsx/dom/jsx-runtime.d.ts +0 -7
- package/plugins/acryl-router/src/core/jsx/dom/render.d.ts +0 -73
- package/plugins/acryl-router/src/core/jsx/dom/utils.d.ts +0 -1
- package/plugins/acryl-router/src/core/jsx/hooks/index.d.ts +0 -47
- package/plugins/acryl-router/src/core/jsx/index.d.ts +0 -76
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/common.d.ts +0 -6
- package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.d.ts +0 -13
- package/plugins/acryl-router/src/core/jsx/intrinsic-elements.d.ts +0 -735
- package/plugins/acryl-router/src/core/jsx/streaming.d.ts +0 -36
- package/plugins/acryl-router/src/core/jsx/types.d.ts +0 -36
- package/plugins/acryl-router/src/core/jsx/utils.d.ts +0 -4
- package/plugins/acryl-router/src/core/request/constants.d.ts +0 -1
- package/plugins/acryl-router/src/core/request.d.ts +0 -306
- package/plugins/acryl-router/src/core/router/reg-exp-router/index.d.ts +0 -6
- package/plugins/acryl-router/src/core/router/reg-exp-router/matcher.d.ts +0 -7
- package/plugins/acryl-router/src/core/router/reg-exp-router/node.d.ts +0 -13
- package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.d.ts +0 -17
- package/plugins/acryl-router/src/core/router/reg-exp-router/router.d.ts +0 -11
- package/plugins/acryl-router/src/core/router/reg-exp-router/trie.d.ts +0 -8
- package/plugins/acryl-router/src/core/router/smart-router/index.d.ts +0 -5
- package/plugins/acryl-router/src/core/router/smart-router/router.d.ts +0 -11
- package/plugins/acryl-router/src/core/router/trie-router/index.d.ts +0 -5
- package/plugins/acryl-router/src/core/router/trie-router/node.d.ts +0 -6
- package/plugins/acryl-router/src/core/router/trie-router/router.d.ts +0 -7
- package/plugins/acryl-router/src/core/router/utils.d.ts +0 -1
- package/plugins/acryl-router/src/core/router.d.ts +0 -97
- package/plugins/acryl-router/src/core/types.d.ts +0 -573
- package/plugins/acryl-router/src/core/utils/accept.d.ts +0 -6
- package/plugins/acryl-router/src/core/utils/body.d.ts +0 -79
- package/plugins/acryl-router/src/core/utils/buffer.d.ts +0 -17
- package/plugins/acryl-router/src/core/utils/color.d.ts +0 -21
- package/plugins/acryl-router/src/core/utils/concurrent.d.ts +0 -11
- package/plugins/acryl-router/src/core/utils/constants.d.ts +0 -4
- package/plugins/acryl-router/src/core/utils/cookie.d.ts +0 -41
- package/plugins/acryl-router/src/core/utils/crypto.d.ts +0 -15
- package/plugins/acryl-router/src/core/utils/handler.d.ts +0 -6
- package/plugins/acryl-router/src/core/utils/headers.d.ts +0 -8
- package/plugins/acryl-router/src/core/utils/html.d.ts +0 -44
- package/plugins/acryl-router/src/core/utils/http-status.d.ts +0 -32
- package/plugins/acryl-router/src/core/utils/mime.d.ts +0 -70
- package/plugins/acryl-router/src/core/utils/stream.d.ts +0 -31
- package/plugins/acryl-router/src/core/utils/types.d.ts +0 -128
- package/plugins/acryl-router/src/core/utils/url.d.ts +0 -44
- package/plugins/acryl-router/src/core/validator/index.d.ts +0 -7
- package/plugins/acryl-router/src/core/validator/utils.d.ts +0 -29
- package/plugins/acryl-router/src/core/validator/validator.d.ts +0 -16
- package/plugins/acryl-router/src/helpers/index.d.ts +0 -17
- package/plugins/acryl-router/src/helpers/schema-validator.d.ts +0 -54
package/lib/kv/json.js
CHANGED
|
@@ -1,224 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdir, open, readFile, readdir, rename, rm } from "node:fs/promises";
|
|
3
|
-
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
-
//#region ../../plugins/acryl-kv-json/src/open.ts
|
|
5
|
-
/**
|
|
6
|
-
* The plain way to open the JSON-file provider, for code without Cordis (an acrylblends app): `openKv({ path })` reads one JSON file into
|
|
7
|
-
* memory and resolves the `kv` port with the function that closes it. The Cordis plugin is a thin wrapper over this, so both run one code
|
|
8
|
-
* path. This entry imports nothing from Cordis.
|
|
9
|
-
*
|
|
10
|
-
* Every write persists the whole map: serialize to a temporary file in the same folder, flush it, rename it over the file, and flush the
|
|
11
|
-
* folder where the platform allows. The call resolves after the rename, so a crash leaves the old file or the new one, never half of one.
|
|
12
|
-
* Writes are grouped: the calls made in one turn of the event loop, and those that queue while a file write is in flight, are applied in
|
|
13
|
-
* call order and persisted together by one write, so a burst of calls costs one flush and one rename, not one each (on Windows each costs
|
|
14
|
-
* tens of milliseconds). One process owns the
|
|
15
|
-
* file: two writers would overwrite each other.
|
|
16
|
-
*/
|
|
17
|
-
/** The file's own format version, for a later change of layout. */
|
|
18
|
-
const FORMAT = 1;
|
|
19
|
-
/** Stray temporary files from a crash end in `.tmp` and start with the file's name. */
|
|
20
|
-
const tempPrefix = (file) => `${basename(file)}.`;
|
|
21
|
-
/** The file content for a map of key to JSON text, keys in code point order, so the same data is the same bytes. */
|
|
22
|
-
function serialize(entries) {
|
|
23
|
-
const body = [...entries.keys()].sort(compareKeys).map((key) => `${JSON.stringify(key)}:${entries.get(key)}`).join(",");
|
|
24
|
-
return `{"version":${FORMAT},"entries":{${body}}}\n`;
|
|
25
|
-
}
|
|
26
|
-
function unreadable(file, reason) {
|
|
27
|
-
return /* @__PURE__ */ new Error(`acryl-kv-json: ${file} is not a readable kv file (${reason}); it was not changed`);
|
|
28
|
-
}
|
|
29
|
-
/** The entries of a file, or none when it does not exist. A file that exists and does not parse is an error: it is never started over. */
|
|
30
|
-
async function load(file) {
|
|
31
|
-
let text;
|
|
32
|
-
try {
|
|
33
|
-
text = await readFile(file, "utf8");
|
|
34
|
-
} catch (error) {
|
|
35
|
-
if (error.code === "ENOENT") return /* @__PURE__ */ new Map();
|
|
36
|
-
throw error;
|
|
37
|
-
}
|
|
38
|
-
let parsed;
|
|
39
|
-
try {
|
|
40
|
-
parsed = JSON.parse(text);
|
|
41
|
-
} catch (error) {
|
|
42
|
-
throw unreadable(file, error.message);
|
|
43
|
-
}
|
|
44
|
-
if (typeof parsed !== "object" || parsed === null || parsed.version !== FORMAT) throw unreadable(file, "not a version 1 kv file");
|
|
45
|
-
const entries = parsed.entries;
|
|
46
|
-
if (typeof entries !== "object" || entries === null || Array.isArray(entries)) throw unreadable(file, "no entries object");
|
|
47
|
-
return new Map(Object.entries(entries).map(([key, value]) => [key, JSON.stringify(value)]));
|
|
48
|
-
}
|
|
49
|
-
/** Remove the temporary files an earlier crash left beside the file. */
|
|
50
|
-
async function removeStrays(file) {
|
|
51
|
-
const prefix = tempPrefix(file);
|
|
52
|
-
for (const name of await readdir(dirname(file))) if (name.startsWith(prefix) && name.endsWith(".tmp")) await rm(join(dirname(file), name), { force: true });
|
|
53
|
-
}
|
|
54
|
-
const RENAME_RETRIES = 8;
|
|
55
|
-
/** Rename over the target. Windows refuses while a scanner or an indexer holds the target for a moment, so it is retried briefly. */
|
|
56
|
-
async function replace(from, to) {
|
|
57
|
-
for (let attempt = 0;; attempt += 1) try {
|
|
58
|
-
await rename(from, to);
|
|
59
|
-
return;
|
|
60
|
-
} catch (error) {
|
|
61
|
-
const code = error.code;
|
|
62
|
-
if (attempt >= RENAME_RETRIES || code !== "EPERM" && code !== "EBUSY" && code !== "EACCES") throw error;
|
|
63
|
-
await new Promise((resolveWait) => setTimeout(resolveWait, 10 * (attempt + 1)));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/** Flush the folder entry of a renamed file (POSIX); Windows cannot open a folder, and a filesystem that refuses is no worse than before. */
|
|
67
|
-
async function flushFolder(folder) {
|
|
68
|
-
if (process.platform === "win32") return;
|
|
69
|
-
try {
|
|
70
|
-
const handle = await open(folder, "r");
|
|
71
|
-
try {
|
|
72
|
-
await handle.sync();
|
|
73
|
-
} finally {
|
|
74
|
-
await handle.close();
|
|
75
|
-
}
|
|
76
|
-
} catch {}
|
|
77
|
-
}
|
|
78
|
-
/** Open (and create, when missing) a JSON-file store. @throws when the file exists and is not a readable kv file. */
|
|
79
|
-
async function openKv(options) {
|
|
80
|
-
const file = resolve(options.path);
|
|
81
|
-
await mkdir(dirname(file), { recursive: true });
|
|
82
|
-
await removeStrays(file);
|
|
83
|
-
let state = await load(file);
|
|
84
|
-
let closed = false;
|
|
85
|
-
let sequence = 0;
|
|
86
|
-
/** Calls waiting for the next file write, in call order. */
|
|
87
|
-
let queue = [];
|
|
88
|
-
/** Whether the loop that writes the queue runs; cleared by the loop itself, so a call queued after it ends starts a new one. */
|
|
89
|
-
let draining = false;
|
|
90
|
-
/** The latest loop, for `close` to wait on. */
|
|
91
|
-
let drained = Promise.resolve();
|
|
92
|
-
const guard = () => {
|
|
93
|
-
if (closed) throw new Error(`acryl-kv-json: ${file} is closed`);
|
|
94
|
-
};
|
|
95
|
-
/** Persist a map: the file is the old one or this one, never between. */
|
|
96
|
-
const persist = async (next) => {
|
|
97
|
-
sequence += 1;
|
|
98
|
-
const temp = join(dirname(file), `${tempPrefix(file)}${process.pid}.${sequence}.tmp`);
|
|
99
|
-
try {
|
|
100
|
-
const handle = await open(temp, "w");
|
|
101
|
-
try {
|
|
102
|
-
await handle.writeFile(serialize(next), "utf8");
|
|
103
|
-
await handle.sync();
|
|
104
|
-
} finally {
|
|
105
|
-
await handle.close();
|
|
106
|
-
}
|
|
107
|
-
await replace(temp, file);
|
|
108
|
-
} catch (error) {
|
|
109
|
-
await rm(temp, { force: true });
|
|
110
|
-
throw error;
|
|
111
|
-
}
|
|
112
|
-
await flushFolder(dirname(file));
|
|
113
|
-
};
|
|
114
|
-
/**
|
|
115
|
-
* Write the queue until it is empty. Each round takes every call queued so far and applies them in order to one copy of the state. A call
|
|
116
|
-
* whose change throws rejects with its error and changes nothing, and the others in the round still apply. The copy becomes the state
|
|
117
|
-
* only once it is on disk. A failed file write rejects every call in its round and leaves the state as it was.
|
|
118
|
-
*/
|
|
119
|
-
const drain = async () => {
|
|
120
|
-
try {
|
|
121
|
-
await Promise.resolve();
|
|
122
|
-
await rounds();
|
|
123
|
-
} finally {
|
|
124
|
-
draining = false;
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
const rounds = async () => {
|
|
128
|
-
while (queue.length > 0) {
|
|
129
|
-
const round = queue;
|
|
130
|
-
queue = [];
|
|
131
|
-
const draft = new Map(state);
|
|
132
|
-
const applied = [];
|
|
133
|
-
for (const call of round) {
|
|
134
|
-
let change;
|
|
135
|
-
try {
|
|
136
|
-
change = call.change((key) => draft.get(key));
|
|
137
|
-
} catch (error) {
|
|
138
|
-
call.reject(error);
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (change.text === void 0) draft.delete(change.key);
|
|
142
|
-
else draft.set(change.key, change.text);
|
|
143
|
-
applied.push({
|
|
144
|
-
call,
|
|
145
|
-
result: change.result
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
if (applied.length === 0) continue;
|
|
149
|
-
try {
|
|
150
|
-
await persist(draft);
|
|
151
|
-
} catch (error) {
|
|
152
|
-
for (const { call } of applied) call.reject(error);
|
|
153
|
-
continue;
|
|
154
|
-
}
|
|
155
|
-
state = draft;
|
|
156
|
-
for (const { call, result } of applied) call.resolve(result);
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
/** Queue one change behind every earlier call; it resolves once a file write that contains it is on disk. */
|
|
160
|
-
const write = (change) => {
|
|
161
|
-
guard();
|
|
162
|
-
const done = new Promise((resolveCall, rejectCall) => {
|
|
163
|
-
queue.push({
|
|
164
|
-
change,
|
|
165
|
-
resolve: resolveCall,
|
|
166
|
-
reject: rejectCall
|
|
167
|
-
});
|
|
168
|
-
});
|
|
169
|
-
if (!draining) {
|
|
170
|
-
draining = true;
|
|
171
|
-
drained = drain();
|
|
172
|
-
}
|
|
173
|
-
return done;
|
|
174
|
-
};
|
|
175
|
-
return {
|
|
176
|
-
kv: {
|
|
177
|
-
async get(key) {
|
|
178
|
-
guard();
|
|
179
|
-
checkKey(key);
|
|
180
|
-
const text = state.get(key);
|
|
181
|
-
return text === void 0 ? void 0 : decodeValue(text);
|
|
182
|
-
},
|
|
183
|
-
async set(key, value) {
|
|
184
|
-
checkKey(key);
|
|
185
|
-
const text = encodeValue(value);
|
|
186
|
-
await write(() => ({
|
|
187
|
-
key,
|
|
188
|
-
text,
|
|
189
|
-
result: void 0
|
|
190
|
-
}));
|
|
191
|
-
},
|
|
192
|
-
async update(key, change) {
|
|
193
|
-
checkKey(key);
|
|
194
|
-
return write((read) => {
|
|
195
|
-
const text = read(key);
|
|
196
|
-
const encoded = encodeValue(runChange(change, text === void 0 ? void 0 : decodeValue(text)));
|
|
197
|
-
return {
|
|
198
|
-
key,
|
|
199
|
-
text: encoded,
|
|
200
|
-
result: decodeValue(encoded)
|
|
201
|
-
};
|
|
202
|
-
});
|
|
203
|
-
},
|
|
204
|
-
async delete(key) {
|
|
205
|
-
checkKey(key);
|
|
206
|
-
await write(() => ({
|
|
207
|
-
key,
|
|
208
|
-
text: void 0,
|
|
209
|
-
result: void 0
|
|
210
|
-
}));
|
|
211
|
-
},
|
|
212
|
-
async list(prefix = "") {
|
|
213
|
-
guard();
|
|
214
|
-
return [...state.keys()].filter((key) => key.startsWith(prefix)).sort(compareKeys);
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
close: async () => {
|
|
218
|
-
closed = true;
|
|
219
|
-
await drained;
|
|
220
|
-
}
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
//#endregion
|
|
1
|
+
import { t as openKv } from "../open-Dp4sxspc.js";
|
|
224
2
|
export { openKv };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { parseAccept } from "./
|
|
2
|
-
import { getCookie, setCookie } from "./cookie.js";
|
|
1
|
+
import { t as parseAccept } from "./accept-CNNHu4Cf.js";
|
|
2
|
+
import { i as getCookie, o as setCookie } from "./cookie-BHIduy2T.js";
|
|
3
3
|
//#region ../../plugins/acryl-router/src/core/middleware/language/language.ts
|
|
4
4
|
const DEFAULT_OPTIONS = {
|
|
5
5
|
order: [
|
package/lib/language.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as languageDetector, i as detectFromQuery, n as detectFromHeader, r as detectFromPath, t as detectFromCookie } from "./language-
|
|
1
|
+
import { a as languageDetector, i as detectFromQuery, n as detectFromHeader, r as detectFromPath, t as detectFromCookie } from "./language-DeGRtLJt.js";
|
|
2
2
|
export { detectFromCookie, detectFromHeader, detectFromPath, detectFromQuery, languageDetector };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { checkOptionalParameter } from "./
|
|
2
|
-
import { UnsupportedPathError } from "./router.js";
|
|
1
|
+
import { t as checkOptionalParameter } from "./url-BPh4d6j-.js";
|
|
2
|
+
import { a as UnsupportedPathError } from "./router-Be_o6nFu.js";
|
|
3
3
|
//#region ../../plugins/acryl-router/src/core/router/linear-router/router.ts
|
|
4
4
|
const emptyParams = Object.create(null);
|
|
5
5
|
const splitPathRe = /\/(:\w+(?:{(?:(?:{[\d,]+})|[^}])+})?)|\/[^\/\?]+|(\?)/g;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { n as getColorEnabledAsync } from "./color-COa3DplO.js";
|
|
2
|
+
//#region ../../plugins/acryl-router/src/core/middleware/logger/index.ts
|
|
3
|
+
const LogPrefix = {
|
|
4
|
+
Outgoing: "-->",
|
|
5
|
+
Incoming: "<--",
|
|
6
|
+
Error: "xxx"
|
|
7
|
+
};
|
|
8
|
+
const humanize = (times) => {
|
|
9
|
+
const [delimiter, separator] = [",", "."];
|
|
10
|
+
return times.map((v) => v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter)).join(separator);
|
|
11
|
+
};
|
|
12
|
+
const time = (start) => {
|
|
13
|
+
const delta = Date.now() - start;
|
|
14
|
+
return humanize([delta < 1e3 ? delta + "ms" : Math.round(delta / 1e3) + "s"]);
|
|
15
|
+
};
|
|
16
|
+
const colorStatus = async (status) => {
|
|
17
|
+
if (await getColorEnabledAsync()) switch (status / 100 | 0) {
|
|
18
|
+
case 5: return `\x1b[31m${status}\x1b[0m`;
|
|
19
|
+
case 4: return `\x1b[33m${status}\x1b[0m`;
|
|
20
|
+
case 3: return `\x1b[36m${status}\x1b[0m`;
|
|
21
|
+
case 2: return `\x1b[32m${status}\x1b[0m`;
|
|
22
|
+
}
|
|
23
|
+
return `${status}`;
|
|
24
|
+
};
|
|
25
|
+
async function log(fn, prefix, method, path, status = 0, elapsed) {
|
|
26
|
+
fn(prefix === LogPrefix.Incoming ? `${prefix} ${method} ${path}` : `${prefix} ${method} ${path} ${await colorStatus(status)} ${elapsed}`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Logger Middleware for Acryl.
|
|
30
|
+
*
|
|
31
|
+
*
|
|
32
|
+
* @param {PrintFunc} [fn=console.log] - Optional function for customized logging behavior.
|
|
33
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const app = new Acryl()
|
|
38
|
+
*
|
|
39
|
+
* app.use(logger())
|
|
40
|
+
* app.get('/', (c) => c.text('Hello Acryl!'))
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
const logger = (fn = console.log) => {
|
|
44
|
+
return async function logger(c, next) {
|
|
45
|
+
const { method, url } = c.req;
|
|
46
|
+
const path = url.slice(url.indexOf("/", 8));
|
|
47
|
+
await log(fn, LogPrefix.Incoming, method, path);
|
|
48
|
+
const start = Date.now();
|
|
49
|
+
await next();
|
|
50
|
+
await log(fn, LogPrefix.Outgoing, method, path, c.res.status, time(start));
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
//#endregion
|
|
54
|
+
export { logger as t };
|
package/lib/logger.js
CHANGED
|
@@ -1,54 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
//#region ../../plugins/acryl-router/src/core/middleware/logger/index.ts
|
|
3
|
-
const LogPrefix = {
|
|
4
|
-
Outgoing: "-->",
|
|
5
|
-
Incoming: "<--",
|
|
6
|
-
Error: "xxx"
|
|
7
|
-
};
|
|
8
|
-
const humanize = (times) => {
|
|
9
|
-
const [delimiter, separator] = [",", "."];
|
|
10
|
-
return times.map((v) => v.replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1" + delimiter)).join(separator);
|
|
11
|
-
};
|
|
12
|
-
const time = (start) => {
|
|
13
|
-
const delta = Date.now() - start;
|
|
14
|
-
return humanize([delta < 1e3 ? delta + "ms" : Math.round(delta / 1e3) + "s"]);
|
|
15
|
-
};
|
|
16
|
-
const colorStatus = async (status) => {
|
|
17
|
-
if (await getColorEnabledAsync()) switch (status / 100 | 0) {
|
|
18
|
-
case 5: return `\x1b[31m${status}\x1b[0m`;
|
|
19
|
-
case 4: return `\x1b[33m${status}\x1b[0m`;
|
|
20
|
-
case 3: return `\x1b[36m${status}\x1b[0m`;
|
|
21
|
-
case 2: return `\x1b[32m${status}\x1b[0m`;
|
|
22
|
-
}
|
|
23
|
-
return `${status}`;
|
|
24
|
-
};
|
|
25
|
-
async function log(fn, prefix, method, path, status = 0, elapsed) {
|
|
26
|
-
fn(prefix === LogPrefix.Incoming ? `${prefix} ${method} ${path}` : `${prefix} ${method} ${path} ${await colorStatus(status)} ${elapsed}`);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Logger Middleware for Acryl.
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* @param {PrintFunc} [fn=console.log] - Optional function for customized logging behavior.
|
|
33
|
-
* @returns {MiddlewareHandler} The middleware handler function.
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* const app = new Acryl()
|
|
38
|
-
*
|
|
39
|
-
* app.use(logger())
|
|
40
|
-
* app.get('/', (c) => c.text('Hello Acryl!'))
|
|
41
|
-
* ```
|
|
42
|
-
*/
|
|
43
|
-
const logger = (fn = console.log) => {
|
|
44
|
-
return async function logger(c, next) {
|
|
45
|
-
const { method, url } = c.req;
|
|
46
|
-
const path = url.slice(url.indexOf("/", 8));
|
|
47
|
-
await log(fn, LogPrefix.Incoming, method, path);
|
|
48
|
-
const start = Date.now();
|
|
49
|
-
await next();
|
|
50
|
-
await log(fn, LogPrefix.Outgoing, method, path, c.res.status, time(start));
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
//#endregion
|
|
1
|
+
import { t as logger } from "./logger-Ckxu8diz.js";
|
|
54
2
|
export { logger };
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { t as connectionOf } from "./connection-C7xgP1hP.js";
|
|
2
|
+
import { BlockList, isIP } from "node:net";
|
|
3
|
+
//#region ../../plugins/acryl-router/src/middleware/loopback-only.ts
|
|
4
|
+
const loopback = new BlockList();
|
|
5
|
+
loopback.addSubnet("127.0.0.0", 8, "ipv4");
|
|
6
|
+
loopback.addSubnet("::1", 128, "ipv6");
|
|
7
|
+
const SAFE_METHODS = /* @__PURE__ */ new Set([
|
|
8
|
+
"GET",
|
|
9
|
+
"HEAD",
|
|
10
|
+
"OPTIONS"
|
|
11
|
+
]);
|
|
12
|
+
/**
|
|
13
|
+
* The authority a loopback request addressed: the `Host` header as a URL, or `undefined` when the request does not come from a loopback peer to the
|
|
14
|
+
* real local port, names another host, or is marked cross-site by the browser. The peer and the port come from the transport (`connectionOf(c)`), never
|
|
15
|
+
* from a header; an in-process call has neither and is refused.
|
|
16
|
+
*/
|
|
17
|
+
const LOOPBACK_HOSTNAMES = [
|
|
18
|
+
"127.0.0.1",
|
|
19
|
+
"localhost",
|
|
20
|
+
"[::1]"
|
|
21
|
+
];
|
|
22
|
+
function loopbackAuthority(c, hostnames = LOOPBACK_HOSTNAMES) {
|
|
23
|
+
const { remoteAddress, localPort } = connectionOf(c);
|
|
24
|
+
const host = c.req.header("host");
|
|
25
|
+
if (remoteAddress === void 0 || localPort === void 0 || host === void 0) return void 0;
|
|
26
|
+
const address = (remoteAddress.replace(/^\[|\]$/gu, "").split("%", 1)[0] ?? "").replace(/^::ffff:/iu, "");
|
|
27
|
+
const family = isIP(address);
|
|
28
|
+
if (family === 0 || !loopback.check(address, family === 4 ? "ipv4" : "ipv6")) return void 0;
|
|
29
|
+
let authority;
|
|
30
|
+
try {
|
|
31
|
+
authority = new URL(`http://${host}`);
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (authority.protocol !== "http:" || Number(authority.port || "80") !== localPort || !hostnames.includes(authority.hostname) || c.req.header("sec-fetch-site") === "cross-site") return void 0;
|
|
36
|
+
return authority;
|
|
37
|
+
}
|
|
38
|
+
/** Whether a changing request is acceptable by its `Origin`: absent (not a browser cross-origin change) or naming this same authority. `null` and any other origin are not. */
|
|
39
|
+
function sameOrigin(c, authority) {
|
|
40
|
+
const origin = c.req.header("origin");
|
|
41
|
+
if (origin === void 0) return true;
|
|
42
|
+
try {
|
|
43
|
+
const parsed = new URL(origin);
|
|
44
|
+
return parsed.protocol === "http:" && parsed.host === authority.host && parsed.pathname === "/";
|
|
45
|
+
} catch {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function originOf(value) {
|
|
50
|
+
if (value === void 0) return void 0;
|
|
51
|
+
try {
|
|
52
|
+
return new URL(value).origin;
|
|
53
|
+
} catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Whether the request comes from a page served by this authority itself: the `own-page` rule of {@link LoopbackOptions.callers}. */
|
|
58
|
+
function fromOwnPage(c, authority) {
|
|
59
|
+
const origin = c.req.header("origin");
|
|
60
|
+
const fetchSite = c.req.header("sec-fetch-site");
|
|
61
|
+
if (origin !== void 0 && originOf(origin) === origin && origin === authority.origin) return fetchSite === void 0 || fetchSite === "same-origin";
|
|
62
|
+
return SAFE_METHODS.has(c.req.method) && fetchSite === "same-origin" && originOf(c.req.header("referer")) === authority.origin;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Only requests from this machine to this app: loopback peer, the real port, an allowed `Host`, and for mutations a matching `Origin` (with
|
|
66
|
+
* `callers: 'own-page'`, every request from this app's own page). Everything else gets a 403.
|
|
67
|
+
*/
|
|
68
|
+
function loopbackOnly(options = {}) {
|
|
69
|
+
const mutations = options.mutations ?? "same-origin";
|
|
70
|
+
const inProcess = options.inProcess ?? "deny";
|
|
71
|
+
const ownPage = options.callers === "own-page";
|
|
72
|
+
return async (c, next) => {
|
|
73
|
+
const connection = connectionOf(c);
|
|
74
|
+
if (inProcess === "allow" && connection.remoteAddress === void 0 && connection.localPort === void 0) {
|
|
75
|
+
await next();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const authority = loopbackAuthority(c, options.hostnames);
|
|
79
|
+
if (authority === void 0) return c.json({ error: "request authority rejected" }, 403);
|
|
80
|
+
if (ownPage) {
|
|
81
|
+
if (!fromOwnPage(c, authority)) return c.json({ error: "only this app's own page may call this" }, 403);
|
|
82
|
+
await next();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (mutations === "same-origin" && !SAFE_METHODS.has(c.req.method) && !sameOrigin(c, authority)) return c.json({ error: "a change must come from this app's own origin" }, 403);
|
|
86
|
+
await next();
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
//#endregion
|
|
90
|
+
export { sameOrigin as a, loopbackOnly as i, fromOwnPage as n, loopbackAuthority as r, LOOPBACK_HOSTNAMES as t };
|
package/lib/loopback-only.js
CHANGED
|
@@ -1,90 +1,2 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import { BlockList, isIP } from "node:net";
|
|
3
|
-
//#region ../../plugins/acryl-router/src/middleware/loopback-only.ts
|
|
4
|
-
const loopback = new BlockList();
|
|
5
|
-
loopback.addSubnet("127.0.0.0", 8, "ipv4");
|
|
6
|
-
loopback.addSubnet("::1", 128, "ipv6");
|
|
7
|
-
const SAFE_METHODS = /* @__PURE__ */ new Set([
|
|
8
|
-
"GET",
|
|
9
|
-
"HEAD",
|
|
10
|
-
"OPTIONS"
|
|
11
|
-
]);
|
|
12
|
-
/**
|
|
13
|
-
* The authority a loopback request addressed: the `Host` header as a URL, or `undefined` when the request does not come from a loopback peer to the
|
|
14
|
-
* real local port, names another host, or is marked cross-site by the browser. The peer and the port come from the transport (`connectionOf(c)`), never
|
|
15
|
-
* from a header; an in-process call has neither and is refused.
|
|
16
|
-
*/
|
|
17
|
-
const LOOPBACK_HOSTNAMES = [
|
|
18
|
-
"127.0.0.1",
|
|
19
|
-
"localhost",
|
|
20
|
-
"[::1]"
|
|
21
|
-
];
|
|
22
|
-
function loopbackAuthority(c, hostnames = LOOPBACK_HOSTNAMES) {
|
|
23
|
-
const { remoteAddress, localPort } = connectionOf(c);
|
|
24
|
-
const host = c.req.header("host");
|
|
25
|
-
if (remoteAddress === void 0 || localPort === void 0 || host === void 0) return void 0;
|
|
26
|
-
const address = (remoteAddress.replace(/^\[|\]$/gu, "").split("%", 1)[0] ?? "").replace(/^::ffff:/iu, "");
|
|
27
|
-
const family = isIP(address);
|
|
28
|
-
if (family === 0 || !loopback.check(address, family === 4 ? "ipv4" : "ipv6")) return void 0;
|
|
29
|
-
let authority;
|
|
30
|
-
try {
|
|
31
|
-
authority = new URL(`http://${host}`);
|
|
32
|
-
} catch {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
if (authority.protocol !== "http:" || Number(authority.port || "80") !== localPort || !hostnames.includes(authority.hostname) || c.req.header("sec-fetch-site") === "cross-site") return void 0;
|
|
36
|
-
return authority;
|
|
37
|
-
}
|
|
38
|
-
/** Whether a changing request is acceptable by its `Origin`: absent (not a browser cross-origin change) or naming this same authority. `null` and any other origin are not. */
|
|
39
|
-
function sameOrigin(c, authority) {
|
|
40
|
-
const origin = c.req.header("origin");
|
|
41
|
-
if (origin === void 0) return true;
|
|
42
|
-
try {
|
|
43
|
-
const parsed = new URL(origin);
|
|
44
|
-
return parsed.protocol === "http:" && parsed.host === authority.host && parsed.pathname === "/";
|
|
45
|
-
} catch {
|
|
46
|
-
return false;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function originOf(value) {
|
|
50
|
-
if (value === void 0) return void 0;
|
|
51
|
-
try {
|
|
52
|
-
return new URL(value).origin;
|
|
53
|
-
} catch {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/** Whether the request comes from a page served by this authority itself: the `own-page` rule of {@link LoopbackOptions.callers}. */
|
|
58
|
-
function fromOwnPage(c, authority) {
|
|
59
|
-
const origin = c.req.header("origin");
|
|
60
|
-
const fetchSite = c.req.header("sec-fetch-site");
|
|
61
|
-
if (origin !== void 0 && originOf(origin) === origin && origin === authority.origin) return fetchSite === void 0 || fetchSite === "same-origin";
|
|
62
|
-
return SAFE_METHODS.has(c.req.method) && fetchSite === "same-origin" && originOf(c.req.header("referer")) === authority.origin;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Only requests from this machine to this app: loopback peer, the real port, an allowed `Host`, and for mutations a matching `Origin` (with
|
|
66
|
-
* `callers: 'own-page'`, every request from this app's own page). Everything else gets a 403.
|
|
67
|
-
*/
|
|
68
|
-
function loopbackOnly(options = {}) {
|
|
69
|
-
const mutations = options.mutations ?? "same-origin";
|
|
70
|
-
const inProcess = options.inProcess ?? "deny";
|
|
71
|
-
const ownPage = options.callers === "own-page";
|
|
72
|
-
return async (c, next) => {
|
|
73
|
-
const connection = connectionOf(c);
|
|
74
|
-
if (inProcess === "allow" && connection.remoteAddress === void 0 && connection.localPort === void 0) {
|
|
75
|
-
await next();
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
const authority = loopbackAuthority(c, options.hostnames);
|
|
79
|
-
if (authority === void 0) return c.json({ error: "request authority rejected" }, 403);
|
|
80
|
-
if (ownPage) {
|
|
81
|
-
if (!fromOwnPage(c, authority)) return c.json({ error: "only this app's own page may call this" }, 403);
|
|
82
|
-
await next();
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
if (mutations === "same-origin" && !SAFE_METHODS.has(c.req.method) && !sameOrigin(c, authority)) return c.json({ error: "a change must come from this app's own origin" }, 403);
|
|
86
|
-
await next();
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
//#endregion
|
|
1
|
+
import { a as sameOrigin, i as loopbackOnly, n as fromOwnPage, r as loopbackAuthority, t as LOOPBACK_HOSTNAMES } from "./loopback-only-BbasoF7R.js";
|
|
90
2
|
export { LOOPBACK_HOSTNAMES, fromOwnPage, loopbackAuthority, loopbackOnly, sameOrigin };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import "./router-Be_o6nFu.js";
|
|
2
|
+
import { t as TrieRouter } from "./trie-router-JydLKUa2.js";
|
|
3
|
+
import { r as matchedRoutes, t as basePath } from "./route-D8m-a2I1.js";
|
|
4
|
+
//#region ../../plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts
|
|
5
|
+
/**
|
|
6
|
+
* Method Not Allowed Middleware for Acryl.
|
|
7
|
+
*
|
|
8
|
+
* Returns a `405 Method Not Allowed` response with an `Allow` header when the request path
|
|
9
|
+
* matches a registered route but the request method is not supported.
|
|
10
|
+
*
|
|
11
|
+
* @param {MethodNotAllowedOptions} options - The options for the middleware.
|
|
12
|
+
* @param {Acryl} options.app - The Acryl instance used by the application.
|
|
13
|
+
* @param {MethodNotAllowedHandler} [options.onMethodNotAllowed] - Generates the response, including its `Allow` header.
|
|
14
|
+
* @returns {MiddlewareHandler} The middleware handler function.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const app = new Acryl()
|
|
19
|
+
*
|
|
20
|
+
* app.use(methodNotAllowed({ app }))
|
|
21
|
+
*
|
|
22
|
+
* app.get('/hello', (c) => c.text('Hello!'))
|
|
23
|
+
* app.post('/hello', (c) => c.text('Posted!'))
|
|
24
|
+
*
|
|
25
|
+
* // PUT /hello -> 405 Method Not Allowed
|
|
26
|
+
* // Allow: GET, HEAD, POST
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```ts
|
|
31
|
+
* app.use(
|
|
32
|
+
* methodNotAllowed({
|
|
33
|
+
* app,
|
|
34
|
+
* onMethodNotAllowed: (c, methods) =>
|
|
35
|
+
* c.json({ error: 'Method Not Allowed' }, 405, { Allow: methods.join(', ') }),
|
|
36
|
+
* })
|
|
37
|
+
* )
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
const methodNotAllowed = (options) => {
|
|
41
|
+
let methodRouter;
|
|
42
|
+
return async function methodNotAllowed(c, next) {
|
|
43
|
+
const routeIndex = c.req.routeIndex;
|
|
44
|
+
await next();
|
|
45
|
+
if (c.res.status !== 404) return;
|
|
46
|
+
if (c.error) return;
|
|
47
|
+
if (!methodRouter) {
|
|
48
|
+
const methodsByPath = /* @__PURE__ */ new Map();
|
|
49
|
+
for (const route of options.app.routes) {
|
|
50
|
+
if (route.method === "ALL" || route.method === "HEAD") continue;
|
|
51
|
+
const methods = methodsByPath.get(route.path) ?? /* @__PURE__ */ new Set();
|
|
52
|
+
methods.add(route.method);
|
|
53
|
+
if (route.method === "GET") methods.add("HEAD");
|
|
54
|
+
methodsByPath.set(route.path, methods);
|
|
55
|
+
}
|
|
56
|
+
methodRouter = new TrieRouter();
|
|
57
|
+
for (const [path, methods] of methodsByPath) methodRouter.add("ALL", path, [...methods]);
|
|
58
|
+
}
|
|
59
|
+
let requestPath = c.req.path;
|
|
60
|
+
const currentRoute = matchedRoutes(c)[routeIndex];
|
|
61
|
+
const sourceRoute = options.app.routes.find((route) => route.handler === methodNotAllowed);
|
|
62
|
+
if (currentRoute && sourceRoute) {
|
|
63
|
+
const currentBasePathParts = basePath(c, routeIndex).split("/").filter(Boolean);
|
|
64
|
+
const sourceBasePathLength = sourceRoute.basePath.split("/").filter(Boolean).length;
|
|
65
|
+
const mountBasePathParts = currentBasePathParts.slice(0, currentBasePathParts.length - sourceBasePathLength);
|
|
66
|
+
if (mountBasePathParts.length > 0) {
|
|
67
|
+
const mountBasePath = `/${mountBasePathParts.join("/")}`;
|
|
68
|
+
requestPath = c.req.path.slice(mountBasePath.length) || "/";
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const allowedMethods = /* @__PURE__ */ new Set();
|
|
72
|
+
for (const [methods] of methodRouter.match("ALL", requestPath)[0]) for (const method of methods) allowedMethods.add(method);
|
|
73
|
+
if (allowedMethods.size === 0 || allowedMethods.has(c.req.method)) return;
|
|
74
|
+
c.res.headers.delete("Allow");
|
|
75
|
+
c.res.headers.delete("Content-Length");
|
|
76
|
+
const methods = [...allowedMethods];
|
|
77
|
+
const allow = methods.join(", ");
|
|
78
|
+
c.res = options.onMethodNotAllowed ? await options.onMethodNotAllowed(c, methods) : c.text("Method Not Allowed", 405, { Allow: allow });
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
//#endregion
|
|
82
|
+
export { methodNotAllowed as t };
|