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,149 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-unused-vars */
2
- import { expectTypeOf } from 'vitest'
3
- import { hc } from './index.ts'
4
- import { Acryl } from '../index.ts'
5
- import { defineWebSocketHelper } from '../helper/websocket/index.ts'
6
- import type { TypedURL } from './types.ts'
7
-
8
- // The Deno adapter is not part of ACRYL; these tests only build client URLs, so a helper that never upgrades stands in for it.
9
- const upgradeWebSocket = defineWebSocketHelper(async () => {})
10
-
11
- describe('WebSockets', () => {
12
- const app = new Acryl()
13
- .get(
14
- '/ws',
15
- upgradeWebSocket(() => ({}))
16
- )
17
- .get('/', (c) => c.json({}))
18
- const client = hc<typeof app>('/')
19
-
20
- it('WebSocket route', () => {
21
- expectTypeOf(client.ws).toMatchTypeOf<{
22
- $ws: () => WebSocket
23
- }>()
24
- })
25
- it('Not WebSocket Route', () => {
26
- expectTypeOf<
27
- typeof client.index extends { $ws: () => WebSocket } ? false : true
28
- >().toEqualTypeOf(true)
29
- })
30
- })
31
-
32
- describe('without the leading slash', () => {
33
- const app = new Acryl()
34
- .get('foo', (c) => c.json({}))
35
- .get('foo/bar', (c) => c.json({}))
36
- .get('foo/:id/baz', (c) => c.json({}))
37
- const client = hc<typeof app, 'http://localhost'>('http://localhost')
38
- it('`foo` should have `$get`', () => {
39
- expectTypeOf(client.foo).toHaveProperty('$get')
40
- expectTypeOf(client.foo.$url()).toEqualTypeOf<TypedURL<'http:', 'localhost', '', '/foo', ''>>()
41
- expectTypeOf(client.foo.$path()).toEqualTypeOf<'/foo'>()
42
- })
43
- it('`foo.bar` should not have `$get`', () => {
44
- expectTypeOf(client.foo.bar).toHaveProperty('$get')
45
- expectTypeOf(client.foo.bar.$url()).toEqualTypeOf<
46
- TypedURL<'http:', 'localhost', '', '/foo/bar', ''>
47
- >()
48
- expectTypeOf(client.foo.bar.$path()).toEqualTypeOf<'/foo/bar'>()
49
- })
50
- it('`foo[":id"].baz` should have `$get`', () => {
51
- expectTypeOf(client.foo[':id'].baz).toHaveProperty('$get')
52
- expectTypeOf(client.foo[':id'].baz.$url()).toEqualTypeOf<
53
- TypedURL<'http:', 'localhost', '', '/foo/:id/baz', ''>
54
- >()
55
- expectTypeOf(
56
- client.foo[':id'].baz.$url({
57
- param: { id: '123' },
58
- })
59
- ).toEqualTypeOf<TypedURL<'http:', 'localhost', '', '/foo/123/baz', ''>>()
60
- expectTypeOf(
61
- client.foo[':id'].baz.$url({
62
- param: { id: '123' },
63
- query: { q: 'acryl' },
64
- })
65
- ).toEqualTypeOf<TypedURL<'http:', 'localhost', '', '/foo/123/baz', `?${string}`>>()
66
-
67
- expectTypeOf(client.foo[':id'].baz.$path()).toEqualTypeOf<'/foo/:id/baz'>()
68
- expectTypeOf(
69
- client.foo[':id'].baz.$path({
70
- param: { id: '123' },
71
- })
72
- ).toEqualTypeOf<'/foo/123/baz'>()
73
- expectTypeOf(
74
- client.foo[':id'].baz.$path({
75
- param: { id: '123' },
76
- query: { q: 'acryl' },
77
- })
78
- ).toEqualTypeOf<`/foo/123/baz?${string}`>()
79
- })
80
- })
81
-
82
- describe('with the leading slash', () => {
83
- const app = new Acryl()
84
- .get('/foo', (c) => c.json({}))
85
- .get('/foo/bar', (c) => c.json({}))
86
- .get('/foo/:id/baz', (c) => c.json({}))
87
- const client = hc<typeof app>('')
88
- it('`foo` should have `$get`', () => {
89
- expectTypeOf(client.foo).toHaveProperty('$get')
90
- })
91
- it('`foo.bar` should not have `$get`', () => {
92
- expectTypeOf(client.foo.bar).toHaveProperty('$get')
93
- })
94
- it('`foo[":id"].baz` should have `$get`', () => {
95
- expectTypeOf(client.foo[':id'].baz).toHaveProperty('$get')
96
- })
97
- })
98
-
99
- describe('app.all()', () => {
100
- const app = new Acryl()
101
- .all('/all-route', (c) => c.json({ msg: 'all methods' }))
102
- .get('/get-route', (c) => c.json({ msg: 'get only' }))
103
- const client = hc<typeof app>('http://localhost', { fetch: app.request })
104
-
105
- it('should NOT expose $all on the client', () => {
106
- expectTypeOf<
107
- (typeof client)['all-route'] extends { $all: unknown } ? true : false
108
- >().toEqualTypeOf<false>()
109
- })
110
-
111
- it('should still expose valid HTTP methods like $get', () => {
112
- expectTypeOf(client['get-route']).toHaveProperty('$get')
113
- })
114
-
115
- it('should expose all standard HTTP methods for routes defined with app.all()', () => {
116
- // $all routes should have all standard HTTP methods typed
117
- expectTypeOf(client['all-route']).toHaveProperty('$get')
118
- expectTypeOf(client['all-route']).toHaveProperty('$post')
119
- expectTypeOf(client['all-route']).toHaveProperty('$put')
120
- expectTypeOf(client['all-route']).toHaveProperty('$delete')
121
- expectTypeOf(client['all-route']).toHaveProperty('$options')
122
- expectTypeOf(client['all-route']).toHaveProperty('$patch')
123
- expectTypeOf(client['all-route']).toHaveProperty('$query')
124
- })
125
-
126
- it('should have correct return type for expanded methods', async () => {
127
- // The response type should match the original handler's return type
128
- const res = await client['all-route'].$get()
129
- expectTypeOf(res.json()).resolves.toEqualTypeOf<{ msg: string }>()
130
- })
131
- })
132
-
133
- describe('with base URL pathname', () => {
134
- const app = new Acryl()
135
- .get('foo', (c) => c.json({}))
136
- .get('foo/bar', (c) => c.json({}))
137
- .get('foo/:id/baz', (c) => c.json({}))
138
- const client = hc<typeof app, 'http://localhost/api'>('http://localhost/api')
139
- it('$path', () => {
140
- expectTypeOf(client.foo.$path()).toEqualTypeOf<'/foo'>()
141
- expectTypeOf(client.foo.bar.$path()).toEqualTypeOf<'/foo/bar'>()
142
- expectTypeOf(
143
- client.foo[':id'].baz.$path({
144
- param: { id: '123' },
145
- query: { q: 'acryl' },
146
- })
147
- ).toEqualTypeOf<`/foo/123/baz?${string}`>()
148
- })
149
- })
@@ -1,405 +0,0 @@
1
- import { HttpResponse, http } from 'msw'
2
- import { setupServer } from 'msw/node'
3
- import { Acryl } from '../app.ts'
4
- import type { Expect, Equal } from '../utils/types.ts'
5
- import { hc } from './client.ts'
6
- import {
7
- buildSearchParams,
8
- deepMerge,
9
- parseResponse,
10
- mergePath,
11
- removeIndexString,
12
- replaceUrlParam,
13
- replaceUrlProtocol,
14
- } from './utils.ts'
15
-
16
- describe('mergePath', () => {
17
- it('Should merge paths correctly', () => {
18
- expect(mergePath('http://localhost', '/api')).toBe('http://localhost/api')
19
- expect(mergePath('http://localhost/', '/api')).toBe('http://localhost/api')
20
- expect(mergePath('http://localhost', 'api')).toBe('http://localhost/api')
21
- expect(mergePath('http://localhost/', 'api')).toBe('http://localhost/api')
22
- expect(mergePath('http://localhost/', '/')).toBe('http://localhost/')
23
- })
24
- })
25
-
26
- describe('replaceUrlParams', () => {
27
- it('Should replace correctly', () => {
28
- const url = 'http://localhost/posts/:postId/comments/:commentId'
29
- const params = {
30
- postId: '123',
31
- commentId: '456',
32
- }
33
- const replacedUrl = replaceUrlParam(url, params)
34
- expect(replacedUrl).toBe('http://localhost/posts/123/comments/456')
35
- })
36
-
37
- it('Should replace correctly when there is regex pattern', () => {
38
- const url = 'http://localhost/posts/:postId{[abc]+}/comments/:commentId{[0-9]+}'
39
- const params = {
40
- postId: 'abc',
41
- commentId: '456',
42
- }
43
- const replacedUrl = replaceUrlParam(url, params)
44
- expect(replacedUrl).toBe('http://localhost/posts/abc/comments/456')
45
- })
46
-
47
- it('Should replace correctly when there is regex pattern with length limit', () => {
48
- const url = 'http://localhost/year/:year{[1-9]{1}[0-9]{3}}/month/:month{[0-9]{2}}'
49
- const params = {
50
- year: '2024',
51
- month: '2',
52
- }
53
- const replacedUrl = replaceUrlParam(url, params)
54
- expect(replacedUrl).toBe('http://localhost/year/2024/month/2')
55
- })
56
-
57
- it('Should replace correctly when it has optional parameters', () => {
58
- const url = 'http://localhost/something/:firstId/:secondId/:version?'
59
- const params = {
60
- firstId: '123',
61
- secondId: '456',
62
- version: undefined,
63
- }
64
- const replacedUrl = replaceUrlParam(url, params)
65
- expect(replacedUrl).toBe('http://localhost/something/123/456')
66
- })
67
-
68
- it('Should not replace a param whose name is a prefix of another param', () => {
69
- const url = 'http://localhost/:idType/:id'
70
- const params = {
71
- id: '1',
72
- idType: '2',
73
- }
74
- const replacedUrl = replaceUrlParam(url, params)
75
- expect(replacedUrl).toBe('http://localhost/2/1')
76
- })
77
-
78
- it('Should replace correctly when parameter value contains $ characters', () => {
79
- expect(replaceUrlParam('http://localhost/items/:id', { id: 'item$&' })).toBe(
80
- 'http://localhost/items/item$&'
81
- )
82
- expect(replaceUrlParam('http://localhost/items/:id', { id: '$100' })).toBe(
83
- 'http://localhost/items/$100'
84
- )
85
- expect(replaceUrlParam('http://localhost/users/:id', { id: 'test$`' })).toBe(
86
- 'http://localhost/users/test$`'
87
- )
88
- expect(replaceUrlParam('http://localhost/users/:id/posts', { id: "test$'" })).toBe(
89
- "http://localhost/users/test$'/posts"
90
- )
91
- })
92
- })
93
-
94
- describe('buildSearchParams', () => {
95
- it('Should build URLSearchParams correctly', () => {
96
- const query = {
97
- id: '123',
98
- type: 'test',
99
- tag: ['a', 'b'],
100
- }
101
- const searchParams = buildSearchParams(query)
102
- expect(searchParams.toString()).toBe('id=123&type=test&tag=a&tag=b')
103
- })
104
-
105
- it('Should skip an undefined entry inside an array, as it does for a top-level value', () => {
106
- // `['a', undefined, 'b']` used to serialise as `tag=a&tag=undefined&tag=b`,
107
- // sending the literal string "undefined" to the server.
108
- const searchParams = buildSearchParams({
109
- tag: ['a', undefined as unknown as string, 'b'],
110
- })
111
- expect(searchParams.toString()).toBe('tag=a&tag=b')
112
- })
113
-
114
- it('Should keep an empty string in an array', () => {
115
- const searchParams = buildSearchParams({ tag: ['a', '', 'b'] })
116
- expect(searchParams.toString()).toBe('tag=a&tag=&tag=b')
117
- })
118
-
119
- it('Should drop an array whose entries are all undefined', () => {
120
- const searchParams = buildSearchParams({
121
- tag: [undefined, undefined] as unknown as string[],
122
- })
123
- expect(searchParams.toString()).toBe('')
124
- })
125
- })
126
-
127
- describe('replaceUrlProtocol', () => {
128
- it('Should replace http to ws', () => {
129
- const url = 'http://localhost'
130
- const newUrl = replaceUrlProtocol(url, 'ws')
131
- expect(newUrl).toBe('ws://localhost')
132
- })
133
-
134
- it('Should replace https to wss', () => {
135
- const url = 'https://localhost'
136
- const newUrl = replaceUrlProtocol(url, 'ws')
137
- expect(newUrl).toBe('wss://localhost')
138
- })
139
-
140
- it('Should replace ws to http', () => {
141
- const url = 'ws://localhost'
142
- const newUrl = replaceUrlProtocol(url, 'http')
143
- expect(newUrl).toBe('http://localhost')
144
- })
145
-
146
- it('Should replace wss to https', () => {
147
- const url = 'wss://localhost'
148
- const newUrl = replaceUrlProtocol(url, 'http')
149
- expect(newUrl).toBe('https://localhost')
150
- })
151
- })
152
-
153
- describe('removeIndexString', () => {
154
- it('Should remove last `/index` string', () => {
155
- let url = 'http://localhost/index'
156
- let newUrl = removeIndexString(url)
157
- expect(newUrl).toBe('http://localhost/')
158
-
159
- url = '/index'
160
- newUrl = removeIndexString(url)
161
- expect(newUrl).toBe('')
162
-
163
- url = '/sub/index'
164
- newUrl = removeIndexString(url)
165
- expect(newUrl).toBe('/sub')
166
-
167
- url = '/subindex'
168
- newUrl = removeIndexString(url)
169
- expect(newUrl).toBe('/subindex')
170
- })
171
-
172
- it('Should remove `/index` with query parameters', () => {
173
- let url = 'http://localhost/index?page=123&limit=20'
174
- let newUrl = removeIndexString(url)
175
- expect(newUrl).toBe('http://localhost/?page=123&limit=20')
176
-
177
- url = 'https://example.com/index?q=search'
178
- newUrl = removeIndexString(url)
179
- expect(newUrl).toBe('https://example.com/?q=search')
180
-
181
- url = '/api/index?filter=test'
182
- newUrl = removeIndexString(url)
183
- expect(newUrl).toBe('/api?filter=test')
184
-
185
- url = '/index?a=1&b=2&c=3'
186
- newUrl = removeIndexString(url)
187
- expect(newUrl).toBe('?a=1&b=2&c=3')
188
- })
189
- })
190
-
191
- describe('deepMerge', () => {
192
- it('should return the source object if the target object is not an object', () => {
193
- const target = null
194
- const source = 'not an object' as unknown as Record<string, unknown>
195
- const result = deepMerge(target, source)
196
- expect(result).toEqual(source)
197
- })
198
-
199
- it('should merge two objects with object properties', () => {
200
- expect(
201
- deepMerge(
202
- { headers: { acryl: '1' }, timeout: 2, params: {} },
203
- { headers: { acryl: '2', demo: 2 }, params: undefined }
204
- )
205
- ).toStrictEqual({
206
- params: undefined,
207
- headers: { acryl: '2', demo: 2 },
208
- timeout: 2,
209
- })
210
- })
211
- })
212
-
213
- describe('parseResponse', async () => {
214
- const _app = new Acryl()
215
- .get('/text', (c) => c.text('hi'))
216
- .get('/json', (c) => c.json({ message: 'hi' }))
217
- .get('/might-error-json', (c) => {
218
- if (Math.random() > 0.5) {
219
- return c.json({ error: 'error' }, 500)
220
- }
221
- return c.json({ data: [{ id: 1 }, { id: 2 }] })
222
- })
223
- .get('/might-error-mixed-json-text', (c) => {
224
- if (Math.random() > 0.5) {
225
- return c.text('500 Internal Server Error', 500)
226
- }
227
- return c.json({ message: 'Success' })
228
- })
229
- .get('/200-explicit', (c) => c.text('OK', 200))
230
- .get('/404', (c) => c.text('404 Not Found', 404))
231
- .get('/500', (c) => c.text('500 Internal Server Error', 500))
232
- .get('/raw', (c) => {
233
- c.header('content-type', '')
234
- return c.body('hello')
235
- })
236
- .get('/rawUnknown', (c) => {
237
- c.header('content-type', 'x/custom-type')
238
- return c.body('hello')
239
- })
240
- .get('/rawBuffer', (c) => {
241
- c.header('content-type', 'x/custom-type')
242
- return c.body(new TextEncoder().encode('acryl'))
243
- })
244
-
245
- const client = hc<typeof _app>('http://localhost')
246
-
247
- const server = setupServer(
248
- http.get('http://localhost/text', () => {
249
- return HttpResponse.text('hi')
250
- }),
251
- http.get('http://localhost/json', () => {
252
- return HttpResponse.json({ message: 'hi' })
253
- }),
254
- http.get('http://localhost/might-error-json', () => {
255
- if (Math.random() > 0.5) {
256
- return HttpResponse.json({ error: 'error' }, { status: 500 })
257
- }
258
- return HttpResponse.json({ data: [{ id: 1 }, { id: 2 }] })
259
- }),
260
- http.get('http://localhost/might-error-mixed-json-text', () => {
261
- if (Math.random() > 0.5) {
262
- return HttpResponse.text('500 Internal Server Error', { status: 500 })
263
- }
264
- return HttpResponse.json({ message: 'Success' })
265
- }),
266
- http.get('http://localhost/200-explicit', () => {
267
- return HttpResponse.text('OK', { status: 200 })
268
- }),
269
- http.get('http://localhost/404', () => {
270
- return HttpResponse.text('404 Not Found', { status: 404 })
271
- }),
272
- http.get('http://localhost/500', () => {
273
- return HttpResponse.text('500 Internal Server Error', { status: 500 })
274
- }),
275
- http.get('http://localhost/raw', () => {
276
- return HttpResponse.text('hello', {
277
- headers: {
278
- 'content-type': '',
279
- },
280
- })
281
- }),
282
- http.get('http://localhost/rawUnknown', () => {
283
- return HttpResponse.text('hello', {
284
- headers: {
285
- 'content-type': 'x/custom-type',
286
- },
287
- })
288
- }),
289
- http.get('http://localhost/rawBuffer', () => {
290
- return HttpResponse.arrayBuffer(new TextEncoder().encode('acryl').buffer, {
291
- headers: {
292
- 'content-type': 'x/custom-type',
293
- },
294
- })
295
- }),
296
- http.get('http://localhost/noRoute', () => HttpResponse.error())
297
- )
298
-
299
- beforeAll(() => server.listen())
300
- afterEach(() => server.resetHandlers())
301
- afterAll(() => server.close())
302
-
303
- await Promise.all([
304
- it('should auto parse the text response - async fetch', async () => {
305
- const result = await parseResponse(client.text.$get())
306
- expect(result).toBe('hi')
307
- type _verify = Expect<Equal<typeof result, 'hi'>>
308
- }),
309
- it('should auto parse the text response - sync fetch', async () => {
310
- const result = await parseResponse(await client.text.$get())
311
- expect(result).toBe('hi')
312
- type _verify = Expect<Equal<typeof result, 'hi'>>
313
- }),
314
- it('should auto parse text response - explicit 200', async () => {
315
- const result = await parseResponse(client['200-explicit'].$get())
316
- expect(result).toBe('OK')
317
- type _verify = Expect<Equal<typeof result, 'OK'>>
318
- }),
319
- it('should auto parse the json response - async fetch', async () => {
320
- const result = await parseResponse(client.json.$get())
321
- expect(result).toEqual({ message: 'hi' })
322
- type _verify = Expect<Equal<typeof result, { message: string }>>
323
- }),
324
- it('should auto parse the json response - sync fetch', async () => {
325
- const result = await parseResponse(await client.json.$get())
326
- expect(result).toEqual({ message: 'hi' })
327
- type _verify = Expect<Equal<typeof result, { message: string }>>
328
- }),
329
- it('should throw error when the response is not ok', async () => {
330
- await expect(parseResponse(client['404'].$get())).rejects.toThrowError('404 Not Found')
331
- }),
332
- it('should parse as text for raw responses without content-type header', async () => {
333
- const result = await parseResponse(client.raw.$get())
334
- expect(result).toBe('hello')
335
- type _verify = Expect<Equal<typeof result, 'hello'>>
336
- }),
337
- it('should parse as unknown string for raw buffer responses with unknown content-type header', async () => {
338
- const result = await parseResponse(client.rawBuffer.$get())
339
- expect(result).toMatchInlineSnapshot('"acryl"')
340
- type _verify = Expect<Equal<typeof result, string>>
341
- }),
342
- it('should throw error matching snapshots', async () => {
343
- // Defined 404 route
344
- await expect(parseResponse(client['404'].$get())).rejects.toThrowErrorMatchingInlineSnapshot(
345
- '[DetailedError: 404 Not Found]'
346
- )
347
-
348
- // Defined 500 route
349
- await expect(parseResponse(client['500'].$get())).rejects.toThrowErrorMatchingInlineSnapshot(
350
- '[DetailedError: 500 Internal Server Error]'
351
- )
352
-
353
- // Not defined route: MSW simulates a network error, so fetch itself rejects
354
- // Note: the error in this test case is thrown at the `fetch` call (.$get()), not during the `parseResponse` call, so I think `parseResponse` should not try to catch and wrap it into a structured error, which could be inconsistent, if the user awaited the fetch.
355
- await expect(
356
- // @ts-expect-error noRoute is not defined
357
- parseResponse(client['noRoute'].$get())
358
- ).rejects.toThrowErrorMatchingInlineSnapshot('[TypeError: Failed to fetch]')
359
- }),
360
- it('(type-only) should bypass error responses in the result type inference - simple 404', async () => {
361
- type ResultType = Awaited<
362
- ReturnType<typeof parseResponse<Awaited<ReturnType<(typeof client)['404']['$get']>>>>
363
- >
364
- type _verify = Expect<Equal<Awaited<ResultType>, undefined>>
365
- }),
366
- it('(type-only) should bypass error responses in the result type inference - conditional - json', async () => {
367
- type ResultType = Awaited<
368
- ReturnType<
369
- typeof parseResponse<Awaited<ReturnType<(typeof client)['might-error-json']['$get']>>>
370
- >
371
- >
372
- type _verify = Expect<Equal<ResultType, { data: { id: number }[] }>>
373
- }),
374
- it('(type-only) should bypass error responses in the result type inference - conditional - mixed json/text', async () => {
375
- type ResultType = Awaited<
376
- ReturnType<
377
- typeof parseResponse<
378
- Awaited<ReturnType<(typeof client)['might-error-mixed-json-text']['$get']>>
379
- >
380
- >
381
- >
382
- type _verify = Expect<Equal<ResultType, { message: string }>>
383
- }),
384
- ])
385
-
386
- it('should parse json response with _bodyInit when body is undefined', async () => {
387
- const mockFetch = vi.fn().mockResolvedValue({
388
- ok: true,
389
- status: 200,
390
- headers: new Headers({ 'content-type': 'application/json' }),
391
- body: undefined,
392
- _bodyInit: '{"message":"test"}',
393
- json: async () => ({ message: 'test' }),
394
- })
395
-
396
- global.fetch = mockFetch
397
-
398
- const mockClientResponse = {
399
- $get: mockFetch,
400
- }
401
-
402
- const result = await parseResponse(mockClientResponse.$get())
403
- expect(result).toEqual({ message: 'test' })
404
- })
405
- })