Skip to content

Commit 2fe06fa

Browse files
committed
docs(id): realign Indonesian docs to v0.15 context namespace API
- Consolidate response helpers into download and empty - Document ctx.get, ctx.set, and ctx.send namespaces - Drop ctx.state in favor of signed session and validated - Move worker pool guide to recipes - Remove wildcard wording from route patterns description - Rename lifecycle events and add security event group - Rename routesDir to routes.directory across config - Rename WrapMware to Wrap.apply and ctx accessors to namespaced form
1 parent 0a99120 commit 2fe06fa

66 files changed

Lines changed: 2184 additions & 2054 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/id/by-design/bearer-auth.md

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
2-
description: "Kenapa Deserve membawa Basic Auth tapi tidak Bearer, dan cara menyusun auth token untuk skema apa pun."
2+
description: "Kenapa Deserve membawa Basic Auth tapi tidak ada middleware Bearer, dan cara menyusun auth token untuk skema apa pun."
33
---
44

55
# Bearer Auth
66

7-
Deserve membawa [Basic Auth](/id/middleware/basic-auth) tapi tidak ada middleware Bearer, dan pemisahan antara keduanya adalah intinya.
7+
Deserve membawa [Basic Auth](/id/middleware/basic-auth) tapi tidak ada middleware Bearer, dan pemisahan antara keduanya adalah seluruh intinya.
88

99
## Kenapa Tidak Dibawa
1010

@@ -22,24 +22,23 @@ Bearer sebaliknya. Format token, tanda tangan, dan sumber kepercayaan semuanya b
2222

2323
Penjaga token adalah komposisi kecil di atas bagian yang sudah ada:
2424

