You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(docs): document render caps and staticHandler option
- Add maxRenderIterations and maxOutputSize router options
- Add the staticHandler advanced option for custom backends
- Update template-limit responses from 500 to 400
Copy file name to clipboardExpand all lines: docs/getting-started/routes-configuration.md
+51-2Lines changed: 51 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ Configure the Deserve routes directory to match the project structure.
8
8
9
9
## Router Options
10
10
11
-
The `Router` constructor accepts configuration options. The common ones are`routesDir` for the route folder and `requestTimeoutMs` for a request timeout. Rendering, request limits, worker pools, and a custom error builder are all configurable too. Proxy trust through `trustProxy` and the worker pool live in[Client IP Resolution](/getting-started/server-configuration#client-ip-resolution) and [Worker Pool](/core-concepts/worker-pool).
11
+
The `Router` constructor accepts one options object. The everyday pair is`routesDir` for the route folder and `requestTimeoutMs` for a request deadline. The sections below cover route loading, request size limits, template render limits, and the two advanced hooks `errorResponseBuilder` and `staticHandler`. Two related options live on their own pages, `trustProxy` under[Client IP Resolution](/getting-started/server-configuration#client-ip-resolution) and the `worker` pool under[Worker Pool](/core-concepts/worker-pool).
12
12
13
13
```typescript twoslash
14
14
import { Router } from'@neabyte/deserve'
@@ -53,7 +53,7 @@ const router = new Router({
53
53
54
54
### `maxIterations`
55
55
56
-
Maximum iterations allowed per <codev-pre>{{#each}}</code> block in DVE templates. The cap prevents event loop starvation from unbounded rendering. The default is `100_000`, and exceeding it makes the engine throw so the server responds with **500 Internal Server Error**.
56
+
Maximum iterations allowed per <codev-pre>{{#each}}</code> block in DVE templates. The cap prevents event loop starvation from one unbounded loop. The default is `100_000`, and exceeding it makes the engine throw so the server responds with **400 Bad Request**.
57
57
58
58
```typescript twoslash
59
59
import { Router } from'@neabyte/deserve'
@@ -67,6 +67,34 @@ const router = new Router({
67
67
68
68
For datasets larger than the limit, use [`streamRender`](/rendering/streaming) instead, and see [Performance and Limits](/rendering/performance#iteration-limit) for how the cap behaves. For CPU-intensive rendering, consider offloading to a [worker pool](/core-concepts/worker-pool).
69
69
70
+
### `maxRenderIterations`
71
+
72
+
Maximum total <codev-pre>{{#each}}</code> body executions across one render, summed over every loop including nested ones. Where `maxIterations` guards a single loop, this guards the whole page. The default is `1_000_000`, and exceeding it responds with **400 Bad Request**.
73
+
74
+
```typescript twoslash
75
+
import { Router } from'@neabyte/deserve'
76
+
// ---cut---
77
+
const router =newRouter({
78
+
routesDir: 'routes',
79
+
viewsDir: './views',
80
+
maxRenderIterations: 500_000
81
+
})
82
+
```
83
+
84
+
### `maxOutputSize`
85
+
86
+
Maximum total output characters produced by one render. The cap stops a small template from expanding into a huge response. The default is `5_000_000`, and exceeding it responds with **400 Bad Request**.
87
+
88
+
```typescript twoslash
89
+
import { Router } from'@neabyte/deserve'
90
+
// ---cut---
91
+
const router =newRouter({
92
+
routesDir: 'routes',
93
+
viewsDir: './views',
94
+
maxOutputSize: 1_000_000
95
+
})
96
+
```
97
+
70
98
### `maxUrlLength`
71
99
72
100
Maximum length of the request URL in characters. A longer URL is rejected with **414 URI Too Long** before any route runs. The default is `8192`:
@@ -123,6 +151,27 @@ const router = new Router({
123
151
})
124
152
```
125
153
154
+
### `staticHandler`
155
+
156
+
Advanced option that replaces how static files are served. It receives the context, the [static options](/static-file/basic#static-file-options) for the matched route, and the URL path, then returns the `Response`. The default implementation already guards path traversal, so override it only for a custom backend such as object storage:
Copy file name to clipboardExpand all lines: docs/getting-started/server-configuration.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -84,7 +84,7 @@ Omit `requestTimeoutMs` for no timeout (default).
84
84
85
85
## Template Iteration Limit
86
86
87
-
The `maxIterations` option caps the iterations per <codev-pre>{{#each}}</code> block in DVE templates, which prevents event loop starvation from unbounded rendering. The default is `100_000`:
87
+
The `maxIterations` option caps the iterations per <codev-pre>{{#each}}</code> block in DVE templates, which prevents event loop starvation from one unbounded loop. The default is `100_000`:
88
88
89
89
```typescript twoslash
90
90
import { Router } from'@neabyte/deserve'
@@ -96,7 +96,7 @@ const router = new Router({
96
96
awaitrouter.serve(8000)
97
97
```
98
98
99
-
If a template exceeds the limit, the server responds with **500 Internal Server Error**. The full rendering behavior lives in [Performance and Limits](/rendering/performance#iteration-limit). For large datasets, use [`streamRender`](/rendering/streaming) instead. For CPU-intensive rendering, consider offloading to a [worker pool](/core-concepts/worker-pool).
99
+
If a template exceeds the limit, the server responds with **400 Bad Request**. Two companion caps, `maxRenderIterations` for the whole-page loop budget and `maxOutputSize` for total output characters, behave the same way and are listed in [Routes Configuration](/getting-started/routes-configuration#configuration-options). The full rendering behavior lives in [Performance and Limits](/rendering/performance#iteration-limit). For large datasets, use [`streamRender`](/rendering/streaming) instead. For CPU-intensive rendering, consider offloading to a [worker pool](/core-concepts/worker-pool).
Copy file name to clipboardExpand all lines: docs/id/getting-started/routes-configuration.md
+52-3Lines changed: 52 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@ Konfigurasi direktori routes Deserve agar cocok dengan struktur proyek.
8
8
9
9
## Opsi Router
10
10
11
-
Konstruktor `Router` menerima opsi konfigurasi. Yang umum adalah `routesDir` untuk folder rute dan `requestTimeoutMs` untuk timeout request. Rendering, batas request, worker pool, dan builder error khusus semuanya bisa dikonfigurasi juga. Kepercayaan proxy lewat `trustProxy` dan worker pool ada di [Resolusi IP Klien](/id/getting-started/server-configuration#resolusi-ip-klien) dan [Worker Pool](/id/core-concepts/worker-pool).
11
+
Konstruktor `Router` menerima satu objek opsi. Pasangan sehari-hari adalah `routesDir` untuk folder rute dan `requestTimeoutMs` untuk tenggat request. Bagian di bawah membahas pemuatan rute, batas ukuran request, batas render template, dan dua kait lanjutan `errorResponseBuilder` serta `staticHandler`. Dua opsi terkait ada di halaman sendiri, `trustProxy` di [Resolusi IP Klien](/id/getting-started/server-configuration#resolusi-ip-klien) dan`worker` pool di[Worker Pool](/id/core-concepts/worker-pool).
12
12
13
13
```typescript twoslash
14
14
import { Router } from'@neabyte/deserve'
@@ -53,7 +53,7 @@ const router = new Router({
53
53
54
54
### `maxIterations`
55
55
56
-
Iterasi maksimum yang diizinkan per blok <codev-pre>{{#each}}</code> di template DVE. Batas ini mencegah event loop kelaparan akibat rendering tak terbatas. Default-nya `100_000`, dan melampauinya membuat mesin melempar sehingga server membalas dengan **500 Internal Server Error**.
56
+
Iterasi maksimum yang diizinkan per blok <codev-pre>{{#each}}</code> di template DVE. Batas ini mencegah event loop kelaparan akibat satu perulangan tak terbatas. Default-nya `100_000`, dan melampauinya membuat mesin melempar sehingga server membalas dengan **400 Bad Request**.
57
57
58
58
```typescript twoslash
59
59
import { Router } from'@neabyte/deserve'
@@ -67,6 +67,34 @@ const router = new Router({
67
67
68
68
Untuk dataset lebih besar dari batas, gunakan [`streamRender`](/id/rendering/streaming), dan lihat [Performa dan Batas](/id/rendering/performance#batas-iterasi) untuk perilaku batasnya. Untuk rendering berat CPU, pertimbangkan mengalihkan ke [worker pool](/id/core-concepts/worker-pool).
69
69
70
+
### `maxRenderIterations`
71
+
72
+
Total maksimum eksekusi badan <codev-pre>{{#each}}</code> dalam satu render, dijumlahkan dari setiap perulangan termasuk yang bersarang. Jika `maxIterations` membatasi satu perulangan, opsi ini membatasi seluruh halaman. Default-nya `1_000_000`, dan melampauinya membalas dengan **400 Bad Request**.
73
+
74
+
```typescript twoslash
75
+
import { Router } from'@neabyte/deserve'
76
+
// ---cut---
77
+
const router =newRouter({
78
+
routesDir: 'routes',
79
+
viewsDir: './views',
80
+
maxRenderIterations: 500_000
81
+
})
82
+
```
83
+
84
+
### `maxOutputSize`
85
+
86
+
Total maksimum karakter keluaran yang dihasilkan satu render. Batas ini mencegah template kecil membengkak menjadi response besar. Default-nya `5_000_000`, dan melampauinya membalas dengan **400 Bad Request**.
87
+
88
+
```typescript twoslash
89
+
import { Router } from'@neabyte/deserve'
90
+
// ---cut---
91
+
const router =newRouter({
92
+
routesDir: 'routes',
93
+
viewsDir: './views',
94
+
maxOutputSize: 1_000_000
95
+
})
96
+
```
97
+
70
98
### `maxUrlLength`
71
99
72
100
Panjang maksimum URL request dalam karakter. URL lebih panjang ditolak dengan **414 URI Too Long** sebelum rute mana pun berjalan. Default-nya `8192`:
@@ -95,7 +123,7 @@ const router = new Router({
95
123
96
124
### `errorResponseBuilder`
97
125
98
-
Opsi lanjutan yang mengganti cara response error dibangun. Ia menerima context, status code, error, dan handler yang diatur dengan [`router.catch()`](/id/error-handling/object-details), lalu mengembalikan `Response` final. Kebanyakan aplikasi membentuk error lewat `router.catch()` saja, dibahas di [Penanganan Error](/id/error-handling/object-details):
126
+
Opsi lanjutan yang mengganti cara response error dibangun. Opsi ini menerima context, status code, error, dan handler yang diatur dengan [`router.catch()`](/id/error-handling/object-details), lalu mengembalikan `Response` final. Kebanyakan aplikasi membentuk error lewat `router.catch()` saja, dibahas di [Penanganan Error](/id/error-handling/object-details):
Opsi lanjutan yang mengganti cara berkas statis dilayani. Opsi ini menerima context, [opsi statis](/id/static-file/basic#opsi-static-file) untuk rute yang cocok, dan path URL, lalu mengembalikan `Response`. Implementasi default sudah menjaga path traversal, jadi ganti hanya untuk backend khusus seperti object storage:
Copy file name to clipboardExpand all lines: docs/id/getting-started/server-configuration.md
+7-7Lines changed: 7 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -84,7 +84,7 @@ Hilangkan `requestTimeoutMs` untuk tanpa timeout (default).
84
84
85
85
## Batas Iterasi Template
86
86
87
-
Opsi `maxIterations` membatasi iterasi per blok <codev-pre>{{#each}}</code> di template DVE, yang mencegah event loop kelaparan akibat rendering tak terbatas. Default-nya `100_000`:
87
+
Opsi `maxIterations` membatasi iterasi per blok <codev-pre>{{#each}}</code> di template DVE, yang mencegah event loop kelaparan akibat satu perulangan tak terbatas. Default-nya `100_000`:
88
88
89
89
```typescript twoslash
90
90
import { Router } from'@neabyte/deserve'
@@ -96,7 +96,7 @@ const router = new Router({
96
96
awaitrouter.serve(8000)
97
97
```
98
98
99
-
Jika template melewati batas, server membalas dengan **500 Internal Server Error**. Perilaku rendering lengkap ada di [Performa dan Batas](/id/rendering/performance#batas-iterasi). Untuk dataset besar, gunakan [`streamRender`](/id/rendering/streaming). Untuk rendering berat CPU, pertimbangkan mengalihkan ke [worker pool](/id/core-concepts/worker-pool).
99
+
Jika template melewati batas, server membalas dengan **400 Bad Request**. Dua batas pendamping, `maxRenderIterations` untuk anggaran perulangan seluruh halaman dan `maxOutputSize` untuk total karakter keluaran, berperilaku sama dan tercantum di [Konfigurasi Rute](/id/getting-started/routes-configuration#opsi-konfigurasi). Perilaku rendering lengkap ada di [Performa dan Batas](/id/rendering/performance#batas-iterasi). Untuk dataset besar, gunakan [`streamRender`](/id/rendering/streaming). Untuk rendering berat CPU, pertimbangkan mengalihkan ke [worker pool](/id/core-concepts/worker-pool).
100
100
101
101
## Resolusi IP Klien
102
102
@@ -158,14 +158,14 @@ ac.abort()
158
158
159
159
### Penanganan Sinyal Proses
160
160
161
-
Tanpa `AbortSignal`, router mendengarkan `SIGINT` dan `SIGTERM` sendiri (hanya `SIGINT` di Windows) dan menguras dengan baik pada salah satunya. Tidak perlu perakitan sinyal manual:
161
+
Tanpa `AbortSignal`, router mendengarkan `SIGINT` dan `SIGTERM` sendiri (hanya `SIGINT` di Windows) dan menyelesaikan request berjalan dengan rapi pada salah satunya. Tidak perlu menyiapkan sinyal secara manual:
162
162
163
163
```typescript twoslash
164
164
import { Router } from'@neabyte/deserve'
165
165
166
166
const router =newRouter()
167
167
168
-
// SIGINT dan SIGTERM menguras otomatis
168
+
// SIGINT dan SIGTERM menuntaskan request otomatis
169
169
awaitrouter.serve(8000, '127.0.0.1')
170
170
```
171
171
@@ -211,10 +211,10 @@ Lihat [Pelaporan Error](/id/middleware/observability/errors) untuk pola lengkapn
211
211
Tujuannya adalah ketersediaan. Satu jalur kode yang cacat atau jahat semestinya tidak bisa membatalkan seluruh proses dan menolak layanan ke setiap rute dan service yang ditampungnya.
212
212
213
213
-**Penyalahgunaan rantai pasok** - dependensi transitif yang memanggil `process.exit()` atau `Deno.exit()`, baik karena kecelakaan maupun sebagai serangan, tidak bisa lagi membuat server crash. Ini selaras dengan [OWASP A03:2025 Software Supply Chain Failures](https://owasp.org/Top10/2025/A03_2025-Software_Supply_Chain_Failures/) dan [CWE-1395](https://cwe.mitre.org/data/definitions/1395.html).
214
-
-**Denial of service** - memblokir terminasi-diri menghapus saklar mati ketersediaan yang mudah, terkait [CWE-400](https://cwe.mitre.org/data/definitions/400.html) dan [CWE-730](https://cwe.mitre.org/data/definitions/730.html).
215
-
-**Kesalahan tak tertangkap** - menjebak unhandled rejection dan uncaught error menjaga satu request buruk dari mengakhiri proses, terkait [CWE-248](https://cwe.mitre.org/data/definitions/248.html).
214
+
-**Denial of service** - memblokir terminasi-diri menghapus tombol mematikan ketersediaan yang mudah, terkait [CWE-400](https://cwe.mitre.org/data/definitions/400.html) dan [CWE-730](https://cwe.mitre.org/data/definitions/730.html).
215
+
-**Kesalahan tak tertangkap** - menjebak unhandled rejection dan uncaught error mencegah satu request buruk mengakhiri proses, terkait [CWE-248](https://cwe.mitre.org/data/definitions/248.html).
216
216
217
-
Ini pertahanan upaya-terbaik, bukan sandbox. Ia menyisip ke titik masuk terminasi yang diketahui ketimbang mengisolasi kode tak tepercaya, jadi ia mengurangi blast radius tanpa mengklaim menghentikan setiap penyalahgunaan yang mungkin. Pasangkan dengan flag izin Deno dan tinjauan dependensi untuk jaminan lebih kuat. Pendekatan berlapis terhadap kesalahan dibahas di [Pertahanan Berlapis](/id/error-handling/defense-in-depth).
217
+
Ini pertahanan upaya-terbaik, bukan sandbox. Pertahanan ini menyisip ke titik masuk terminasi yang diketahui ketimbang mengisolasi kode tak tepercaya, jadi ia memperkecil dampak kesalahan tanpa mengklaim menghentikan setiap penyalahgunaan yang mungkin. Pasangkan dengan flag izin Deno dan tinjauan dependensi untuk jaminan lebih kuat. Pendekatan berlapis terhadap kesalahan dibahas di [Pertahanan Berlapis](/id/error-handling/defense-in-depth).
Copy file name to clipboardExpand all lines: docs/id/rendering/performance.md
+20-4Lines changed: 20 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ description: "Karakteristik performa dan perilaku caching mesin template Deserve
4
4
5
5
# Performa dan Batas
6
6
7
-
Mesin DVE meng-cache template terkompilasi dan menjaga rendering dengan dua batas, jadi halaman besar tetap cepat dan template liar gagal dengan jelas alih-alih menggantung server.
7
+
Mesin DVE meng-cache template terkompilasi dan mengawal rendering dengan dua batas, jadi halaman besar tetap cepat dan template yang tak terkendali gagal dengan jelas alih-alih menggantung server.
8
8
9
9
## Caching
10
10
@@ -27,7 +27,7 @@ Cache hanya mencakup kompilasi template, bukan data atau logika backend. Perubah
27
27
28
28
## Batas Iterasi
29
29
30
-
Setiap blok <codev-pre>{{#each}}</code> dibatasi `100_000` iterasi secara default, yang mencegah event loop kelaparan akibat perulangan tak terbatas. Setel dengan `maxIterations`:
30
+
Setiap blok <codev-pre>{{#each}}</code> dibatasi `100_000` iterasi secara default, yang mencegah event loop kelaparan akibat satu perulangan tak terbatas. Setel dengan `maxIterations`:
31
31
32
32
```typescript twoslash
33
33
import { Router } from'@neabyte/deserve'
@@ -38,8 +38,24 @@ const router = new Router({
38
38
})
39
39
```
40
40
41
-
Ketika perulangan melewati batas, mesin melempar dan server membalas **500**. Untuk dataset sangat besar, gunakan [streaming rendering](/id/rendering/streaming). Untuk rendering berat CPU, alihkan ke [worker pool](/id/core-concepts/worker-pool).
41
+
Ketika perulangan melewati batas, mesin melempar dan server membalas **400 Bad Request**. Untuk dataset sangat besar, gunakan [streaming rendering](/id/rendering/streaming). Untuk rendering berat CPU, alihkan ke [worker pool](/id/core-concepts/worker-pool).
42
+
43
+
## Batas Anggaran Render
44
+
45
+
Dua batas lain mengawal seluruh render, bukan hanya satu perulangan. `maxRenderIterations` menjumlahkan setiap eksekusi badan <codev-pre>{{#each}}</code> di seluruh halaman, termasuk perulangan bersarang, dan default-nya `1_000_000`. `maxOutputSize` membatasi total karakter yang boleh dihasilkan satu render dan default-nya `5_000_000`:
46
+
47
+
```typescript twoslash
48
+
import { Router } from'@neabyte/deserve'
49
+
// ---cut---
50
+
const router =newRouter({
51
+
viewsDir: './views',
52
+
maxRenderIterations: 500_000,
53
+
maxOutputSize: 2_000_000
54
+
})
55
+
```
56
+
57
+
Melewati salah satu batas membalas dengan **400 Bad Request**, status yang sama dengan batas per perulangan. Ketiganya diatur di [opsi Router](/id/getting-started/routes-configuration#opsi-konfigurasi).
42
58
43
59
## Batas Kedalaman Include
44
60
45
-
Include template dibatasi 64 tingkat bersarang, jadi rantai include melingkar atau liar melempar error alih-alih berputar selamanya. Menjaga partial tetap dangkal aman jauh di dalam batas ini.
61
+
Include template dibatasi 64 tingkat bersarang, jadi rantai include melingkar atau tak terkendali melempar error alih-alih berputar selamanya. Melewati batas ini membalas dengan **400 Bad Request**. Selama struktur partial tidak terlalu dalam, render tetap jauh di dalam batas ini.
0 commit comments