create-acrylblends 0.0.0-stage → 0.1.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.
Files changed (106) hide show
  1. package/README.md +61 -2
  2. package/bin/create-acrylblends.js +4 -0
  3. package/dist/index.d.ts +56 -0
  4. package/dist/index.js +274 -0
  5. package/dist/index.js.map +1 -0
  6. package/docs/framework/LICENSE +23 -0
  7. package/docs/framework/README.md +63 -0
  8. package/docs/framework/UPSTREAM.md +3 -0
  9. package/docs/framework/agents/index.md +24 -0
  10. package/docs/framework/api/acryl.md +259 -0
  11. package/docs/framework/api/context.md +527 -0
  12. package/docs/framework/api/exception.md +80 -0
  13. package/docs/framework/api/index.md +12 -0
  14. package/docs/framework/api/presets.md +65 -0
  15. package/docs/framework/api/request.md +396 -0
  16. package/docs/framework/api/routing.md +303 -0
  17. package/docs/framework/api/summary.md +140 -0
  18. package/docs/framework/concepts/benchmarks.md +26 -0
  19. package/docs/framework/concepts/developer-experience.md +5 -0
  20. package/docs/framework/concepts/middleware.md +21 -0
  21. package/docs/framework/concepts/motivation.md +14 -0
  22. package/docs/framework/concepts/routers.md +63 -0
  23. package/docs/framework/concepts/stacks.md +235 -0
  24. package/docs/framework/concepts/web-standard.md +37 -0
  25. package/docs/framework/cordis/acryl-in-a-cordis-app.md +146 -0
  26. package/docs/framework/cordis/concepts.md +105 -0
  27. package/docs/framework/cordis/middleware.md +8 -0
  28. package/docs/framework/cordis/migration-from-0-3.md +111 -0
  29. package/docs/framework/cordis/migration-from-0-4.md +14 -0
  30. package/docs/framework/cordis/migration-from-dsh-webserver.md +109 -0
  31. package/docs/framework/cordis/mounting.md +85 -0
  32. package/docs/framework/cordis/node-server.md +75 -0
  33. package/docs/framework/cordis/plugin-lifecycle.md +111 -0
  34. package/docs/framework/cordis/surfaces.md +71 -0
  35. package/docs/framework/cordis/transport-and-cancellation.md +57 -0
  36. package/docs/framework/cordis/validation.md +135 -0
  37. package/docs/framework/getting-started/basic.md +196 -0
  38. package/docs/framework/getting-started/bun.md +221 -0
  39. package/docs/framework/getting-started/nodejs.md +344 -0
  40. package/docs/framework/getting-started/other-runtimes.md +23 -0
  41. package/docs/framework/guides/best-practices.md +231 -0
  42. package/docs/framework/guides/create-acrylblends.md +79 -0
  43. package/docs/framework/guides/examples.md +3 -0
  44. package/docs/framework/guides/faq.md +19 -0
  45. package/docs/framework/guides/helpers.md +33 -0
  46. package/docs/framework/guides/jsx-dom.md +299 -0
  47. package/docs/framework/guides/jsx.md +440 -0
  48. package/docs/framework/guides/middleware.md +253 -0
  49. package/docs/framework/guides/rpc.md +886 -0
  50. package/docs/framework/guides/testing.md +133 -0
  51. package/docs/framework/guides/validation.md +383 -0
  52. package/docs/framework/helpers/accepts.md +60 -0
  53. package/docs/framework/helpers/adapter.md +87 -0
  54. package/docs/framework/helpers/conninfo.md +112 -0
  55. package/docs/framework/helpers/cookie.md +232 -0
  56. package/docs/framework/helpers/css.md +285 -0
  57. package/docs/framework/helpers/dev.md +67 -0
  58. package/docs/framework/helpers/factory.md +180 -0
  59. package/docs/framework/helpers/html.md +123 -0
  60. package/docs/framework/helpers/jwt.md +184 -0
  61. package/docs/framework/helpers/proxy.md +118 -0
  62. package/docs/framework/helpers/route.md +143 -0
  63. package/docs/framework/helpers/ssg.md +393 -0
  64. package/docs/framework/helpers/streaming.md +119 -0
  65. package/docs/framework/helpers/testing.md +101 -0
  66. package/docs/framework/helpers/websocket.md +215 -0
  67. package/docs/framework/middleware/builtin/basic-auth.md +165 -0
  68. package/docs/framework/middleware/builtin/bearer-auth.md +138 -0
  69. package/docs/framework/middleware/builtin/body-limit.md +71 -0
  70. package/docs/framework/middleware/builtin/cache.md +122 -0
  71. package/docs/framework/middleware/builtin/combine.md +94 -0
  72. package/docs/framework/middleware/builtin/compress.md +59 -0
  73. package/docs/framework/middleware/builtin/context-storage.md +78 -0
  74. package/docs/framework/middleware/builtin/cors.md +135 -0
  75. package/docs/framework/middleware/builtin/csrf.md +105 -0
  76. package/docs/framework/middleware/builtin/etag.md +54 -0
  77. package/docs/framework/middleware/builtin/ip-restriction.md +69 -0
  78. package/docs/framework/middleware/builtin/jsx-renderer.md +286 -0
  79. package/docs/framework/middleware/builtin/jwk.md +192 -0
  80. package/docs/framework/middleware/builtin/jwt.md +145 -0
  81. package/docs/framework/middleware/builtin/language.md +232 -0
  82. package/docs/framework/middleware/builtin/logger.md +74 -0
  83. package/docs/framework/middleware/builtin/loopback-only.md +31 -0
  84. package/docs/framework/middleware/builtin/method-not-allowed.md +48 -0
  85. package/docs/framework/middleware/builtin/method-override.md +80 -0
  86. package/docs/framework/middleware/builtin/mount.md +106 -0
  87. package/docs/framework/middleware/builtin/pretty-json.md +53 -0
  88. package/docs/framework/middleware/builtin/request-id.md +94 -0
  89. package/docs/framework/middleware/builtin/secure-headers.md +247 -0
  90. package/docs/framework/middleware/builtin/timeout.md +98 -0
  91. package/docs/framework/middleware/builtin/timing.md +101 -0
  92. package/docs/framework/middleware/builtin/trailing-slash.md +74 -0
  93. package/docs/framework/middleware/third-party.md +4 -0
  94. package/docs/framework/upstream.json +9 -0
  95. package/package.json +47 -3
  96. package/templates/bun/gitignore +1 -0
  97. package/templates/bun/package.json +19 -0
  98. package/templates/bun/src/index.ts +7 -0
  99. package/templates/bun/test/app.test.ts +8 -0
  100. package/templates/bun/tsconfig.json +15 -0
  101. package/templates/nodejs/gitignore +1 -0
  102. package/templates/nodejs/package.json +22 -0
  103. package/templates/nodejs/src/app.ts +7 -0
  104. package/templates/nodejs/src/index.ts +9 -0
  105. package/templates/nodejs/test/app.test.ts +9 -0
  106. package/templates/nodejs/tsconfig.json +16 -0
