acrylblends 0.6.1 → 0.6.2

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 (119) hide show
  1. package/README.md +8 -6
  2. package/docs/framework/UPSTREAM.md +1 -1
  3. package/docs/framework/api/presets.md +0 -3
  4. package/docs/framework/cordis/acryl-in-a-cordis-app.md +3 -0
  5. package/docs/framework/getting-started/basic.md +4 -4
  6. package/docs/framework/guides/jsx.md +1 -1
  7. package/docs/framework/guides/middleware.md +1 -1
  8. package/docs/framework/helpers/cookie.md +1 -1
  9. package/docs/framework/helpers/dev.md +0 -3
  10. package/docs/framework/helpers/jwt.md +1 -1
  11. package/docs/framework/helpers/proxy.md +0 -3
  12. package/docs/framework/middleware/builtin/basic-auth.md +6 -6
  13. package/docs/framework/middleware/builtin/cache.md +0 -3
  14. package/docs/framework/middleware/builtin/combine.md +1 -1
  15. package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
  16. package/docs/framework/middleware/builtin/logger.md +1 -1
  17. package/docs/framework/middleware/builtin/mount.md +0 -3
  18. package/docs/framework/upstream.json +2 -2
  19. package/lib/accepts.d.ts +1 -1
  20. package/lib/acryl-base.d.ts +1 -1
  21. package/lib/adapter.d.ts +1 -1
  22. package/lib/{app-CmAYW1Al.d.ts → app-BdrVHBlJ.d.ts} +1 -1
  23. package/lib/basic-auth.d.ts +1 -1
  24. package/lib/bearer-auth.d.ts +1 -1
  25. package/lib/body-limit.d.ts +1 -1
  26. package/lib/cache.d.ts +43 -0
  27. package/lib/cache.js +169 -0
  28. package/lib/client.d.ts +2 -2
  29. package/lib/combine.d.ts +1 -1
  30. package/lib/compress.d.ts +1 -1
  31. package/lib/conninfo.d.ts +2 -2
  32. package/lib/{context-Bm7rI-oK.d.ts → context-B5Y1lLha.d.ts} +1 -1
  33. package/lib/context-storage.d.ts +1 -1
  34. package/lib/{cookie-ClMaKDQf.d.ts → cookie-D9_nQbsM.d.ts} +1 -1
  35. package/lib/cookie.d.ts +3 -3
  36. package/lib/cors.d.ts +1 -1
  37. package/lib/csrf.d.ts +1 -1
  38. package/lib/dev.d.ts +19 -0
  39. package/lib/dev.js +50 -0
  40. package/lib/etag.d.ts +1 -1
  41. package/lib/factory.d.ts +2 -2
  42. package/lib/{index-B-3F4wt2.d.ts → index-DtEoak1i.d.ts} +2 -2
  43. package/lib/{index-UTBmM3GX.d.ts → index-Kqou8Fjh.d.ts} +2 -2
  44. package/lib/{index-oOClm_Xk.d.ts → index-m12zcmph.d.ts} +3 -3
  45. package/lib/index.d.ts +4 -4
  46. package/lib/ip-restriction.d.ts +2 -2
  47. package/lib/jwk.d.ts +4 -4
  48. package/lib/{jwt-Dg493Tai.d.ts → jwt-BA65QhnJ.d.ts} +1 -1
  49. package/lib/jwt.d.ts +4 -4
  50. package/lib/language.d.ts +1 -1
  51. package/lib/linear-router-C3FPib6h.js +96 -0
  52. package/lib/logger.d.ts +1 -1
  53. package/lib/loopback-only.d.ts +1 -1
  54. package/lib/method-not-allowed.d.ts +2 -2
  55. package/lib/method-override.d.ts +2 -2
  56. package/lib/mount.d.ts +44 -0
  57. package/lib/mount.js +67 -0
  58. package/lib/node-server/conninfo.d.ts +1 -1
  59. package/lib/node-server/serve-static.d.ts +1 -1
  60. package/lib/node-server.d.ts +1 -1
  61. package/lib/pattern-router-HZxjDGEQ.js +41 -0
  62. package/lib/powered-by.d.ts +1 -1
  63. package/lib/pretty-json.d.ts +1 -1
  64. package/lib/proxy.d.ts +72 -0
  65. package/lib/proxy.js +121 -0
  66. package/lib/quick.d.ts +8 -0
  67. package/lib/quick.js +17 -0
  68. package/lib/request-id.d.ts +1 -1
  69. package/lib/request.d.ts +1 -1
  70. package/lib/route.d.ts +1 -1
  71. package/lib/router/linear-router.js +1 -95
  72. package/lib/router/pattern-router.js +1 -40
  73. package/lib/schema-validator.d.ts +1 -1
  74. package/lib/secure-headers.d.ts +1 -1
  75. package/lib/serve-static.d.ts +1 -1
  76. package/lib/streaming.d.ts +1 -1
  77. package/lib/testing.d.ts +4 -4
  78. package/lib/timeout.d.ts +1 -1
  79. package/lib/timing.d.ts +1 -1
  80. package/lib/tiny.d.ts +8 -0
  81. package/lib/tiny.js +15 -0
  82. package/lib/trailing-slash.d.ts +1 -1
  83. package/lib/{types-CHesD1KG.d.ts → types-Bd29gh2o.d.ts} +3 -3
  84. package/lib/{types-CwrQjlaM.d.ts → types-D9DEXMjE.d.ts} +3 -1
  85. package/lib/{types-CDO6I3B0.d.ts → types-ZM9gIiKh.d.ts} +1 -1
  86. package/lib/types.d.ts +1 -1
  87. package/lib/utils/body.d.ts +1 -1
  88. package/lib/utils/cookie.d.ts +1 -1
  89. package/lib/utils/crypto.d.ts +1 -1
  90. package/lib/utils/ipaddr.d.ts +1 -1
  91. package/lib/utils/jwt.d.ts +1 -1
  92. package/lib/utils/types.d.ts +2 -2
  93. package/lib/validator.d.ts +2 -2
  94. package/lib/ws.d.ts +1 -1
  95. package/package.json +25 -1
  96. package/plugins/acryl-inspect/upstream.json +1 -1
  97. package/plugins/acryl-node-server/upstream.json +1 -1
  98. package/plugins/acryl-router/src/core/helper/dev/index.test.ts +181 -0
  99. package/plugins/acryl-router/src/core/helper/dev/index.ts +79 -0
  100. package/plugins/acryl-router/src/core/helper/proxy/index.test.ts +356 -0
  101. package/plugins/acryl-router/src/core/helper/proxy/index.ts +203 -0
  102. package/plugins/acryl-router/src/core/middleware/cache/index.test.ts +1211 -0
  103. package/plugins/acryl-router/src/core/middleware/cache/index.ts +323 -0
  104. package/plugins/acryl-router/src/core/middleware/mount/index.test.ts +334 -0
  105. package/plugins/acryl-router/src/core/middleware/mount/index.ts +108 -0
  106. package/plugins/acryl-router/src/core/preset/quick.test.ts +42 -0
  107. package/plugins/acryl-router/src/core/preset/quick.ts +24 -0
  108. package/plugins/acryl-router/src/core/preset/tiny.test.ts +42 -0
  109. package/plugins/acryl-router/src/core/preset/tiny.ts +20 -0
  110. package/plugins/acryl-router/src/core/utils/types.ts +3 -0
  111. package/plugins/acryl-router/src/helpers/index.ts +2 -0
  112. package/plugins/acryl-router/src/middleware/index.ts +2 -0
  113. package/plugins/acryl-router/src/service.ts +22 -5
  114. package/plugins/acryl-router/upstream.json +2 -2
  115. package/plugins/acryl-router-http/upstream.json +1 -1
  116. package/plugins/acryl-state/upstream.json +1 -1
  117. package/plugins/desktop/upstream.json +1 -1
  118. package/plugins/desktop-web/upstream.json +1 -1
  119. package/templates/todo/upstream.json +1 -1
