create-acrylblends 0.0.0-stage → 0.1.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 (106) hide show
  1. package/bin/create-acrylblends.js +4 -0
  2. package/dist/index.d.ts +56 -0
  3. package/dist/index.js +274 -0
  4. package/dist/index.js.map +1 -0
  5. package/docs/framework/LICENSE +23 -0
  6. package/docs/framework/README.md +63 -0
  7. package/docs/framework/UPSTREAM.md +3 -0
  8. package/docs/framework/agents/index.md +24 -0
  9. package/docs/framework/api/acryl.md +259 -0
  10. package/docs/framework/api/context.md +527 -0
  11. package/docs/framework/api/exception.md +80 -0
  12. package/docs/framework/api/index.md +12 -0
  13. package/docs/framework/api/presets.md +65 -0
  14. package/docs/framework/api/request.md +396 -0
  15. package/docs/framework/api/routing.md +303 -0
  16. package/docs/framework/api/summary.md +140 -0
  17. package/docs/framework/concepts/benchmarks.md +26 -0
  18. package/docs/framework/concepts/developer-experience.md +5 -0
  19. package/docs/framework/concepts/middleware.md +21 -0
  20. package/docs/framework/concepts/motivation.md +14 -0
  21. package/docs/framework/concepts/routers.md +63 -0
  22. package/docs/framework/concepts/stacks.md +235 -0
  23. package/docs/framework/concepts/web-standard.md +37 -0
  24. package/docs/framework/cordis/acryl-in-a-cordis-app.md +146 -0
  25. package/docs/framework/cordis/concepts.md +105 -0
  26. package/docs/framework/cordis/middleware.md +8 -0
  27. package/docs/framework/cordis/migration-from-0-3.md +111 -0
  28. package/docs/framework/cordis/migration-from-0-4.md +14 -0
  29. package/docs/framework/cordis/migration-from-dsh-webserver.md +103 -0
  30. package/docs/framework/cordis/mounting.md +85 -0
  31. package/docs/framework/cordis/node-server.md +75 -0
  32. package/docs/framework/cordis/plugin-lifecycle.md +111 -0
  33. package/docs/framework/cordis/surfaces.md +71 -0
  34. package/docs/framework/cordis/transport-and-cancellation.md +57 -0
  35. package/docs/framework/cordis/validation.md +135 -0
  36. package/docs/framework/getting-started/basic.md +196 -0
  37. package/docs/framework/getting-started/bun.md +221 -0
  38. package/docs/framework/getting-started/nodejs.md +344 -0
  39. package/docs/framework/getting-started/other-runtimes.md +23 -0
  40. package/docs/framework/guides/best-practices.md +231 -0
  41. package/docs/framework/guides/create-acrylblends.md +79 -0
  42. package/docs/framework/guides/examples.md +3 -0
  43. package/docs/framework/guides/faq.md +19 -0
  44. package/docs/framework/guides/helpers.md +33 -0
  45. package/docs/framework/guides/jsx-dom.md +299 -0
  46. package/docs/framework/guides/jsx.md +440 -0
  47. package/docs/framework/guides/middleware.md +253 -0
  48. package/docs/framework/guides/rpc.md +886 -0
  49. package/docs/framework/guides/testing.md +133 -0
  50. package/docs/framework/guides/validation.md +383 -0
  51. package/docs/framework/helpers/accepts.md +60 -0
  52. package/docs/framework/helpers/adapter.md +87 -0
  53. package/docs/framework/helpers/conninfo.md +112 -0
  54. package/docs/framework/helpers/cookie.md +232 -0
  55. package/docs/framework/helpers/css.md +285 -0
  56. package/docs/framework/helpers/dev.md +67 -0
  57. package/docs/framework/helpers/factory.md +180 -0
  58. package/docs/framework/helpers/html.md +123 -0
  59. package/docs/framework/helpers/jwt.md +184 -0
  60. package/docs/framework/helpers/proxy.md +118 -0
  61. package/docs/framework/helpers/route.md +143 -0
  62. package/docs/framework/helpers/ssg.md +393 -0
  63. package/docs/framework/helpers/streaming.md +119 -0
  64. package/docs/framework/helpers/testing.md +101 -0
  65. package/docs/framework/helpers/websocket.md +215 -0
  66. package/docs/framework/middleware/builtin/basic-auth.md +165 -0
  67. package/docs/framework/middleware/builtin/bearer-auth.md +138 -0
  68. package/docs/framework/middleware/builtin/body-limit.md +71 -0
  69. package/docs/framework/middleware/builtin/cache.md +122 -0
  70. package/docs/framework/middleware/builtin/combine.md +94 -0
  71. package/docs/framework/middleware/builtin/compress.md +59 -0
  72. package/docs/framework/middleware/builtin/context-storage.md +78 -0
  73. package/docs/framework/middleware/builtin/cors.md +135 -0
  74. package/docs/framework/middleware/builtin/csrf.md +105 -0
  75. package/docs/framework/middleware/builtin/etag.md +54 -0
  76. package/docs/framework/middleware/builtin/ip-restriction.md +69 -0
  77. package/docs/framework/middleware/builtin/jsx-renderer.md +286 -0
  78. package/docs/framework/middleware/builtin/jwk.md +192 -0
  79. package/docs/framework/middleware/builtin/jwt.md +145 -0
  80. package/docs/framework/middleware/builtin/language.md +232 -0
  81. package/docs/framework/middleware/builtin/logger.md +74 -0
  82. package/docs/framework/middleware/builtin/loopback-only.md +31 -0
  83. package/docs/framework/middleware/builtin/method-not-allowed.md +48 -0
  84. package/docs/framework/middleware/builtin/method-override.md +80 -0
  85. package/docs/framework/middleware/builtin/mount.md +106 -0
  86. package/docs/framework/middleware/builtin/pretty-json.md +53 -0
  87. package/docs/framework/middleware/builtin/request-id.md +94 -0
  88. package/docs/framework/middleware/builtin/secure-headers.md +247 -0
  89. package/docs/framework/middleware/builtin/timeout.md +98 -0
  90. package/docs/framework/middleware/builtin/timing.md +101 -0
  91. package/docs/framework/middleware/builtin/trailing-slash.md +74 -0
  92. package/docs/framework/middleware/third-party.md +4 -0
  93. package/docs/framework/upstream.json +9 -0
  94. package/package.json +47 -3
  95. package/templates/bun/gitignore +1 -0
  96. package/templates/bun/package.json +19 -0
  97. package/templates/bun/src/index.ts +7 -0
  98. package/templates/bun/test/app.test.ts +8 -0
  99. package/templates/bun/tsconfig.json +15 -0
  100. package/templates/nodejs/gitignore +1 -0
  101. package/templates/nodejs/package.json +22 -0
  102. package/templates/nodejs/src/app.ts +7 -0
  103. package/templates/nodejs/src/index.ts +9 -0
  104. package/templates/nodejs/test/app.test.ts +9 -0
  105. package/templates/nodejs/tsconfig.json +16 -0
  106. package/README.md +0 -3