@@ -0,0 +1,221 @@
1
+ # Bun
2
+
3
+ > **Experimental.** Bun is not a verified runtime yet: the Acryl application code is the same, but the `bun` template and this guide are not covered by the release checks. Node.js is the verified runtime.
4
+
5
+
6
+ [Bun](https://bun.com) is another JavaScript runtime. It's not Node.js. Bun includes a transcompiler, so we can write the code in TypeScript or plain JavaScript.
7
+ Acryl also works on Bun.
8
+
9
+ ## 1. Install Bun
10
+
11
+ To install `bun` command, follow the instruction in [the official web site](https://bun.com).
12
+
13
+ ## 2. Setup
14
+
15
+ ### 2.1. Setup a new project
16
+
17
+ A starter for Bun is available. Start your project with "bun create" command.
18
+ Select `bun` template for this example.
19
+
20
+ ```sh
21
+ bun create acrylblends@latest my-app
22
+ ```
23
+
24
+ Move into my-app and install the dependencies.
25
+
26
+ ```sh
27
+ cd my-app
28
+ bun install
29
+ ```
30
+
31
+ ### 2.2. Setup an existing project
32
+
33
+ On an existing Bun project, we only need to install `acrylblends` dependencies on the project root directory via
34
+
35
+ ```sh
36
+ bun add acrylblends
37
+ ```
38
+
39
+ Then add the `dev` command to your existing `package.json`.
40
+
41
+ ```json
42
+ {
43
+ "scripts": {
44
+ "dev": "bun run --hot src/index.ts"
45
+ }
46
+ }
47
+ ```
48
+
49
+ See the Bun starter template for a minimal example setup. This is the output of running `bun create acrylblends@latest`.
50
+
51
+ ## 3. Hello World
52
+
53
+ "Hello World" script is below. Almost the same as writing on other platforms.
54
+
55
+ ```ts
56
+ import { Acryl } from 'acrylblends'
57
+
58
+ const app = new Acryl()
59
+ app.get('/', (c) => c.text('Hello Bun!'))
60
+
61
+ export default app
62
+ ```
63
+
64
+ If you are setting up Acryl on an existing project, the `bun run dev` command expects the "Hello World" script to be placed in `src/index.ts`
65
+
66
+ ## 4. Run
67
+
68
+ Run the command.
69
+
70
+ ```sh
71
+ bun run dev
72
+ ```
73
+
74
+ Then, access `http://localhost:3000` in your browser.
75
+
76
+ ## Change port number
77
+
78
+ You can specify the port number with exporting the `port`.
79
+
80
+ <!-- prettier-ignore -->
81
+ ```ts
82
+ import { Acryl } from 'acrylblends'
83
+
84
+ const app = new Acryl()
85
+ app.get('/', (c) => c.text('Hello Bun!'))
86
+
87
+ export default {
88
+ port: 3000,
89
+ fetch: app.fetch,
90
+ }
91
+ ```
92
+
93
+ ## Serve static files
94
+
95
+ To serve static files, use `serveStatic` from `acrylblends/bun`.
96
+
97
+ > **Not yet available.** The Bun adapter, `acrylblends/bun`, is not part of acrylblends yet. The code below shows the planned usage.
98
+
99
+ ```ts
100
+ import { serveStatic } from 'acrylblends/bun'
101
+
102
+ const app = new Acryl()
103
+
104
+ app.use('/static/*', serveStatic({ root: './' }))
105
+ app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))
106
+ app.get('/', (c) => c.text('You can access: /static/hello.txt'))
107
+ app.get('*', serveStatic({ path: './static/fallback.txt' }))
108
+ ```
109
+
110
+ For the above code, it will work well with the following directory structure.
111
+
112
+ ```
113
+ ./
114
+ ├── favicon.ico
115
+ ├── src
116
+ └── static
117
+ ├── demo
118
+ │ └── index.html
119
+ ├── fallback.txt
120
+ ├── hello.txt
121
+ └── images
122
+ └── dinotocat.png
123
+ ```
124
+
125
+ ### `rewriteRequestPath`
126
+
127
+ If you want to map `http://localhost:3000/static/*` to `./statics`, you can use the `rewriteRequestPath` option:
128
+
129
+ ```ts
130
+ app.get(
131
+ '/static/*',
132
+ serveStatic({
133
+ root: './',
134
+ rewriteRequestPath: (path) =>
135
+ path.replace(/^\/static/, '/statics'),
136
+ })
137
+ )
138
+ ```
139
+
140
+ ### `mimes`
141
+
142
+ You can add MIME types with `mimes`:
143
+
144
+ ```ts
145
+ app.get(
146
+ '/static/*',
147
+ serveStatic({
148
+ mimes: {
149
+ m3u8: 'application/vnd.apple.mpegurl',
150
+ ts: 'video/mp2t',
151
+ },
152
+ })
153
+ )
154
+ ```
155
+
156
+ ### `onFound`
157
+
158
+ You can specify handling when the requested file is found with `onFound`:
159
+
160
+ ```ts
161
+ app.get(
162
+ '/static/*',
163
+ serveStatic({
164
+ // ...
165
+ onFound: (_path, c) => {
166
+ c.header('Cache-Control', `public, immutable, max-age=31536000`)
167
+ },
168
+ })
169
+ )
170
+ ```
171
+
172
+ ### `onNotFound`
173
+
174
+ You can specify handling when the requested file is not found with `onNotFound`:
175
+
176
+ ```ts
177
+ app.get(
178
+ '/static/*',
179
+ serveStatic({
180
+ onNotFound: (path, c) => {
181
+ console.log(`${path} is not found, you access ${c.req.path}`)
182
+ },
183
+ })
184
+ )
185
+ ```
186
+
187
+ ### `precompressed`
188
+
189
+ The `precompressed` option checks if files with extensions like `.br` or `.gz` are available and serves them based on the `Accept-Encoding` header. It prioritizes Brotli, then Zstd, and Gzip. If none are available, it serves the original file.
190
+
191
+ ```ts
192
+ app.get(
193
+ '/static/*',
194
+ serveStatic({
195
+ precompressed: true,
196
+ })
197
+ )
198
+ ```
199
+
200
+ ## Testing
201
+
202
+ You can use `bun:test` for testing on Bun.
203
+
204
+ ```ts
205
+ import { describe, expect, it } from 'bun:test'
206
+ import app from '.'
207
+
208
+ describe('My first test', () => {
209
+ it('Should return 200 Response', async () => {
210
+ const req = new Request('http://localhost/')
211
+ const res = await app.fetch(req)
212
+ expect(res.status).toBe(200)
213
+ })
214
+ })
215
+ ```
216
+
217
+ Then, run the command.
218
+
219
+ ```sh
220
+ bun test index.test.ts
221
+ ```
@@ -0,0 +1,344 @@
1
+ # Node.js
2
+
3
+ [Node.js](https://nodejs.org/) is an open-source, cross-platform JavaScript runtime environment.
4
+
5
+ On Node.js, Acryl runs through the Node.js adapter, `acrylblends/node-server`.
6
+
7
+ > **Note.** Verified on Node.js 22.19 and newer, which runs TypeScript files directly.
8
+
9
+ ## 1. Setup
10
+
11
+ A starter for Node.js is available.
12
+ Start your project with "create-acrylblends" command.
13
+ Select `nodejs` template for this example.
14
+
15
+ **npm**
16
+
17
+ ```sh
18
+ npm create acrylblends@latest my-app
19
+ ```
20
+
21
+ **yarn**
22
+
23
+ ```sh
24
+ yarn create acrylblends my-app
25
+ ```
26
+
27
+ **pnpm**
28
+
29
+ ```sh
30
+ pnpm create acrylblends my-app
31
+ ```
32
+
33
+ **bun**
34
+
35
+ ```sh
36
+ bun create acrylblends@latest my-app
37
+ ```
38
+
39
+ Move to `my-app` and install the dependencies.
40
+
41
+ **npm**
42
+
43
+ ```sh
44
+ cd my-app
45
+ npm i
46
+ ```
47
+
48
+ **yarn**
49
+
50
+ ```sh
51
+ cd my-app
52
+ yarn
53
+ ```
54
+
55
+ **pnpm**
56
+
57
+ ```sh
58
+ cd my-app
59
+ pnpm i
60
+ ```
61
+
62
+ **bun**
63
+
64
+ ```sh
65
+ cd my-app
66
+ bun i
67
+ ```
68
+
69
+ ## 2. Hello World
70
+
71
+ Edit `src/index.ts`:
72
+
73
+ ```ts
74
+ import { serve } from 'acrylblends/node-server'
75
+ import { Acryl } from 'acrylblends'
76
+
77
+ const app = new Acryl()
78
+ app.get('/', (c) => c.text('Hello Node.js!'))
79
+
80
+ serve(app)
81
+ ```
82
+
83
+ If you want to gracefully shut down the server, write it like this:
84
+
85
+ ```ts
86
+ const server = serve(app)
87
+
88
+ // graceful shutdown
89
+ process.on('SIGINT', () => {
90
+ server.close()
91
+ process.exit(0)
92
+ })
93
+ process.on('SIGTERM', () => {
94
+ server.close((err) => {
95
+ if (err) {
96
+ console.error(err)
97
+ process.exit(1)
98
+ }
99
+ process.exit(0)
100
+ })
101
+ })
102
+ ```
103
+
104
+ > **Note.** On Node.js, `serve()` wraps the `node:http` module and returns the underlying server instance, so closing it is up to you. Bun serves Fetch handlers natively and manages the server itself, which is why its guide doesn't include this step.
105
+
106
+ ## 3. Run
107
+
108
+ Run the development server locally. Then, access `http://localhost:3000` in your Web browser.
109
+
110
+ **npm**
111
+
112
+ ```sh
113
+ npm run dev
114
+ ```
115
+
116
+ **yarn**
117
+
118
+ ```sh
119
+ yarn dev
120
+ ```
121
+
122
+ **pnpm**
123
+
124
+ ```sh
125
+ pnpm dev
126
+ ```
127
+
128
+ ## Change port number
129
+
130
+ You can specify the port number with the `port` option.
131
+
132
+ ```ts
133
+ serve({
134
+ fetch: app.fetch,
135
+ port: 8787,
136
+ })
137
+ ```
138
+
139
+ ## WebSocket
140
+
141
+ WebSocket support is built into `acrylblends/node-server`. Install `ws` and, if you use TypeScript, `@types/ws`. Then create a `WebSocketServer` with `{ noServer: true }` and pass it to `serve()` with the `websocket` option.
142
+
143
+ ```ts
144
+ import { serve, upgradeWebSocket } from 'acrylblends/node-server'
145
+ import { Acryl } from 'acrylblends'
146
+ import { WebSocketServer } from 'ws'
147
+
148
+ const app = new Acryl()
149
+
150
+ app.get(
151
+ '/ws',
152
+ upgradeWebSocket(() => ({
153
+ onMessage(event, ws) {
154
+ ws.send(String(event.data))
155
+ },
156
+ }))
157
+ )
158
+
159
+ const wss = new WebSocketServer({ noServer: true })
160
+
161
+ serve({
162
+ fetch: app.fetch,
163
+ websocket: { server: wss },
164
+ })
165
+ ```
166
+
167
+ ## Access the raw Node.js APIs
168
+
169
+ You can access the Node.js APIs from `c.env.incoming` and `c.env.outgoing`.
170
+
171
+ ```ts
172
+ import { Acryl } from 'acrylblends'
173
+ import { serve, type HttpBindings } from 'acrylblends/node-server'
174
+ // or `Http2Bindings` if you use HTTP2
175
+
176
+ type Bindings = HttpBindings & {
177
+ /* ... */
178
+ }
179
+
180
+ const app = new Acryl<{ Bindings: Bindings }>()
181
+
182
+ app.get('/', (c) => {
183
+ return c.json({
184
+ remoteAddress: c.env.incoming.socket.remoteAddress,
185
+ })
186
+ })
187
+
188
+ serve(app)
189
+ ```
190
+
191
+ ## Serve static files
192
+
193
+ You can use `serveStatic` to serve static files from the local file system. For example, suppose the directory structure is as follows:
194
+
195
+ ```sh
196
+ ./
197
+ ├── favicon.ico
198
+ ├── index.ts
199
+ └── static
200
+ ├── hello.txt
201
+ └── image.png
202
+ ```
203
+
204
+ If a request to the path `/static/*` comes in and you want to return a file under `./static`, you can write the following:
205
+
206
+ ```ts
207
+ import { serveStatic } from 'acrylblends/node-server'
208
+
209
+ app.use('/static/*', serveStatic({ root: './' }))
210
+ ```
211
+
212
+ **Warning.**
213
+
214
+ The `root` option resolves paths relative to the current working directory (`process.cwd()`). This means the behavior depends on **where you run your Node.js process from**, not where your source file is located. If you start your server from a different directory, file resolution may fail.
215
+
216
+ For reliable path resolution that always points to the same directory as your source file, use `import.meta.url`:
217
+
218
+ ```ts
219
+ import { fileURLToPath } from 'node:url'
220
+ import { serveStatic } from 'acrylblends/node-server'
221
+
222
+ app.use(
223
+ '/static/*',
224
+ serveStatic({ root: fileURLToPath(new URL('./', import.meta.url)) })
225
+ )
226
+ ```
227
+
228
+ Use the `path` option to serve `favicon.ico` in the directory root:
229
+
230
+ ```ts
231
+ app.use('/favicon.ico', serveStatic({ path: './favicon.ico' }))
232
+ ```
233
+
234
+ If a request to the path `/hello.txt` or `/image.png` comes in and you want to return a file named `./static/hello.txt` or `./static/image.png`, you can use the following:
235
+
236
+ ```ts
237
+ app.use('*', serveStatic({ root: './static' }))
238
+ ```
239
+
240
+ ### `rewriteRequestPath`
241
+
242
+ If you want to map `http://localhost:3000/static/*` to `./statics`, you can use the `rewriteRequestPath` option:
243
+
244
+ ```ts
245
+ app.get(
246
+ '/static/*',
247
+ serveStatic({
248
+ root: './',
249
+ rewriteRequestPath: (path) =>
250
+ path.replace(/^\/static/, '/statics'),
251
+ })
252
+ )
253
+ ```
254
+
255
+ ## http2
256
+
257
+ You can run acrylblends on a [Node.js http2 Server](https://nodejs.org/api/http2.html).
258
+
259
+ ### unencrypted http2
260
+
261
+ ```ts
262
+ import { createServer } from 'node:http2'
263
+
264
+ const server = serve({
265
+ fetch: app.fetch,
266
+ createServer,
267
+ })
268
+ ```
269
+
270
+ ### encrypted http2
271
+
272
+ ```ts
273
+ import { createSecureServer } from 'node:http2'
274
+ import { readFileSync } from 'node:fs'
275
+
276
+ const server = serve({
277
+ fetch: app.fetch,
278
+ createServer: createSecureServer,
279
+ serverOptions: {
280
+ key: readFileSync('localhost-privkey.pem'),
281
+ cert: readFileSync('localhost-cert.pem'),
282
+ },
283
+ })
284
+ ```
285
+
286
+ ## Building & Deployment
287
+
288
+ **npm**
289
+
290
+ ```sh
291
+ npm run build
292
+ ```
293
+
294
+ **yarn**
295
+
296
+ ```sh
297
+ yarn run build
298
+ ```
299
+
300
+ **pnpm**
301
+
302
+ ```sh
303
+ pnpm run build
304
+ ```
305
+
306
+ **bun**
307
+
308
+ ```sh
309
+ bun run build
310
+ ```
311
+
312
+ ### Dockerfile
313
+
314
+ Here is an example of a Node.js Dockerfile.
315
+
316
+ ```Dockerfile
317
+ FROM node:22-alpine AS base
318
+
319
+ FROM base AS builder
320
+
321
+ RUN apk add --no-cache gcompat
322
+ WORKDIR /app
323
+
324
+ COPY package*json tsconfig.json src ./
325
+
326
+ RUN npm ci && \
327
+ npm run build && \
328
+ npm prune --production
329
+
330
+ FROM base AS runner
331
+ WORKDIR /app
332
+
333
+ RUN addgroup --system --gid 1001 nodejs
334
+ RUN adduser --system --uid 1001 acrylblends
335
+
336
+ COPY --from=builder --chown=acrylblends:nodejs /app/node_modules /app/node_modules
337
+ COPY --from=builder --chown=acrylblends:nodejs /app/dist /app/dist
338
+ COPY --from=builder --chown=acrylblends:nodejs /app/package.json /app/package.json
339
+
340
+ USER acrylblends
341
+ EXPOSE 3000
342
+
343
+ CMD ["node", "/app/dist/index.js"]
344
+ ```
@@ -0,0 +1,23 @@
1
+ # Other runtimes
2
+
3
+ Acryl is built on Web Standards, so the same application code is expected to run wherever a `fetch`-style handler can run. Only Node.js ([guide](nodejs.md)) is verified so far. Bun is experimental ([guide](bun.md)).
4
+
5
+ The following runtimes and platforms are **not yet verified**. There are no getting-started pages for them yet, and their adapters (for example `acrylblends/cloudflare-workers`
6
+ or `acrylblends/aws-lambda`) are not part of acrylblends yet:
7
+
8
+ - Deno, and Deno Deploy
9
+ - Cloudflare Workers, and Cloudflare Pages
10
+ - Fastly Compute
11
+ - AWS Lambda, and Lambda@Edge
12
+ - Vercel
13
+ - Netlify
14
+ - Next.js
15
+ - Supabase Functions
16
+ - Google Cloud Run
17
+ - Azure Functions
18
+ - Alibaba Cloud Function Compute
19
+ - CloudBase
20
+ - Service Worker
21
+ - WebAssembly (WASI)
22
+
23
+ A page is added here, with a getting-started guide, when a platform has been verified with a test that runs on it.