acrylblends 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/dist/index.d.ts +6 -1
  2. package/dist/index.js +84 -5
  3. package/dist/index.js.map +1 -1
  4. package/docs/framework/LICENSE +23 -0
  5. package/docs/framework/README.md +63 -0
  6. package/docs/framework/UPSTREAM.md +3 -0
  7. package/docs/framework/api-summary.md +138 -0
  8. package/docs/framework/concepts.md +105 -0
  9. package/docs/framework/context.md +129 -0
  10. package/docs/framework/getting-started.md +146 -0
  11. package/docs/framework/helpers.md +118 -0
  12. package/docs/framework/middleware.md +154 -0
  13. package/docs/framework/migration-from-0-3.md +108 -0
  14. package/docs/framework/migration-from-dsh-webserver.md +103 -0
  15. package/docs/framework/node-server.md +75 -0
  16. package/docs/framework/plugin-lifecycle.md +111 -0
  17. package/docs/framework/request.md +106 -0
  18. package/docs/framework/routing.md +188 -0
  19. package/docs/framework/surfaces.md +71 -0
  20. package/docs/framework/upstream.json +9 -0
  21. package/docs/framework/validation.md +135 -0
  22. package/package.json +4 -2
  23. package/plugins/acryl-inspect/plugin.json +2 -1
  24. package/plugins/acryl-inspect/src/report.ts +21 -13
  25. package/plugins/acryl-inspect/src/service.ts +9 -7
  26. package/plugins/acryl-inspect/tests/report.spec.ts +13 -8
  27. package/plugins/acryl-inspect/tests/service.spec.ts +11 -10
  28. package/plugins/acryl-inspect/upstream.json +2 -2
  29. package/plugins/acryl-node-server/LICENSE +26 -0
  30. package/plugins/acryl-node-server/plugin.json +2 -1
  31. package/plugins/acryl-node-server/src/adapter/conninfo.ts +23 -0
  32. package/plugins/acryl-node-server/src/adapter/early-hints.ts +55 -0
  33. package/plugins/acryl-node-server/src/adapter/error.ts +11 -0
  34. package/plugins/acryl-node-server/src/adapter/headers.ts +249 -0
  35. package/plugins/acryl-node-server/src/adapter/index.ts +6 -0
  36. package/plugins/acryl-node-server/src/adapter/listener.ts +540 -0
  37. package/plugins/acryl-node-server/src/adapter/request.ts +797 -0
  38. package/plugins/acryl-node-server/src/adapter/response.ts +186 -0
  39. package/plugins/acryl-node-server/src/adapter/serve-static.ts +238 -0
  40. package/plugins/acryl-node-server/src/adapter/server.ts +36 -0
  41. package/plugins/acryl-node-server/src/adapter/types.ts +82 -0
  42. package/plugins/acryl-node-server/src/adapter/url.ts +42 -0
  43. package/plugins/acryl-node-server/src/adapter/utils/response/constants.ts +1 -0
  44. package/plugins/acryl-node-server/src/adapter/utils/response.ts +4 -0
  45. package/plugins/acryl-node-server/src/adapter/utils/stream.ts +88 -0
  46. package/plugins/acryl-node-server/src/adapter/utils.ts +96 -0
  47. package/plugins/acryl-node-server/src/adapter/websocket-types.ts +45 -0
  48. package/plugins/acryl-node-server/src/adapter/websocket.ts +375 -0
  49. package/plugins/acryl-node-server/src/index.ts +19 -6
  50. package/plugins/acryl-node-server/tests/adapter/app.ts +76 -0
  51. package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +1 -0
  52. package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
  53. package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +1 -0
  54. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +1 -0
  55. package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +1 -0
  56. package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +5 -0
  57. package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +1 -0
  58. package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
  59. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +1 -0
  60. package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +1 -0
  61. package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +1 -0
  62. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +1 -0
  63. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +1 -0
  64. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +1 -0
  65. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +1 -0
  66. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +1 -0
  67. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +34 -0
  68. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +248 -0
  69. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +457 -0
  70. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +23 -0
  71. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +27 -0
  72. package/plugins/acryl-node-server/tests/adapter/headers.test.ts +252 -0
  73. package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +190 -0
  74. package/plugins/acryl-node-server/tests/adapter/listener.test.ts +727 -0
  75. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +189 -0
  76. package/plugins/acryl-node-server/tests/adapter/request.test.ts +1230 -0
  77. package/plugins/acryl-node-server/tests/adapter/response.test.ts +285 -0
  78. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +849 -0
  79. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +790 -0
  80. package/plugins/acryl-node-server/tests/adapter/server.test.ts +1302 -0
  81. package/plugins/acryl-node-server/tests/adapter/setup.ts +16 -0
  82. package/plugins/acryl-node-server/tests/adapter/url.test.ts +76 -0
  83. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +23 -0
  84. package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +75 -0
  85. package/plugins/acryl-node-server/tests/adapter/utils.test.ts +235 -0
  86. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +260 -0
  87. package/plugins/acryl-node-server/tests/server.spec.ts +44 -8
  88. package/plugins/acryl-node-server/upstream.json +3 -3
  89. package/plugins/acryl-router/LICENSE +26 -0
  90. package/plugins/acryl-router/plugin.json +2 -1
  91. package/plugins/acryl-router/src/client.ts +2 -0
  92. package/plugins/acryl-router/src/connection.ts +42 -0
  93. package/plugins/acryl-router/src/core/app-base.ts +544 -0
  94. package/plugins/acryl-router/src/core/app.test.ts +3833 -0
  95. package/plugins/acryl-router/src/core/app.ts +34 -0
  96. package/plugins/acryl-router/src/core/client/client.test.ts +2313 -0
  97. package/plugins/acryl-router/src/core/client/client.ts +249 -0
  98. package/plugins/acryl-router/src/core/client/fetch-result-please.ts +95 -0
  99. package/plugins/acryl-router/src/core/client/index.ts +17 -0
  100. package/plugins/acryl-router/src/core/client/types.test.ts +149 -0
  101. package/plugins/acryl-router/src/core/client/types.ts +393 -0
  102. package/plugins/acryl-router/src/core/client/utils.test.ts +405 -0
  103. package/plugins/acryl-router/src/core/client/utils.ts +117 -0
  104. package/plugins/acryl-router/src/core/compose.test.ts +751 -0
  105. package/plugins/acryl-router/src/core/compose.ts +73 -0
  106. package/plugins/acryl-router/src/core/context.test.ts +629 -0
  107. package/plugins/acryl-router/src/core/context.ts +781 -0
  108. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +344 -0
  109. package/plugins/acryl-router/src/core/helper/accepts/accepts.ts +96 -0
  110. package/plugins/acryl-router/src/core/helper/accepts/index.ts +6 -0
  111. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +55 -0
  112. package/plugins/acryl-router/src/core/helper/adapter/index.ts +90 -0
  113. package/plugins/acryl-router/src/core/helper/conninfo/index.ts +6 -0
  114. package/plugins/acryl-router/src/core/helper/conninfo/types.ts +45 -0
  115. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +510 -0
  116. package/plugins/acryl-router/src/core/helper/cookie/index.ts +146 -0
  117. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +434 -0
  118. package/plugins/acryl-router/src/core/helper/factory/index.ts +375 -0
  119. package/plugins/acryl-router/src/core/helper/html/index.test.ts +78 -0
  120. package/plugins/acryl-router/src/core/helper/html/index.ts +57 -0
  121. package/plugins/acryl-router/src/core/helper/route/index.test.ts +259 -0
  122. package/plugins/acryl-router/src/core/helper/route/index.ts +144 -0
  123. package/plugins/acryl-router/src/core/helper/streaming/index.ts +9 -0
  124. package/plugins/acryl-router/src/core/helper/streaming/sse.ts +101 -0
  125. package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +128 -0
  126. package/plugins/acryl-router/src/core/helper/streaming/stream.ts +45 -0
  127. package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +34 -0
  128. package/plugins/acryl-router/src/core/helper/streaming/text.ts +15 -0
  129. package/plugins/acryl-router/src/core/helper/streaming/utils.ts +11 -0
  130. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +42 -0
  131. package/plugins/acryl-router/src/core/helper/testing/index.ts +28 -0
  132. package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +124 -0
  133. package/plugins/acryl-router/src/core/helper/websocket/index.ts +140 -0
  134. package/plugins/acryl-router/src/core/http-exception.test.ts +45 -0
  135. package/plugins/acryl-router/src/core/http-exception.ts +77 -0
  136. package/plugins/acryl-router/src/core/index.ts +53 -0
  137. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +434 -0
  138. package/plugins/acryl-router/src/core/middleware/basic-auth/index.ts +152 -0
  139. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +1018 -0
  140. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.ts +220 -0
  141. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +273 -0
  142. package/plugins/acryl-router/src/core/middleware/body-limit/index.ts +110 -0
  143. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +355 -0
  144. package/plugins/acryl-router/src/core/middleware/combine/index.ts +171 -0
  145. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +535 -0
  146. package/plugins/acryl-router/src/core/middleware/compress/index.ts +142 -0
  147. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +43 -0
  148. package/plugins/acryl-router/src/core/middleware/context-storage/index.ts +58 -0
  149. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +532 -0
  150. package/plugins/acryl-router/src/core/middleware/cors/index.ts +163 -0
  151. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +534 -0
  152. package/plugins/acryl-router/src/core/middleware/csrf/index.ts +150 -0
  153. package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +21 -0
  154. package/plugins/acryl-router/src/core/middleware/etag/digest.ts +95 -0
  155. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +503 -0
  156. package/plugins/acryl-router/src/core/middleware/etag/index.ts +135 -0
  157. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +217 -0
  158. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.ts +278 -0
  159. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +1135 -0
  160. package/plugins/acryl-router/src/core/middleware/jwk/index.ts +1 -0
  161. package/plugins/acryl-router/src/core/middleware/jwk/jwk.ts +195 -0
  162. package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +48 -0
  163. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +802 -0
  164. package/plugins/acryl-router/src/core/middleware/jwt/index.ts +9 -0
  165. package/plugins/acryl-router/src/core/middleware/jwt/jwt.ts +189 -0
  166. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +552 -0
  167. package/plugins/acryl-router/src/core/middleware/language/index.ts +12 -0
  168. package/plugins/acryl-router/src/core/middleware/language/language.ts +314 -0
  169. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +204 -0
  170. package/plugins/acryl-router/src/core/middleware/logger/index.ts +95 -0
  171. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +292 -0
  172. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.ts +141 -0
  173. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +221 -0
  174. package/plugins/acryl-router/src/core/middleware/method-override/index.ts +147 -0
  175. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +37 -0
  176. package/plugins/acryl-router/src/core/middleware/powered-by/index.ts +35 -0
  177. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +218 -0
  178. package/plugins/acryl-router/src/core/middleware/pretty-json/index.ts +67 -0
  179. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +168 -0
  180. package/plugins/acryl-router/src/core/middleware/request-id/index.ts +7 -0
  181. package/plugins/acryl-router/src/core/middleware/request-id/request-id.ts +59 -0
  182. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +671 -0
  183. package/plugins/acryl-router/src/core/middleware/secure-headers/index.ts +8 -0
  184. package/plugins/acryl-router/src/core/middleware/secure-headers/permissions-policy.ts +101 -0
  185. package/plugins/acryl-router/src/core/middleware/secure-headers/secure-headers.ts +340 -0
  186. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +450 -0
  187. package/plugins/acryl-router/src/core/middleware/serve-static/index.ts +135 -0
  188. package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +50 -0
  189. package/plugins/acryl-router/src/core/middleware/serve-static/path.ts +25 -0
  190. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +70 -0
  191. package/plugins/acryl-router/src/core/middleware/timeout/index.ts +58 -0
  192. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +310 -0
  193. package/plugins/acryl-router/src/core/middleware/timing/index.ts +8 -0
  194. package/plugins/acryl-router/src/core/middleware/timing/timing.ts +256 -0
  195. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +381 -0
  196. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.ts +156 -0
  197. package/plugins/acryl-router/src/core/request/constants.ts +1 -0
  198. package/plugins/acryl-router/src/core/request.test.ts +751 -0
  199. package/plugins/acryl-router/src/core/request.ts +502 -0
  200. package/plugins/acryl-router/src/core/router/common.case.test.ts +1132 -0
  201. package/plugins/acryl-router/src/core/router/linear-router/index.ts +6 -0
  202. package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +80 -0
  203. package/plugins/acryl-router/src/core/router/linear-router/router.ts +152 -0
  204. package/plugins/acryl-router/src/core/router/pattern-router/index.ts +6 -0
  205. package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +46 -0
  206. package/plugins/acryl-router/src/core/router/pattern-router/router.ts +54 -0
  207. package/plugins/acryl-router/src/core/router/reg-exp-router/index.ts +7 -0
  208. package/plugins/acryl-router/src/core/router/reg-exp-router/matcher.ts +33 -0
  209. package/plugins/acryl-router/src/core/router/reg-exp-router/node.ts +170 -0
  210. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +154 -0
  211. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.ts +165 -0
  212. package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +265 -0
  213. package/plugins/acryl-router/src/core/router/reg-exp-router/router.ts +174 -0
  214. package/plugins/acryl-router/src/core/router/reg-exp-router/trie.ts +84 -0
  215. package/plugins/acryl-router/src/core/router/smart-router/index.ts +6 -0
  216. package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +13 -0
  217. package/plugins/acryl-router/src/core/router/smart-router/router.ts +70 -0
  218. package/plugins/acryl-router/src/core/router/trie-router/index.ts +6 -0
  219. package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +896 -0
  220. package/plugins/acryl-router/src/core/router/trie-router/node.ts +221 -0
  221. package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +8 -0
  222. package/plugins/acryl-router/src/core/router/trie-router/router.ts +18 -0
  223. package/plugins/acryl-router/src/core/router/utils.ts +1 -0
  224. package/plugins/acryl-router/src/core/router.ts +103 -0
  225. package/plugins/acryl-router/src/core/types.test.ts +4134 -0
  226. package/plugins/acryl-router/src/core/types.ts +2782 -0
  227. package/plugins/acryl-router/src/core/utils/accept.test.ts +299 -0
  228. package/plugins/acryl-router/src/core/utils/accept.ts +268 -0
  229. package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +56 -0
  230. package/plugins/acryl-router/src/core/utils/basic-auth.ts +26 -0
  231. package/plugins/acryl-router/src/core/utils/body.test.ts +496 -0
  232. package/plugins/acryl-router/src/core/utils/body.ts +263 -0
  233. package/plugins/acryl-router/src/core/utils/buffer.test.ts +147 -0
  234. package/plugins/acryl-router/src/core/utils/buffer.ts +117 -0
  235. package/plugins/acryl-router/src/core/utils/color.test.ts +23 -0
  236. package/plugins/acryl-router/src/core/utils/color.ts +56 -0
  237. package/plugins/acryl-router/src/core/utils/compress.ts +10 -0
  238. package/plugins/acryl-router/src/core/utils/concurrent.test.ts +69 -0
  239. package/plugins/acryl-router/src/core/utils/concurrent.ts +55 -0
  240. package/plugins/acryl-router/src/core/utils/constants.ts +4 -0
  241. package/plugins/acryl-router/src/core/utils/cookie.test.ts +460 -0
  242. package/plugins/acryl-router/src/core/utils/cookie.ts +281 -0
  243. package/plugins/acryl-router/src/core/utils/crypto.test.ts +43 -0
  244. package/plugins/acryl-router/src/core/utils/crypto.ts +58 -0
  245. package/plugins/acryl-router/src/core/utils/encode.test.ts +61 -0
  246. package/plugins/acryl-router/src/core/utils/encode.ts +34 -0
  247. package/plugins/acryl-router/src/core/utils/filepath.test.ts +78 -0
  248. package/plugins/acryl-router/src/core/utils/filepath.ts +60 -0
  249. package/plugins/acryl-router/src/core/utils/handler.ts +15 -0
  250. package/plugins/acryl-router/src/core/utils/headers.ts +355 -0
  251. package/plugins/acryl-router/src/core/utils/html.test.ts +16 -0
  252. package/plugins/acryl-router/src/core/utils/html.ts +182 -0
  253. package/plugins/acryl-router/src/core/utils/http-status.ts +72 -0
  254. package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +149 -0
  255. package/plugins/acryl-router/src/core/utils/ipaddr.ts +374 -0
  256. package/plugins/acryl-router/src/core/utils/jwt/index.ts +7 -0
  257. package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +86 -0
  258. package/plugins/acryl-router/src/core/utils/jwt/jwa.ts +38 -0
  259. package/plugins/acryl-router/src/core/utils/jwt/jws.ts +235 -0
  260. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +1788 -0
  261. package/plugins/acryl-router/src/core/utils/jwt/jwt.ts +292 -0
  262. package/plugins/acryl-router/src/core/utils/jwt/types.ts +157 -0
  263. package/plugins/acryl-router/src/core/utils/jwt/utf8.ts +7 -0
  264. package/plugins/acryl-router/src/core/utils/mime.test.ts +64 -0
  265. package/plugins/acryl-router/src/core/utils/mime.ts +94 -0
  266. package/plugins/acryl-router/src/core/utils/stream.test.ts +212 -0
  267. package/plugins/acryl-router/src/core/utils/stream.ts +107 -0
  268. package/plugins/acryl-router/src/core/utils/types.test.ts +295 -0
  269. package/plugins/acryl-router/src/core/utils/types.ts +123 -0
  270. package/plugins/acryl-router/src/core/utils/url.test.ts +384 -0
  271. package/plugins/acryl-router/src/core/utils/url.ts +337 -0
  272. package/plugins/acryl-router/src/core/validator/index.ts +8 -0
  273. package/plugins/acryl-router/src/core/validator/utils.test.ts +82 -0
  274. package/plugins/acryl-router/src/core/validator/utils.ts +69 -0
  275. package/plugins/acryl-router/src/core/validator/validator.test.ts +1488 -0
  276. package/plugins/acryl-router/src/core/validator/validator.ts +185 -0
  277. package/plugins/acryl-router/src/helpers/index.ts +13 -3
  278. package/plugins/acryl-router/src/helpers/schema-validator.ts +35 -0
  279. package/plugins/acryl-router/src/index.ts +6 -6
  280. package/plugins/acryl-router/src/middleware/index.ts +25 -6
  281. package/plugins/acryl-router/src/middleware/loopback-only.ts +53 -14
  282. package/plugins/acryl-router/src/service.ts +262 -64
  283. package/plugins/acryl-router/tests/docs-examples.spec.ts +152 -0
  284. package/plugins/acryl-router/tests/live-install.spec.ts +2 -2
  285. package/plugins/acryl-router/tests/loader.spec.ts +3 -2
  286. package/plugins/acryl-router/tests/loopback-only.spec.ts +80 -0
  287. package/plugins/acryl-router/tests/service.spec.ts +281 -66
  288. package/plugins/acryl-router/tests/shadow-state.spec.ts +79 -0
  289. package/plugins/acryl-router/upstream.json +2 -2
  290. package/plugins/acryl-router-http/plugin.json +2 -1
  291. package/plugins/acryl-router-http/src/bridge.ts +3 -1
  292. package/plugins/acryl-router-http/tests/adapter.spec.ts +16 -12
  293. package/plugins/acryl-router-http/tests/surfaces.spec.ts +12 -10
  294. package/plugins/acryl-router-http/upstream.json +3 -3
  295. package/plugins/acryl-state/NOTICE +30 -0
  296. package/plugins/acryl-state/plugin.json +1 -1
  297. package/plugins/acryl-state/src/cell.ts +1 -1
  298. package/plugins/acryl-state/src/service.ts +33 -15
  299. package/plugins/acryl-state/upstream.json +6 -4
  300. package/plugins/builder/script.ts +4 -7
  301. package/plugins/extensions/index.ts +6 -5
  302. package/plugins/extensions/resolve.ts +28 -3
  303. package/plugins/openai/prompt.ts +9 -7
  304. package/plugins/tsconfig.json +5 -4
  305. package/shared/AGENTS.core.md +54 -0
  306. package/templates/agent/AGENTS.md +6 -0
  307. package/templates/agent/README.md +2 -2
  308. package/templates/agent/blend.yaml +1 -1
  309. package/templates/agent/src/routes.ts +37 -27
  310. package/templates/agent/test/model.test.ts +2 -1
  311. package/templates/agent/tsconfig.json +8 -5
  312. package/templates/blank/AGENTS.md +5 -0
  313. package/templates/blank/README.md +1 -1
  314. package/templates/blank/src/routes.ts +6 -4
  315. package/templates/blank/tsconfig.json +2 -4
  316. package/templates/todo/AGENTS.md +5 -0
  317. package/templates/todo/src/page.ts +1 -1
  318. package/templates/todo/src/todo.ts +58 -29
  319. package/templates/todo/tsconfig.json +2 -4
  320. package/templates/todo/upstream.json +2 -2
  321. package/plugins/acryl-router/src/compose.ts +0 -21
  322. package/plugins/acryl-router/src/context.ts +0 -59
  323. package/plugins/acryl-router/src/helpers/read-body.ts +0 -59
  324. package/plugins/acryl-router/src/helpers/sse.ts +0 -83
  325. package/plugins/acryl-router/src/helpers/validate.ts +0 -44
  326. package/plugins/acryl-router/src/http-error.ts +0 -21
  327. package/plugins/acryl-router/src/middleware/body-limit.ts +0 -25
  328. package/plugins/acryl-router/src/middleware/cors.ts +0 -46
  329. package/plugins/acryl-router/src/middleware/logger.ts +0 -21
  330. package/plugins/acryl-router/src/middleware/request-id.ts +0 -24
  331. package/plugins/acryl-router/src/middleware/secure-headers.ts +0 -23
  332. package/plugins/acryl-router/src/pattern.ts +0 -89
  333. package/plugins/acryl-router/src/registrar.ts +0 -90
  334. package/plugins/acryl-router/src/table.ts +0 -156
  335. package/plugins/acryl-router/src/types.ts +0 -73
  336. package/plugins/acryl-router/src/util.ts +0 -23
  337. package/plugins/acryl-router/tests/api.spec.ts +0 -223
  338. package/plugins/acryl-router/tests/conformance.ts +0 -170
  339. package/plugins/acryl-router/tests/helpers.spec.ts +0 -172
  340. package/plugins/acryl-router/tests/middleware.spec.ts +0 -183
  341. package/plugins/acryl-router/tests/table.spec.ts +0 -47
