acrylblends 0.11.0 → 1.0.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 (93) hide show
  1. package/README.md +131 -53
  2. package/dist/index.d.ts +29 -2
  3. package/dist/index.js +450 -69
  4. package/dist/index.js.map +1 -1
  5. package/docs/framework/README.md +5 -3
  6. package/docs/framework/agents/index.md +1 -1
  7. package/docs/framework/api/acryl.md +5 -17
  8. package/docs/framework/api/context.md +12 -61
  9. package/docs/framework/api/presets.md +1 -1
  10. package/docs/framework/api/request.md +3 -3
  11. package/docs/framework/api/summary.md +1 -1
  12. package/docs/framework/concepts/web-standard.md +6 -16
  13. package/docs/framework/cordis/acryl-in-a-cordis-app.md +13 -8
  14. package/docs/framework/cordis/migration-from-0-4.md +1 -1
  15. package/docs/framework/cordis/migration-to-1-0.md +45 -0
  16. package/docs/framework/cordis/node-server.md +2 -2
  17. package/docs/framework/getting-started/basic.md +15 -10
  18. package/docs/framework/getting-started/desktop.md +1 -1
  19. package/docs/framework/getting-started/other-runtimes.md +10 -14
  20. package/docs/framework/guides/create-acrylblends.md +4 -2
  21. package/docs/framework/guides/data.md +1 -1
  22. package/docs/framework/guides/faq.md +1 -1
  23. package/docs/framework/guides/jsx-dom.md +1 -1
  24. package/docs/framework/guides/production.md +43 -0
  25. package/docs/framework/guides/rpc.md +3 -11
  26. package/docs/framework/helpers/adapter.md +13 -43
  27. package/docs/framework/helpers/conninfo.md +1 -36
  28. package/docs/framework/helpers/streaming.md +1 -1
  29. package/docs/framework/helpers/websocket.md +4 -11
  30. package/docs/framework/middleware/builtin/basic-auth.md +1 -1
  31. package/docs/framework/middleware/builtin/cache.md +2 -22
  32. package/docs/framework/middleware/builtin/compress.md +1 -1
  33. package/docs/framework/middleware/builtin/context-storage.md +10 -14
  34. package/docs/framework/middleware/builtin/cors.md +1 -2
  35. package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
  36. package/docs/framework/middleware/builtin/jsx-renderer.md +1 -1
  37. package/docs/framework/middleware/builtin/logger.md +1 -1
  38. package/docs/framework/middleware/builtin/loopback-only.md +1 -1
  39. package/docs/framework/middleware/builtin/mount.md +1 -1
  40. package/docs/framework/middleware/builtin/request-id.md +13 -20
  41. package/docs/framework/middleware/builtin/timing.md +1 -2
  42. package/lib/cordis/door.d.ts +5 -0
  43. package/lib/cordis/door.js +8 -4
  44. package/lib/cordis/inspect.js +1 -1
  45. package/lib/cordis/router-http.js +1 -1
  46. package/lib/cordis/router.d.ts +1 -2
  47. package/lib/cordis/router.js +2 -3
  48. package/lib/cordis/state.js +1 -1
  49. package/lib/door/host.js +1 -1
  50. package/lib/drivers.d.ts +66 -0
  51. package/lib/drivers.js +16 -0
  52. package/lib/index.d.ts +1 -2
  53. package/lib/index.js +1 -2
  54. package/lib/{snapshot-text-yaWlezbd.js → snapshot-text-DmE0YfeZ.js} +2 -2
  55. package/lib/{src-DNzw0Qsb.js → src-2Z4mJg0x.js} +0 -1
  56. package/package.json +5 -121
  57. package/plugins/acryl-door/src/index.ts +8 -0
  58. package/plugins/acryl-router/src/index.ts +0 -1
  59. package/plugins/agent-panel/drivers.ts +1 -16
  60. package/plugins/agent-panel/index.ts +1 -1
  61. package/plugins/agent-panel/registry.ts +16 -0
  62. package/plugins/driver-acp/README.md +53 -0
  63. package/plugins/driver-acp/chat.ts +258 -0
  64. package/plugins/driver-acp/connection.ts +239 -0
  65. package/plugins/driver-acp/index.ts +65 -0
  66. package/plugins/driver-acp/plugin.json +12 -0
  67. package/plugins/driver-acp/provenance.json +20 -0
  68. package/plugins/driver-pty/index.ts +1 -0
  69. package/shared/library-history.json +464 -0
  70. package/docs/framework/getting-started/aws-lambda.md +0 -115
  71. package/docs/framework/getting-started/cloudflare-pages.md +0 -53
  72. package/docs/framework/getting-started/cloudflare-workers.md +0 -67
  73. package/docs/framework/getting-started/lambda-edge.md +0 -41
  74. package/docs/framework/getting-started/netlify.md +0 -25
  75. package/docs/framework/getting-started/service-worker.md +0 -33
  76. package/docs/framework/getting-started/vercel.md +0 -28
  77. package/lib/aws-lambda.d.ts +0 -324
  78. package/lib/aws-lambda.js +0 -357
  79. package/lib/cloudflare-pages.d.ts +0 -58
  80. package/lib/cloudflare-pages.js +0 -78
  81. package/lib/cloudflare-workers.d.ts +0 -21
  82. package/lib/cloudflare-workers.js +0 -80
  83. package/lib/deprecated-BP4fPt38.js +0 -10
  84. package/lib/deprecated-CTy4N7ng.d.ts +0 -12
  85. package/lib/lambda-edge.d.ts +0 -92
  86. package/lib/lambda-edge.js +0 -105
  87. package/lib/netlify.d.ts +0 -29
  88. package/lib/netlify.js +0 -30
  89. package/lib/service-worker.d.ts +0 -48
  90. package/lib/service-worker.js +0 -38
  91. package/lib/vercel.d.ts +0 -10
  92. package/lib/vercel.js +0 -9
  93. package/plugins/acryl-router/src/deprecated.ts +0 -15
