acrylblends 0.6.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/README.md +4 -3
  2. package/docs/framework/README.md +2 -2
  3. package/docs/framework/UPSTREAM.md +1 -1
  4. package/docs/framework/guides/jsx.md +51 -1
  5. package/docs/framework/helpers/ssg.md +3 -6
  6. package/docs/framework/middleware/builtin/jsx-renderer.md +0 -3
  7. package/docs/framework/upstream.json +2 -2
  8. package/lib/accepts.d.ts +1 -1
  9. package/lib/acryl-base.d.ts +1 -1
  10. package/lib/adapter.d.ts +1 -1
  11. package/lib/{app-wFwpg-bt.d.ts → app-D8riatvv.d.ts} +1 -1
  12. package/lib/{base-ddiVmiE7.js → base-NSN_SNv-.js} +1 -0
  13. package/lib/basic-auth.d.ts +1 -1
  14. package/lib/bearer-auth.d.ts +1 -1
  15. package/lib/body-limit.d.ts +1 -1
  16. package/lib/cache.d.ts +1 -1
  17. package/lib/cache.js +4 -4
  18. package/lib/{client-BHTr318g.js → client-DDLXwhBo.js} +2 -125
  19. package/lib/client.d.ts +2 -2
  20. package/lib/client.js +2 -1
  21. package/lib/combine.d.ts +1 -1
  22. package/lib/{components-DYZdxJIJ.js → components-JXVm45kK.js} +1 -1
  23. package/lib/{components-Ce5FRyHU.js → components-cEW3ovK0.js} +3 -3
  24. package/lib/compress.d.ts +1 -1
  25. package/lib/conninfo.d.ts +2 -2
  26. package/lib/{context-DVQBjuns.d.ts → context-DS3fYyG-.d.ts} +1 -1
  27. package/lib/context-storage.d.ts +1 -1
  28. package/lib/cookie.d.ts +1 -1
  29. package/lib/cors.d.ts +1 -1
  30. package/lib/csrf.d.ts +1 -1
  31. package/lib/dev.d.ts +2 -2
  32. package/lib/etag.d.ts +1 -1
  33. package/lib/factory.d.ts +2 -2
  34. package/lib/{hooks-Bq5q9IMl.js → hooks-w72iLeFR.js} +6 -6
  35. package/lib/{index-CUTfU69R.d.ts → index-Bb7YJKCq.d.ts} +2 -2
  36. package/lib/{index-CsvB-F9j.d.ts → index-BvFh1Gfx.d.ts} +1 -1
  37. package/lib/{index-Cqcdluyn.d.ts → index-CTy4N7ng.d.ts} +2 -2
  38. package/lib/index.d.ts +4 -4
  39. package/lib/ip-restriction.d.ts +2 -2
  40. package/lib/jsx/dom/client.js +1 -1
  41. package/lib/jsx/dom/jsx-dev-runtime.js +1 -1
  42. package/lib/jsx/dom/jsx-runtime.js +1 -1
  43. package/lib/jsx/dom/server.js +2 -2
  44. package/lib/jsx/dom.js +4 -4
  45. package/lib/jsx/jsx-dev-runtime.js +1 -1
  46. package/lib/jsx/jsx-runtime.js +1 -1
  47. package/lib/jsx/streaming.js +1 -1
  48. package/lib/{jsx-dev-runtime-kAhR_4C7.js → jsx-dev-runtime-CWLRA2F3.js} +2 -2
  49. package/lib/jsx-renderer.d.ts +75 -0
  50. package/lib/jsx-renderer.js +99 -0
  51. package/lib/jsx.js +4 -4
  52. package/lib/jwk.d.ts +1 -1
  53. package/lib/jwt.d.ts +1 -1
  54. package/lib/language.d.ts +1 -1
  55. package/lib/logger.d.ts +1 -1
  56. package/lib/loopback-only.d.ts +1 -1
  57. package/lib/method-not-allowed.d.ts +2 -2
  58. package/lib/method-override.d.ts +2 -2
  59. package/lib/mount.d.ts +1 -1
  60. package/lib/node-server/conninfo.d.ts +1 -1
  61. package/lib/node-server/register.d.ts +1 -0
  62. package/lib/node-server/register.js +73 -0
  63. package/lib/node-server/serve-static.d.ts +1 -1
  64. package/lib/node-server/serve-static.js +1 -1
  65. package/lib/node-server.d.ts +1 -1
  66. package/lib/node-server.js +1 -1
  67. package/lib/powered-by.d.ts +1 -1
  68. package/lib/pretty-json.d.ts +1 -1
  69. package/lib/quick.d.ts +1 -1
  70. package/lib/request-id.d.ts +1 -1
  71. package/lib/request.d.ts +1 -1
  72. package/lib/route.d.ts +1 -1
  73. package/lib/schema-validator.d.ts +1 -1
  74. package/lib/secure-headers.d.ts +1 -1
  75. package/lib/{serve-static-Cw23shXv.js → serve-static-B14MF1Va.js} +1 -0
  76. package/lib/serve-static.d.ts +1 -1
  77. package/lib/ssg-BwjcA-Ge.js +389 -0
  78. package/lib/ssg.d.ts +156 -0
  79. package/lib/ssg.js +2 -0
  80. package/lib/streaming.d.ts +1 -1
  81. package/lib/testing.d.ts +3 -3
  82. package/lib/testing.js +1 -1
  83. package/lib/timeout.d.ts +1 -1
  84. package/lib/timing.d.ts +1 -1
  85. package/lib/tiny.d.ts +1 -1
  86. package/lib/trailing-slash.d.ts +1 -1
  87. package/lib/{types-nEL8VPDC.d.ts → types-Dv_nV2cv.d.ts} +1 -1
  88. package/lib/{types-CQiGmsWW.d.ts → types-zNxyEpG2.d.ts} +2 -2
  89. package/lib/types.d.ts +1 -1
  90. package/lib/utils/body.d.ts +1 -1
  91. package/lib/utils/ipaddr.d.ts +1 -1
  92. package/lib/utils-Cx61GFMC.js +125 -0
  93. package/lib/validator.d.ts +1 -1
  94. package/lib/ws.d.ts +1 -1
  95. package/package.json +13 -1
  96. package/plugins/acryl-inspect/upstream.json +1 -1
  97. package/plugins/acryl-node-server/src/register.ts +86 -0
  98. package/plugins/acryl-node-server/upstream.json +5 -3
  99. package/plugins/acryl-router/src/core/helper/ssg/index.ts +14 -0
  100. package/plugins/acryl-router/src/core/helper/ssg/middleware.ts +83 -0
  101. package/plugins/acryl-router/src/core/helper/ssg/plugins.ts +72 -0
  102. package/plugins/acryl-router/src/core/helper/ssg/ssg.ts +471 -0
  103. package/plugins/acryl-router/src/core/helper/ssg/utils.ts +118 -0
  104. package/plugins/acryl-router/src/core/jsx/dom/render.ts +6 -6
  105. package/plugins/acryl-router/src/core/middleware/cache/index.ts +4 -4
  106. package/plugins/acryl-router/src/core/middleware/jsx-renderer/index.ts +162 -0
  107. package/plugins/acryl-router/src/helpers/index.ts +1 -0
  108. package/plugins/acryl-router/src/middleware/index.ts +1 -0
  109. package/plugins/acryl-router/upstream.json +2 -2
  110. package/plugins/acryl-router-http/upstream.json +1 -1
  111. package/plugins/acryl-state/upstream.json +1 -1
  112. package/plugins/desktop/main.ts +4 -1
  113. package/plugins/desktop/upstream.json +1 -1
  114. package/plugins/desktop-web/main.ts +3 -1
  115. package/plugins/desktop-web/upstream.json +1 -1
  116. package/plugins/extensions/resolve.ts +4 -0
  117. package/shared/AGENTS.core.md +3 -0
  118. package/templates/agent/package.json +7 -3
  119. package/templates/agent/tsconfig.json +10 -2
  120. package/templates/blank/package.json +7 -3
  121. package/templates/blank/src/about.tsx +14 -0
  122. package/templates/blank/src/routes.ts +2 -0
  123. package/templates/blank/test/app.test.ts +15 -0
  124. package/templates/blank/tsconfig.json +3 -1
  125. package/templates/todo/package.json +7 -3
  126. package/templates/todo/tsconfig.json +3 -1
  127. package/templates/todo/upstream.json +1 -1
  128. package/plugins/acryl-inspect/tests/report.spec.ts +0 -69
  129. package/plugins/acryl-inspect/tests/service.spec.ts +0 -121
  130. package/plugins/acryl-node-server/tests/adapter/app.ts +0 -76
  131. package/plugins/acryl-node-server/tests/adapter/assets/.static/plain.txt +0 -1
  132. package/plugins/acryl-node-server/tests/adapter/assets/favicon.ico +0 -0
  133. package/plugins/acryl-node-server/tests/adapter/assets/secret.txt +0 -1
  134. package/plugins/acryl-node-server/tests/adapter/assets/static/acryl.html +0 -1
  135. package/plugins/acryl-node-server/tests/adapter/assets/static/admin/secret.txt +0 -1
  136. package/plugins/acryl-node-server/tests/adapter/assets/static/data.json +0 -5
  137. package/plugins/acryl-node-server/tests/adapter/assets/static/extensionless +0 -1
  138. package/plugins/acryl-node-server/tests/adapter/assets/static/foo..bar.txt +0 -0
  139. package/plugins/acryl-node-server/tests/adapter/assets/static/index.html +0 -1
  140. package/plugins/acryl-node-server/tests/adapter/assets/static/plain.txt +0 -1
  141. package/plugins/acryl-node-server/tests/adapter/assets/static-with-context-path/plain.txt +0 -1
  142. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin +0 -1
  143. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.bin.br +0 -1
  144. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt +0 -1
  145. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.br +0 -1
  146. package/plugins/acryl-node-server/tests/adapter/assets/static-with-precompressed/hello.txt.zst +0 -1
  147. package/plugins/acryl-node-server/tests/adapter/conninfo.test.ts +0 -34
  148. package/plugins/acryl-node-server/tests/adapter/content-length.test.ts +0 -248
  149. package/plugins/acryl-node-server/tests/adapter/early-hints.test.ts +0 -457
  150. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-cert.pem +0 -23
  151. package/plugins/acryl-node-server/tests/adapter/fixtures/keys/agent1-key.pem +0 -27
  152. package/plugins/acryl-node-server/tests/adapter/headers.test.ts +0 -252
  153. package/plugins/acryl-node-server/tests/adapter/helpers/request.ts +0 -190
  154. package/plugins/acryl-node-server/tests/adapter/listener.test.ts +0 -727
  155. package/plugins/acryl-node-server/tests/adapter/request-client-disconnect.test.ts +0 -189
  156. package/plugins/acryl-node-server/tests/adapter/request.test.ts +0 -1230
  157. package/plugins/acryl-node-server/tests/adapter/response.test.ts +0 -285
  158. package/plugins/acryl-node-server/tests/adapter/serve-static.test.ts +0 -849
  159. package/plugins/acryl-node-server/tests/adapter/server-socket.test.ts +0 -790
  160. package/plugins/acryl-node-server/tests/adapter/server.test.ts +0 -1312
  161. package/plugins/acryl-node-server/tests/adapter/setup.ts +0 -16
  162. package/plugins/acryl-node-server/tests/adapter/url.test.ts +0 -76
  163. package/plugins/acryl-node-server/tests/adapter/utils/response.test.ts +0 -23
  164. package/plugins/acryl-node-server/tests/adapter/utils/stream.test.ts +0 -75
  165. package/plugins/acryl-node-server/tests/adapter/utils.test.ts +0 -235
  166. package/plugins/acryl-node-server/tests/adapter/websocket.test.ts +0 -260
  167. package/plugins/acryl-node-server/tests/server.spec.ts +0 -141
  168. package/plugins/acryl-router/src/core/app.test.ts +0 -3833
  169. package/plugins/acryl-router/src/core/client/client.test.ts +0 -2313
  170. package/plugins/acryl-router/src/core/client/types.test.ts +0 -149
  171. package/plugins/acryl-router/src/core/client/utils.test.ts +0 -405
  172. package/plugins/acryl-router/src/core/compose.test.ts +0 -751
  173. package/plugins/acryl-router/src/core/context.test.ts +0 -629
  174. package/plugins/acryl-router/src/core/helper/accepts/accepts.test.ts +0 -344
  175. package/plugins/acryl-router/src/core/helper/adapter/index.test.ts +0 -55
  176. package/plugins/acryl-router/src/core/helper/cookie/index.test.ts +0 -510
  177. package/plugins/acryl-router/src/core/helper/css/common.case.test.tsx +0 -506
  178. package/plugins/acryl-router/src/core/helper/css/index.test.tsx +0 -678
  179. package/plugins/acryl-router/src/core/helper/dev/index.test.ts +0 -181
  180. package/plugins/acryl-router/src/core/helper/factory/index.test.ts +0 -434
  181. package/plugins/acryl-router/src/core/helper/html/index.test.ts +0 -78
  182. package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +0 -356
  183. package/plugins/acryl-router/src/core/helper/route/index.test.ts +0 -259
  184. package/plugins/acryl-router/src/core/helper/streaming/sse.test.tsx +0 -557
  185. package/plugins/acryl-router/src/core/helper/streaming/stream.test.ts +0 -128
  186. package/plugins/acryl-router/src/core/helper/streaming/text.test.ts +0 -34
  187. package/plugins/acryl-router/src/core/helper/testing/index.test.ts +0 -42
  188. package/plugins/acryl-router/src/core/helper/websocket/index.test.ts +0 -124
  189. package/plugins/acryl-router/src/core/http-exception.test.ts +0 -45
  190. package/plugins/acryl-router/src/core/jsx/base.test.tsx +0 -97
  191. package/plugins/acryl-router/src/core/jsx/children.test.ts +0 -52
  192. package/plugins/acryl-router/src/core/jsx/components.test.tsx +0 -936
  193. package/plugins/acryl-router/src/core/jsx/context-isolation.test.ts +0 -655
  194. package/plugins/acryl-router/src/core/jsx/dom/client.test.tsx +0 -128
  195. package/plugins/acryl-router/src/core/jsx/dom/components.test.tsx +0 -330
  196. package/plugins/acryl-router/src/core/jsx/dom/context.test.tsx +0 -184
  197. package/plugins/acryl-router/src/core/jsx/dom/css.test.tsx +0 -149
  198. package/plugins/acryl-router/src/core/jsx/dom/hooks/index.test.tsx +0 -172
  199. package/plugins/acryl-router/src/core/jsx/dom/index.test.tsx +0 -3681
  200. package/plugins/acryl-router/src/core/jsx/dom/intrinsic-element/components.test.tsx +0 -1344
  201. package/plugins/acryl-router/src/core/jsx/dom/server.test.tsx +0 -199
  202. package/plugins/acryl-router/src/core/jsx/hooks/dom.test.tsx +0 -859
  203. package/plugins/acryl-router/src/core/jsx/hooks/string.test.tsx +0 -40
  204. package/plugins/acryl-router/src/core/jsx/index.test.tsx +0 -1744
  205. package/plugins/acryl-router/src/core/jsx/intrinsic-element/components.test.tsx +0 -666
  206. package/plugins/acryl-router/src/core/jsx/jsx-runtime.test.tsx +0 -85
  207. package/plugins/acryl-router/src/core/jsx/streaming.test.tsx +0 -1281
  208. package/plugins/acryl-router/src/core/jsx/utils.test.ts +0 -366
  209. package/plugins/acryl-router/src/core/middleware/basic-auth/index.test.ts +0 -434
  210. package/plugins/acryl-router/src/core/middleware/bearer-auth/index.test.ts +0 -1018
  211. package/plugins/acryl-router/src/core/middleware/body-limit/index.test.ts +0 -273
  212. package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +0 -1211
  213. package/plugins/acryl-router/src/core/middleware/combine/index.test.ts +0 -355
  214. package/plugins/acryl-router/src/core/middleware/compress/index.test.ts +0 -535
  215. package/plugins/acryl-router/src/core/middleware/context-storage/index.test.ts +0 -43
  216. package/plugins/acryl-router/src/core/middleware/cors/index.test.ts +0 -532
  217. package/plugins/acryl-router/src/core/middleware/csrf/index.test.ts +0 -534
  218. package/plugins/acryl-router/src/core/middleware/etag/digest.test.ts +0 -21
  219. package/plugins/acryl-router/src/core/middleware/etag/index.test.ts +0 -503
  220. package/plugins/acryl-router/src/core/middleware/ip-restriction/index.test.ts +0 -217
  221. package/plugins/acryl-router/src/core/middleware/jwk/index.test.ts +0 -1135
  222. package/plugins/acryl-router/src/core/middleware/jwk/keys.test.json +0 -48
  223. package/plugins/acryl-router/src/core/middleware/jwt/index.test.ts +0 -802
  224. package/plugins/acryl-router/src/core/middleware/language/index.test.ts +0 -552
  225. package/plugins/acryl-router/src/core/middleware/logger/index.test.ts +0 -204
  226. package/plugins/acryl-router/src/core/middleware/method-not-allowed/index.test.ts +0 -292
  227. package/plugins/acryl-router/src/core/middleware/method-override/index.test.ts +0 -221
  228. package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +0 -334
  229. package/plugins/acryl-router/src/core/middleware/powered-by/index.test.ts +0 -37
  230. package/plugins/acryl-router/src/core/middleware/pretty-json/index.test.ts +0 -218
  231. package/plugins/acryl-router/src/core/middleware/request-id/index.test.ts +0 -168
  232. package/plugins/acryl-router/src/core/middleware/secure-headers/index.test.ts +0 -671
  233. package/plugins/acryl-router/src/core/middleware/serve-static/index.test.ts +0 -450
  234. package/plugins/acryl-router/src/core/middleware/serve-static/path.test.ts +0 -50
  235. package/plugins/acryl-router/src/core/middleware/timeout/index.test.ts +0 -70
  236. package/plugins/acryl-router/src/core/middleware/timing/index.test.ts +0 -310
  237. package/plugins/acryl-router/src/core/middleware/trailing-slash/index.test.ts +0 -381
  238. package/plugins/acryl-router/src/core/preset/quick.test.ts +0 -42
  239. package/plugins/acryl-router/src/core/preset/tiny.test.ts +0 -42
  240. package/plugins/acryl-router/src/core/request.test.ts +0 -751
  241. package/plugins/acryl-router/src/core/router/common.case.test.ts +0 -1132
  242. package/plugins/acryl-router/src/core/router/linear-router/router.test.ts +0 -80
  243. package/plugins/acryl-router/src/core/router/pattern-router/router.test.ts +0 -46
  244. package/plugins/acryl-router/src/core/router/reg-exp-router/prepared-router.test.ts +0 -154
  245. package/plugins/acryl-router/src/core/router/reg-exp-router/router.test.ts +0 -265
  246. package/plugins/acryl-router/src/core/router/smart-router/router.test.ts +0 -13
  247. package/plugins/acryl-router/src/core/router/trie-router/node.test.ts +0 -896
  248. package/plugins/acryl-router/src/core/router/trie-router/router.test.ts +0 -8
  249. package/plugins/acryl-router/src/core/types.test.ts +0 -4134
  250. package/plugins/acryl-router/src/core/utils/accept.test.ts +0 -299
  251. package/plugins/acryl-router/src/core/utils/basic-auth.test.ts +0 -56
  252. package/plugins/acryl-router/src/core/utils/body.test.ts +0 -496
  253. package/plugins/acryl-router/src/core/utils/buffer.test.ts +0 -147
  254. package/plugins/acryl-router/src/core/utils/color.test.ts +0 -23
  255. package/plugins/acryl-router/src/core/utils/concurrent.test.ts +0 -69
  256. package/plugins/acryl-router/src/core/utils/cookie.test.ts +0 -460
  257. package/plugins/acryl-router/src/core/utils/crypto.test.ts +0 -43
  258. package/plugins/acryl-router/src/core/utils/encode.test.ts +0 -61
  259. package/plugins/acryl-router/src/core/utils/filepath.test.ts +0 -78
  260. package/plugins/acryl-router/src/core/utils/html.test.ts +0 -16
  261. package/plugins/acryl-router/src/core/utils/ipaddr.test.ts +0 -149
  262. package/plugins/acryl-router/src/core/utils/jwt/jwa.test.ts +0 -86
  263. package/plugins/acryl-router/src/core/utils/jwt/jwt.test.ts +0 -1788
  264. package/plugins/acryl-router/src/core/utils/mime.test.ts +0 -64
  265. package/plugins/acryl-router/src/core/utils/stream.test.ts +0 -212
  266. package/plugins/acryl-router/src/core/utils/types.test.ts +0 -295
  267. package/plugins/acryl-router/src/core/utils/url.test.ts +0 -384
  268. package/plugins/acryl-router/src/core/validator/utils.test.ts +0 -82
  269. package/plugins/acryl-router/src/core/validator/validator.test.ts +0 -1488
  270. package/plugins/acryl-router/tests/docs-examples.spec.ts +0 -152
  271. package/plugins/acryl-router/tests/jsx.spec.tsx +0 -63
  272. package/plugins/acryl-router/tests/live-install.spec.ts +0 -64
  273. package/plugins/acryl-router/tests/loader.spec.ts +0 -72
  274. package/plugins/acryl-router/tests/loopback-only.spec.ts +0 -80
  275. package/plugins/acryl-router/tests/no-dom/consumer.ts +0 -11
  276. package/plugins/acryl-router/tests/no-dom/tsconfig.json +0 -13
  277. package/plugins/acryl-router/tests/service.spec.ts +0 -426
  278. package/plugins/acryl-router/tests/shadow-state.spec.ts +0 -79
  279. package/plugins/acryl-router-http/tests/adapter.spec.ts +0 -174
  280. package/plugins/acryl-router-http/tests/stream.spec.ts +0 -133
  281. package/plugins/acryl-router-http/tests/surfaces.spec.ts +0 -101
  282. package/plugins/acryl-state/src/react.ts +0 -11
  283. package/plugins/acryl-state/tests/cell.spec.ts +0 -71
  284. package/plugins/acryl-state/tests/react.spec.ts +0 -39
  285. package/plugins/acryl-state/tests/service.spec.ts +0 -132