package/README.md CHANGED
@@ -22,7 +22,7 @@ One <code>Request</code> in, one <code>Response</code> out: routing, middleware,
22
22
  import { Acryl } from 'acrylblends'
23
23
 
24
24
  const app = new Acryl()
25
- app.get('/', (c) => c.text('Hello Acryl!'))
25
+ app.get('/', (c) => c.text('Acryl!'))
26
26
 
27
27
  export default app
28
28
  ```
@@ -68,7 +68,7 @@ import { Acryl } from 'acrylblends'
68
68
 
69
69
  const app = new Acryl()
70
70
 
71
- app.get('/', (c) => c.text('Hello Acryl!'))
71
+ app.get('/', (c) => c.text('Acryl!'))
72
72
 
73
73
  export default app
74
74
  ```
@@ -202,7 +202,7 @@ Export the app's type, and `acrylblends/client` calls its routes with typed path
202
202
  // api.ts
203
203
  import { Acryl } from 'acrylblends'
204
204
 
205
- const app = new Acryl().get('/api/hello', (c) => c.json({ message: 'Hello Acryl!' }))
205
+ const app = new Acryl().get('/api/hello', (c) => c.json({ message: 'Acryl!' }))
206
206
  export type AppType = typeof app
207
207
  export default app
208
208
  ```
@@ -231,7 +231,7 @@ import app from './index.ts'
231
231
  test('GET / says hello', async () => {
232
232
  const response = await app.request('/')
233
233
  assert.equal(response.status, 200)
234
- assert.equal(await response.text(), 'Hello Acryl!')
234
+ assert.equal(await response.text(), 'Acryl!')
235
235
  })
236
236
  ```
237
237
 
