acrylblends 0.5.0 → 0.5.1
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 +325 -0
- package/docs/framework/UPSTREAM.md +1 -1
- package/docs/framework/cordis/migration-from-dsh-webserver.md +6 -0
- package/docs/framework/upstream.json +2 -2
- package/package.json +1 -1
- package/plugins/acryl-inspect/upstream.json +1 -1
- package/plugins/acryl-node-server/tests/adapter/server.test.ts +10 -0
- package/plugins/acryl-node-server/upstream.json +2 -2
- package/plugins/acryl-router/upstream.json +1 -1
- package/plugins/acryl-router-http/upstream.json +1 -1
- package/plugins/acryl-state/upstream.json +1 -1
- package/templates/todo/upstream.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/acrylblends/acrylblends/main/docs/assets/acrylblends-logo.png" alt="ACRYLBLENDS" width="120">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">acrylblends</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center"><strong>Acryl, a small web framework on Web Standards, for Node.js.</strong><br>
|
|
8
|
+
One <code>Request</code> in, one <code>Response</code> out: routing, middleware, validation, a typed client and a Node.js server, with no dependencies.</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://github.com/acryldev/acryl/blob/main/docs/framework/README.md">Documentation</a> ·
|
|
12
|
+
<a href="https://github.com/acryldev/acryl/blob/main/docs/framework/getting-started/basic.md">Getting started</a> ·
|
|
13
|
+
<a href="https://github.com/acryldev/acryl/blob/main/docs/framework/api/index.md">API</a> ·
|
|
14
|
+
<a href="https://acrylblends.github.io">acrylblends.github.io</a> ·
|
|
15
|
+
<a href="https://acryl.dev">acryl.dev</a> ·
|
|
16
|
+
<a href="https://github.com/acrylblends/acrylblends">GitHub</a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { Acryl } from 'acrylblends'
|
|
23
|
+
|
|
24
|
+
const app = new Acryl()
|
|
25
|
+
app.get('/', (c) => c.text('Hello Acryl!'))
|
|
26
|
+
|
|
27
|
+
export default app
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Contents
|
|
31
|
+
|
|
32
|
+
- [Requirements](#requirements)
|
|
33
|
+
- [Quick start](#quick-start)
|
|
34
|
+
- [Start from a template](#start-from-a-template)
|
|
35
|
+
- [A first API](#a-first-api)
|
|
36
|
+
- [Middleware](#middleware)
|
|
37
|
+
- [Validation](#validation)
|
|
38
|
+
- [Typed client](#typed-client)
|
|
39
|
+
- [Testing](#testing)
|
|
40
|
+
- [Serving on Node.js](#serving-on-nodejs)
|
|
41
|
+
- [What is in the package](#what-is-in-the-package)
|
|
42
|
+
- [Upgrading from 0.4](#upgrading-from-04)
|
|
43
|
+
- [The acrylblends command](#the-acrylblends-command)
|
|
44
|
+
- [Links](#links)
|
|
45
|
+
- [License](#license)
|
|
46
|
+
|
|
47
|
+
## Requirements
|
|
48
|
+
|
|
49
|
+
- **Node.js 22.19 or newer.** Node.js is the verified runtime, and it runs `.ts` files directly, so there is no build step.
|
|
50
|
+
- **Bun** runs the same app (`export default app`) and is experimental.
|
|
51
|
+
- `acrylblends` has no dependencies. Its types need only Node's types (`@types/node`), not the DOM library.
|
|
52
|
+
|
|
53
|
+
## Quick start
|
|
54
|
+
|
|
55
|
+
Create a folder and install the package:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
mkdir my-app && cd my-app
|
|
59
|
+
npm init -y
|
|
60
|
+
npm pkg set type=module
|
|
61
|
+
npm install acrylblends
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Write the app in `index.ts`:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { Acryl } from 'acrylblends'
|
|
68
|
+
|
|
69
|
+
const app = new Acryl()
|
|
70
|
+
|
|
71
|
+
app.get('/', (c) => c.text('Hello Acryl!'))
|
|
72
|
+
|
|
73
|
+
export default app
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Serve it on Node.js with the adapter in `server.ts`:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { serve } from 'acrylblends/node-server'
|
|
80
|
+
import app from './index.ts'
|
|
81
|
+
|
|
82
|
+
serve({ fetch: app.fetch, port: 3000 }, (info) => {
|
|
83
|
+
console.log(`Listening on http://localhost:${info.port}`)
|
|
84
|
+
})
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Run it and open http://localhost:3000:
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
node server.ts
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
For Bun, `bun run index.ts` serves the same `export default app`.
|
|
94
|
+
|
|
95
|
+
## Start from a template
|
|
96
|
+
|
|
97
|
+
`create-acrylblends` creates a ready project with `dev`, `test` and `start` scripts:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
npm create acrylblends@latest my-app
|
|
101
|
+
cd my-app
|
|
102
|
+
npm install
|
|
103
|
+
npm run dev
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The `nodejs` template is a minimal Acryl app. `bun` is the same for Bun (experimental). `acryl-app` is a Cordis app built from plugins,
|
|
107
|
+
with an agent that can extend it while it runs. See the
|
|
108
|
+
[create-acrylblends guide](https://github.com/acryldev/acryl/blob/main/docs/framework/guides/create-acrylblends.md).
|
|
109
|
+
|
|
110
|
+
## A first API
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { Acryl } from 'acrylblends'
|
|
114
|
+
import { HTTPException } from 'acrylblends/http-exception'
|
|
115
|
+
|
|
116
|
+
type Book = { id: string, title: string }
|
|
117
|
+
const books = new Map<string, Book>()
|
|
118
|
+
|
|
119
|
+
const app = new Acryl()
|
|
120
|
+
|
|
121
|
+
app.get('/api/books', (c) => c.json([...books.values()]))
|
|
122
|
+
|
|
123
|
+
app.get('/api/books/:id', (c) => {
|
|
124
|
+
const book = books.get(c.req.param('id'))
|
|
125
|
+
if (book === undefined) throw new HTTPException(404, { message: 'no such book' })
|
|
126
|
+
return c.json(book)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
app.post('/api/books', async (c) => {
|
|
130
|
+
const { title } = await c.req.json<{ title: string }>()
|
|
131
|
+
const book = { id: crypto.randomUUID(), title }
|
|
132
|
+
books.set(book.id, book)
|
|
133
|
+
return c.json(book, 201)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
app.notFound((c) => c.json({ error: 'not found' }, 404))
|
|
137
|
+
app.onError((error, c) => error instanceof HTTPException ? error.getResponse() : c.json({ error: 'internal error' }, 500))
|
|
138
|
+
|
|
139
|
+
export default app
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Read more: [Routing](https://github.com/acryldev/acryl/blob/main/docs/framework/api/routing.md),
|
|
143
|
+
[Context](https://github.com/acryldev/acryl/blob/main/docs/framework/api/context.md),
|
|
144
|
+
[Request](https://github.com/acryldev/acryl/blob/main/docs/framework/api/request.md),
|
|
145
|
+
[Exceptions](https://github.com/acryldev/acryl/blob/main/docs/framework/api/exception.md).
|
|
146
|
+
|
|
147
|
+
## Middleware
|
|
148
|
+
|
|
149
|
+
Each built-in middleware has its own subpath:
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { Acryl } from 'acrylblends'
|
|
153
|
+
import { cors } from 'acrylblends/cors'
|
|
154
|
+
import { logger } from 'acrylblends/logger'
|
|
155
|
+
import { secureHeaders } from 'acrylblends/secure-headers'
|
|
156
|
+
import { bearerAuth } from 'acrylblends/bearer-auth'
|
|
157
|
+
|
|
158
|
+
const app = new Acryl()
|
|
159
|
+
|
|
160
|
+
app.use(logger())
|
|
161
|
+
app.use(secureHeaders())
|
|
162
|
+
app.use('/api/*', cors())
|
|
163
|
+
app.use('/admin/*', bearerAuth({ token: process.env.ADMIN_TOKEN ?? '' }))
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Built in: `basic-auth`, `bearer-auth`, `body-limit`, `combine`, `compress`, `context-storage`, `cors`, `csrf`, `etag`, `ip-restriction`,
|
|
167
|
+
`jwk`, `jwt`, `language`, `logger`, `method-not-allowed`, `method-override`, `powered-by`, `pretty-json`, `request-id`, `secure-headers`,
|
|
168
|
+
`serve-static`, `timeout`, `timing`, `trailing-slash`, plus ACRYL's `loopback-only`. Each one is documented under
|
|
169
|
+
[Middleware](https://github.com/acryldev/acryl/tree/main/docs/framework/middleware/builtin). To write your own, see the
|
|
170
|
+
[middleware guide](https://github.com/acryldev/acryl/blob/main/docs/framework/guides/middleware.md).
|
|
171
|
+
|
|
172
|
+
## Validation
|
|
173
|
+
|
|
174
|
+
`acrylblends/validator` validates any part of a request: `json`, `form`, `query`, `param`, `header`, `cookie`. The validated value is typed
|
|
175
|
+
in the handler:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
import { Acryl } from 'acrylblends'
|
|
179
|
+
import { validator } from 'acrylblends/validator'
|
|
180
|
+
|
|
181
|
+
const app = new Acryl()
|
|
182
|
+
|
|
183
|
+
app.post(
|
|
184
|
+
'/api/books',
|
|
185
|
+
validator('json', (value, c) => {
|
|
186
|
+
const title = (value as { title?: unknown }).title
|
|
187
|
+
if (typeof title !== 'string' || title === '') return c.json({ error: 'title is required' }, 400)
|
|
188
|
+
return { title }
|
|
189
|
+
}),
|
|
190
|
+
(c) => c.json({ title: c.req.valid('json').title }, 201),
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`acrylblends/schema-validator` drives the same validator with any [Standard Schema](https://standardschema.dev) library (Zod, Valibot,
|
|
195
|
+
ArkType and others). See the [validation guide](https://github.com/acryldev/acryl/blob/main/docs/framework/guides/validation.md).
|
|
196
|
+
|
|
197
|
+
## Typed client
|
|
198
|
+
|
|
199
|
+
Export the app's type, and `acrylblends/client` calls its routes with typed paths, inputs and answers:
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
// api.ts
|
|
203
|
+
import { Acryl } from 'acrylblends'
|
|
204
|
+
|
|
205
|
+
const app = new Acryl().get('/api/hello', (c) => c.json({ message: 'Hello Acryl!' }))
|
|
206
|
+
export type AppType = typeof app
|
|
207
|
+
export default app
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
// client.ts
|
|
212
|
+
import { hc } from 'acrylblends/client'
|
|
213
|
+
import type { AppType } from './api.ts'
|
|
214
|
+
|
|
215
|
+
const client = hc<AppType>('http://localhost:3000')
|
|
216
|
+
const answer = await client.api.hello.$get()
|
|
217
|
+
console.log((await answer.json()).message)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
See [RPC](https://github.com/acryldev/acryl/blob/main/docs/framework/guides/rpc.md).
|
|
221
|
+
|
|
222
|
+
## Testing
|
|
223
|
+
|
|
224
|
+
`app.request()` answers a request in process, with no server and no port, so tests need nothing else running:
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import assert from 'node:assert/strict'
|
|
228
|
+
import { test } from 'node:test'
|
|
229
|
+
import app from './index.ts'
|
|
230
|
+
|
|
231
|
+
test('GET / says hello', async () => {
|
|
232
|
+
const response = await app.request('/')
|
|
233
|
+
assert.equal(response.status, 200)
|
|
234
|
+
assert.equal(await response.text(), 'Hello Acryl!')
|
|
235
|
+
})
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Run it with `node --test`. `acrylblends/testing` adds `testClient`, the typed client over `app.request()`. See the
|
|
239
|
+
[testing guide](https://github.com/acryldev/acryl/blob/main/docs/framework/guides/testing.md).
|
|
240
|
+
|
|
241
|
+
## Serving on Node.js
|
|
242
|
+
|
|
243
|
+
`acrylblends/node-server` serves any Acryl app on Node's `http` module (or `http2` and `https` with `createServer`), streams bodies, aborts
|
|
244
|
+
`c.req.raw.signal` when the client goes away, and serves files:
|
|
245
|
+
|
|
246
|
+
```ts
|
|
247
|
+
import { Acryl } from 'acrylblends'
|
|
248
|
+
import { serve } from 'acrylblends/node-server'
|
|
249
|
+
import { serveStatic } from 'acrylblends/node-server/serve-static'
|
|
250
|
+
import { getConnInfo } from 'acrylblends/node-server/conninfo'
|
|
251
|
+
|
|
252
|
+
const app = new Acryl()
|
|
253
|
+
app.use('/static/*', serveStatic({ root: './' }))
|
|
254
|
+
app.get('/ip', (c) => c.text(getConnInfo(c).remote.address ?? 'unknown'))
|
|
255
|
+
|
|
256
|
+
const server = serve({ fetch: app.fetch, port: 3000, hostname: '127.0.0.1' })
|
|
257
|
+
process.on('SIGTERM', () => { server.close() })
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
See [Node.js](https://github.com/acryldev/acryl/blob/main/docs/framework/getting-started/nodejs.md).
|
|
261
|
+
|
|
262
|
+
## What is in the package
|
|
263
|
+
|
|
264
|
+
| Import | What |
|
|
265
|
+
| --- | --- |
|
|
266
|
+
| `acrylblends` | `Acryl`, `Context`, `AcrylRequest`, and the types |
|
|
267
|
+
| `acrylblends/<middleware>` | each built-in middleware, for example `acrylblends/cors` |
|
|
268
|
+
| `acrylblends/validator`, `acrylblends/schema-validator` | request validation |
|
|
269
|
+
| `acrylblends/client`, `acrylblends/testing` | the typed client and its in-process test version |
|
|
270
|
+
| `acrylblends/accepts`, `adapter`, `cookie`, `factory`, `html`, `route`, `streaming`, `ws`, `conninfo` | helpers ([helpers docs](https://github.com/acryldev/acryl/tree/main/docs/framework/helpers)) |
|
|
271
|
+
| `acrylblends/http-exception` | `HTTPException` |
|
|
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
|
+
| `acrylblends/utils/*` | the utilities the framework is built from |
|
|
274
|
+
| `acrylblends/node-server` | `serve`, `createAdaptorServer`, `getRequestListener`; with `node-server/serve-static` and `node-server/conninfo` |
|
|
275
|
+
|
|
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
|
|
278
|
+
([FAQ](https://github.com/acryldev/acryl/blob/main/docs/framework/guides/faq.md)).
|
|
279
|
+
|
|
280
|
+
To extend the context's typed variables, augment the root module:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
declare module 'acrylblends' {
|
|
284
|
+
interface ContextVariableMap {
|
|
285
|
+
user: string
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Upgrading from 0.4
|
|
291
|
+
|
|
292
|
+
From 0.5 the package's root is the framework. `App` and `AppRequest`, the 0.4 names, still work as deprecated aliases of `Acryl` and
|
|
293
|
+
`AcrylRequest` for one release. The scaffolding API that was the root in 0.4 is now `acrylblends/cli`. See
|
|
294
|
+
[Migration from 0.4](https://github.com/acryldev/acryl/blob/main/docs/framework/cordis/migration-from-0-4.md).
|
|
295
|
+
|
|
296
|
+
## The acrylblends command
|
|
297
|
+
|
|
298
|
+
The package also carries the `acrylblends` command. It scaffolds Cordis apps with ACRYL's plugins as code you own (instance, settings,
|
|
299
|
+
plugins installed while the app runs, an agent that builds plugins, durable tasks, the app as data in `blend.yaml`, a save that refuses
|
|
300
|
+
secrets):
|
|
301
|
+
|
|
302
|
+
```sh
|
|
303
|
+
npx acrylblends init my-app --agent -y
|
|
304
|
+
cd my-app && npm install && npm run dev
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
See the [ACRYLBLENDS documentation](https://github.com/acrylblends/acrylblends/blob/main/docs/README.md) and
|
|
308
|
+
[Acryl in a Cordis app](https://github.com/acryldev/acryl/blob/main/docs/framework/cordis/acryl-in-a-cordis-app.md).
|
|
309
|
+
|
|
310
|
+
## Links
|
|
311
|
+
|
|
312
|
+
| | |
|
|
313
|
+
| --- | --- |
|
|
314
|
+
| Framework documentation | https://github.com/acryldev/acryl/blob/main/docs/framework/README.md |
|
|
315
|
+
| ACRYLBLENDS website | https://acrylblends.github.io |
|
|
316
|
+
| ACRYL website | https://acryl.dev |
|
|
317
|
+
| This package's source and issues | https://github.com/acrylblends/acrylblends ([issues](https://github.com/acrylblends/acrylblends/issues)) |
|
|
318
|
+
| The framework's source | https://github.com/acryldev/acryl (`plugins/acryl-router`, `plugins/acryl-node-server`) |
|
|
319
|
+
| For coding agents | https://github.com/acryldev/acryl/blob/main/docs/framework/agents/index.md |
|
|
320
|
+
| npm | https://www.npmjs.com/package/acrylblends |
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
MIT. Copyright (c) 2026 WebBoxes s.r.o. The framework is ported from MIT-licensed open-source projects. Their notices are kept in the
|
|
325
|
+
package's `LICENSE` file.
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
# Generated copy
|
|
2
2
|
|
|
3
|
-
This folder is a copy of `docs/framework` of acryldev/acryl at commit `
|
|
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.
|
|
@@ -91,6 +91,12 @@ an `Allow` header on every route; a missing or wrong agent-hook token is 401 wit
|
|
|
91
91
|
must be the app's own loopback address. Its routes refuse an in-process call on purpose (the guard needs a socket to check), so its tests
|
|
92
92
|
run over loopback through the same adapter (`tests/serve-api.ts`), which is the "test over the Host" below.
|
|
93
93
|
|
|
94
|
+
`acryl-agent-control` (the door `acryl control`, workers and the MCP config use) moved the same way and kept its trust model exactly:
|
|
95
|
+
operator routes still answer a non-loopback peer or a missing or wrong secret with 403 `{ "error": "forbidden" }`, which `acryl control`
|
|
96
|
+
reads as "refused", never the bearer middleware's 401. What changed there: an oversized body is 413 (was 400), a wrong method's `Allow`
|
|
97
|
+
lists what the router serves (`GET, HEAD` for the audit log), and a page route's refusal carries `loopbackOnly`'s message instead of
|
|
98
|
+
`forbidden`. Only the page channel's WebSocket stays a webServer upgrade.
|
|
99
|
+
|
|
94
100
|
## Completion check
|
|
95
101
|
|
|
96
102
|
A capability is migrated when:
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
"source": {
|
|
3
3
|
"repo": "acryldev/acryl",
|
|
4
4
|
"path": "docs/framework",
|
|
5
|
-
"commit": "
|
|
5
|
+
"commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
|
|
6
6
|
},
|
|
7
7
|
"files": 87,
|
|
8
|
-
"digest": "sha256:
|
|
8
|
+
"digest": "sha256:31bf1c46fbe74d7d2664b3b935a18bd916b8cab1b9ee9c2b006b8a75617a04f6"
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -186,6 +186,7 @@ describe('various response body types', () => {
|
|
|
186
186
|
const largeText = 'a'.repeat(1024 * 1024 * 10)
|
|
187
187
|
let server: ServerType
|
|
188
188
|
let resolveReadableStreamPromise: () => void
|
|
189
|
+
let resolveReadableStreamFirstChunkPromise: () => void
|
|
189
190
|
let resolveEventStreamPromise: () => void
|
|
190
191
|
let resolveEventStreamWithoutTransferEncodingPromise: () => void
|
|
191
192
|
beforeAll(() => {
|
|
@@ -223,11 +224,17 @@ describe('various response body types', () => {
|
|
|
223
224
|
const readableStreamPromise = new Promise<void>((resolve) => {
|
|
224
225
|
resolveReadableStreamPromise = resolve
|
|
225
226
|
})
|
|
227
|
+
const readableStreamFirstChunkPromise = new Promise<void>((resolve) => {
|
|
228
|
+
resolveReadableStreamFirstChunkPromise = resolve
|
|
229
|
+
})
|
|
226
230
|
app.get('/readable-stream', () => {
|
|
227
231
|
const stream = new ReadableStream({
|
|
228
232
|
async start(controller) {
|
|
229
233
|
await readableStreamPromise
|
|
230
234
|
controller.enqueue('Hello!')
|
|
235
|
+
// The second chunk waits until the client has the first, so the two arrive as two reads on every platform (TCP may join
|
|
236
|
+
// two back-to-back writes into one read, as it does on Windows).
|
|
237
|
+
await readableStreamFirstChunkPromise
|
|
231
238
|
controller.enqueue(' Node!')
|
|
232
239
|
controller.close()
|
|
233
240
|
},
|
|
@@ -376,6 +383,9 @@ describe('various response body types', () => {
|
|
|
376
383
|
expect(headers.get('transfer-encoding')).toBe('chunked')
|
|
377
384
|
resolveReadableStreamPromise()
|
|
378
385
|
},
|
|
386
|
+
onChunk: (_chunk, index) => {
|
|
387
|
+
if (index === 0) resolveReadableStreamFirstChunkPromise()
|
|
388
|
+
},
|
|
379
389
|
}
|
|
380
390
|
)
|
|
381
391
|
expect(res.status).toBe(200)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"source": {
|
|
3
3
|
"repo": "acryldev/acryl",
|
|
4
4
|
"path": "plugins/acryl-node-server",
|
|
5
|
-
"commit": "
|
|
5
|
+
"commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
|
|
6
6
|
},
|
|
7
7
|
"vendored": [
|
|
8
8
|
"src",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"LICENSE"
|
|
11
11
|
],
|
|
12
12
|
"rewrittenSpecifiers": 28,
|
|
13
|
-
"digest": "sha256:
|
|
13
|
+
"digest": "sha256:2adaa64028c1f2a40ed94c0eacf64d32c8c3b8171b52338cb02bfae2fd56ab7c",
|
|
14
14
|
"testsNotRun": {},
|
|
15
15
|
"notice": [
|
|
16
16
|
"LICENSE"
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"examples/acryl-todo/src/index.ts": "src/todo.ts",
|
|
6
6
|
"examples/acryl-todo/src/page.ts": "src/page.ts"
|
|
7
7
|
},
|
|
8
|
-
"commit": "
|
|
8
|
+
"commit": "5743482e4199ded676a77f594bce15fd4aa0ca2f"
|
|
9
9
|
},
|
|
10
10
|
"rewrittenSpecifiers": 4,
|
|
11
11
|
"digest": "sha256:9093704776563001f7f472f94cc5c2fdd79206342c1cb59c11fce62aa74df3ed"
|