@@ -1,503 +0,0 @@
1
- import { RETAINED_304_HEADERS, etag } from './index.ts'
2
- import { Acryl } from '../../app.ts'
3
-
4
- const createPatternedBody = (length: number) => {
5
- const body = new Uint8Array(length)
6
- for (let i = 0; i < body.byteLength; i++) {
7
- body[i] = i % 256
8
- }
9
- return body
10
- }
11
-
12
- describe('Etag Middleware', () => {
13
- it('Should return etag header', async () => {
14
- const app = new Acryl()
15
- app.use('/etag/*', etag())
16
- app.get('/etag/abc', (c) => {
17
- return c.text('Acryl is hot')
18
- })
19
- app.get('/etag/def', (c) => {
20
- return c.json({ message: 'Acryl is hot' })
21
- })
22
- let res = await app.request('http://localhost/etag/abc')
23
- expect(res.headers.get('ETag')).not.toBeFalsy()
24
- expect(res.headers.get('ETag')).toBe('"ba73e68ded3fb25dd2a1c90023bada7880da6ab7"')
25
-
26
- res = await app.request('http://localhost/etag/def')
27
- expect(res.headers.get('ETag')).not.toBeFalsy()
28
- expect(res.headers.get('ETag')).toBe('"13ac584bb97a25fdb954fc1813d2f03f8f5e017c"')
29
- })
30
-
31
- it('Should return etag header with another algorithm', async () => {
32
- const app = new Acryl()
33
- app.use(
34
- '/etag/*',
35
- etag({
36
- generateDigest: (body) =>
37
- crypto.subtle.digest(
38
- {
39
- name: 'SHA-256',
40
- },
41
- body
42
- ),
43
- })
44
- )
45
- app.get('/etag/abc', (c) => {
46
- return c.text('Acryl is hot')
47
- })
48
- app.get('/etag/def', (c) => {
49
- return c.json({ message: 'Acryl is hot' })
50
- })
51
- let res = await app.request('http://localhost/etag/abc')
52
- expect(res.headers.get('ETag')).not.toBeFalsy()
53
- expect(res.headers.get('ETag')).toBe(
54
- '"07c00dd761cfbb8e0765274785818aa0a59629d41cd66034acbde90dafe85cf3"'
55
- )
56
-
57
- res = await app.request('http://localhost/etag/def')
58
- expect(res.headers.get('ETag')).not.toBeFalsy()
59
- expect(res.headers.get('ETag')).toBe(
60
- '"49c6a1aa5026288ec59011aa6b3df0af8efc3d7531af06150dc7f018979efff7"'
61
- )
62
- })
63
-
64
- it('Should return etag header - binary', async () => {
65
- const app = new Acryl()
66
- app.use('/etag/*', etag())
67
- app.get('/etag', async (c) => {
68
- return c.body(new Uint8Array(1))
69
- })
70
-
71
- const res = await app.request('http://localhost/etag')
72
- expect(res.headers.get('ETag')).not.toBeFalsy()
73
- const etagHeader = res.headers.get('ETag')
74
- expect(etagHeader).toBe('"5ba93c9db0cff93f52b521d7420e43f6eda2784f"')
75
- })
76
-
77
- it('Should not be the same etag - arrayBuffer', async () => {
78
- const app = new Acryl()
79
- app.use('/etag/*', etag())
80
- app.get('/etag/ab1', (c) => {
81
- return c.body(new ArrayBuffer(1))
82
- })
83
- app.get('/etag/ab2', (c) => {
84
- return c.body(new ArrayBuffer(2))
85
- })
86
-
87
- let res = await app.request('http://localhost/etag/ab1')
88
- const hash = res.headers.get('Etag')
89
- res = await app.request('http://localhost/etag/ab2')
90
- expect(res.headers.get('ETag')).not.toBe(hash)
91
- })
92
-
93
- it('Should not be the same etag - Uint8Array', async () => {
94
- const app = new Acryl()
95
- app.use('/etag/*', etag())
96
- app.get('/etag/ui1', (c) => {
97
- return c.body(new Uint8Array([1, 2, 3]))
98
- })
99
- app.get('/etag/ui2', (c) => {
100
- return c.body(new Uint8Array([1, 2, 3, 4]))
101
- })
102
-
103
- let res = await app.request('http://localhost/etag/ui1')
104
- const hash = res.headers.get('Etag')
105
- res = await app.request('http://localhost/etag/ui2')
106
- expect(res.headers.get('ETag')).not.toBe(hash)
107
- })
108
-
109
- it('Should not be the same etag - ReadableStream', async () => {
110
- const app = new Acryl()
111
- app.use('/etag/*', etag())
112
- app.get('/etag/rs1', (c) => {
113
- return c.body(
114
- new ReadableStream({
115
- start(controller) {
116
- controller.enqueue(new Uint8Array([1]))
117
- controller.enqueue(new Uint8Array([2]))
118
- controller.close()
119
- },
120
- })
121
- )
122
- })
123
- app.get('/etag/rs2', (c) => {
124
- return c.body(
125
- new ReadableStream({
126
- start(controller) {
127
- controller.enqueue(new Uint8Array([1]))
128
- controller.enqueue(new Uint8Array([3]))
129
- controller.close()
130
- },
131
- })
132
- )
133
- })
134
-
135
- let res = await app.request('http://localhost/etag/rs1')
136
- const hash = res.headers.get('Etag')
137
- res = await app.request('http://localhost/etag/rs2')
138
- expect(res.headers.get('ETag')).not.toBe(hash)
139
- })
140
-
141
- it('Should return the same etag regardless of ReadableStream chunk boundaries', async () => {
142
- const app = new Acryl()
143
- app.use('/etag/*', etag())
144
- const body = createPatternedBody(1_000_000)
145
- app.get('/etag/rs1', (c) => {
146
- return c.body(
147
- new ReadableStream({
148
- start(controller) {
149
- controller.enqueue(body)
150
- controller.close()
151
- },
152
- })
153
- )
154
- })
155
- app.get('/etag/rs2', (c) => {
156
- return c.body(
157
- new ReadableStream({
158
- start(controller) {
159
- controller.enqueue(body.slice(0, 1))
160
- controller.enqueue(body.slice(1, 32_769))
161
- controller.enqueue(body.slice(32_769))
162
- controller.close()
163
- },
164
- })
165
- )
166
- })
167
-
168
- const res1 = await app.request('http://localhost/etag/rs1')
169
- const res2 = await app.request('http://localhost/etag/rs2')
170
- const expected = '"550563e0460b33a3540278a8446a70bb96eb5172"'
171
- expect(res1.headers.get('ETag')).toBe(expected)
172
- expect(res2.headers.get('ETag')).toBe(expected)
173
- })
174
-
175
- it('Should preserve the SHA-1 digest for bodies up to 256 KiB', async () => {
176
- const app = new Acryl()
177
- app.use('/etag/*', etag())
178
- app.get('/etag', (c) => c.body(createPatternedBody(256 * 1024)))
179
-
180
- const res = await app.request('http://localhost/etag')
181
- expect(res.headers.get('ETag')).toBe('"37ef77696fc255bf53b4cdd014b223676f2dc8bb"')
182
- })
183
-
184
- it('Should not return etag header when the stream is empty', async () => {
185
- const app = new Acryl()
186
- app.use('/etag/*', etag())
187
- app.get('/etag/abc', (c) => {
188
- const stream = new ReadableStream({
189
- start(controller) {
190
- controller.close()
191
- },
192
- })
193
- return c.body(stream)
194
- })
195
- const res = await app.request('http://localhost/etag/abc')
196
- expect(res.status).toBe(200)
197
- expect(res.headers.get('ETag')).toBeNull()
198
- })
199
-
200
- it('Should not return etag header when body is null', async () => {
201
- const app = new Acryl()
202
- app.use('/etag/*', etag())
203
- app.get('/etag/abc', () => new Response(null, { status: 500 }))
204
- const res = await app.request('http://localhost/etag/abc')
205
- expect(res.status).toBe(500)
206
- expect(res.headers.get('ETag')).toBeNull()
207
- })
208
-
209
- it('Should return etag header - weak', async () => {
210
- const app = new Acryl()
211
- app.use('/etag/*', etag({ weak: true }))
212
- app.get('/etag/abc', (c) => {
213
- return c.text('Acryl is hot')
214
- })
215
-
216
- const res = await app.request('http://localhost/etag/abc')
217
- expect(res.headers.get('ETag')).not.toBeFalsy()
218
- expect(res.headers.get('ETag')).toBe('W/"ba73e68ded3fb25dd2a1c90023bada7880da6ab7"')
219
- })
220
-
221
- it('Should handle conditional GETs', async () => {
222
- const app = new Acryl()
223
- app.use('/etag/*', etag())
224
- app.get('/etag/ghi', (c) =>
225
- c.text('Acryl is great', 200, {
226
- 'cache-control': 'public, max-age=120',
227
- date: 'Mon, Feb 27 2023 12:08:36 GMT',
228
- expires: 'Mon, Feb 27 2023 12:10:36 GMT',
229
- server: 'Upstream 1.2',
230
- vary: 'Accept-Language',
231
- })
232
- )
233
-
234
- // unconditional GET
235
- let res = await app.request('http://localhost/etag/ghi')
236
- expect(res.status).toBe(200)
237
- expect(res.headers.get('ETag')).not.toBeFalsy()
238
- const etagHeaderValue = res.headers.get('ETag') || ''
239
-
240
- // conditional GET with the wrong ETag:
241
- res = await app.request('http://localhost/etag/ghi', {
242
- headers: {
243
- 'If-None-Match': '"not the right etag"',
244
- },
245
- })
246
- expect(res.status).toBe(200)
247
-
248
- // conditional GET with matching ETag:
249
- res = await app.request('http://localhost/etag/ghi', {
250
- headers: {
251
- 'If-None-Match': etagHeaderValue,
252
- },
253
- })
254
- expect(res.status).toBe(304)
255
- expect(res.headers.get('Etag')).toBe(etagHeaderValue)
256
- expect(await res.text()).toBe('')
257
- expect(res.headers.get('cache-control')).toBe('public, max-age=120')
258
- expect(res.headers.get('date')).toBe('Mon, Feb 27 2023 12:08:36 GMT')
259
- expect(res.headers.get('expires')).toBe('Mon, Feb 27 2023 12:10:36 GMT')
260
- expect(res.headers.get('server')).toBeFalsy()
261
- expect(res.headers.get('vary')).toBe('Accept-Language')
262
-
263
- // conditional GET with matching ETag among list:
264
- res = await app.request('http://localhost/etag/ghi', {
265
- headers: {
266
- 'If-None-Match': `"mismatch 1", ${etagHeaderValue}, "mismatch 2"`,
267
- },
268
- })
269
- expect(res.status).toBe(304)
270
-
271
- // conditional GET with matching ETag among list, OWS before the comma (RFC 9110):
272
- res = await app.request('http://localhost/etag/ghi', {
273
- headers: {
274
- 'If-None-Match': `"mismatch 1", ${etagHeaderValue} , "mismatch 2"`,
275
- },
276
- })
277
- expect(res.status).toBe(304)
278
-
279
- // conditional GET with `*` wildcard:
280
- res = await app.request('http://localhost/etag/ghi', {
281
- headers: {
282
- 'If-None-Match': '*',
283
- },
284
- })
285
- expect(res.status).toBe(304)
286
- })
287
-
288
- it('Should handle conditional QUERY requests', async () => {
289
- const app = new Acryl()
290
- app.use('/etag/*', etag())
291
- app.on('QUERY', '/etag/query', (c) => c.text('Acryl is great'))
292
-
293
- // unconditional QUERY
294
- let res = await app.request('http://localhost/etag/query', {
295
- method: 'QUERY',
296
- body: 'select *',
297
- })
298
- expect(res.status).toBe(200)
299
- expect(res.headers.get('ETag')).not.toBeFalsy()
300
- const etagHeaderValue = res.headers.get('ETag') || ''
301
-
302
- // conditional QUERY with the wrong ETag:
303
- res = await app.request('http://localhost/etag/query', {
304
- method: 'QUERY',
305
- body: 'select *',
306
- headers: {
307
- 'If-None-Match': '"not the right etag"',
308
- },
309
- })
310
- expect(res.status).toBe(200)
311
-
312
- // conditional QUERY with matching ETag:
313
- res = await app.request('http://localhost/etag/query', {
314
- method: 'QUERY',
315
- body: 'select *',
316
- headers: {
317
- 'If-None-Match': etagHeaderValue,
318
- },
319
- })
320
- expect(res.status).toBe(304)
321
- expect(res.headers.get('ETag')).toBe(etagHeaderValue)
322
- expect(await res.text()).toBe('')
323
-
324
- // conditional QUERY with `*` wildcard:
325
- res = await app.request('http://localhost/etag/query', {
326
- method: 'QUERY',
327
- body: 'select *',
328
- headers: {
329
- 'If-None-Match': '*',
330
- },
331
- })
332
- expect(res.status).toBe(304)
333
- })
334
-
335
- it('Should not return 304 on unsafe methods or error responses', async () => {
336
- const app = new Acryl()
337
- app.use('/etag/*', etag())
338
- app.put('/etag/put', (c) => c.text('created', 201, { ETag: '"etag-123"' }))
339
- app.get('/etag/not-found', (c) => c.text('not found', 404, { ETag: '"etag-123"' }))
340
-
341
- // Unsafe methods:
342
- let res = await app.request('http://localhost/etag/put', {
343
- method: 'PUT',
344
- headers: {
345
- 'If-None-Match': '*',
346
- },
347
- })
348
- expect(res.status).toBe(201)
349
- expect(await res.text()).toBe('created')
350
-
351
- res = await app.request('http://localhost/etag/put', {
352
- method: 'PUT',
353
- headers: {
354
- 'If-None-Match': '"etag-123"',
355
- },
356
- })
357
- expect(res.status).toBe(201)
358
- expect(await res.text()).toBe('created')
359
-
360
- // Error responses:
361
- res = await app.request('http://localhost/etag/not-found', {
362
- headers: {
363
- 'If-None-Match': '*',
364
- },
365
- })
366
- expect(res.status).toBe(404)
367
-
368
- res = await app.request('http://localhost/etag/not-found', {
369
- headers: {
370
- 'If-None-Match': '"etag-123"',
371
- },
372
- })
373
- expect(res.status).toBe(404)
374
- })
375
-
376
- it('Should not return duplicate etag header values', async () => {
377
- const app = new Acryl()
378
- app.use('/etag/*', etag())
379
- app.use('/etag/*', etag())
380
- app.get('/etag/abc', (c) => c.text('Acryl is hot'))
381
-
382
- const res = await app.request('http://localhost/etag/abc')
383
- expect(res.headers.get('ETag')).not.toBeFalsy()
384
- expect(res.headers.get('ETag')).toBe('"ba73e68ded3fb25dd2a1c90023bada7880da6ab7"')
385
- })
386
-
387
- it('Should not override ETag headers from upstream', async () => {
388
- const app = new Acryl()
389
- app.use('/etag/*', etag())
390
- app.get('/etag/predefined', (c) =>
391
- c.text('This response has an ETag', 200, { ETag: '"f-0194-d"' })
392
- )
393
-
394
- const res = await app.request('http://localhost/etag/predefined')
395
- expect(res.headers.get('ETag')).toBe('"f-0194-d"')
396
- })
397
-
398
- it('Should retain the default and the specified headers', async () => {
399
- const cacheControl = 'public, max-age=120'
400
- const message = 'Hello!'
401
- const app = new Acryl()
402
- app.use(
403
- '/etag/*',
404
- etag({
405
- retainedHeaders: ['x-message-retain', 'X-Message-Retain-Upper', ...RETAINED_304_HEADERS],
406
- })
407
- )
408
- app.get('/etag', (c) => {
409
- return c.text('Acryl is hot', 200, {
410
- 'cache-control': cacheControl,
411
- 'x-message-retain': message,
412
- 'X-Message-Retain-Upper': message,
413
- 'x-message': message,
414
- })
415
- })
416
- const res = await app.request('/etag', {
417
- headers: {
418
- 'If-None-Match': '"ba73e68ded3fb25dd2a1c90023bada7880da6ab7"',
419
- },
420
- })
421
- expect(res.status).toBe(304)
422
- expect(res.headers.get('ETag')).not.toBeFalsy()
423
- expect(res.headers.get('ETag')).toBe('"ba73e68ded3fb25dd2a1c90023bada7880da6ab7"')
424
- expect(res.headers.get('Cache-Control')).toBe(cacheControl)
425
- expect(res.headers.get('x-message-retain')).toBe(message)
426
- expect(res.headers.get('X-Message-Retain-Upper')).toBe(message)
427
- expect(res.headers.get('x-message')).toBeFalsy()
428
- })
429
-
430
- it('Should return 304 when weak ETag in If-None-Match matches the generated ETag', async () => {
431
- const app = new Acryl()
432
- app.use('/etag/*', etag())
433
- app.get('/etag/abc', (c) => {
434
- return c.text('Acryl is hot')
435
- })
436
- let res = await app.request('http://localhost/etag/abc')
437
- const headerEtag = res.headers.get('ETag')!
438
-
439
- expect(headerEtag).not.toBeFalsy()
440
-
441
- res = await app.request('http://localhost/etag/abc', {
442
- headers: {
443
- 'If-None-Match': 'W/"ba73e68ded3fb25dd2a1c90023bada7880da6ab7"',
444
- },
445
- })
446
-
447
- expect(res.status).toBe(304)
448
- })
449
-
450
- describe('When crypto is not available', () => {
451
- let _crypto: Crypto | undefined
452
- beforeAll(() => {
453
- _crypto = globalThis.crypto
454
- Object.defineProperty(globalThis, 'crypto', {
455
- value: {},
456
- })
457
- })
458
-
459
- afterAll(() => {
460
- Object.defineProperty(globalThis, 'crypto', {
461
- value: _crypto,
462
- })
463
- })
464
-
465
- it('Should not generate etag', async () => {
466
- const app = new Acryl()
467
- app.use('/etag/*', etag())
468
- app.get('/etag/no-digest', (c) => c.text('Acryl is hot'))
469
- const res = await app.request('/etag/no-digest')
470
- expect(res.status).toBe(200)
471
- expect(res.headers.get('ETag')).toBeNull()
472
- })
473
- })
474
-
475
- it('Should remove all non-retained headers on 304 without skipping any', async () => {
476
- const app = new Acryl()
477
- app.use('/etag/*', etag())
478
- app.get('/etag/multi-headers', (c) => {
479
- c.header('X-Custom-1', 'val1')
480
- c.header('X-Custom-2', 'val2')
481
- c.header('X-Custom-3', 'val3')
482
- c.header('X-Custom-4', 'val4')
483
- c.header('Cache-Control', 'max-age=3600')
484
- return c.text('Acryl is hot')
485
- })
486
- const res1 = await app.request('http://localhost/etag/multi-headers')
487
- const etagHeader = res1.headers.get('ETag')!
488
- expect(res1.status).toBe(200)
489
-
490
- const res2 = await app.request('http://localhost/etag/multi-headers', {
491
- headers: {
492
- 'If-None-Match': etagHeader,
493
- },
494
- })
495
- expect(res2.status).toBe(304)
496
- expect(res2.headers.get('ETag')).toBe(etagHeader)
497
- expect(res2.headers.get('Cache-Control')).toBe('max-age=3600')
498
- expect(res2.headers.get('X-Custom-1')).toBeNull()
499
- expect(res2.headers.get('X-Custom-2')).toBeNull()
500
- expect(res2.headers.get('X-Custom-3')).toBeNull()
501
- expect(res2.headers.get('X-Custom-4')).toBeNull()
502
- })
503
- })