@@ -271,10 +271,12 @@ See [Node.js](https://github.com/acryldev/acryl/blob/main/docs/framework/getting
271
271
  | `acrylblends/http-exception` | `HTTPException` |
272
272
  | `acrylblends/router/*` | the routers: `reg-exp-router`, `smart-router`, `trie-router`, `pattern-router`, `linear-router` ([routers](https://github.com/acryldev/acryl/blob/main/docs/framework/concepts/routers.md)) |
273
273
  | `acrylblends/utils/*` | the utilities the framework is built from |
274
+ | `acrylblends/tiny`, `acrylblends/quick` | the presets: `Acryl` with another router (`PatternRouter`; `LinearRouter` and `TrieRouter`) ([presets](https://github.com/acryldev/acryl/blob/main/docs/framework/api/presets.md)) |
275
+ | `acrylblends/cache`, `acrylblends/mount` | the cache middleware and mounting another framework's fetch handler |
276
+ | `acrylblends/proxy`, `acrylblends/dev` | the proxy helper and the dev helpers (`showRoutes`, `inspectRoutes`, `getRouterName`) |
274
277
  | `acrylblends/node-server` | `serve`, `createAdaptorServer`, `getRequestListener`; with `node-server/serve-static` and `node-server/conninfo` |
275
278
 
276
- Every subpath is listed in the package's `exports`. JSX, SSG, the cache, mount, proxy and dev helpers and other runtimes' adapters are
277
- being ported. The docs mark them "not yet available" until they ship
279
+ Every subpath is listed in the package's `exports`. JSX, SSG and other runtimes' adapters are being ported. The docs mark them "not yet available" until they ship
278
280
  ([FAQ](https://github.com/acryldev/acryl/blob/main/docs/framework/guides/faq.md)).
279
281
 
280
282
  To extend the context's typed variables, augment the root module:
@@ -1,3 +1,3 @@
1
1
  # Generated copy
2
2
 
3
- This folder is a copy of `docs/framework` of acryldev/acryl at commit `5743482e4199ded676a77f594bce15fd4aa0ca2f`, made by `scripts/sync-framework.mjs`. Do not edit it here: change the text in ACRYL and sync again. `pnpm run verify:framework` fails when a page differs from the recorded digest.
3
+ This folder is a copy of `docs/framework` of acryldev/acryl at commit `0174cb01625bfd32d0162ad56179c582f353321e`, made by `scripts/sync-framework.mjs`. Do not edit it here: change the text in ACRYL and sync again. `pnpm run verify:framework` fails when a page differs from the recorded digest.
@@ -1,8 +1,5 @@
1
1
  # Presets
2
2
 
3
- > **Partly available.** The default router (`SmartRouter`), `RegExpRouter`, `TrieRouter`, `LinearRouter` and `PatternRouter` are available and are chosen with the `router` option of `new Acryl()` (see [Routers](../concepts/routers.md)). The presets `acrylblends/quick` and `acrylblends/tiny` are **not yet available**; their examples below are not checked by the docs tests.
4
-
5
-
6
3
  Acryl has several routers, each designed for a specific purpose.
7
4
  You can specify the router you want to use in the constructor of Acryl.
8
5
 
@@ -43,6 +43,9 @@ export function apply(ctx: Context): void {
43
43
  | `GET /todo/todos/42` | `{ "id": "42" }` |
44
44
  | `GET /todo/` | 404: `/todo` and `/todo/` are different paths (see below) |
45
45
 
46
+ The app can come from `acryl-router` or from the published `acrylblends` package: `route` takes any app by its routes
47
+ (`MountableApp`), so an `Acryl` imported from `acrylblends` mounts as it is, with its middleware and its own `onError`.
48
+
46
49
  ### `/todo/` is a 404 until you choose
47
50
 
48
51
  `/todo/` is the first thing people type, and by default it is not found: the router treats `/todo` and `/todo/` as two paths. Choose
@@ -63,7 +63,7 @@ import { Acryl } from 'acrylblends'
63
63
  const app = new Acryl()
64
64
 
65
65
  app.get('/', (c) => {
66
- return c.text('Hello Acryl!')
66
+ return c.text('Acryl!')
67
67
  })
68
68
 
69
69
  export default app
@@ -83,7 +83,7 @@ const app = new Acryl()
83
83
  app.get('/api/hello', (c) => {
84
84
  return c.json({
85
85
  ok: true,
86
- message: 'Hello Acryl!',
86
+ message: 'Acryl!',
87
87
  })
88
88
  })
89
89
  ```
@@ -162,7 +162,7 @@ app.use(
162
162
  '/admin/*',
163
163
  basicAuth({
164
164
  username: 'admin',
165
- password: 'secret',
165
+ password: process.env.ADMIN_PASSWORD!,
166
166
  })
167
167
  )
168
168
 
@@ -181,7 +181,7 @@ An app is a function from `Request` to `Response`, so a test needs no server:
181
181
  import { Acryl } from 'acrylblends'
182
182
 
183
183
  const app = new Acryl()
184
- app.get('/', (c) => c.text('Hello Acryl!'))
184
+ app.get('/', (c) => c.text('Acryl!'))
185
185
 
186
186
  const response = await app.request('/')
187
187
  console.log(response.status, await response.text())
@@ -54,7 +54,7 @@ const Top: FC<{ messages: string[] }> = (props: {
54
54
  }) => {
55
55
  return (
56
56
  <Layout>
57
- <h1>Hello Acryl!</h1>
57
+ <h1>Acryl!</h1>
58
58
  <ul>
59
59
  {props.messages.map((message) => {
60
60
  return <li>{message}!!</li>
@@ -95,7 +95,7 @@ app.use(
95
95
  '/auth/*',
96
96
  basicAuth({
97
97
  username: 'acrylblends',
98
- password: 'acoolproject',
98
+ password: process.env.BASIC_AUTH_PASSWORD!,
99
99
  })
100
100
  )
101
101
  ```
@@ -37,7 +37,7 @@ app.get('/cookie', (c) => {
37
37
 
38
38
  ```ts
39
39
  app.get('/signed-cookie', (c) => {
40
- const secret = 'secret' // make sure it's a large enough string to be secure
40
+ const secret = process.env.COOKIE_SECRET! // a long random string, kept out of the source
41
41
 
42
42
  await setSignedCookie(c, 'cookie_name0', 'cookie_value', secret)
43
43
  const fortuneCookie = await getSignedCookie(
@@ -1,8 +1,5 @@
1
1
  # Dev Helper
2
2
 
3
- > **Not yet available.** The dev helper (`acrylblends/dev`) is documented here so the page structure matches the rest of the framework, and is not part of acrylblends yet. The code on this page is not checked by the docs tests.
4
-
5
-
6
3
  Dev Helper provides useful methods you can use in development.
7
4
 
8
5
  ```ts
@@ -35,7 +35,7 @@ const payload = {
35
35
  role: 'admin',
36
36
  exp: Math.floor(Date.now() / 1000) + 60 * 5, // Token expires in 5 minutes
37
37
  }
38
- const secret = 'mySecretKey'
38
+ const secret = process.env.JWT_SECRET!
39
39
  const token = await sign(payload, secret)
40
40
  ```
41
41
 
@@ -1,8 +1,5 @@
1
1
  # Proxy Helper
2
2
 
3
- > **Not yet available.** The proxy helper (`acrylblends/proxy`) is documented here so the page structure matches the rest of the framework, and is not part of acrylblends yet. The code on this page is not checked by the docs tests.
4
-
5
-
6
3
  Proxy Helper provides useful functions when using Acryl application as a (reverse) proxy.
7
4
 
8
5
  ## Import
@@ -21,7 +21,7 @@ app.use(
21
21
  '/auth/*',
22
22
  basicAuth({
23
23
  username: 'acrylblends',
24
- password: 'acoolproject',
24
+ password: process.env.BASIC_AUTH_PASSWORD!,
25
25
  })
26
26
  )
27
27
 
@@ -41,7 +41,7 @@ app.get('/auth/page', (c) => {
41
41
 
42
42
  app.delete(
43
43
  '/auth/page',
44
- basicAuth({ username: 'acrylblends', password: 'acoolproject' }),
44
+ basicAuth({ username: 'acrylblends', password: process.env.BASIC_AUTH_PASSWORD! }),
45
45
  (c) => {
46
46
  return c.text('Page deleted')
47
47
  }
@@ -100,7 +100,7 @@ app.use(
100
100
  '/auth/*',
101
101
  basicAuth({
102
102
  username: 'acrylblends',
103
- password: 'acoolproject',
103
+ password: process.env.BASIC_AUTH_PASSWORD!,
104
104
  onAuthSuccess: (c, username) => {
105
105
  c.set('username', username)
106
106
  },
@@ -129,18 +129,18 @@ app.use(
129
129
  basicAuth(
130
130
  {
131
131
  username: 'acrylblends',
132
- password: 'acoolproject',
132
+ password: process.env.BASIC_AUTH_PASSWORD!,
133
133
  // Define other params in the first object
134
134
  realm: 'www.example.com',
135
135
  },
136
136
  {
137
137
  username: 'acrylblends-admin',
138
- password: 'super-secure',
138
+ password: process.env.ADMIN_PASSWORD!,
139
139
  // Cannot redefine other params here
140
140
  },
141
141
  {
142
142
  username: 'acrylblends-user-1',
143
- password: 'a-secret',
143
+ password: process.env.USER_1_PASSWORD!,
144
144
  // Or here
145
145
  }
146
146
  )
@@ -1,8 +1,5 @@
1
1
  # Cache Middleware
2
2
 
3
- > **Not yet available.** The cache middleware (`acrylblends/cache`) is documented here so the page structure matches the rest of the framework, and is not part of acrylblends yet. The code on this page is not checked by the docs tests.
4
-
5
-
6
3
  The Cache middleware uses the Web Standards' [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache).
7
4
 
8
5
  The Cache middleware currently supports Cloudflare Workers projects using custom domains and Deno projects using [Deno 1.26+](https://github.com/denoland/deno/releases/tag/v1.26.0). Also available with Deno Deploy.
@@ -39,7 +39,7 @@ app.use(
39
39
  )
40
40
  )
41
41
 
42
- app.get('/', (c) => c.text('Hello Acryl!'))
42
+ app.get('/', (c) => c.text('Acryl!'))
43
43
  ```
44
44
 
45
45
  ### some
@@ -28,7 +28,7 @@ app.use(
28
28
  })
29
29
  )
30
30
 
31
- app.get('/', (c) => c.text('Hello Acryl!'))
31
+ app.get('/', (c) => c.text('Acryl!'))
32
32
  ```
33
33
 
34
34
  Pass the `getConninfo` from the [ConnInfo helper](../../helpers/conninfo.md) appropriate for your environment as the first argument of `ipRestriction`. For a runtime whose adapter is not yet available there is no `getConnInfo` to pass yet.
@@ -15,7 +15,7 @@ import { logger } from 'acrylblends/logger'
15
15
  const app = new Acryl()
16
16
 
17
17
  app.use(logger())
18
- app.get('/', (c) => c.text('Hello Acryl!'))
18
+ app.get('/', (c) => c.text('Acryl!'))
19
19
  ```
20
20
 
21
21
  ## Logging Details
@@ -1,8 +1,5 @@
1
1
  # Mount Middleware
2
2
 
3
- > **Not yet available.** The `acrylblends/mount` subpath (an app can still call `app.mount()`) is documented here so the page structure matches the rest of the framework, and is not part of acrylblends yet. The code on this page is not checked by the docs tests.
4
-
5
-
6
3
  The Mount Middleware lets you mount an application built with another framework into your Acryl application.
7
4
 
8
5
  ## Import
@@ -2,8 +2,8 @@
2
2
  "source": {
3
3
  "repo": "acryldev/acryl",
4
4
  "path": "docs/framework",
5
- "commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
5
+ "commit": "0174cb01625bfd32d0162ad56179c582f353321e"
6
6
  },
7
7
  "files": 87,
8
- "digest": "sha256:31bf1c46fbe74d7d2664b3b935a18bd916b8cab1b9ee9c2b006b8a75617a04f6"
8
+ "digest": "sha256:be8b4bb2555dbc97ef94caa57f6b071f5c0f173f0711eecc2836a537a1a71681"
9
9
  }
package/lib/accepts.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as Context } from "./context-Bm7rI-oK.js";
1
+ import { t as Context } from "./context-B5Y1lLha.js";
2
2
  import { t as AcceptHeader } from "./headers-tu2YYN8T.js";
3
3
 
4
4
  //#region ../../plugins/acryl-router/src/core/helper/accepts/accepts.d.ts
@@ -1,2 +1,2 @@
1
- import { $ as Acryl, et as AcrylOptions } from "./context-Bm7rI-oK.js";
1
+ import { $ as Acryl, et as AcrylOptions } from "./context-B5Y1lLha.js";
2
2
  export { Acryl as AcrylBase, AcrylOptions };
package/lib/adapter.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as Context } from "./context-Bm7rI-oK.js";
1
+ import { t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/helper/adapter/index.d.ts
4
4
  type Runtime = 'node' | 'deno' | 'bun' | 'workerd' | 'fastly' | 'edge-light' | 'other';
@@ -1,4 +1,4 @@
1
- import { $ as Acryl$1, J as Schema, _ as Env, et as AcrylOptions, h as BlankSchema, p as BlankEnv } from "./context-Bm7rI-oK.js";
1
+ import { $ as Acryl$1, J as Schema, _ as Env, et as AcrylOptions, h as BlankSchema, p as BlankEnv } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/app.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, t as Context } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler, t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/middleware/basic-auth/index.d.ts
4
4
  type MessageFunction = (c: Context) => string | object | Promise<string | object>;
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, _ as Env, t as Context } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler, _ as Env, t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/middleware/bearer-auth/index.d.ts
4
4
  type MessageFunction = (c: Context) => string | object | Promise<string | object>;
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, t as Context } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler, t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/middleware/body-limit/index.d.ts
4
4
  type OnError = (c: Context) => Response | Promise<Response>;
package/lib/cache.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import { I as MiddlewareHandler, t as Context } from "./context-B5Y1lLha.js";
2
+ import { c as StatusCode } from "./http-status-DaAwGAFL.js";
3
+
4
+ //#region ../../plugins/acryl-router/src/core/middleware/cache/index.d.ts
5
+ /**
6
+ * Cache Middleware for Acryl.
7
+ *
8
+ *
9
+ * @param {Object} options - The options for the cache middleware.
10
+ * @param {string | Function} options.cacheName - The name of the cache. Can be used to store multiple caches with different identifiers.
11
+ * @param {boolean} [options.wait=false] - A boolean indicating if Acryl should wait for the Promise of the `cache.put` function to resolve before continuing with the request. Required to be true for the Deno environment.
12
+ * @param {string} [options.cacheControl] - A string of directives for the `Cache-Control` header.
13
+ * @param {string | string[]} [options.vary] - Adds the configured request headers to the cache key variants and sets the `Vary` header in the response. If the original response header already contains a `Vary` header, the values are merged, removing any duplicates.
14
+ * @param {Function} [options.keyGenerator] - Generates keys for every request in the `cacheName` store. This can be used to cache data based on request parameters or context parameters. QUERY keys additionally include a digest of the request content and its representation metadata.
15
+ * @param {number} [options.maxQueryBodySize=65536] - The maximum QUERY request body size in bytes that can be cached. Larger QUERY requests bypass the cache.
16
+ * @param {number[]} [options.cacheableStatusCodes=[200]] - An array of status codes that can be cached.
17
+ * @param {Function | false} [options.onCacheNotAvailable] - A callback invoked with the reason when `globalThis.caches` is not available or QUERY caching cannot use Web Crypto. By default, the reason is logged to the console. Set to `false` to suppress the log, or provide a custom function.
18
+ * @returns {MiddlewareHandler} The middleware handler function.
19
+ * @throws {Error} If the `vary` option includes "*".
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * app.use(
24
+ * '*',
25
+ * cache({
26
+ * cacheName: 'my-app',
27
+ * cacheControl: 'max-age=3600',
28
+ * })
29
+ * )
30
+ * ```
31
+ */
32
+ declare const cache: (options: {
33
+ cacheName: string | ((c: Context) => Promise<string> | string);
34
+ wait?: boolean;
35
+ cacheControl?: string;
36
+ vary?: string | string[];
37
+ keyGenerator?: (c: Context) => Promise<string> | string;
38
+ maxQueryBodySize?: number;
39
+ cacheableStatusCodes?: StatusCode[];
40
+ onCacheNotAvailable?: ((reason: string) => void) | false;
41
+ }) => MiddlewareHandler;
42
+ //#endregion
43
+ export { cache };
package/lib/cache.js ADDED
@@ -0,0 +1,169 @@
1
+ import { sha256 } from "./utils/crypto.js";
2
+ import { cloneRawRequest } from "./request.js";
3
+ //#region ../../plugins/acryl-router/src/core/middleware/cache/index.ts
4
+ /**
5
+ * status codes that can be cached by default.
6
+ */
7
+ const defaultCacheableStatusCodes = [200];
8
+ const defaultMaxQueryBodySize = 64 * 1024;
9
+ const cacheKeyPath = "/.acryl-router/cache";
10
+ const cacheKeyParameter = "__hono_cache_key";
11
+ const cacheMethodKeyParameter = "__hono_cache_method";
12
+ const queryDigestKeyParameter = "__hono_query_digest";
13
+ const cacheVaryKeyParameter = "__hono_cache_vary";
14
+ const queryRepresentationMetadataHeaders = [
15
+ "content-type",
16
+ "content-encoding",
17
+ "content-language",
18
+ "content-location"
19
+ ];
20
+ const shouldSkipCacheControl = (cacheControl) => !!cacheControl && /(?:^|,\s*)(?:private|no-(?:store|cache))(?:\s*(?:=|,|$))/i.test(cacheControl);
21
+ const parseVaryDirectives = (vary) => {
22
+ if (vary == null) return [];
23
+ return (Array.isArray(vary) ? vary : vary.split(",")).map((directive) => directive.trim().toLowerCase()).filter(Boolean);
24
+ };
25
+ const createCacheKey = (key, requestUrl, request, varyHeaders) => {
26
+ const url = new URL(cacheKeyPath, requestUrl);
27
+ url.searchParams.append(cacheKeyParameter, key);
28
+ url.searchParams.append(cacheMethodKeyParameter, request.method);
29
+ if (request.method === "QUERY") url.searchParams.append(queryDigestKeyParameter, request.digest);
30
+ for (const header of varyHeaders) url.searchParams.append(cacheVaryKeyParameter, JSON.stringify(header));
31
+ return url.href;
32
+ };
33
+ const shouldSkipCache = (res, optionsVaryDirectives, responseVary) => responseVary.length && (!optionsVaryDirectives || responseVary.some((name) => !optionsVaryDirectives.has(name))) || shouldSkipCacheControl(res.headers.get("Cache-Control")) || res.headers.has("Set-Cookie");
34
+ const reportCacheNotAvailable = (onCacheNotAvailable, reason) => {
35
+ if (onCacheNotAvailable === false) {} else if (onCacheNotAvailable) onCacheNotAvailable(reason);
36
+ else console.log(reason);
37
+ };
38
+ const createQueryDigest = async (c, maxQueryBodySize) => {
39
+ if (!globalThis.crypto?.subtle) return;
40
+ if (c.req.raw.bodyUsed && Object.keys(c.req.bodyCache)[0] === "formData") return;
41
+ try {
42
+ const requestHeaders = c.req.raw.headers;
43
+ const metadata = new TextEncoder().encode(JSON.stringify(queryRepresentationMetadataHeaders.map((header) => [header, requestHeaders.get(header)])));
44
+ const body = (await cloneRawRequest(c.req)).body;
45
+ const chunks = [];
46
+ let bodySize = 0;
47
+ if (body) {
48
+ const reader = body.getReader();
49
+ for (;;) {
50
+ const { done, value } = await reader.read();
51
+ if (done) break;
52
+ bodySize += value.byteLength;
53
+ if (bodySize > maxQueryBodySize) {
54
+ reader.cancel().catch(() => {});
55
+ return;
56
+ }
57
+ chunks.push(value);
58
+ }
59
+ }
60
+ const data = new Uint8Array(metadata.byteLength + bodySize);
61
+ data.set(metadata);
62
+ let offset = metadata.byteLength;
63
+ for (const chunk of chunks) {
64
+ data.set(chunk, offset);
65
+ offset += chunk.byteLength;
66
+ }
67
+ return await sha256(data) ?? void 0;
68
+ } catch {
69
+ return;
70
+ }
71
+ };
72
+ /**
73
+ * Cache Middleware for Acryl.
74
+ *
75
+ *
76
+ * @param {Object} options - The options for the cache middleware.
77
+ * @param {string | Function} options.cacheName - The name of the cache. Can be used to store multiple caches with different identifiers.
78
+ * @param {boolean} [options.wait=false] - A boolean indicating if Acryl should wait for the Promise of the `cache.put` function to resolve before continuing with the request. Required to be true for the Deno environment.
79
+ * @param {string} [options.cacheControl] - A string of directives for the `Cache-Control` header.
80
+ * @param {string | string[]} [options.vary] - Adds the configured request headers to the cache key variants and sets the `Vary` header in the response. If the original response header already contains a `Vary` header, the values are merged, removing any duplicates.
81
+ * @param {Function} [options.keyGenerator] - Generates keys for every request in the `cacheName` store. This can be used to cache data based on request parameters or context parameters. QUERY keys additionally include a digest of the request content and its representation metadata.
82
+ * @param {number} [options.maxQueryBodySize=65536] - The maximum QUERY request body size in bytes that can be cached. Larger QUERY requests bypass the cache.
83
+ * @param {number[]} [options.cacheableStatusCodes=[200]] - An array of status codes that can be cached.
84
+ * @param {Function | false} [options.onCacheNotAvailable] - A callback invoked with the reason when `globalThis.caches` is not available or QUERY caching cannot use Web Crypto. By default, the reason is logged to the console. Set to `false` to suppress the log, or provide a custom function.
85
+ * @returns {MiddlewareHandler} The middleware handler function.
86
+ * @throws {Error} If the `vary` option includes "*".
87
+ *
88
+ * @example
89
+ * ```ts
90
+ * app.use(
91
+ * '*',
92
+ * cache({
93
+ * cacheName: 'my-app',
94
+ * cacheControl: 'max-age=3600',
95
+ * })
96
+ * )
97
+ * ```
98
+ */
99
+ const cache = (options) => {
100
+ if (!globalThis.caches) {
101
+ reportCacheNotAvailable(options.onCacheNotAvailable, "Cache Middleware is not enabled because caches is not defined.");
102
+ return async (_c, next) => await next();
103
+ }
104
+ if (!globalThis.crypto?.subtle) reportCacheNotAvailable(options.onCacheNotAvailable, "Cache Middleware cannot cache QUERY requests because Web Crypto is not available.");
105
+ if (options.wait === void 0) options.wait = false;
106
+ const cacheControlDirectives = options.cacheControl?.split(",").map((directive) => directive.toLowerCase());
107
+ const optionsVaryList = parseVaryDirectives(options.vary);
108
+ const varyDirectives = optionsVaryList.length ? new Set(optionsVaryList) : void 0;
109
+ if (varyDirectives?.has("*")) throw new Error("Middleware vary configuration cannot include \"*\", as it disallows effective caching.");
110
+ const cacheableStatusCodes = new Set(options.cacheableStatusCodes ?? defaultCacheableStatusCodes);
111
+ const maxQueryBodySize = options.maxQueryBodySize ?? defaultMaxQueryBodySize;
112
+ const addHeader = (c, responseVary) => {
113
+ if (cacheControlDirectives) {
114
+ const existingDirectives = c.res.headers.get("Cache-Control")?.split(",").map((d) => d.trim().split("=", 1)[0].toLowerCase()) ?? [];
115
+ for (const directive of cacheControlDirectives) {
116
+ let [name, value] = directive.trim().split("=", 2);
117
+ name = name.toLowerCase();
118
+ if (!existingDirectives.includes(name)) c.header("Cache-Control", `${name}${value ? `=${value}` : ""}`, { append: true });
119
+ }
120
+ }
121
+ if (varyDirectives) if (responseVary.length === 0) c.header("Vary", Array.from(varyDirectives).join(", "));
122
+ else {
123
+ const merged = new Set(varyDirectives);
124
+ for (const directive of responseVary) merged.add(directive);
125
+ if (merged.has("*")) c.header("Vary", "*");
126
+ else c.header("Vary", Array.from(merged).join(", "));
127
+ }
128
+ };
129
+ return async function cache(c, next) {
130
+ if (c.req.method !== "GET" && c.req.method !== "QUERY" || c.req.raw.headers.has("Authorization")) {
131
+ await next();
132
+ return;
133
+ }
134
+ let cacheKeyRequest = { method: "GET" };
135
+ if (c.req.method === "QUERY") {
136
+ const digest = await createQueryDigest(c, maxQueryBodySize);
137
+ if (digest === void 0) {
138
+ await next();
139
+ return;
140
+ }
141
+ cacheKeyRequest = {
142
+ method: "QUERY",
143
+ digest
144
+ };
145
+ }
146
+ let key = c.req.url;
147
+ if (options.keyGenerator) key = await options.keyGenerator(c);
148
+ const varyHeaders = [];
149
+ if (varyDirectives) for (const directive of varyDirectives) {
150
+ const value = c.req.raw.headers.get(directive) ?? "";
151
+ varyHeaders.push([directive, value]);
152
+ }
153
+ key = createCacheKey(key, c.req.url, cacheKeyRequest, varyHeaders);
154
+ const cacheName = typeof options.cacheName === "function" ? await options.cacheName(c) : options.cacheName;
155
+ const cache = await caches.open(cacheName);
156
+ const response = await cache.match(key);
157
+ if (response) return new Response(response.body, response);
158
+ await next();
159
+ if (!cacheableStatusCodes.has(c.res.status)) return;
160
+ const responseVary = parseVaryDirectives(c.res.headers.get("Vary"));
161
+ addHeader(c, responseVary);
162
+ if (shouldSkipCache(c.res, varyDirectives, responseVary)) return;
163
+ const res = c.res.clone();
164
+ if (options.wait) await cache.put(key, res);
165
+ else c.executionCtx.waitUntil(cache.put(key, res));
166
+ };
167
+ };
168
+ //#endregion
169
+ export { cache };
package/lib/client.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { a as ClientResponse, c as InferRequestType, i as ClientRequestOptions, l as InferResponseType, o as Fetch, r as ClientRequest, t as ApplyGlobalResponse, u as PickResponseByStatusCode } from "./types-CHesD1KG.js";
2
- import { n as DetailedError, r as hc, t as parseResponse } from "./index-oOClm_Xk.js";
1
+ import { a as ClientResponse, c as InferRequestType, i as ClientRequestOptions, l as InferResponseType, o as Fetch, r as ClientRequest, t as ApplyGlobalResponse, u as PickResponseByStatusCode } from "./types-Bd29gh2o.js";
2
+ import { n as DetailedError, r as hc, t as parseResponse } from "./index-m12zcmph.js";
3
3
  export { type ApplyGlobalResponse, type ClientRequest, type ClientRequestOptions, type ClientResponse, DetailedError, type Fetch, type InferRequestType, type InferResponseType, type PickResponseByStatusCode, hc, parseResponse };
package/lib/combine.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, t as Context } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler, t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/middleware/combine/index.d.ts
4
4
  type Condition = (c: Context) => boolean;
package/lib/compress.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler } from "./context-B5Y1lLha.js";
2
2
  import { COMPRESSIBLE_CONTENT_TYPE_REGEX } from "./utils/compress.js";
3
3
 
4
4
  //#region ../../plugins/acryl-router/src/core/middleware/compress/index.d.ts
package/lib/conninfo.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { t as Context } from "./context-Bm7rI-oK.js";
2
- import { i as NetAddrInfo, n as ConnInfo, r as GetConnInfo, t as AddressType } from "./types-CDO6I3B0.js";
1
+ import { t as Context } from "./context-B5Y1lLha.js";
2
+ import { i as NetAddrInfo, n as ConnInfo, r as GetConnInfo, t as AddressType } from "./types-ZM9gIiKh.js";
3
3
 
4
4
  //#region ../../plugins/acryl-router/src/connection.d.ts
5
5
  /** An in-process caller (the terminal UI, a test) passes nothing, so a handler that needs a trusted peer must refuse an empty one. */
@@ -1,7 +1,7 @@
1
1
  import { c as Result, l as Router } from "./router-CvUxUTOq.js";
2
2
  import { i as ResponseHeader, n as CustomHeader, r as RequestHeader } from "./headers-tu2YYN8T.js";
3
3
  import { c as StatusCode, n as ContentfulStatusCode, o as RedirectStatusCode } from "./http-status-DaAwGAFL.js";
4
- import { S as Simplify, T as UnionToIntersection, b as RemoveBlankRecord, c as IfAnyThenEmptyObject, d as IsAny, g as JSONValue, m as JSONParsed, u as InvalidJSONValue } from "./types-CwrQjlaM.js";
4
+ import { C as Simplify, E as UnionToIntersection, _ as JSONValue, d as InvalidJSONValue, f as IsAny, h as JSONParsed, l as IfAnyThenEmptyObject, x as RemoveBlankRecord } from "./types-D9DEXMjE.js";
5
5
  import { t as BaseMime } from "./mime-BQOYHl-l.js";
6
6
 
7
7
  //#region ../../plugins/acryl-router/src/core/request/constants.d.ts
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, _ as Env, t as Context } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler, _ as Env, t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/middleware/context-storage/index.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { n as BufferSource } from "./types-CwrQjlaM.js";
1
+ import { n as BufferSource } from "./types-D9DEXMjE.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/utils/cookie.d.ts
4
4
  type Cookie = Record<string, string>;