@@ -1,6 +1,6 @@
1
1
  # Adapter Helper
2
2
 
3
- The Adapter Helper provides a seamless way to interact with various platforms through a unified interface.
3
+ The Adapter Helper reads an app's environment the same way on every runtime it runs on.
4
4
 
5
5
  ## Import
6
6
 
@@ -11,50 +11,25 @@ import { env, getRuntimeKey } from 'acrylblends/adapter'
11
11
 
12
12
  ## `env()`
13
13
 
14
- The `env()` function facilitates retrieving environment variables across different runtimes, extending beyond just Cloudflare Workers' Bindings. The value that can be retrieved with `env(c)` may be different for each runtime.
14
+ The `env()` function returns the environment the host gives the app. On Node.js, the verified runtime, that is `process.env`; on Bun it is `Bun.env` (and `process.env`), and the two entries a `.env` file adds are there as well. A host that passes its own environment to `app.fetch(request, env)` gets that instead.
15
15
 
16
16
  ```ts
17
17
  import { env } from 'acrylblends/adapter'
18
18
 
19
19
  app.get('/env', (c) => {
20
- // NAME is process.env.NAME on Node.js or Bun
21
- // NAME is the value written in `wrangler.toml` on Cloudflare
20
+ // NAME is process.env.NAME on Node.js and Bun
22
21
  const { NAME } = env<{ NAME: string }>(c)
23
22
  return c.text(NAME)
24
23
  })
25
24
  ```
26
25
 
