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.
- package/README.md +131 -53
- package/dist/index.d.ts +29 -2
- package/dist/index.js +450 -69
- package/dist/index.js.map +1 -1
- package/docs/framework/README.md +5 -3
- package/docs/framework/agents/index.md +1 -1
- package/docs/framework/api/acryl.md +5 -17
- package/docs/framework/api/context.md +12 -61
- package/docs/framework/api/presets.md +1 -1
- package/docs/framework/api/request.md +3 -3
- package/docs/framework/api/summary.md +1 -1
- package/docs/framework/concepts/web-standard.md +6 -16
- package/docs/framework/cordis/acryl-in-a-cordis-app.md +13 -8
- package/docs/framework/cordis/migration-from-0-4.md +1 -1
- package/docs/framework/cordis/migration-to-1-0.md +45 -0
- package/docs/framework/cordis/node-server.md +2 -2
- package/docs/framework/getting-started/basic.md +15 -10
- package/docs/framework/getting-started/desktop.md +1 -1
- package/docs/framework/getting-started/other-runtimes.md +10 -14
- package/docs/framework/guides/create-acrylblends.md +4 -2
- package/docs/framework/guides/data.md +1 -1
- package/docs/framework/guides/faq.md +1 -1
- package/docs/framework/guides/jsx-dom.md +1 -1
- package/docs/framework/guides/production.md +43 -0
- package/docs/framework/guides/rpc.md +3 -11
- package/docs/framework/helpers/adapter.md +13 -43
- package/docs/framework/helpers/conninfo.md +1 -36
- package/docs/framework/helpers/streaming.md +1 -1
- package/docs/framework/helpers/websocket.md +4 -11
- package/docs/framework/middleware/builtin/basic-auth.md +1 -1
- package/docs/framework/middleware/builtin/cache.md +2 -22
- package/docs/framework/middleware/builtin/compress.md +1 -1
- package/docs/framework/middleware/builtin/context-storage.md +10 -14
- package/docs/framework/middleware/builtin/cors.md +1 -2
- package/docs/framework/middleware/builtin/ip-restriction.md +1 -1
- package/docs/framework/middleware/builtin/jsx-renderer.md +1 -1
- package/docs/framework/middleware/builtin/logger.md +1 -1
- package/docs/framework/middleware/builtin/loopback-only.md +1 -1
- package/docs/framework/middleware/builtin/mount.md +1 -1
- package/docs/framework/middleware/builtin/request-id.md +13 -20
- package/docs/framework/middleware/builtin/timing.md +1 -2
- package/lib/cordis/door.d.ts +5 -0
- package/lib/cordis/door.js +8 -4
- package/lib/cordis/inspect.js +1 -1
- package/lib/cordis/router-http.js +1 -1
- package/lib/cordis/router.d.ts +1 -2
- package/lib/cordis/router.js +2 -3
- package/lib/cordis/state.js +1 -1
- package/lib/door/host.js +1 -1
- package/lib/drivers.d.ts +66 -0
- package/lib/drivers.js +16 -0
- package/lib/index.d.ts +1 -2
- package/lib/index.js +1 -2
- package/lib/{snapshot-text-yaWlezbd.js → snapshot-text-DmE0YfeZ.js} +2 -2
- package/lib/{src-DNzw0Qsb.js → src-2Z4mJg0x.js} +0 -1
- package/package.json +5 -121
- package/plugins/acryl-door/src/index.ts +8 -0
- package/plugins/acryl-router/src/index.ts +0 -1
- package/plugins/agent-panel/drivers.ts +1 -16
- package/plugins/agent-panel/index.ts +1 -1
- package/plugins/agent-panel/registry.ts +16 -0
- package/plugins/driver-acp/README.md +53 -0
- package/plugins/driver-acp/chat.ts +258 -0
- package/plugins/driver-acp/connection.ts +239 -0
- package/plugins/driver-acp/index.ts +65 -0
- package/plugins/driver-acp/plugin.json +12 -0
- package/plugins/driver-acp/provenance.json +20 -0
- package/plugins/driver-pty/index.ts +1 -0
- package/shared/library-history.json +464 -0
- package/docs/framework/getting-started/aws-lambda.md +0 -115
- package/docs/framework/getting-started/cloudflare-pages.md +0 -53
- package/docs/framework/getting-started/cloudflare-workers.md +0 -67
- package/docs/framework/getting-started/lambda-edge.md +0 -41
- package/docs/framework/getting-started/netlify.md +0 -25
- package/docs/framework/getting-started/service-worker.md +0 -33
- package/docs/framework/getting-started/vercel.md +0 -28
- package/lib/aws-lambda.d.ts +0 -324
- package/lib/aws-lambda.js +0 -357
- package/lib/cloudflare-pages.d.ts +0 -58
- package/lib/cloudflare-pages.js +0 -78
- package/lib/cloudflare-workers.d.ts +0 -21
- package/lib/cloudflare-workers.js +0 -80
- package/lib/deprecated-BP4fPt38.js +0 -10
- package/lib/deprecated-CTy4N7ng.d.ts +0 -12
- package/lib/lambda-edge.d.ts +0 -92
- package/lib/lambda-edge.js +0 -105
- package/lib/netlify.d.ts +0 -29
- package/lib/netlify.js +0 -30
- package/lib/service-worker.d.ts +0 -48
- package/lib/service-worker.js +0 -38
- package/lib/vercel.d.ts +0 -10
- package/lib/vercel.js +0 -9
- package/plugins/acryl-router/src/deprecated.ts +0 -15
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Adapter Helper
|
|
2
2
|
|
|
3
|
-
The Adapter Helper
|
|
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
|
|
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
|
|
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
|
-
|
|
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, '
|
|
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() === '
|
|
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
|
|
50
|
+
### Available runtime keys
|
|
78
51
|
|
|
79
|
-
|
|
52
|
+
The keys follow [WinterCG's Runtime Keys proposal](https://runtime-keys.proposal.wintercg.org/):
|
|
80
53
|
|
|
81
|
-
- `
|
|
82
|
-
- `
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
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
|
|
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
|
-
|
|
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
|
|
4
|
+
The Node.js and Bun adapters are available.
|
|
5
5
|
|
|
6
6
|
## Import
|
|
7
7
|
|
|
8
|
-
The Node.js adapter (`acrylblends/node-server`)
|
|
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`
|
|
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/
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.**
|
|
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`.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
64
|
-
|
|
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
|
-
|
|
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/
|
|
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
|
|
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/>.
|
|
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
|
|
|
@@ -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
|
|
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
|
-
##
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
Without
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
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.**
|
|
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
|
|
package/lib/cordis/door.d.ts
CHANGED
|
@@ -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;
|
package/lib/cordis/door.js
CHANGED
|
@@ -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-
|
|
5
|
-
import "../src-
|
|
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({
|
|
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)");
|
package/lib/cordis/inspect.js
CHANGED
|
@@ -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-
|
|
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. */
|
package/lib/cordis/router.d.ts
CHANGED
|
@@ -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,
|
|
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 };
|
package/lib/cordis/router.js
CHANGED
|
@@ -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-
|
|
7
|
-
export { Acryl,
|
|
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 };
|
package/lib/cordis/state.js
CHANGED
|
@@ -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-
|
|
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-
|
|
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 };
|
package/lib/drivers.d.ts
ADDED
|
@@ -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
|
-
|
|
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