@@ -0,0 +1,185 @@
1
+ import type { Context } from '../context.ts'
2
+ import { getCookie } from '../helper/cookie/index.ts'
3
+ import { HTTPException } from '../http-exception.ts'
4
+ import type { Env, MiddlewareHandler, TypedResponse, ValidationTargets, FormValue } from '../types.ts'
5
+ import type { BodyData } from '../utils/body.ts'
6
+ import { bufferToFormData } from '../utils/buffer.ts'
7
+ import type { InferInput } from './utils.ts'
8
+
9
+ type ValidationTargetKeysWithBody = 'form' | 'json'
10
+ type ValidationTargetByMethod<M> = M extends 'get' | 'head' // GET and HEAD request must not have a body content.
11
+ ? Exclude<keyof ValidationTargets, ValidationTargetKeysWithBody>
12
+ : keyof ValidationTargets
13
+
14
+ export type ValidationFunction<
15
+ InputType,
16
+ OutputType,
17
+ E extends Env = {},
18
+ P extends string = string,
19
+ > = (
20
+ value: InputType,
21
+ c: Context<E, P>
22
+ ) => OutputType | TypedResponse | Promise<OutputType> | Promise<TypedResponse>
23
+
24
+ const jsonRegex = /^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/i
25
+ const multipartRegex = /^multipart\/form-data(;\s?boundary=[a-zA-Z0-9'"()+_,\-./:=?]+)?$/i
26
+ const urlencodedRegex = /^application\/x-www-form-urlencoded(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/i
27
+
28
+ export type ExtractValidationResponse<VF> = VF extends (value: any, c: any) => infer R
29
+ ? R extends Promise<infer PR>
30
+ ? PR extends TypedResponse<infer T, infer S, infer F>
31
+ ? TypedResponse<T, S, F>
32
+ : PR extends Response
33
+ ? PR
34
+ : PR extends undefined
35
+ ? never // undefined → never
36
+ : never // anything else → never
37
+ : R extends TypedResponse<infer T, infer S, infer F>
38
+ ? TypedResponse<T, S, F>
39
+ : R extends Response
40
+ ? R
41
+ : R extends undefined
42
+ ? never // undefined → never
43
+ : never // anything else → never
44
+ : never // Can't extract → never
45
+
46
+ export const validator = <
47
+ InputType,
48
+ P extends string,
49
+ M extends string,
50
+ U extends ValidationTargetByMethod<M>,
51
+ P2 extends string = P,
52
+ // Capture the actual validation function as a type
53
+ VF extends (
54
+ value: unknown extends InputType ? ValidationTargets[U] : InputType,
55
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
56
+ c: Context<any, P2>
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ ) => any = (
59
+ value: unknown extends InputType ? ValidationTargets[U] : InputType,
60
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
61
+ c: Context<any, P2>
62
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
63
+ ) => any,
64
+ V extends {
65
+ in: {
66
+ [K in U]: K extends 'json'
67
+ ? unknown extends InputType
68
+ ? ExtractValidatorOutput<VF>
69
+ : InputType
70
+ : InferInput<ExtractValidatorOutput<VF>, K, FormValue>
71
+ }
72
+ out: { [K in U]: ExtractValidatorOutput<VF> }
73
+ } = {
74
+ in: {
75
+ [K in U]: K extends 'json'
76
+ ? unknown extends InputType
77
+ ? ExtractValidatorOutput<VF>
78
+ : InputType
79
+ : InferInput<ExtractValidatorOutput<VF>, K, FormValue>
80
+ }
81
+ out: { [K in U]: ExtractValidatorOutput<VF> }
82
+ },
83
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
84
+ E extends Env = any,
85
+ >(
86
+ target: U,
87
+ validationFunc: VF
88
+ ): MiddlewareHandler<E, P, V, ExtractValidationResponse<VF>> => {
89
+ return async (c, next) => {
90
+ let value = {}
91
+ const contentType = c.req.header('Content-Type')
92
+
93
+ switch (target) {
94
+ case 'json':
95
+ if (!contentType || !jsonRegex.test(contentType)) {
96
+ break
97
+ }
98
+ try {
99
+ value = await c.req.json()
100
+ } catch {
101
+ const message = 'Malformed JSON in request body'
102
+ throw new HTTPException(400, { message })
103
+ }
104
+ break
105
+ case 'form': {
106
+ if (
107
+ !contentType ||
108
+ !(multipartRegex.test(contentType) || urlencodedRegex.test(contentType))
109
+ ) {
110
+ break
111
+ }
112
+
113
+ let formData: FormData
114
+
115
+ if (c.req.bodyCache.formData) {
116
+ formData = await c.req.bodyCache.formData
117
+ } else {
118
+ try {
119
+ const arrayBuffer = await c.req.arrayBuffer()
120
+ formData = await bufferToFormData(arrayBuffer, contentType)
121
+ c.req.bodyCache.formData = formData
122
+ } catch (e) {
123
+ let message = 'Malformed FormData request.'
124
+ message += e instanceof Error ? ` ${e.message}` : ` ${String(e)}`
125
+ throw new HTTPException(400, { message })
126
+ }
127
+ }
128
+
129
+ const form: BodyData<{ all: true }> = Object.create(null)
130
+ formData.forEach((value, key) => {
131
+ if (key.endsWith('[]')) {
132
+ ;((form[key] ??= []) as unknown[]).push(value)
133
+ } else if (Array.isArray(form[key])) {
134
+ ;(form[key] as unknown[]).push(value)
135
+ } else if (Object.hasOwn(form, key)) {
136
+ form[key] = [form[key] as string | File, value]
137
+ } else {
138
+ form[key] = value
139
+ }
140
+ })
141
+ value = form
142
+ break
143
+ }
144
+ case 'query':
145
+ value = Object.fromEntries(
146
+ Object.entries(c.req.queries()).map(([k, v]) => {
147
+ return v.length === 1 ? [k, v[0]] : [k, v]
148
+ })
149
+ )
150
+ break
151
+ case 'param':
152
+ value = c.req.param() as Record<string, string>
153
+ break
154
+ case 'header':
155
+ value = c.req.header()
156
+ break
157
+ case 'cookie':
158
+ value = getCookie(c)
159
+ break
160
+ }
161
+
162
+ const res = await validationFunc(value as never, c as never)
163
+
164
+ if (res instanceof Response) {
165
+ return res as ExtractValidationResponse<VF>
166
+ }
167
+
168
+ c.req.addValidatedData(target, res as never)
169
+
170
+ return (await next()) as ExtractValidationResponse<VF>
171
+ }
172
+ }
173
+
174
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
175
+ export type ExtractValidatorOutput<VF> = VF extends (value: any, c: any) => infer R
176
+ ? R extends Promise<infer PR>
177
+ ? // eslint-disable-next-line @typescript-eslint/no-explicit-any
178
+ PR extends Response | TypedResponse<any, any, any>
179
+ ? never
180
+ : PR
181
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
182
+ R extends Response | TypedResponse<any, any, any>
183
+ ? never
184
+ : R
185
+ : never
@@ -1,3 +1,13 @@
1
- export { readBytes, readJson, readText, type ReadBodyOptions } from './read-body.ts'
2
- export { streamSSE, type SseOptions, type SseStream } from './sse.ts'
3
- export { valid, validate, type StandardSchema, type ValidationTarget } from './validate.ts'
1
+ export { getConnInfo, connectionOf } from '../connection.ts'
2
+ export type { AddressType, ConnInfo, GetConnInfo, NetAddrInfo } from '../core/helper/conninfo/index.ts'
3
+ export { accepts } from '../core/helper/accepts/index.ts'
4
+ export { createFactory, createMiddleware, Factory } from '../core/helper/factory/index.ts'
5
+ export { deleteCookie, generateCookie, generateSignedCookie, getCookie, getSignedCookie, setCookie, setSignedCookie } from '../core/helper/cookie/index.ts'
6
+ export { getExtension, getMimeType, mimes, type BaseMime } from '../core/utils/mime.ts'
7
+ export { html, raw } from '../core/helper/html/index.ts'
8
+ export { matchedRoutes, routePath, baseRoutePath, basePath } from '../core/helper/route/index.ts'
9
+ export { testClient } from '../core/helper/testing/index.ts'
10
+ export { stream, streamSSE, streamText, SSEStreamingApi, type SSEMessage } from '../core/helper/streaming/index.ts'
11
+ export { validator, type ValidationFunction } from '../core/validator/index.ts'
12
+ export { schemaValidator, type StandardSchema } from './schema-validator.ts'
13
+ export { createWSMessageEvent, defineWebSocketHelper, WSContext, type SendOptions, type UpgradeWebSocket, type WSContextInit, type WSEvents, type WSMessageReceive, type WSReadyState } from '../core/helper/websocket/index.ts'
@@ -0,0 +1,35 @@
1
+ import type { Env, MiddlewareHandler, ValidationTargets } from '../core/types.ts'
2
+ import { validator } from '../core/validator/index.ts'
3
+
4
+ /** The slice of the Standard Schema interface this needs; Schemastery (what Cordis uses), Zod and Valibot all implement it. */
5
+ export interface StandardSchema<T = unknown> {
6
+ readonly '~standard': {
7
+ validate(value: unknown): StandardResult<T> | Promise<StandardResult<T>>
8
+ }
9
+ }
10
+
11
+ type StandardResult<T> =
12
+ | { readonly value: T, readonly issues?: undefined }
13
+ | { readonly issues: readonly { readonly message: string, readonly path?: readonly unknown[] | undefined }[] }
14
+
15
+ const pathOf = (path: readonly unknown[] | undefined): string =>
16
+ (path ?? []).map(part => String(typeof part === 'object' && part !== null && 'key' in part ? (part as { key: unknown }).key : part)).join('.')
17
+
18
+ /**
19
+ * The core `validator` driven by a Standard Schema. A failure answers 400 with `{ error, issues }`; success makes the parsed value the
20
+ * handler's `c.req.valid(target)`, typed by the schema.
21
+ */
22
+ export function schemaValidator<Target extends keyof ValidationTargets, Out, E extends Env = Env, P extends string = string>(
23
+ target: Target,
24
+ schema: StandardSchema<Out>,
25
+ ): MiddlewareHandler<E, P, { in: { [K in Target]: Out }, out: { [K in Target]: Out } }> {
26
+ const middleware = validator(target, async (value, c) => {
27
+ const result = await schema['~standard'].validate(value)
28
+ if (result.issues !== undefined) {
29
+ return c.json({ error: `invalid ${target}`, issues: result.issues.map(issue => ({ message: issue.message, path: pathOf(issue.path) })) }, 400)
30
+ }
31
+ return result.value
32
+ })
33
+ // The core infers its own input and output types from the function; the schema's output type is the one a handler should see.
34
+ return middleware as unknown as MiddlewareHandler<E, P, { in: { [K in Target]: Out }, out: { [K in Target]: Out } }>
35
+ }
@@ -1,6 +1,6 @@
1
- export { Router, Config, apply, name, type RouterHttpService } from './service.ts'
2
- export { RouteTable, type RouteTableOptions } from './table.ts'
3
- export { compose } from './compose.ts'
4
- export { HttpError } from './http-error.ts'
5
- export type { Registrar, RouteHandlers, UseArguments } from './registrar.ts'
6
- export type { ConnectionInfo, ErrorHandler, NotFoundHandler, ResponseBody, Handler, Method, Middleware, Next, RouteContext, RouteMethod, TrailingSlash } from './types.ts'
1
+ export { Router, Config, apply, name, type MountableApp, type RouterHttpService, type TrailingSlash } from './service.ts'
2
+ export { connectionOf, getConnInfo, type ConnectionInfo, type RouterBindings, type RouterEnv } from './connection.ts'
3
+ export { App, Context } from './core/index.ts'
4
+ export type { AppRequest, ContextRenderer, ContextVariableMap, Env, ErrorHandler, ExecutionContext, Handler, Input, MiddlewareHandler, Next, NotFoundHandler, NotFoundResponse, Schema, ToSchema, TypedResponse, ValidationTargets } from './core/index.ts'
5
+ export { HTTPException } from './core/http-exception.ts'
6
+ export type { ContentfulStatusCode, StatusCode } from './core/utils/http-status.ts'
@@ -1,6 +1,25 @@
1
- export { bodyLimit, BODY_LIMIT_KEY, type BodyLimitOptions } from './body-limit.ts'
2
- export { cors, type CorsOptions } from './cors.ts'
3
- export { logger, type LogSink } from './logger.ts'
4
- export { loopbackAuthority, loopbackOnly, sameOrigin, type LoopbackOptions } from './loopback-only.ts'
5
- export { requestId, type RequestIdOptions } from './request-id.ts'
6
- export { secureHeaders, type SecureHeadersOptions } from './secure-headers.ts'
1
+ export { basicAuth } from '../core/middleware/basic-auth/index.ts'
2
+ export { bearerAuth } from '../core/middleware/bearer-auth/index.ts'
3
+ export { bodyLimit } from '../core/middleware/body-limit/index.ts'
4
+ export { every, except, some } from '../core/middleware/combine/index.ts'
5
+ export { compress } from '../core/middleware/compress/index.ts'
6
+ export { contextStorage, getContext, tryGetContext } from '../core/middleware/context-storage/index.ts'
7
+ export { cors } from '../core/middleware/cors/index.ts'
8
+ export { csrf } from '../core/middleware/csrf/index.ts'
9
+ export { etag } from '../core/middleware/etag/index.ts'
10
+ export { jwk } from '../core/middleware/jwk/index.ts'
11
+ export { AlgorithmTypes, decode, jwt, sign, verify, verifyWithJwks, type JwtVariables } from '../core/middleware/jwt/index.ts'
12
+ export { ipRestriction, type IPRestrictionRule, type IPRestrictionRules } from '../core/middleware/ip-restriction/index.ts'
13
+ export { detectFromCookie, detectFromHeader, detectFromPath, detectFromQuery, languageDetector } from '../core/middleware/language/index.ts'
14
+ export { logger } from '../core/middleware/logger/index.ts'
15
+ export { methodNotAllowed } from '../core/middleware/method-not-allowed/index.ts'
16
+ export { methodOverride } from '../core/middleware/method-override/index.ts'
17
+ export { poweredBy } from '../core/middleware/powered-by/index.ts'
18
+ export { prettyJSON } from '../core/middleware/pretty-json/index.ts'
19
+ export { requestId, type RequestIdVariables } from '../core/middleware/request-id/index.ts'
20
+ export { serveStatic, type ServeStaticOptions } from '../core/middleware/serve-static/index.ts'
21
+ export { NONCE, secureHeaders, type SecureHeadersVariables } from '../core/middleware/secure-headers/index.ts'
22
+ export { timeout } from '../core/middleware/timeout/index.ts'
23
+ export { endTime, setMetric, startTime, timing, wrapTime, type TimingVariables } from '../core/middleware/timing/index.ts'
24
+ export { appendTrailingSlash, trimTrailingSlash } from '../core/middleware/trailing-slash/index.ts'
25
+ export { LOOPBACK_HOSTNAMES, fromOwnPage, loopbackAuthority, loopbackOnly, sameOrigin, type LoopbackOptions } from './loopback-only.ts'
@@ -1,5 +1,7 @@
1
1
  import { BlockList, isIP } from 'node:net'
2
- import type { Middleware, RouteContext } from '../types.ts'
2
+ import { connectionOf } from '../connection.ts'
3
+ import type { Context } from '../core/context.ts'
4
+ import type { MiddlewareHandler } from '../core/types.ts'
3
5
 
4
6
  export interface LoopbackOptions {
5
7
  /** Hostnames a `Host` header may name. Default: the loopback names `127.0.0.1`, `localhost` and `[::1]`. */
@@ -17,6 +19,13 @@ export interface LoopbackOptions {
17
19
  * checked in full: only a call with no connection facts at all counts as in process.
18
20
  */
19
21
  readonly inProcess?: 'deny' | 'allow'
22
+ /**
23
+ * Who may call. `local` (default): any program on this machine, a browser page only as `mutations` allows. `own-page`: only this app's own page,
24
+ * for private routes a script on the machine must not drive or read either. A request then shows an `Origin` that is exactly this authority (with
25
+ * `Sec-Fetch-Site` absent or `same-origin`), or, for a read (GET, HEAD, OPTIONS), which browsers often send without `Origin`, `Sec-Fetch-Site:
26
+ * same-origin` and a `Referer` from this authority. `mutations` is not consulted: every request is held to that rule.
27
+ */
28
+ readonly callers?: 'local' | 'own-page'
20
29
  }
21
30
 
22
31
  const loopback = new BlockList()
@@ -27,15 +36,15 @@ const SAFE_METHODS = new Set(['GET', 'HEAD', 'OPTIONS'])
27
36
 
28
37
  /**
29
38
  * 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
30
- * real local port, names another host, or is marked cross-site by the browser. The peer and the port come from the transport (`c.connection`), never
39
+ * 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
31
40
  * from a header; an in-process call has neither and is refused.
32
41
  */
33
42
  export const LOOPBACK_HOSTNAMES: readonly string[] = ['127.0.0.1', 'localhost', '[::1]']
34
43
 
35
- export function loopbackAuthority(c: RouteContext, hostnames: readonly string[] = LOOPBACK_HOSTNAMES): URL | undefined {
36
- const { remoteAddress, localPort } = c.connection
37
- const host = c.req.headers.get('host')
38
- if (remoteAddress === undefined || localPort === undefined || host === null) return undefined
44
+ export function loopbackAuthority(c: Context, hostnames: readonly string[] = LOOPBACK_HOSTNAMES): URL | undefined {
45
+ const { remoteAddress, localPort } = connectionOf(c)
46
+ const host = c.req.header('host')
47
+ if (remoteAddress === undefined || localPort === undefined || host === undefined) return undefined
39
48
  const address = (remoteAddress.replace(/^\[|\]$/gu, '').split('%', 1)[0] ?? '').replace(/^::ffff:/iu, '')
40
49
  const family = isIP(address)
41
50
  if (family === 0 || !loopback.check(address, family === 4 ? 'ipv4' : 'ipv6')) return undefined
@@ -49,15 +58,15 @@ export function loopbackAuthority(c: RouteContext, hostnames: readonly string[]
49
58
  authority.protocol !== 'http:'
50
59
  || Number(authority.port || '80') !== localPort
51
60
  || !hostnames.includes(authority.hostname)
52
- || c.req.headers.get('sec-fetch-site') === 'cross-site'
61
+ || c.req.header('sec-fetch-site') === 'cross-site'
53
62
  ) return undefined
54
63
  return authority
55
64
  }
56
65
 
57
66
  /** 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. */
58
- export function sameOrigin(c: RouteContext, authority: URL): boolean {
59
- const origin = c.req.headers.get('origin')
60
- if (origin === null) return true
67
+ export function sameOrigin(c: Context, authority: URL): boolean {
68
+ const origin = c.req.header('origin')
69
+ if (origin === undefined) return true
61
70
  try {
62
71
  const parsed = new URL(origin)
63
72
  return parsed.protocol === 'http:' && parsed.host === authority.host && parsed.pathname === '/'
@@ -66,17 +75,47 @@ export function sameOrigin(c: RouteContext, authority: URL): boolean {
66
75
  }
67
76
  }
68
77
 
69
- /** Only requests from this machine to this app: loopback peer, the real port, an allowed `Host`, and for mutations a matching `Origin`. Everything else gets a 403. */
70
- export function loopbackOnly(options: LoopbackOptions = {}): Middleware {
78
+ function originOf(value: string | undefined): string | undefined {
79
+ if (value === undefined) return undefined
80
+ try {
81
+ return new URL(value).origin
82
+ } catch {
83
+ return undefined
84
+ }
85
+ }
86
+
87
+ /** Whether the request comes from a page served by this authority itself: the `own-page` rule of {@link LoopbackOptions.callers}. */
88
+ export function fromOwnPage(c: Context, authority: URL): boolean {
89
+ const origin = c.req.header('origin')
90
+ const fetchSite = c.req.header('sec-fetch-site')
91
+ if (origin !== undefined && originOf(origin) === origin && origin === authority.origin) return fetchSite === undefined || fetchSite === 'same-origin'
92
+ return SAFE_METHODS.has(c.req.method) && fetchSite === 'same-origin' && originOf(c.req.header('referer')) === authority.origin
93
+ }
94
+
95
+ /**
96
+ * Only requests from this machine to this app: loopback peer, the real port, an allowed `Host`, and for mutations a matching `Origin` (with
97
+ * `callers: 'own-page'`, every request from this app's own page). Everything else gets a 403.
98
+ */
99
+ export function loopbackOnly(options: LoopbackOptions = {}): MiddlewareHandler {
71
100
  const mutations = options.mutations ?? 'same-origin'
72
101
  const inProcess = options.inProcess ?? 'deny'
102
+ const ownPage = options.callers === 'own-page'
73
103
  return async (c, next) => {
74
- if (inProcess === 'allow' && c.connection.remoteAddress === undefined && c.connection.localPort === undefined) return next()
104
+ const connection = connectionOf(c)
105
+ if (inProcess === 'allow' && connection.remoteAddress === undefined && connection.localPort === undefined) {
106
+ await next()
107
+ return
108
+ }
75
109
  const authority = loopbackAuthority(c, options.hostnames)
76
110
  if (authority === undefined) return c.json({ error: 'request authority rejected' }, 403)
111
+ if (ownPage) {
112
+ if (!fromOwnPage(c, authority)) return c.json({ error: 'only this app\'s own page may call this' }, 403)
113
+ await next()
114
+ return
115
+ }
77
116
  if (mutations === 'same-origin' && !SAFE_METHODS.has(c.req.method) && !sameOrigin(c, authority)) {
78
117
  return c.json({ error: 'a change must come from this app\'s own origin' }, 403)
79
118
  }
80
- return next()
119
+ await next()
81
120
  }
82
121
  }