27
- Supported Runtimes, Serverless Platforms and Cloud Services:
28
-
29
- - Cloudflare Workers
30
- - `wrangler.toml`
31
- - `wrangler.jsonc`
32
- - Deno
33
- - [`Deno.env`](https://docs.deno.com/runtime/manual/basics/env_variables)
34
- - `.env` file
35
- - Bun
36
- - [`Bun.env`](https://bun.com/guides/runtime/set-env)
37
- - `process.env`
38
- - Node.js
39
- - `process.env`
40
- - Vercel
41
- - [Environment Variables on Vercel](https://vercel.com/docs/projects/environment-variables)
42
- - AWS Lambda
43
- - [Environment Variables on AWS Lambda](https://docs.aws.amazon.com/lambda/latest/dg/samples-blank.html#samples-blank-architecture)
44
- - Lambda@Edge\
45
- Environment Variables on Lambda are [not supported](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/add-origin-custom-headers.html) by Lambda@Edge, you need to use [Lambda@Edge event](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html) as an alternative.
46
- - Fastly Compute\
47
- On Fastly Compute, you can use the ConfigStore to manage user-defined data.
48
- - Netlify\
49
- On Netlify, you can use the [Netlify Contexts](https://docs.netlify.com/site-deploys/overview/#deploy-contexts) to manage user-defined data.
50
-
51
26
  ### Specify the runtime
52
27
 
53
- You can specify the runtime to get environment variables by passing the runtime key as the second argument.
28
+ `env()` reads the runtime itself. Pass the runtime key as the second argument when a host embeds the app and detects it differently, or in a test that fixes the key:
54
29
 
55
30
  ```ts
56
31
  app.get('/env', (c) => {
57
- const { NAME } = env<{ NAME: string }>(c, 'workerd')
32
+ const { NAME } = env<{ NAME: string }>(c, 'node')
58
33
  return c.text(NAME)
59
34
  })
60
35
  ```
@@ -65,23 +40,18 @@ The `getRuntimeKey()` function returns the identifier of the current runtime.
65
40
 
66
41
  ```ts
67
42
  app.get('/', (c) => {
68
- if (getRuntimeKey() === 'workerd') {
69
- return c.text('You are on Cloudflare')
70
- } else if (getRuntimeKey() === 'bun') {
43
+ if (getRuntimeKey() === 'bun') {
71
44
  return c.text('You are on Bun')
72
45
  }
73
- ...
46
+ return c.text(`You are on ${getRuntimeKey()}`)
74
47
  })
75
48
  ```
76
49
 
77
- ### Available Runtimes Keys
50
+ ### Available runtime keys
78
51
 
79
- Here are the available runtimes keys, unavailable runtime key runtimes may be supported and labeled as `other`, with some being inspired by [WinterCG's Runtime Keys](https://runtime-keys.proposal.wintercg.org/):
52
+ The keys follow [WinterCG's Runtime Keys proposal](https://runtime-keys.proposal.wintercg.org/):
80
53
 
81
- - `workerd` - Cloudflare Workers
82
- - `deno`
83
- - `bun`
84
- - `node`
85
- - `edge-light` - Vercel Edge Functions
86
- - `fastly` - Fastly Compute
87
- - `other` - Other unknown runtimes keys
54
+ - `node` - Node.js, the verified runtime
55
+ - `bun` - Bun, experimental
56
+ - `deno`, `workerd`, `edge-light`, `fastly` - keys the helper still recognizes for a host that embeds an app in that runtime; 1.0 ships no adapter for them (see [Other runtimes](../getting-started/other-runtimes.md))
57
+ - `other` - a runtime the helper does not recognize
@@ -4,14 +4,7 @@ The ConnInfo Helper helps you to get the connection information. For example, yo
4
4
 
5
5
  ## Import
6
6
 
7
- Each adapter has its own `getConnInfo`: `acrylblends/node-server`, `acrylblends/cloudflare-workers`, `acrylblends/vercel`, `acrylblends/aws-lambda`, `acrylblends/netlify`, `acrylblends/lambda-edge` and `acrylblends/bun`. The Bun example is not type-checked by the docs tests, which run without Bun's types.
8
-
9
- **Cloudflare Workers**
10
-
11
- ```ts
12
- import { Acryl } from 'acrylblends'
13
- import { getConnInfo } from 'acrylblends/cloudflare-workers'
14
- ```
7
+ Each adapter has its own `getConnInfo`: `acrylblends/node-server` and `acrylblends/bun` (experimental).
15
8
 
16
9
  **Bun**
17
10
 
@@ -20,34 +13,6 @@ import { Acryl } from 'acrylblends'
20
13
  import { getConnInfo } from 'acrylblends/bun'
21
14
  ```
22
15
 
23
- **Vercel**
24
-
25
- ```ts
26
- import { Acryl } from 'acrylblends'
27
- import { getConnInfo } from 'acrylblends/vercel'
28
- ```
29
-
30
- **AWS Lambda**
31
-
32
- ```ts
33
- import { Acryl } from 'acrylblends'
34
- import { getConnInfo } from 'acrylblends/aws-lambda'
35
- ```
36
-
37
- **Netlify**
38
-
39
- ```ts
40
- import { Acryl } from 'acrylblends'
41
- import { getConnInfo } from 'acrylblends/netlify'
42
- ```
43
-
44
- **Lambda@Edge**
45
-
46
- ```ts
47
- import { Acryl } from 'acrylblends'
48
- import { getConnInfo } from 'acrylblends/lambda-edge'
49
- ```
50
-
51
16
  **Node.js**
52
17
 
53
18
  ```ts
@@ -47,7 +47,7 @@ app.get('/streamText', (c) => {
47
47
 
48
48
  **Warning.**
49
49
 
50
- If you are developing an application for Cloudflare Workers, streaming may not work well on Wrangler. If so, add `Identity` for `Content-Encoding` header.
50
+ A proxy or a host that compresses the response body can hold a stream back until it ends. If a stream arrives only when it is complete, send `Content-Encoding: Identity` for that route.
51
51
 
52
52
  ```ts
53
53
  app.get('/streamText', (c) => {
@@ -1,18 +1,11 @@
1
1
  # WebSocket Helper
2
2
 
3
3
  WebSocket Helper is a helper for server-side WebSockets in Acryl applications.
4
- The Node.js, Cloudflare Workers and Bun adapters are available.
4
+ The Node.js and Bun adapters are available.
5
5
 
6
6
  ## Import
7
7
 
8
- The Node.js adapter (`acrylblends/node-server`), the Cloudflare Workers adapter (`acrylblends/cloudflare-workers`) and the Bun adapter (`acrylblends/bun`) provide `upgradeWebSocket`. The other platforms have no WebSocket support in their adapters. The Bun adapter is checked on Bun in the framework's release check; its examples below are not type-checked by the docs tests, which run without Bun's types.
9
-
10
- **Cloudflare Workers**
11
-
12
- ```ts
13
- import { Acryl } from 'acrylblends'
14
- import { upgradeWebSocket } from 'acrylblends/cloudflare-workers'
15
- ```
8
+ The Node.js adapter (`acrylblends/node-server`) and the Bun adapter (`acrylblends/bun`, experimental) provide `upgradeWebSocket`. The other platforms have no adapter in 1.0.
16
9
 
17
10
  **Bun**
18
11
 
@@ -63,7 +56,7 @@ app.get(
63
56
 
64
57
  Available events:
65
58
 
66
- - `onOpen` - Currently, Cloudflare Workers does not support it.
59
+ - `onOpen`
67
60
  - `onMessage`
68
61
  - `onClose`
69
62
  - `onError`
@@ -103,7 +96,7 @@ See the examples using WebSocket Helper.
103
96
  ```ts
104
97
  // server.ts
105
98
  import { Acryl } from 'acrylblends'
106
- import { upgradeWebSocket } from 'acrylblends/cloudflare-workers'
99
+ import { upgradeWebSocket } from 'acrylblends/node-server'
107
100
 
108
101
  const app = new Acryl().get(
109
102
  '/ws',
@@ -1,7 +1,7 @@
1
1
  # Basic Auth Middleware
2
2
 
3
3
  This middleware can apply Basic authentication to a specified path.
4
- Implementing Basic authentication with Cloudflare Workers or other platforms is more complicated than it seems, but with this middleware, it's a breeze.
4
+ Implementing Basic authentication by hand is more complicated than it seems, but with this middleware, it's a breeze.
5
5
 
6
6
  For more information about how the Basic auth scheme works under the hood, see the [MDN docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication#basic_authentication_scheme).
7
7
 
@@ -2,11 +2,7 @@
2
2
 
3
3
  The Cache middleware uses the Web Standards' [Cache API](https://developer.mozilla.org/en-US/docs/Web/API/Cache).
4
4
 
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.
6
-
7
- Cloudflare Workers respects the `Cache-Control` header and return cached responses. For details, refer to [Cache on Cloudflare Docs](https://developers.cloudflare.com/workers/runtime-apis/cache/). Deno does not respect headers, so if you need to update the cache, you will need to implement your own mechanism.
8
-
9
- See [Usage](#usage) below for instructions on each platform.
5
+ It needs a Cache API on the host: the middleware reads `globalThis.caches`. Node.js, the verified runtime, does not provide one, so on Node the middleware is not enabled and says so in one line; a host that embeds an app in a runtime with a Cache API (or provides `globalThis.caches` itself) gets it. `Cache-Control` handling and the QUERY-request cache below are implemented by the middleware, not by the platform.
10
6
 
11
7
  ## Import
12
8
 
@@ -17,28 +13,12 @@ import { cache } from 'acrylblends/cache'
17
13
 
18
14
  ## Usage
19
15
 
20
- **Cloudflare Workers**
21
-
22
- ```ts
23
- app.get(
24
- '*',
25
- cache({
26
- cacheName: 'my-app',
27
- cacheControl: 'max-age=3600',
28
- })
29
- )
30
- ```
31
-
32
- **Deno**
33
-
34
16
  ```ts
35
- // Must use `wait: true` for the Deno runtime
36
17
  app.get(
37
18
  '*',
38
19
  cache({
39
20
  cacheName: 'my-app',
40
21
  cacheControl: 'max-age=3600',
41
- wait: true,
42
22
  })
43
23
  )
44
24
  ```
@@ -59,7 +39,7 @@ The name of the cache. Can be used to store multiple caches with different ident
59
39
 
60
40
  ### *(optional)* wait: `boolean`
61
41
 
62
- 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_. The default is `false`.
42
+ A boolean indicating if Acryl should wait for the Promise of the `cache.put` function to resolve before continuing with the request. The default is `false`. A runtime whose Cache API only completes a write after the response has finished needs `true`, or the write is dropped.
63
43
 
64
44
  ### *(optional)* cacheControl: `string`
65
45
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  This middleware compresses the response body, according to `Accept-Encoding` request header.
4
4
 
5
- > **Note.** On Cloudflare Workers and Deno Deploy, the response body will be compressed automatically, so there is no need to use this middleware.
5
+ > **Note.** Node.js and Bun do not compress a response on their own, so this middleware is what compresses it. A host that already compresses at its edge does not need it.
6
6
 
7
7
  ## Import
8
8
 
@@ -2,9 +2,7 @@
2
2
 
3
3
  The Context Storage Middleware stores the Acryl `Context` in the `AsyncLocalStorage`, to make it globally accessible.
4
4
 
5
- > **Note.** This middleware uses `AsyncLocalStorage`. The runtime should support it.
6
- >
7
- > **Cloudflare Workers**: To enable `AsyncLocalStorage`, add the [`nodejs_compat` or `nodejs_als` flag](https://developers.cloudflare.com/workers/configuration/compatibility-dates/#nodejs-compatibility-flag) to your `wrangler.toml` file.
5
+ > **Note.** This middleware uses `AsyncLocalStorage`. Node.js, the verified runtime, provides it; a host that embeds an app in a runtime without it cannot use this middleware.
8
6
 
9
7
  ## Import
10
8
 
@@ -47,22 +45,20 @@ app.get('/', (c) => {
47
45
  })
48
46
  ```
49
47
 
50
- On Cloudflare Workers, you can access the bindings outside the handler.
48
+ Anything a handler puts on the context can be read further down the call stack, without passing `c` through every function:
51
49
 
52
50
  ```ts
53
- type Env = {
54
- Bindings: {
55
- KV: KVNamespace
56
- }
57
- }
58
-
59
- const app = new Acryl<Env>()
51
+ const app = new Acryl()
60
52
 
61
53
  app.use(contextStorage())
54
+ app.use(async (c, next) => {
55
+ c.set('user', 'ada')
56
+ await next()
57
+ })
62
58
 
63
- const setKV = (value: string) => {
64
- return getContext<Env>().env.KV.put('key', value)
65
- }
59
+ app.get('/', (c) => c.text(`Hello ${getUser()}`))
60
+
61
+ const getUser = () => getContext().get('user')
66
62
  ```
67
63
 
68
64
  ## tryGetContext
@@ -1,7 +1,6 @@
1
1
  # CORS Middleware
2
2
 
3
- There are many use cases of Cloudflare Workers as Web APIs and calling them from external front-end application.
4
- For them we have to implement CORS, let's do this with middleware as well.
3
+ A web API is often called from a page served by another origin. For that we have to implement CORS, and this middleware does it.
5
4
 
6
5
  ## Import
7
6
 
@@ -31,7 +31,7 @@ app.use(
31
31
  app.get('/', (c) => c.text('Acryl!'))
32
32
  ```
33
33
 
34
- Pass the `getConninfo` from the [ConnInfo helper](../../helpers/conninfo.md) appropriate for your environment as the first argument of `ipRestriction`. Every adapter has one (`acrylblends/bun`, `acrylblends/aws-lambda`, `acrylblends/node-server` and the others).
34
+ Pass the `getConninfo` from the [ConnInfo helper](../../helpers/conninfo.md) appropriate for your environment as the first argument of `ipRestriction`. Every adapter has one (`acrylblends/node-server` and `acrylblends/bun`).
35
35
 
36
36
  ## Rules
37
37
 
@@ -224,7 +224,7 @@ app.get('/page/info', (c) => {
224
224
 
225
225
  **Warning.**
226
226
 
227
- You can't use `useRequestContext()` with the Deno's `precompile` JSX option. Use the `react-jsx`:
227
+ You can't use `useRequestContext()` with a JSX option that precompiles the templates ahead of the build. Use `react-jsx`:
228
228
 
229
229
  ```json
230
230
  "compilerOptions": {
@@ -32,7 +32,7 @@ By using the Logger Middleware, you can easily monitor the flow of requests and
32
32
  You can also extend the middleware further by providing your own `PrintFunc` function for tailored logging behavior.
33
33
 
34
34
  > **Tip.**
35
- > To disable _status code coloring_, you can set a `NO_COLOR` environment variable. This is a common way to disable ANSI color escape codes in logging libraries, and is described at <https://no-color.org/>. Note that Cloudflare Workers do not have a `process.env` object, so will default to plaintext log output.
35
+ > To disable _status code coloring_, you can set a `NO_COLOR` environment variable. This is a common way to disable ANSI color escape codes in logging libraries, and is described at <https://no-color.org/>.
36
36
 
37
37
  ## PrintFunc
38
38
 
@@ -3,7 +3,7 @@
3
3
  The guard for a local app's own routes, such as a control API a desktop window calls:
4
4
 
5
5
  ```ts
6
- import { loopbackOnly } from 'acryl-router/middleware'
6
+ import { loopbackOnly } from 'acrylblends/loopback-only'
7
7
 
8
8
  app.use('/control/*', loopbackOnly())
9
9
  ```
@@ -29,7 +29,7 @@ app.all('/itty-router/*', mount(ittyRouter.handle))
29
29
 
30
30
  By default, the mounted application receives a new `Request` with the matched path prefix removed from its URL. A request to `/itty-router/hello` reaches itty-router as `/hello`.
31
31
 
32
- The mounted application is called as `handler(request, c.env, c.executionCtx)`, the same arguments as a Cloudflare Workers `fetch` handler. Use `optionHandler` to pass different arguments.
32
+ The mounted application is called as `handler(request, c.env, c.executionCtx)`, the three arguments a `fetch`-style handler takes. Use `optionHandler` to pass different arguments.
33
33
 
34
34
  ## Options
35
35
 
@@ -72,23 +72,16 @@ The header name used for the request ID. The default is `X-Request-Id`.
72
72
 
73
73
  The request ID generation function. By default, it uses `crypto.randomUUID()`.
74
74
 
75
- ## Platform specific Request IDs
76
-
77
- Some platform (such as AWS Lambda) already generate their own Request IDs per request.
78
- Without any additional configuration, this middleware is unaware of these specific Request IDs
79
- and generates a new Request ID. This can lead to confusion when looking at your application logs.
80
-
81
- To unify these IDs, use the `generator` function to capture the platform specific Request ID and to use it in this middleware.
82
-
83
- ### Platform specific links
84
-
85
- - AWS Lambda
86
- - [AWS documentation: Context object](https://docs.aws.amazon.com/lambda/latest/dg/nodejs-context.html)
87
- - Acryl: Access AWS Lambda Object
88
- - Cloudflare
89
- - [Cloudflare Ray ID
90
- ](https://developers.cloudflare.com/fundamentals/reference/cloudflare-ray-id/)
91
- - Deno
92
- - [Request ID on the Deno Blog](https://deno.com/blog/zero-config-debugging-deno-opentelemetry#:~:text=s%20automatically%20have-,unique%20request%20IDs,-associated%20with%20them)
93
- - Fastly
94
- - [Fastly documentation: req.xid](https://www.fastly.com/documentation/reference/vcl/variables/client-request/req-xid/)
75
+ ## An ID that came from earlier in the chain
76
+
77
+ A proxy, a load balancer or the host that starts the app may already put a request id on the request.
78
+ Without configuration this middleware is unaware of it and generates a new one, which makes the two logs hard to line up.
79
+ Use the `generator` function to read the incoming one and fall back to a fresh id:
80
+
81
+ ```ts
82
+ app.use(
83
+ requestId({
84
+ generator: (c) => c.req.header('X-Request-Id') ?? crypto.randomUUID(),
85
+ })
86
+ )
87
+ ```
@@ -3,8 +3,7 @@
3
3
  The [Server-Timing](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing) Middleware provides
4
4
  performance metrics in the response headers.
5
5
 
6
- > **Note.** On Cloudflare Workers, the timer metrics may not be accurate,
7
- > since [timers only show the time of last I/O](https://developers.cloudflare.com/workers/learning/security-model/#step-1-disallow-timers-and-multi-threading).
6
+ > **Note.** The metrics come from timers around the handler, so they measure wall-clock time on the host the app runs on.
8
7
 
9
8
  ## Import
10
9
 
@@ -153,6 +153,11 @@ interface Config {
153
153
  tools?: {
154
154
  expose?: string[];
155
155
  };
156
+ /**
157
+ * The door is a development tool: with `NODE_ENV=production` the plugin starts nothing (no route, no `.acryl/` file, no service), and with `ACRYL_DOOR=off` it never does. A host that means to
158
+ * run it in production (a packaged desktop app whose user drives it with an agent) says so here; `ACRYL_DOOR=off` still wins.
159
+ */
160
+ allowInProduction?: boolean;
156
161
  }
157
162
  declare const Config: z<Config>;
158
163
  declare function apply(ctx: Context, rawConfig?: Config): void;
@@ -1,12 +1,12 @@
1
1
  import { t as Acryl } from "../app-BM0rTCp7.js";
2
2
  import { n as clientModules } from "../client-modules-CLvWOjbd.js";
3
3
  import { MAX_SNAPSHOT_NODES, MAX_WAIT_MS, UiControlError, parseUiRequest } from "../door/protocol.js";
4
- import { a as INVALID_JSON, c as operatorOnly, d as AuditLog, f as auditPath, i as DOOR_PREFIX, l as privateApi, o as error, p as UiChannel, r as pageChannelRoutes, s as jsonBody, t as renderSnapshot, u as readJson } from "../snapshot-text-yaWlezbd.js";
5
- import "../src-DNzw0Qsb.js";
4
+ import { a as INVALID_JSON, c as operatorOnly, d as AuditLog, f as auditPath, i as DOOR_PREFIX, l as privateApi, o as error, p as UiChannel, r as pageChannelRoutes, s as jsonBody, t as renderSnapshot, u as readJson } from "../snapshot-text-DmE0YfeZ.js";
5
+ import "../src-2Z4mJg0x.js";
6
6
  import { isAbsolute, join, relative, resolve } from "node:path";
7
- import { randomBytes } from "node:crypto";
8
7
  import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
9
8
  import z from "@deepseek-ai/schemastery";
9
+ import { randomBytes } from "node:crypto";
10
10
  //#region ../../plugins/acryl-door/src/host/verbs.ts
11
11
  /**
12
12
  * The one verb list (spec 049 slice 13). Every face of the door reads it: the operator client (`acryl <verb>`, its `verbs` and `brief`),
@@ -696,7 +696,10 @@ const inject = [
696
696
  "appInstance",
697
697
  "nodeServer"
698
698
  ];
699
- const Config = z.object({ tools: z.object({ expose: z.array(z.string().pattern(/^(?!door_)[A-Za-z][A-Za-z0-9_-]{0,63}$/u)).description("App tools (from the tools registry) the door offers; none by default.") }) });
699
+ const Config = z.object({
700
+ allowInProduction: z.boolean().default(false).description("Run in production too (NODE_ENV=production); ACRYL_DOOR=off still turns it off."),
701
+ tools: z.object({ expose: z.array(z.string().pattern(/^(?!door_)[A-Za-z][A-Za-z0-9_-]{0,63}$/u)).description("App tools (from the tools registry) the door offers; none by default.") })
702
+ });
700
703
  /** The page module, served compiled from source by the app's own TypeScript. */
701
704
  const PAGE_DIR = join(import.meta.dirname, import.meta.url.endsWith(".ts") ? "page" : join("..", "src", "page"));
702
705
  /** The operator client this build runs: the source next to this file, or the built `cli.js`. */
@@ -719,6 +722,7 @@ function loopbackUrl(url) {
719
722
  }
720
723
  function apply(ctx, rawConfig = {}) {
721
724
  const config = Config(rawConfig);
725
+ if (process.env.ACRYL_DOOR === "off" || process.env.NODE_ENV === "production" && config.allowInProduction !== true) return;
722
726
  const app = ctx.get("appInstance");
723
727
  const server = ctx.get("nodeServer");
724
728
  if (typeof app?.root !== "string") throw new Error("acryl-door: the appInstance service has no app folder (root)");
@@ -1,6 +1,6 @@
1
1
  import { t as Acryl } from "../app-BM0rTCp7.js";
2
2
  import { loopbackOnly } from "../loopback-only.js";
3
- import "../src-DNzw0Qsb.js";
3
+ import "../src-2Z4mJg0x.js";
4
4
  import "../middleware-CPQ8himN.js";
5
5
  import { Service } from "@deepseek-ai/cordis";
6
6
  //#region ../../plugins/acryl-inspect/src/report.ts
@@ -1,8 +1,8 @@
1
1
  import { n as UpgradeEmitter, r as UpgradeHub } from "../test-websocket-ZXHNHQSU.js";
2
2
  import "./node-server.js";
3
- import { pipeline } from "node:stream/promises";
4
3
  import { Readable } from "node:stream";
5
4
  import { Service } from "@deepseek-ai/cordis";
5
+ import { pipeline } from "node:stream/promises";
6
6
  //#region ../../plugins/acryl-router-http/src/bridge.ts
7
7
  const FALLBACK_ORIGIN = "http://localhost";
8
8
  /** Build the Web `Request` for an incoming message. The body, when the method has one, is streamed, not buffered. */
@@ -2,7 +2,6 @@ import { B as NotFoundHandler, L as MiddlewareHandler, O as Handler, Q as Valida
2
2
  import { c as StatusCode, n as ContentfulStatusCode } from "../http-status-DaAwGAFL.js";
3
3
  import { a as getConnInfo, i as connectionOf, n as RouterBindings, r as RouterEnv, t as ConnectionInfo } from "../connection-ZLEso7XL.js";
4
4
  import { t as Acryl } from "../app-D8riatvv.js";
5
- import { n as AppRequest, t as App } from "../deprecated-CTy4N7ng.js";
6
5
  import { a as TrailingSlash, i as RouterHttpService, n as MountableApp, o as apply, r as Router, s as name, t as Config } from "../index-D4nVR3wu.js";
7
6
  import { t as HTTPException } from "../http-exception-kpGJkmpi.js";
8
- export { Acryl, type AcrylRequest, App, type AppRequest, Config, type ConnectionInfo, type ContentfulStatusCode, Context, type ContextRenderer, type ContextVariableMap, type Env, type ErrorHandler, type ExecutionContext, HTTPException, type Handler, type Input, type MiddlewareHandler, type MountableApp, type Next, type NotFoundHandler, type NotFoundResponse, Router, type RouterBindings, type RouterEnv, type RouterHttpService, type Schema, type StatusCode, type ToSchema, type TrailingSlash, type TypedResponse, type ValidationTargets, apply, connectionOf, getConnInfo, name };
7
+ export { Acryl, type AcrylRequest, Config, type ConnectionInfo, type ContentfulStatusCode, Context, type ContextRenderer, type ContextVariableMap, type Env, type ErrorHandler, type ExecutionContext, HTTPException, type Handler, type Input, type MiddlewareHandler, type MountableApp, type Next, type NotFoundHandler, type NotFoundResponse, Router, type RouterBindings, type RouterEnv, type RouterHttpService, type Schema, type StatusCode, type ToSchema, type TrailingSlash, type TypedResponse, type ValidationTargets, apply, connectionOf, getConnInfo, name };
@@ -1,7 +1,6 @@
1
1
  import { HTTPException } from "../http-exception.js";
2
2
  import { t as Context } from "../context-DDO0cfuP.js";
3
3
  import { t as Acryl } from "../app-BM0rTCp7.js";
4
- import { t as App } from "../deprecated-BP4fPt38.js";
5
4
  import { n as getConnInfo, t as connectionOf } from "../connection-C7xgP1hP.js";
6
- import { i as name, n as Router, r as apply, t as Config } from "../src-DNzw0Qsb.js";
7
- export { Acryl, App, Config, Context, HTTPException, Router, apply, connectionOf, getConnInfo, name };
5
+ import { i as name, n as Router, r as apply, t as Config } from "../src-2Z4mJg0x.js";
6
+ export { Acryl, Config, Context, HTTPException, Router, apply, connectionOf, getConnInfo, name };
@@ -3,7 +3,7 @@ import { methodNotAllowed } from "../method-not-allowed.js";
3
3
  import { r as streamSSE } from "../streaming-DHST3Scg.js";
4
4
  import { loopbackOnly } from "../loopback-only.js";
5
5
  import "../helpers-CvTauQT5.js";
6
- import "../src-DNzw0Qsb.js";
6
+ import "../src-2Z4mJg0x.js";
7
7
  import "../middleware-CPQ8himN.js";
8
8
  import { Service } from "@deepseek-ai/cordis";
9
9
  //#region ../../plugins/acryl-state/src/cell.ts
package/lib/door/host.js CHANGED
@@ -1,2 +1,2 @@
1
- import { d as AuditLog, f as auditPath, n as HEARTBEAT_MS, p as UiChannel, r as pageChannelRoutes, t as renderSnapshot } from "../snapshot-text-yaWlezbd.js";
1
+ import { d as AuditLog, f as auditPath, n as HEARTBEAT_MS, p as UiChannel, r as pageChannelRoutes, t as renderSnapshot } from "../snapshot-text-DmE0YfeZ.js";
2
2
  export { AuditLog, HEARTBEAT_MS, UiChannel, auditPath, pageChannelRoutes, renderSnapshot };
@@ -0,0 +1,66 @@
1
+ //#region ../../plugins/agent-panel/drivers.d.ts
2
+ /**
3
+ * The drivers the agent panel can offer, in one registry (the `drivers` service the panel provides). A driver is one of two kinds of session:
4
+ *
5
+ * - `chat`: a message in, the panel's own events out (`text`, `tool`, `error`). The app's agent, the headless coding agents and a harness chat are chat drivers.
6
+ * - `terminal`: bytes in, bytes out, a real pseudo-terminal (the `driver-pty` plugin). Nothing is forced to speak bytes.
7
+ *
8
+ * This module is `acrylblends/drivers`: the contract a driver plugin writes against, with no dependency on Cordis. The panel lists every registered driver and picks the view by `kind`. A plugin that provides drivers injects `drivers`: with no panel mounted it is pending,
9
+ * and a panel without such a plugin simply lists none of its drivers.
10
+ */
11
+ /** One event of a chat run. The panel adds `change` (a plugin was installed or removed) and `done` itself. */
12
+ type ChatEvent = {
13
+ readonly event: 'text';
14
+ readonly data: {
15
+ readonly text: string;
16
+ };
17
+ } | {
18
+ readonly event: 'tool';
19
+ readonly data: Record<string, unknown>;
20
+ } | {
21
+ readonly event: 'error';
22
+ readonly data: {
23
+ readonly message: string;
24
+ };
25
+ };
26
+ interface ChatDriver {
27
+ readonly kind: 'chat';
28
+ readonly name: string;
29
+ /** Runs one message. Aborting `signal` stops the run. */
30
+ start(options: {
31
+ message: string;
32
+ signal: AbortSignal;
33
+ }): AsyncIterable<ChatEvent>;
34
+ }
35
+ /** A live pseudo-terminal session. */
36
+ interface TerminalSession {
37
+ readonly id: string;
38
+ onData(listener: (chunk: string) => void): () => void;
39
+ onExit(listener: (code: number | null) => void): () => void;
40
+ write(data: string): void;
41
+ resize(cols: number, rows: number): void;
42
+ /** Resolves when the process (group) is gone. */
43
+ kill(): Promise<void>;
44
+ }
45
+ interface TerminalDriver {
46
+ readonly kind: 'terminal';
47
+ readonly name: string;
48
+ start(options: {
49
+ cwd: string;
50
+ env: NodeJS.ProcessEnv;
51
+ cols: number;
52
+ rows: number;
53
+ }): TerminalSession;
54
+ }
55
+ type Driver = ChatDriver | TerminalDriver;
56
+ interface Drivers {
57
+ /** Add a driver. Returns the function that removes it; a plugin registers inside `ctx.effect` so the driver leaves with it. */
58
+ register(driver: Driver): () => void;
59
+ list(): Driver[];
60
+ get(name: string): Driver | undefined;
61
+ /** Whether a request may use the drivers' endpoints: it comes from the app's own page and carries the panel's token. */
62
+ authorized(headers: Headers): boolean;
63
+ }
64
+ declare function createDrivers(authorized?: (headers: Headers) => boolean): Drivers;
65
+ //#endregion
66
+ export { ChatDriver, ChatEvent, Driver, Drivers, TerminalDriver, TerminalSession, createDrivers };
package/lib/drivers.js ADDED
@@ -0,0 +1,16 @@
1
+ //#region ../../plugins/agent-panel/drivers.ts
2
+ function createDrivers(authorized = () => true) {
3
+ const table = /* @__PURE__ */ new Map();
4
+ return {
5
+ register(driver) {
6
+ if (table.has(driver.name)) throw new Error(`driver "${driver.name}" is already registered`);
7
+ table.set(driver.name, driver);
8
+ return () => void (table.get(driver.name) === driver && table.delete(driver.name));
9
+ },
10
+ list: () => [...table.values()],
11
+ get: (name) => table.get(name),
12
+ authorized
13
+ };
14
+ }
15
+ //#endregion
16
+ export { createDrivers };
package/lib/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { B as NotFoundHandler, L as MiddlewareHandler, O as Handler, Q as ValidationTargets, V as NotFoundResponse, X as ToSchema, Y as Schema, Z as TypedResponse, a as ExecutionContext, j as Input, n as ContextRenderer, r as ContextVariableMap, s as AcrylRequest, t as Context, v as Env, y as ErrorHandler, z as Next } from "./context-DS3fYyG-.js";
2
2
  import { t as Acryl } from "./app-D8riatvv.js";
3
3
  import { c as InferRequestType, i as ClientRequestOptions, l as InferResponseType } from "./types-zNxyEpG2.js";
4
- import { n as AppRequest, t as App } from "./deprecated-CTy4N7ng.js";
5
- export { Acryl, type AcrylRequest, App, type AppRequest, type ClientRequestOptions, Context, type ContextRenderer, type ContextVariableMap, type Env, type ErrorHandler, type ExecutionContext, type Handler, type InferRequestType, type InferResponseType, type Input, type MiddlewareHandler, type Next, type NotFoundHandler, type NotFoundResponse, type Schema, type ToSchema, type TypedResponse, type ValidationTargets };
4
+ export { Acryl, type AcrylRequest, type ClientRequestOptions, Context, type ContextRenderer, type ContextVariableMap, type Env, type ErrorHandler, type ExecutionContext, type Handler, type InferRequestType, type InferResponseType, type Input, type MiddlewareHandler, type Next, type NotFoundHandler, type NotFoundResponse, type Schema, type ToSchema, type TypedResponse, type ValidationTargets };
package/lib/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { t as Context } from "./context-DDO0cfuP.js";
2
2
  import { t as Acryl } from "./app-BM0rTCp7.js";
3
3
  import "./core-CaY8XDZ6.js";
4
- import { t as App } from "./deprecated-BP4fPt38.js";
5
- export { Acryl, App, Context };
4
+ export { Acryl, Context };