@@ -0,0 +1,133 @@
1
+ # Testing
2
+
3
+ [Vitest]: https://vitest.dev/
4
+
5
+ Testing is important.
6
+ In actuality, it is easy to test Acryl's applications.
7
+ The way to create a test environment differs from each runtime, but the basic steps are the same.
8
+ In this section, let's test with [Vitest] on Node.js. The same tests run on Bun with its own test runner, because an app is a function from `Request` to `Response`.
9
+
10
+ ## Request and Response
11
+
12
+ All you need to do is create a Request and pass it to the Acryl application to validate the Response. You can then use the useful `app.request` method.
13
+
14
+ > **Tip.** For a typed test client see the [testing helper](../helpers/testing.md).
15
+
16
+ For example, consider an application that provides the following REST API.
17
+
18
+ ```ts
19
+ app.get('/posts', (c) => {
20
+ return c.text('Many posts')
21
+ })
22
+
23
+ app.post('/posts', (c) => {
24
+ return c.json(
25
+ {
26
+ message: 'Created',
27
+ },
28
+ 201,
29
+ {
30
+ 'X-Custom': 'Thank you',
31
+ }
32
+ )
33
+ })
34
+ ```
35
+
36
+ Make a request to `GET /posts` and test the response.
37
+
38
+ ```ts
39
+ describe('Example', () => {
40
+ test('GET /posts', async () => {
41
+ const res = await app.request('/posts')
42
+ expect(res.status).toBe(200)
43
+ expect(await res.text()).toBe('Many posts')
44
+ })
45
+ })
46
+ ```
47
+
48
+ To make a request to `POST /posts`, do the following.
49
+
50
+ ```ts
51
+ test('POST /posts', async () => {
52
+ const res = await app.request('/posts', {
53
+ method: 'POST',
54
+ })
55
+ expect(res.status).toBe(201)
56
+ expect(res.headers.get('X-Custom')).toBe('Thank you')
57
+ expect(await res.json()).toEqual({
58
+ message: 'Created',
59
+ })
60
+ })
61
+ ```
62
+
63
+ To make a request to `POST /posts` with `JSON` data, do the following.
64
+
65
+ ```ts
66
+ test('POST /posts', async () => {
67
+ const res = await app.request('/posts', {
68
+ method: 'POST',
69
+ body: JSON.stringify({ message: 'hello acrylblends' }),
70
+ headers: new Headers({ 'Content-Type': 'application/json' }),
71
+ })
72
+ expect(res.status).toBe(201)
73
+ expect(res.headers.get('X-Custom')).toBe('Thank you')
74
+ expect(await res.json()).toEqual({
75
+ message: 'Created',
76
+ })
77
+ })
78
+ ```
79
+
80
+ To make a request to `POST /posts` with `multipart/form-data` data, do the following.
81
+
82
+ ```ts
83
+ test('POST /posts', async () => {
84
+ const formData = new FormData()
85
+ formData.append('message', 'hello')
86
+ const res = await app.request('/posts', {
87
+ method: 'POST',
88
+ body: formData,
89
+ })
90
+ expect(res.status).toBe(201)
91
+ expect(res.headers.get('X-Custom')).toBe('Thank you')
92
+ expect(await res.json()).toEqual({
93
+ message: 'Created',
94
+ })
95
+ })
96
+ ```
97
+
98
+ You can also pass an instance of the Request class.
99
+
100
+ ```ts
101
+ test('POST /posts', async () => {
102
+ const req = new Request('http://localhost/posts', {
103
+ method: 'POST',
104
+ })
105
+ const res = await app.request(req)
106
+ expect(res.status).toBe(201)
107
+ expect(res.headers.get('X-Custom')).toBe('Thank you')
108
+ expect(await res.json()).toEqual({
109
+ message: 'Created',
110
+ })
111
+ })
112
+ ```
113
+
114
+ In this way, you can test it as like an End-to-End.
115
+
116
+ ## Env
117
+
118
+ To set `c.env` for testing, you can pass it as the 3rd parameter to `app.request`. This is useful for mocking values like platform bindings:
119
+
120
+ ```ts
121
+ const MOCK_ENV = {
122
+ API_HOST: 'example.com',
123
+ DB: {
124
+ prepare: () => {
125
+ /* mocked D1 */
126
+ },
127
+ },
128
+ }
129
+
130
+ test('GET /posts', async () => {
131
+ const res = await app.request('/posts', {}, MOCK_ENV)
132
+ })
133
+ ```
@@ -0,0 +1,383 @@
1
+ # Validation
2
+
3
+ Acryl provides only a very thin Validator.
4
+ However, it can be powerful when combined with a third-party Validator.
5
+ In addition, the RPC feature allows you to share API specifications with your clients through types.
6
+
7
+ ## Manual validator
8
+
9
+ First, introduce a way to validate incoming values without using the third-party Validator.
10
+
11
+ Import `validator` from `acrylblends/validator`.
12
+
13
+ ```ts
14
+ import { validator } from 'acrylblends/validator'
15
+ ```
16
+
17
+ To validate form data, specify `form` as the first argument and a callback as the second argument.
18
+ In the callback, validates the value and return the validated values at the end.
19
+ The `validator` can be used as middleware.
20
+
21
+ ```ts
22
+ app.post(
23
+ '/posts',
24
+ validator('form', (value, c) => {
25
+ const body = value['body']
26
+ if (!body || typeof body !== 'string') {
27
+ return c.text('Invalid!', 400)
28
+ }
29
+ return {
30
+ body: body,
31
+ }
32
+ }),
33
+ //...
34
+ ```
35
+
36
+ Within the handler, you can get the validated value with `c.req.valid('form')`.
37
+
38
+ ```ts
39
+ , (c) => {
40
+ const { body } = c.req.valid('form')
41
+ // ... do something
42
+ return c.json(
43
+ {
44
+ message: 'Created!',
45
+ },
46
+ 201
47
+ )
48
+ }
49
+ ```
50
+
51
+ Validation targets include `json`, `query`, `header`, `param` and `cookie` in addition to `form`.
52
+
53
+ **Warning.**
54
+
55
+ When you validate `json` or `form`, the request _must_ contain a matching `content-type` header (e.g. `Content-Type: application/json` for `json`). Otherwise, the request body will not be parsed and you will receive an empty object (`{}`) as value in the callback.
56
+
57
+ It is important to set the `content-type` header when testing using
58
+ [`app.request()`](../api/request.md).
59
+
60
+ Given an application like this.
61
+
62
+ ```ts
63
+ const app = new Acryl()
64
+ app.post(
65
+ '/testing',
66
+ validator('json', (value, c) => {
67
+ // pass-through validator
68
+ return value
69
+ }),
70
+ (c) => {
71
+ const body = c.req.valid('json')
72
+ return c.json(body)
73
+ }
74
+ )
75
+ ```
76
+
77
+ Your tests can be written like this.
78
+
79
+ ```ts
80
+ // ❌ this will not work
81
+ const res = await app.request('/testing', {
82
+ method: 'POST',
83
+ body: JSON.stringify({ key: 'value' }),
84
+ })
85
+ const data = await res.json()
86
+ console.log(data) // {}
87
+
88
+ // ✅ this will work
89
+ const res = await app.request('/testing', {
90
+ method: 'POST',
91
+ body: JSON.stringify({ key: 'value' }),
92
+ headers: new Headers({ 'Content-Type': 'application/json' }),
93
+ })
94
+ const data = await res.json()
95
+ console.log(data) // { key: 'value' }
96
+ ```
97
+
98
+ **Warning.**
99
+
100
+ When you validate `header`, you need to use **lowercase** name as the key.
101
+
102
+ If you want to validate the `Idempotency-Key` header, you need to use `idempotency-key` as the key.
103
+
104
+ ```ts
105
+ // ❌ this will not work
106
+ app.post(
107
+ '/api',
108
+ validator('header', (value, c) => {
109
+ // idempotencyKey is always undefined
110
+ // so this middleware always return 400 as not expected
111
+ const idempotencyKey = value['Idempotency-Key']
112
+
113
+ if (idempotencyKey == undefined || idempotencyKey === '') {
114
+ throw new HTTPException(400, {
115
+ message: 'Idempotency-Key is required',
116
+ })
117
+ }
118
+ return { idempotencyKey }
119
+ }),
120
+ (c) => {
121
+ const { idempotencyKey } = c.req.valid('header')
122
+ // ...
123
+ }
124
+ )
125
+
126
+ // ✅ this will work
127
+ app.post(
128
+ '/api',
129
+ validator('header', (value, c) => {
130
+ // can retrieve the value of the header as expected
131
+ const idempotencyKey = value['idempotency-key']
132
+
133
+ if (idempotencyKey == undefined || idempotencyKey === '') {
134
+ throw new HTTPException(400, {
135
+ message: 'Idempotency-Key is required',
136
+ })
137
+ }
138
+ return { idempotencyKey }
139
+ }),
140
+ (c) => {
141
+ const { idempotencyKey } = c.req.valid('header')
142
+ // ...
143
+ }
144
+ )
145
+ ```
146
+
147
+ ## Multiple validators
148
+
149
+ You can also include multiple validators to validate different parts of request:
150
+
151
+ ```ts
152
+ app.post(
153
+ '/posts/:id',
154
+ validator('param', ...),
155
+ validator('query', ...),
156
+ validator('json', ...),
157
+ (c) => {
158
+ //...
159
+ }
160
+ )
161
+ ```
162
+
163
+ ## With Zod
164
+
165
+ You can use [Zod](https://zod.dev), one of third-party validators.
166
+ We recommend using a third-party validator.
167
+
168
+ Install from the Npm registry.
169
+
170
+ **npm**
171
+
172
+ ```sh
173
+ npm i zod
174
+ ```
175
+
176
+ **yarn**
177
+
178
+ ```sh
179
+ yarn add zod
180
+ ```
181
+
182
+ **pnpm**
183
+
184
+ ```sh
185
+ pnpm add zod
186
+ ```
187
+
188
+ **bun**
189
+
190
+ ```sh
191
+ bun add zod
192
+ ```
193
+
194
+ Import `z` from `zod`.
195
+
196
+ ```ts
197
+ import * as z from 'zod'
198
+ ```
199
+
200
+ Write your schema.
201
+
202
+ ```ts
203
+ const schema = z.object({
204
+ body: z.string(),
205
+ })
206
+ ```
207
+
208
+ You can use the schema in the callback function for validation and return the validated value.
209
+
210
+ ```ts
211
+ const route = app.post(
212
+ '/posts',
213
+ validator('form', (value, c) => {
214
+ const parsed = schema.safeParse(value)
215
+ if (!parsed.success) {
216
+ return c.text('Invalid!', 401)
217
+ }
218
+ return parsed.data
219
+ }),
220
+ (c) => {
221
+ const { body } = c.req.valid('form')
222
+ // ... do something
223
+ return c.json(
224
+ {
225
+ message: 'Created!',
226
+ },
227
+ 201
228
+ )
229
+ }
230
+ )
231
+ ```
232
+
233
+ ## Standard Schema validator
234
+
235
+ [Standard Schema](https://standardschema.dev/) is a specification that gives TypeScript validation libraries a common interface, so a tool can accept Zod, Valibot, ArkType and
236
+ others without an adapter for each.
237
+
238
+ `schemaValidator` is part of acrylblends: it validates a request target with any Standard Schema and makes the parsed value available as `c.req.valid(target)`.
239
+
240
+ ```ts
241
+ import { schemaValidator } from 'acrylblends/schema-validator'
242
+ ```
243
+
244
+ A failed validation answers 400 with `{ "error": "invalid <target>", "issues": [{ "message", "path" }] }`. The failure shapes, the JSON `Content-Type` rule and a body that
245
+ is not JSON are described in [Validation with Standard Schema](../cordis/validation.md).
246
+
247
+ ### With Zod
248
+
249
+ You can use Zod with the schema validator:
250
+
251
+ **npm**
252
+
253
+ ```sh
254
+ npm i zod
255
+ ```
256
+
257
+ **yarn**
258
+
259
+ ```sh
260
+ yarn add zod
261
+ ```
262
+
263
+ **pnpm**
264
+
265
+ ```sh
266
+ pnpm add zod
267
+ ```
268
+
269
+ **bun**
270
+
271
+ ```sh
272
+ bun add zod
273
+ ```
274
+
275
+ ```ts
276
+ import * as z from 'zod'
277
+ import { schemaValidator } from 'acrylblends/schema-validator'
278
+
279
+ const schema = z.object({
280
+ name: z.string(),
281
+ age: z.number(),
282
+ })
283
+
284
+ app.post('/author', schemaValidator('json', schema), (c) => {
285
+ const data = c.req.valid('json')
286
+ return c.json({
287
+ success: true,
288
+ message: `${data.name} is ${data.age}`,
289
+ })
290
+ })
291
+ ```
292
+
293
+ ### With Valibot
294
+
295
+ [Valibot](https://valibot.dev/) is a lightweight alternative to Zod with a modular design:
296
+
297
+ **npm**
298
+
299
+ ```sh
300
+ npm i valibot
301
+ ```
302
+
303
+ **yarn**
304
+
305
+ ```sh
306
+ yarn add valibot
307
+ ```
308
+
309
+ **pnpm**
310
+
311
+ ```sh
312
+ pnpm add valibot
313
+ ```
314
+
315
+ **bun**
316
+
317
+ ```sh
318
+ bun add valibot
319
+ ```
320
+
321
+ ```ts
322
+ import * as v from 'valibot'
323
+ import { schemaValidator } from 'acrylblends/schema-validator'
324
+
325
+ const schema = v.object({
326
+ name: v.string(),
327
+ age: v.number(),
328
+ })
329
+
330
+ app.post('/author', schemaValidator('json', schema), (c) => {
331
+ const data = c.req.valid('json')
332
+ return c.json({
333
+ success: true,
334
+ message: `${data.name} is ${data.age}`,
335
+ })
336
+ })
337
+ ```
338
+
339
+ ### With ArkType
340
+
341
+ [ArkType](https://arktype.io/) offers TypeScript-native syntax for runtime validation:
342
+
343
+ **npm**
344
+
345
+ ```sh
346
+ npm i arktype
347
+ ```
348
+
349
+ **yarn**
350
+
351
+ ```sh
352
+ yarn add arktype
353
+ ```
354
+
355
+ **pnpm**
356
+
357
+ ```sh
358
+ pnpm add arktype
359
+ ```
360
+
361
+ **bun**
362
+
363
+ ```sh
364
+ bun add arktype
365
+ ```
366
+
367
+ ```ts
368
+ import { type } from 'arktype'
369
+ import { schemaValidator } from 'acrylblends/schema-validator'
370
+
371
+ const schema = type({
372
+ name: 'string',
373
+ age: 'number',
374
+ })
375
+
376
+ app.post('/author', schemaValidator('json', schema), (c) => {
377
+ const data = c.req.valid('json')
378
+ return c.json({
379
+ success: true,
380
+ message: `${data.name} is ${data.age}`,
381
+ })
382
+ })
383
+ ```
@@ -0,0 +1,60 @@
1
+ # Accepts Helper
2
+
3
+ Accepts Helper helps to handle Accept headers in the Requests.
4
+
5
+ ## Import
6
+
7
+ ```ts
8
+ import { Acryl } from 'acrylblends'
9
+ import { accepts } from 'acrylblends/accepts'
10
+ ```
11
+
12
+ ## `accepts()`
13
+
14
+ The `accepts()` function looks at the Accept header, such as Accept-Encoding and Accept-Language, and returns the proper value.
15
+
16
+ ```ts
17
+ import { accepts } from 'acrylblends/accepts'
18
+
19
+ app.get('/', (c) => {
20
+ const accept = accepts(c, {
21
+ header: 'Accept-Language',
22
+ supports: ['en', 'ja', 'zh'],
23
+ default: 'en',
24
+ })
25
+ return c.json({ lang: accept })
26
+ })
27
+ ```
28
+
29
+ ### `AcceptHeader` type
30
+
31
+ The definition of the `AcceptHeader` type is as follows.
32
+
33
+ ```ts
34
+ export type AcceptHeader =
35
+ | 'Accept'
36
+ | 'Accept-Charset'
37
+ | 'Accept-Encoding'
38
+ | 'Accept-Language'
39
+ | 'Accept-Patch'
40
+ | 'Accept-Post'
41
+ | 'Accept-Ranges'
42
+ ```
43
+
44
+ ## Options
45
+
46
+ ### **(required)** header: `AcceptHeader`
47
+
48
+ The target accept header.
49
+
50
+ ### **(required)** supports: `string[]`
51
+
52
+ The header values which your application supports.
53
+
54
+ ### **(required)** default: `string`
55
+
56
+ The default values.
57
+
58
+ ### *(optional)* match: `(accepts: Accept[], config: acceptsConfig) => string`
59
+
60
+ The custom match function.
@@ -0,0 +1,87 @@
1
+ # Adapter Helper
2
+
3
+ The Adapter Helper provides a seamless way to interact with various platforms through a unified interface.
4
+
5
+ ## Import
6
+
7
+ ```ts
8
+ import { Acryl } from 'acrylblends'
9
+ import { env, getRuntimeKey } from 'acrylblends/adapter'
10
+ ```
11
+
12
+ ## `env()`
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.
15
+
16
+ ```ts
17
+ import { env } from 'acrylblends/adapter'
18
+
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
22
+ const { NAME } = env<{ NAME: string }>(c)
23
+ return c.text(NAME)
24
+ })
25
+ ```
26
+
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
+ ### Specify the runtime
52
+
53
+ You can specify the runtime to get environment variables by passing the runtime key as the second argument.
54
+
55
+ ```ts
56
+ app.get('/env', (c) => {
57
+ const { NAME } = env<{ NAME: string }>(c, 'workerd')
58
+ return c.text(NAME)
59
+ })
60
+ ```
61
+
62
+ ## `getRuntimeKey()`
63
+
64
+ The `getRuntimeKey()` function returns the identifier of the current runtime.
65
+
66
+ ```ts
67
+ app.get('/', (c) => {
68
+ if (getRuntimeKey() === 'workerd') {
69
+ return c.text('You are on Cloudflare')
70
+ } else if (getRuntimeKey() === 'bun') {
71
+ return c.text('You are on Bun')
72
+ }
73
+ ...
74
+ })
75
+ ```
76
+
77
+ ### Available Runtimes Keys
78
+
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/):
80
+
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