package/lib/cookie.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { t as Context } from "./context-Bm7rI-oK.js";
2
- import { n as BufferSource } from "./types-CwrQjlaM.js";
3
- import { a as SignedCookie, i as CookiePrefixOptions, r as CookieOptions, t as Cookie } from "./cookie-ClMaKDQf.js";
1
+ import { t as Context } from "./context-B5Y1lLha.js";
2
+ import { n as BufferSource } from "./types-D9DEXMjE.js";
3
+ import { a as SignedCookie, i as CookiePrefixOptions, r as CookieOptions, t as Cookie } from "./cookie-D9_nQbsM.js";
4
4
 
5
5
  //#region ../../plugins/acryl-router/src/core/helper/cookie/index.d.ts
6
6
  interface GetCookie {
package/lib/cors.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, t as Context } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler, t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/middleware/cors/index.d.ts
4
4
  type CORSOptions = {
package/lib/csrf.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { I as MiddlewareHandler, t as Context } from "./context-Bm7rI-oK.js";
1
+ import { I as MiddlewareHandler, t as Context } from "./context-B5Y1lLha.js";
2
2
 
3
3
  //#region ../../plugins/acryl-router/src/core/middleware/csrf/index.d.ts
4
4
  type IsAllowedOriginHandler = (origin: string, context: Context) => boolean | Promise<boolean>;