25-
- **Baca header** - [`ctx.header('authorization')`](/id/core-concepts/context-object#akses-data-request) mengembalikan nilai `Authorization` mentah.
25+
- **Baca header** - [`ctx.get.header('authorization')`](/id/core-concepts/context-object#ctx-get-header-key) mengembalikan nilai `Authorization` mentah.
2626
- **Berjalan lebih awal** - [middleware global](/id/middleware/global) berjalan sebelum route handler dan bisa menghentikan request dengan mengembalikan `Response`.
2727
- **Tolak bersih** - [`ctx.handleError(401, ...)`](/id/core-concepts/context-object#penanganan-error) mengarah lewat [`router.catch()`](/id/error-handling/object-details) saat satu diatur.
28-
- **Bawa hasilnya** - [`ctx.state`](/id/core-concepts/context-object#berbagi-state) menyerahkan identitas terdekode ke handler di hilir.
28+
- **Bawa hasilnya** - [`ctx.set.session(...)`](/id/core-concepts/context-object#ctx-set-session-data) menandatangani identitas terdekode ke sebuah cookie yang dibaca balik handler, dibahas di [middleware session](/id/middleware/session).
2929

3030
## Sebuah Penjaga Bearer
3131

32-
Middleware ini menarik token dari header, memverifikasinya, dan menyimpan hasilnya untuk handler berikutnya. Placeholder `verifyToken` mewakili skema pilihan, sebuah pengecekan JWT, lookup JWKS, atau panggilan introspeksi.
32+
Middleware ini menarik token dari header, memverifikasinya, dan menyimpan hasilnya untuk handler berikutnya. Placeholder `verifyToken` mewakili skema pilihan, sebuah pengecekan JWT, lookup JWKS, atau panggilan introspeksi. Menyimpan identitas butuh [middleware session](/id/middleware/session) terdaftar lebih dulu.
3333

3434
```typescript twoslash
35-
import type { Context } from '@neabyte/deserve'
36-
import { Router } from '@neabyte/deserve'
35+
import { Router, type Context } from '@neabyte/deserve'
3736

3837
const router = new Router()
3938
declare function verifyToken(token: string): Promise<{ userId: string } | null>
4039
// ---cut---
4140
router.use(async (ctx, next) => {
42-
const header = ctx.header('authorization')
41+
const header = ctx.get.header('authorization')
4342
const spaceIndex = header ? header.indexOf(' ') : -1
4443
const scheme = spaceIndex > 0 ? header!.slice(0, spaceIndex) : ''
4544

@@ -56,47 +55,46 @@ router.use(async (ctx, next) => {
5655
}
5756

5857
// Serahkan identitas ke handler
59-
ctx.state.userId = claims.userId
58+
await ctx.set.session({ userId: claims.userId })
6059
return await next()
6160
})
6261

6362
await router.serve(8000)
6463
```
6564

66-
Handler lalu membaca identitas langsung dari state, tanpa parsing token sendiri.
65+
Handler lalu membaca identitas langsung dari session, tanpa parsing token sendiri.
6766

6867
```typescript twoslash
6968
import type { Context } from '@neabyte/deserve'
7069
// ---cut---
7170
export function GET(ctx: Context): Response {
7271
// Baca apa yang disimpan penjaga
73-
const userId = ctx.state.userId
74-
return ctx.send.json({ userId })
72+
const session = ctx.get.session()
73+
return ctx.send.json({ userId: session?.userId })
7574
}
7675
```
7776

7877
## Mengarahkan Kegagalan Lewat Satu Handler
7978

80-
Penjaga di atas mengembalikan `401` dari dalam middleware. Untuk mengirim setiap kegagalan auth lewat satu tempat, bungkus middleware dengan [`WrapMware`](/id/middleware/global#membungkus-middleware-dengan-penanganan-error) dan lempar saat ditolak, lalu bentuk balasannya dengan [`router.catch()`](/id/error-handling/object-details).
79+
Penjaga di atas mengembalikan `401` dari dalam middleware. Untuk mengirim setiap kegagalan auth lewat satu tempat, bungkus middleware dengan [`Wrap.apply`](/id/middleware/global#membungkus-middleware-dengan-penanganan-error) dan lempar saat ditolak, lalu bentuk balasannya dengan [`router.catch()`](/id/error-handling/object-details).
8180

8281
```typescript twoslash
83-
import type { Context } from '@neabyte/deserve'
84-
import { Router, WrapMware } from '@neabyte/deserve'
82+
import { Router, Wrap, type Context } from '@neabyte/deserve'
8583

8684
const router = new Router()
8785
declare function verifyToken(token: string): Promise<{ userId: string } | null>
8886
// ---cut---
8987
// Lemparan sampai router.catch saat dibungkus
90-
const bearer = WrapMware('Bearer', async (ctx: Context, next) => {
91-
const header = ctx.header('authorization')
88+
const bearer = Wrap.apply('Bearer', async (ctx: Context, next) => {
89+
const header = ctx.get.header('authorization')
9290
if (!header?.toLowerCase().startsWith('bearer ')) {
9391
throw new Error('Missing Bearer token')
9492
}
9593
const claims = await verifyToken(header.slice(7).trim())
9694
if (!claims) {
9795
throw new Error('Invalid token')
9896
}
99-
ctx.state.userId = claims.userId
97+
await ctx.set.session({ userId: claims.userId })
10098
return await next()
10199
})
102100

@@ -121,22 +119,21 @@ Ini pola pembungkusan yang sama dipakai [Basic Auth](/id/middleware/basic-auth)
121119
Penjaga token sering cocok di prefix API sementara halaman publik tetap terbuka. Middleware per-path membatasi pengecekan ke satu prefix, bentuk yang sama ditunjukkan di [middleware global](/id/middleware/global#middleware-per-path).
122120

123121
```typescript twoslash
124-
import type { Context } from '@neabyte/deserve'
125-
import { Router } from '@neabyte/deserve'
122+
import { Router, type Context } from '@neabyte/deserve'
126123

127124
const router = new Router()
128125
declare function verifyToken(token: string): Promise<{ userId: string } | null>
129126
// ---cut---
130127
// Jaga hanya rute /api
131128
router.use('/api', async (ctx, next) => {
132-
const header = ctx.header('authorization')
129+
const header = ctx.get.header('authorization')
133130
const claims = header?.toLowerCase().startsWith('bearer ')
134131
? await verifyToken(header.slice(7).trim())
135132
: null
136133
if (!claims) {
137134
return await ctx.handleError(401, new Error('Invalid token'))
138135
}
139-
ctx.state.userId = claims.userId
136+
await ctx.set.session({ userId: claims.userId })
140137
return await next()
141138
})
142139
```

docs/id/by-design/cache.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import type { Context } from '@neabyte/deserve'
2929
const cache = new Map<string, unknown>()
3030

3131
export async function GET(ctx: Context): Promise<Response> {
32-
const key = ctx.pathname
32+
const key = ctx.get.pathname()
3333

3434
// Sajikan nilai cache ketika ada
3535
const hit = cache.get(key)
@@ -64,7 +64,7 @@ const ttlMs = 30_000
6464
const cache = new Map<string, { value: unknown, expiresAt: number }>()
6565
6666
export function GET(ctx: Context): Response {
67-
const key = ctx.pathname
67+
const key = ctx.get.pathname()
6868
const entry = cache.get(key)
6969
7070
// Entri segar menang, yang lama dibuang
@@ -96,4 +96,4 @@ Dua kasus menuntut lebih dari map lokal-proses. Sebuah cache yang harus bertahan
9696

9797
## Berbagi Per-Request
9898

99-
Caching lintas request adalah satu kebutuhan, mengoper sebuah nilai sepanjang satu request adalah kebutuhan lain. Sebuah nilai yang dihitung di middleware dan dibaca handler tak masuk cache sama sekali, ia masuk [`ctx.state`](/id/core-concepts/context-object#berbagi-state), yang hidup persis satu request dan hilang saat response dikirim.
99+
Caching lintas request adalah satu kebutuhan, mengoper sebuah nilai sepanjang satu request adalah kebutuhan lain. Sebuah nilai yang dihitung di middleware dan dibaca handler tak masuk cache sama sekali. Untuk identitas per-pengguna [session](/id/middleware/session) bertanda tangan membawanya lewat `ctx.set.session()` dan `ctx.get.session()`, dan untuk input tervalidasi [middleware validate](/id/middleware/validation/overview) menyerahkannya lewat `ctx.get.validated()`. Apa pun selain itu handler turunkan ulang dari request yang sudah dipegangnya.

docs/id/by-design/compress.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ import type { Context } from '@neabyte/deserve'
5757
// ---cut---
5858
export function GET(ctx: Context): Response {
5959
// Larang lapisan apa pun menulis ulang body
60-
ctx.setHeader('Cache-Control', 'no-transform')
60+
ctx.set.header('Cache-Control', 'no-transform')
6161
return ctx.send.json({
6262
message: 'sent verbatim'
6363
})
6464
}
6565
```
6666

67-
Mengatur header lewat [`ctx.setHeader`](/id/core-concepts/context-object#header-response) adalah jalur yang sama dipakai di tempat lain, jadi opt-out ini terbaca seperti header lain.
67+
Mengatur header lewat [`ctx.set.header`](/id/core-concepts/context-object#ctx-set-header-key-value) adalah jalur yang sama dipakai di tempat lain, jadi opt-out ini terbaca seperti header lain.
6868

6969
## Body yang Sudah Ter-encode
7070

docs/id/by-design/https-redirect.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ await router.serve(8000)
3838

3939
## Membaca Skema Asli
4040

41-
Ketika aplikasi memang perlu tahu apakah klien memakai HTTPS, jawabannya ada di header forwarded yang diatur proxy, bukan di koneksi lokal. Proxy tepercaya menambahkan [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto), dibaca lewat [`ctx.header`](/id/core-concepts/context-object#akses-data-request).
41+
Ketika aplikasi memang perlu tahu apakah klien memakai HTTPS, jawabannya ada di header forwarded yang diatur proxy, bukan di koneksi lokal. Proxy tepercaya menambahkan [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto), dibaca lewat [`ctx.get.header`](/id/core-concepts/context-object#ctx-get-header-key).
4242

4343
```typescript twoslash
4444
import type { Context } from '@neabyte/deserve'
4545
// ---cut---
4646
export function GET(ctx: Context): Response {
4747
// Skema yang benar-benar dipakai klien
48-
const proto = ctx.header('x-forwarded-proto') ?? 'http'
48+
const proto = ctx.get.header('x-forwarded-proto') ?? 'http'
4949
return ctx.send.json({
5050
secure: proto === 'https'
5151
})
5252
}
5353
```
5454

55-
Percayai header ini hanya di belakang proxy yang dikonfigurasi lewat [`trustProxy`](/id/getting-started/server-configuration#resolusi-ip-klien), batas kepercayaan yang sama diandalkan [`ctx.ip`](/id/by-design/request-id#ip-adalah-sumber-kebenaran). Klien yang tak tepercaya bisa mengatur header apa pun, jadi nilainya tak berarti tanpa batas itu.
55+
Percayai header ini hanya di belakang proxy yang dikonfigurasi lewat [`trustProxy`](/id/getting-started/server-configuration#resolusi-ip-klien), batas kepercayaan yang sama diandalkan [`ctx.get.ip()`](/id/core-concepts/context-object#ctx-get-ip-options). Klien yang tak tepercaya bisa mengatur header apa pun, jadi nilainya tak berarti tanpa batas itu.
5656

5757
## Menyajikan HTTPS Langsung
5858

docs/id/by-design/locale-redirect.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ Pilihan bahasa adalah keputusan produk, bukan aturan transport. Locale mana yang
1414

1515
## Membaca Preferensi
1616

17-
Browser mengirim daftar bahasanya di header [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language), dibaca lewat [`ctx.header`](/id/core-concepts/context-object#akses-data-request). Sebuah pencocokan kecil terhadap locale yang didukung aplikasi memberi targetnya, lalu [`ctx.send.redirect`](/id/response/redirect) mengirim pengunjung ke sana.
17+
Browser mengirim daftar bahasanya di header [`Accept-Language`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language), dibaca lewat [`ctx.get.header`](/id/core-concepts/context-object#ctx-get-header-key). Sebuah pencocokan kecil terhadap locale yang didukung aplikasi memberi targetnya, lalu [`ctx.send.redirect`](/id/response/redirect) mengirim pengunjung ke sana.
1818

1919
```typescript twoslash
2020
import type { Context } from '@neabyte/deserve'
2121
// ---cut---
2222
export function GET(ctx: Context): Response {
2323
// Baca petunjuk bahasa browser
24-
const header = ctx.header('accept-language') ?? ''
24+
const header = ctx.get.header('accept-language') ?? ''
2525
const supported = ['en', 'id']
2626

2727
// Cocokkan locale didukung atau default
@@ -37,7 +37,7 @@ Sebuah 302 menjaga redirect tetap sementara, jadi kunjungan berikutnya tetap bis
3737

3838
## Berbagi Pilihan dengan Rute Berikutnya
3939

40-
Ketika beberapa rute butuh locale yang diresolusi, middleware bisa meresolusinya sekali dan menyimpannya di [`ctx.state`](/id/core-concepts/context-object#berbagi-state) alih-alih redirect, jadi tiap handler membaca nilai yang sama.
40+
Ketika beberapa rute butuh locale yang diresolusi, middleware bisa meresolusinya sekali dan menyimpannya di [session](/id/middleware/session) bertanda tangan alih-alih redirect, jadi tiap handler membaca nilai yang sama lewat `ctx.get.session()`.
4141

4242
```typescript twoslash
4343
import { Router } from '@neabyte/deserve'
@@ -46,15 +46,16 @@ const router = new Router()
4646
// ---cut---
4747
router.use(async (ctx, next) => {
4848
// Resolusi locale sekali per request
49-
const header = ctx.header('accept-language') ?? ''
49+
const header = ctx.get.header('accept-language') ?? ''
5050
const preferred = header.split(',')[0]?.slice(0, 2) ?? 'en'
5151

5252
// Bagikan ke route handler
53-
ctx.state.locale = ['en', 'id'].includes(preferred) ? preferred : 'en'
53+
const locale = ['en', 'id'].includes(preferred) ? preferred : 'en'
54+
await ctx.set.session({ locale })
5455
return await next()
5556
})
5657

5758
await router.serve(8000)
5859
```
5960

60-
Bentuk redirect mengirim pengunjung ke URL terlokalisasi, sementara bentuk state menjaga satu URL dan mengoper locale ke dalam. Keduanya tinggal di file rute polos, jadi aturannya ada di mana bahasa penting dan tak di tempat lain.
61+
Bentuk redirect mengirim pengunjung ke URL terlokalisasi, sementara bentuk session menjaga satu URL dan mengoper locale ke dalam. Keduanya tinggal di file rute polos, jadi aturannya ada di mana bahasa penting dan tak di tempat lain.

docs/id/by-design/method-override.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ Deserve juga merutekan pada `req.method` asli, yang tak bisa ditulis ulang handl
2222

2323
## Setiap Metode Adalah Rute
2424

25-
Sebuah file rute mengekspor satu fungsi per metode, dan namanya adalah metodenya. Tak ada tabel untuk didaftarkan dan tak ada verb untuk diterjemahkan. Sebuah file seperti `items/[id].ts` membaca `id`-nya dari path lewat [`ctx.param`](/id/core-concepts/context-object#akses-data-request).
25+
Sebuah file rute mengekspor satu fungsi per metode, dan namanya adalah metodenya. Tak ada tabel untuk didaftarkan dan tak ada verb untuk diterjemahkan. Sebuah file seperti `items/[id].ts` membaca `id`-nya dari path lewat [`ctx.get.param`](/id/core-concepts/context-object#ctx-get-param-key).
2626

2727
```typescript twoslash
2828
import type { Context } from '@neabyte/deserve'
2929
// ---cut---
3030
// Baca satu item lewat id
3131
export function GET(ctx: Context): Response {
3232
return ctx.send.json({
33-
id: ctx.param('id')
33+
id: ctx.get.param('id')
3434
})
3535
}
3636

@@ -67,7 +67,7 @@ await fetch(
6767
)
6868
```
6969

70-
Membangun stateless atau stateful adalah gerakan yang sama, tinggal tambahkan filenya. Sebuah endpoint REST stateless adalah handler yang membaca request dan membalas, sementara alur stateful menambah [middleware session](/id/middleware/session) dan membaca data per-pengguna dari [`ctx.state`](/id/core-concepts/context-object#berbagi-state). Metodenya tetap asli di kedua jalur, tanpa apa pun untuk disamarkan saat masuk.
70+
Membangun stateless atau stateful adalah gerakan yang sama, tinggal tambahkan filenya. Sebuah endpoint REST stateless adalah handler yang membaca request dan membalas, sementara alur stateful menambah [middleware session](/id/middleware/session) dan membaca data per-pengguna lewat `ctx.get.session()`. Metodenya tetap asli di kedua jalur, tanpa apa pun untuk disamarkan saat masuk.
7171

7272
Sebuah API REST atau RESTful penuh muncul dari sini tanpa konfigurasi tambahan. Verb-nya sudah sejajar dengan aksinya, `GET` untuk membaca, `POST` untuk membuat, `PUT` dan `PATCH` untuk memperbarui, `DELETE` untuk menghapus, jadi sebuah resource hanyalah file rute dengan handler itu. Perilakunya terbaca sama di setiap endpoint, yang membuat seluruh API terasa mulus.
7373

0 commit comments

Comments
 (0)