jskelet 0.5.5 → 0.6.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 (156) hide show
  1. package/AGENTS.md +19 -15
  2. package/CHANGELOG.md +165 -15
  3. package/README.md +16 -21
  4. package/bin/jskelet.mjs +23 -9
  5. package/docs/01-baslangic.md +4 -3
  6. package/docs/02-mimari.md +10 -4
  7. package/docs/03-routing.md +14 -7
  8. package/docs/04-render-ve-sablonlar.md +60 -43
  9. package/docs/05-islands.md +12 -8
  10. package/docs/06-cache.md +18 -7
  11. package/docs/07-yapilandirma.md +69 -27
  12. package/docs/08-build.md +15 -9
  13. package/docs/09-dev-araclari.md +22 -8
  14. package/docs/10-dagitim.md +14 -13
  15. package/docs/11-tasima.md +51 -17
  16. package/docs/12-panel-ve-oturum.md +10 -4
  17. package/docs/README.md +10 -33
  18. package/docs/en/01-getting-started.md +4 -3
  19. package/docs/en/02-architecture.md +12 -6
  20. package/docs/en/03-routing.md +15 -8
  21. package/docs/en/04-rendering.md +71 -59
  22. package/docs/en/05-islands.md +13 -8
  23. package/docs/en/06-caching.md +21 -7
  24. package/docs/en/07-configuration.md +69 -29
  25. package/docs/en/08-build.md +16 -10
  26. package/docs/en/09-dev-tools.md +24 -8
  27. package/docs/en/10-deployment.md +14 -14
  28. package/docs/en/11-migration.md +51 -16
  29. package/docs/en/12-dashboards-and-sessions.md +9 -4
  30. package/docs/en/README.md +10 -35
  31. package/package.json +48 -13
  32. package/src/build/tasks/client.mjs +91 -10
  33. package/src/build/tasks/icons.mjs +11 -1
  34. package/src/client/index.js +2 -2
  35. package/src/compile/codegen.js +4 -0
  36. package/src/compile/compile-all.js +12 -21
  37. package/src/compile/expr.js +5 -0
  38. package/src/compile/parse.js +64 -8
  39. package/src/compile/resolve.js +3 -0
  40. package/src/config/defaults.js +48 -5
  41. package/src/config/index.js +138 -27
  42. package/src/dev-server.mjs +26 -3
  43. package/src/http/cookies-entry.js +1 -0
  44. package/src/http/cookies.js +18 -0
  45. package/src/logo.png +0 -0
  46. package/src/migrate/apply.mjs +262 -0
  47. package/src/migrate/babel.mjs +79 -0
  48. package/src/migrate/classify.mjs +155 -0
  49. package/src/migrate/config.mjs +126 -0
  50. package/src/migrate/fs-walk.mjs +191 -0
  51. package/src/migrate/parse.mjs +26 -0
  52. package/src/migrate/scan.mjs +177 -0
  53. package/src/migrate/transform/expr-source.mjs +168 -0
  54. package/src/migrate/transform/island.mjs +67 -0
  55. package/src/migrate/transform/jsx-to-component.mjs +302 -0
  56. package/src/migrate/transform/jsx-to-jsk.mjs +330 -0
  57. package/src/migrate/transform/page-split.mjs +435 -0
  58. package/src/migrate/write.mjs +81 -0
  59. package/src/migrate.mjs +171 -0
  60. package/src/server/auth/handoff.js +94 -11
  61. package/src/server/create-app.js +37 -10
  62. package/src/server/ejs-adapter.js +59 -0
  63. package/src/server/html-cache.js +178 -32
  64. package/src/server/image-optimizer.js +94 -26
  65. package/src/server/middleware/dev-gate.js +21 -8
  66. package/src/server/middleware/robots-txt.js +341 -0
  67. package/src/server/port-guard.js +255 -0
  68. package/src/server/prewarm.js +137 -51
  69. package/src/server/render.js +30 -10
  70. package/src/server/status-page.js +105 -4
  71. package/src/start.mjs +18 -3
  72. package/src/templates/layout.ejs +8 -28
  73. package/src/templates/layout.jsk +30 -0
  74. package/src/templates/layout.render.js +41 -0
  75. package/src/views/helpers/tags.js +86 -3
  76. package/types/build/resolve-peer.d.mts +13 -0
  77. package/types/client/dom.d.ts +55 -0
  78. package/types/client/form.d.ts +19 -0
  79. package/types/client/index.d.ts +20 -0
  80. package/types/client/registry.d.ts +53 -0
  81. package/types/client/safe-image.d.ts +19 -0
  82. package/types/client/shared-cookie.d.ts +82 -0
  83. package/types/client/store.d.ts +18 -0
  84. package/types/client/swap.d.ts +46 -0
  85. package/types/compile/codegen.d.ts +32 -0
  86. package/types/compile/compile-all.d.ts +42 -0
  87. package/types/compile/errors.d.ts +30 -0
  88. package/types/compile/expr.d.ts +67 -0
  89. package/types/compile/index.d.ts +10 -0
  90. package/types/compile/parse.d.ts +82 -0
  91. package/types/compile/resolve.d.ts +46 -0
  92. package/types/compile/scan-exports.d.ts +9 -0
  93. package/types/config/defaults.d.ts +477 -0
  94. package/types/config/index.d.ts +304 -0
  95. package/types/config/pattern.d.ts +38 -0
  96. package/types/http/control-flow.d.ts +45 -0
  97. package/types/http/cookies-entry.d.ts +5 -0
  98. package/types/http/cookies.d.ts +113 -0
  99. package/types/http/request-cache.d.ts +13 -0
  100. package/types/http/request-context.d.ts +67 -0
  101. package/types/http/shared-cookie.d.ts +73 -0
  102. package/types/index.d.ts +30 -0
  103. package/types/log.d.mts +153 -0
  104. package/types/server/admin/actions.d.ts +16 -0
  105. package/types/server/admin/auth.d.ts +52 -0
  106. package/types/server/admin/event-log.d.ts +38 -0
  107. package/types/server/admin/gate.d.ts +43 -0
  108. package/types/server/admin/inventory.d.ts +40 -0
  109. package/types/server/admin/mount.d.ts +6 -0
  110. package/types/server/admin/router.d.ts +6 -0
  111. package/types/server/admin/snapshot.d.ts +6 -0
  112. package/types/server/assets.d.ts +47 -0
  113. package/types/server/auth/handoff.d.ts +12 -0
  114. package/types/server/cache-deps.d.ts +16 -0
  115. package/types/server/cache-vary.d.ts +30 -0
  116. package/types/server/cloudflare.d.ts +163 -0
  117. package/types/server/create-app.d.ts +25 -0
  118. package/types/server/data-cache.d.ts +116 -0
  119. package/types/server/dev/devtools.d.ts +44 -0
  120. package/types/server/dev/report.d.ts +229 -0
  121. package/types/server/dev/socket.d.ts +17 -0
  122. package/types/server/dev/version-check.d.mts +15 -0
  123. package/types/server/ejs-adapter.d.ts +11 -0
  124. package/types/server/head-hints.d.ts +40 -0
  125. package/types/server/html-cache.d.ts +207 -0
  126. package/types/server/image-optimizer.d.ts +68 -0
  127. package/types/server/logs/access-middleware.d.ts +7 -0
  128. package/types/server/logs/file-sink.d.ts +17 -0
  129. package/types/server/logs/pipeline.d.ts +37 -0
  130. package/types/server/logs/s3-put.d.ts +85 -0
  131. package/types/server/logs/s3-sink.d.ts +26 -0
  132. package/types/server/metadata.d.ts +38 -0
  133. package/types/server/middleware/compression.d.ts +17 -0
  134. package/types/server/middleware/csrf.d.ts +4 -0
  135. package/types/server/middleware/dev-gate.d.ts +2 -0
  136. package/types/server/middleware/headers.d.ts +2 -0
  137. package/types/server/middleware/redirects.d.ts +2 -0
  138. package/types/server/middleware/robots-txt.d.ts +33 -0
  139. package/types/server/middleware/static-precompressed.d.ts +5 -0
  140. package/types/server/middleware/trailing-slash.d.ts +11 -0
  141. package/types/server/middleware/upstream-proxy.d.ts +21 -0
  142. package/types/server/og-image.d.ts +149 -0
  143. package/types/server/port-guard.d.ts +50 -0
  144. package/types/server/prewarm.d.ts +131 -0
  145. package/types/server/redis.d.ts +163 -0
  146. package/types/server/render.d.ts +101 -0
  147. package/types/server/router.d.ts +5 -0
  148. package/types/server/status-page.d.ts +24 -0
  149. package/types/server/upstream-limiter.d.ts +123 -0
  150. package/types/server/upstream-tracking.d.ts +42 -0
  151. package/types/shared/cookie-domain.d.ts +29 -0
  152. package/types/templates/layout.render.d.ts +7 -0
  153. package/types/version.d.mts +10 -0
  154. package/types/views/components/loader.d.ts +5 -0
  155. package/types/views/helpers/html.d.ts +39 -0
  156. package/types/views/helpers/tags.d.ts +127 -0
@@ -51,7 +51,7 @@ controller data → import edilmiş render(data, helpers) → HTML
51
51
  {/if}
52
52
 
53
53
  {#each items as item, i}
54
- <li data-i="{{ i }}">{{ item }}</li>
54
+ <li :data-i="i">{{ item }}</li>
55
55
  {/each}
56
56
 
57
57
  <Link href="/" text="Home" />
@@ -99,19 +99,30 @@ code --install-extension extensions/vscode-jsk
99
99
 
100
100
  Ayrıntılar uzantı README'sinde.
101
101
 
102
+ ### Yerleşik layout etiketleri
103
+
104
+ `.jsk` ifade dilinde `asset()` / `hasAsset()` çağrılamaz. Layout’ta stylesheet,
105
+ script ve JSON-LD döngüleri için yerleşikler:
106
+
107
+ | Etiket | Props | Çıktı |
108
+ | --- | --- | --- |
109
+ | `Stylesheets` | `styles` | `app.css` + sayfa sheet’leri (`data-jskelet-css`) |
110
+ | `BodyScripts` | `entries`, `devtools`, `devBasePath` | `main.js`, entry’ler, isteğe bağlı overlay |
111
+ | `JsonLd` | `items` (`structuredData`) | `application/ld+json` script’leri |
112
+
102
113
  ### EJS ile birlikte yaşam
103
114
 
104
115
  Aynı `view` id için derlenmiş `.jsk` varsa o kullanılır; yoksa `.ejs` dosyası
105
- EJS ile render edilir. Mevcut uygulamalar değişmeden çalışır. `jskelet init`
106
- yeni iskeleti `.jsk` ile kurar.
116
+ **yalnızca `ejs` peer’i kuruluysa** render edilir. `jskelet init` yeni iskeleti
117
+ `.jsk` ile kurar.
107
118
 
108
- ## EJS motoru (legacy)
119
+ ## EJS motoru (legacy peer)
109
120
 
110
- EJS hâlâ desteklenir. Motor ilk render'da bir kez kurulur; bileşen taraması
111
- dosya sistemine dokunduğu için her istekte yapılamaz ve config yüklenmeden
112
- hesaplanamaz.
121
+ EJS opsiyonel peer bağımlılıktır (`npm i ejs`). `.jsk`-only uygulamalar kurmak
122
+ zorunda değildir. Bir `.ejs` view veya layout istendiğinde paket uygulamadan
123
+ yüklenir; yoksa göç yolunu gösteren bir hata fırlatılır.
113
124
 
114
- Ayarlar:
125
+ Motor ilk EJS render’da bir kez kurulur. Ayarlar:
115
126
 
116
127
  | Ayar | Değer | Sebebi |
117
128
  | --- | --- | --- |
@@ -120,9 +131,7 @@ Ayarlar:
120
131
  | `rmWhitespace` | `true` | çıktı boyutu |
121
132
  | `async` | `true` | şablon içinde `await` kullanılabilir |
122
133
 
123
- Gömülü kullanımlar (test, script) için `resetRenderEngine()` dışa açık: bileşen
124
- dosyaları değişince kaydı yeniler. Dev sunucusu süreci yeniden başlattığı için
125
- normal akışta gerekmez.
134
+ Gömülü kullanımlar (test, script) için `resetRenderEngine()` dışa açık.
126
135
 
127
136
  ## Layout
128
137
 
@@ -130,50 +139,33 @@ normal akışta gerekmez.
130
139
 
131
140
  1. `jskelet.config.mjs` → `layout` verilmişse o kullanılır. Yol, **views
132
141
  dizininin üst dizinine** göre çözülür: `views` varsayılansa
133
- `layout: "views/ozel.ejs"` → `<root>/views/ozel.ejs`.
142
+ `layout: "views/ozel.jsk"` → `<root>/views/ozel.jsk`.
134
143
  2. Verilmemişse `views/layout.jsk` (derlenmiş) varsa o kullanılır.
135
- 3. Yoksa `views/layout.ejs` varsa o kullanılır.
144
+ 3. Yoksa `views/layout.ejs` varsa o kullanılır (EJS peer gerekir).
136
145
  4. O da yoksa framework'ün kendi minimal layout'u kullanılır
137
- (`node_modules/jskelet/src/templates/layout.ejs`, ayrıca
138
- `jskelet/layout` belirteciyle de erişilebilir).
146
+ (`node_modules/jskelet/src/templates/layout.jsk`, `jskelet/layout`;
147
+ legacy kopya `jskelet/layout/ejs`).
139
148
 
140
149
  Üçüncü seçenek yeni bir projenin tek route ile çalışabilmesi için var. Kendi
141
- layout'unuza geçmenin en pratik yolu o dosyayı `views/layout.ejs` olarak
150
+ layout'unuza geçmenin en pratik yolu o dosyayı `views/layout.jsk` olarak
142
151
  kopyalamaktır.
143
152
 
144
153
  ### Framework'ün varsayılan layout'u
145
154
 
146
- ```ejs
155
+ ```jsk
147
156
  <!DOCTYPE html>
148
- <html lang="<%= lang %>">
157
+ <html :lang="lang">
149
158
  <head>
150
159
  <meta charset="utf-8">
151
160
  <meta name="viewport" content="width=device-width, initial-scale=1">
152
- <%- extraHead %>
153
- <% if (hasAsset('app.css')) { %>
154
- <link rel="stylesheet" href="<%= asset('app.css') %>" data-jskelet-css="app.css">
155
- <% } %>
156
- <% styles.forEach(function (sheet) { %>
157
- <% if (hasAsset(sheet)) { %>
158
- <link rel="stylesheet" href="<%= asset(sheet) %>" data-jskelet-css="<%= sheet %>">
159
- <% } %>
160
- <% }); %>
161
- <%- headMeta %>
162
- <% structuredData.forEach(function (item) { %>
163
- <script type="application/ld+json"><%- jsonScript(item) %></script>
164
- <% }); %>
161
+ {{{ extraHead }}}
162
+ <Stylesheets :styles="styles" />
163
+ {{{ headMeta }}}
164
+ <JsonLd :items="structuredData" />
165
165
  </head>
166
- <body class="<%= bodyClass %>">
167
- <%- body %>
168
- <% if (hasAsset('main.js')) { %>
169
- <script type="module" src="<%= asset('main.js') %>"></script>
170
- <% } %>
171
- <% entries.forEach(function (entry) { %>
172
- <script type="module" src="<%= asset(entry) %>"></script>
173
- <% }); %>
174
- <% if (devtools) { %>
175
- <script type="module" src="<%= devBasePath %>/overlay.js"></script>
176
- <% } %>
166
+ <body :class="bodyClass">
167
+ {{{ body }}}
168
+ <BodyScripts :entries="entries" :devtools="devtools" :devBasePath="devBasePath" />
177
169
  </body>
178
170
  </html>
179
171
  ```
@@ -187,7 +179,7 @@ Dikkat edilecek noktalar:
187
179
  sheet'leri de aynı şekilde basılır. Build çalışmadıysa `hasAsset` false olur
188
180
  ve etiket hiç basılmaz.
189
181
  - **`hasAsset` kontrolleri** build eksikken sayfanın 404 veren dosyaları
190
- istememesini sağlar.
182
+ istememesini sağlar (`Stylesheets` / `BodyScripts` içinde).
191
183
  - **Devtools script'i** yalnızca `NODE_ENV=development` iken basılır; prod
192
184
  çıktısında hiç yoktur.
193
185
 
@@ -511,6 +503,31 @@ return {
511
503
  `renderHeadMeta(metadata)` fonksiyonu dışa açıktır; layout dışında (ör. bir
512
504
  fragment ya da e-posta) aynı etiketleri üretmek gerekirse kullanılabilir.
513
505
 
506
+ ## robots.txt
507
+
508
+ `robots.txt`'i uygulama yazar: `public/robots.txt` ya da düz bir route.
509
+ Framework bu gövdeyi değiştirmez; başarılı metin yanıtının **altına** bir
510
+ JSkelet notu ve `Disallow` kuralları ekler. Dosya ya da route yoksa framework
511
+ bir `robots.txt` uydurmaz.
512
+
513
+ Eklenen yollar:
514
+
515
+ - `/_jskelet/` — yönetim paneli, uzak görsel proxy, auth handoff
516
+ - `/__jskelet/` — geliştirme araçları
517
+ - `/_fragment/` — layout'suz parça yanıtları
518
+
519
+ Bu öneklerin dışına taşınmış bir uç da eklenir, ama yalnızca gerçekten
520
+ mount edildiyse: `admin.basePath`, `images.remote.path`,
521
+ `auth.crossSubdomainHandoff.path`. `brand.devBasePath` yalnızca
522
+ development'ta yazılır; production'da o yol uygulamanın kendi sayfası
523
+ olabilir.
524
+
525
+ Not, config'teki marka adıyla başlar (`brand.name`, varsayılan `JSkelet`).
526
+ Alttaki grup `User-agent: *` ile birlikte dosyada adı geçen diğer ajanları
527
+ da tekrarlar. Google, belirli bir ajana ait grubu `*` ile birleştirmez;
528
+ aynı ajanın ikinci grubunu birleştirir. Not dosyada zaten varsa ikinci kez
529
+ eklenmez.
530
+
514
531
  ## Dinamik OG görselleri
515
532
 
516
533
  Next.js `ImageResponse` / `opengraph-image.tsx` karşılığı. JSX yok: kart
@@ -118,25 +118,29 @@ Pratik sonucu: bir modal'ı `hidden` başlatabilirsiniz, island'ı yine bağlan
118
118
  ```
119
119
  client/
120
120
  ├── entries/
121
- │ ├── main.js her sayfada yüklenen ortak bootstrap
121
+ │ ├── main.js her sayfada yüklenen ortak bootstrap (veya main.ts)
122
122
  │ └── chart.js yalnızca isteyen sayfalarda
123
123
  └── islands/
124
- ├── counter.js
124
+ ├── counter.ts .js veya .ts
125
125
  └── chart.js
126
126
  ```
127
127
 
128
- `client/entries/*.js` içindeki **her dosya bir esbuild entry'sidir**. `main.js`
129
- layout tarafından her sayfada yüklenir (manifest'te varsa). Ek entry'ler
130
- yalnızca onları isteyen sayfalarda yüklenir:
128
+ `client/entries/*.{js,ts,mts}` içindeki **her dosya bir esbuild entry'sidir**.
129
+ `main.js` (veya `main.ts`) layout tarafından her sayfada yüklenir (manifest'te
130
+ varsa). Ek entry'ler yalnızca onları isteyen sayfalarda yüklenir. Aynı stem için
131
+ iki uzantı (`main.js` + `main.ts`) build hatasıdır.
131
132
 
132
133
  ```js
133
- // controller
134
+ // controller — manifest anahtarı her zaman *.js kalır
134
135
  return { view: "pages/markets", entries: ["chart.js"] };
135
136
  ```
136
137
 
137
138
  Layout `entries` dizisindeki her adı `asset(entry)` ile çözüp bir
138
- `<script type="module">` basar. Ad manifest anahtarıdır, yani dosya adının
139
- kendisi (`chart.js`), hash'li hâli değil.
139
+ `<script type="module">` basar. Ad manifest anahtarıdır (`chart.js`), kaynak
140
+ dosya `chart.ts` olsa bile hash'siz anahtar `.js` kalır.
141
+
142
+ Paylaşılan `@/lib` modülleri sunucuda da import ediliyorsa **`.js` kalsın** —
143
+ Node runtime `.ts` çözmez; `.ts` yalnızca esbuild client hattında derlenir.
140
144
 
141
145
  Kod bölme (`splitting: true`) açık: iki entry'nin paylaştığı modüller ortak bir
142
146
  chunk'a çıkar ve iki kez indirilmez.
package/docs/06-cache.md CHANGED
@@ -223,7 +223,11 @@ kabul edilebilir, çünkü fiyat gibi canlı alanlar istemcide WebSocket'ten
223
223
  güncelleniyor.
224
224
 
225
225
  Store LRU'dur: erişilen girdi sona taşınır, sınır (`cache().maxEntries`,
226
- varsayılan 500) aşılınca en eski düşürülür.
226
+ varsayılan 500) aşılınca en eski düşürülür. Config 500'ün üstünü isteyebilir;
227
+ **800'ü geçemez** — daha yükseği uyarıyla 800'e çekilir. Bunun yanında süreç
228
+ içi HTML string + sıkıştırılmış gövde **256 MB**'yi geçemez. Sayı tavanının
229
+ altında kalan şişman sayfa veya `vary.host` kopyası da bu bütçede LRU ile
230
+ düşer. Tek sayfa 256 MB'den büyükse saklanmaz; yanıt o istekte yine gider.
227
231
 
228
232
  ## Ne önbelleğe yazılır
229
233
 
@@ -1145,9 +1149,9 @@ export default {
1145
1149
  html: { "/": 60, "/haber/:slug": 300 },
1146
1150
  prewarm: {
1147
1151
  onVisit: {
1148
- perPage: 20, // sayfa başına en fazla link
1149
- concurrency: 2, // opsiyonel
1150
- rps: 4, // opsiyonel; 0 = sınırsız
1152
+ perPage: 20, // sayfa başına en fazla link; tavan 20
1153
+ concurrency: 2, // tavan 2
1154
+ rps: 2, // tavan 2; 0 da 2'ye çekilir
1151
1155
  },
1152
1156
  },
1153
1157
  };
@@ -1163,7 +1167,14 @@ Kurallar:
1163
1167
  `private`, degraded veya `no-store` yanıtlar link çıkarmaz.
1164
1168
  - Isıtma isteğinin kendi UA'sı (`brand.prewarmUserAgent`) tetiklemez — sonsuz
1165
1169
  crawl olmaz.
1166
- - Zaten taze olan yollar kuyruğa girmez.
1170
+ - Zaten taze olan yollar kuyruğa girmez. Anahtar `h=host|/yol?` biçimindedir;
1171
+ kontrol vary önekini ve sondaki `?` işaretini de görür. `vary.host` açıkken
1172
+ yalnızca bu isteğin host'u sıcak sayılır.
1173
+ - Bekleyen kuyruk en fazla 64 yoldur; taşan link bu turda alınmaz.
1174
+ - `perPage` 20, `rps` 2, `concurrency` 2 tavanıdır. Daha yükseği (ve `rps: 0`)
1175
+ uyarıyla tavana çekilir. Isıtma isteği loopback'e gider; `vary.host` açıkken
1176
+ public host `x-forwarded-host` ile taşınır, `h=127.0.0.1` diye ikinci girdi
1177
+ açılmaz.
1167
1178
  - `nofollow`, `target="_blank"`, `data-no-prefetch`, `prewarmSkip` ve
1168
1179
  `navigation.exclude` Speculation Rules ile aynı muafiyetleri paylaşır.
1169
1180
  - Query string ısıtılmaz (varsayılan cache politikası query'yi dinamik sayar).
@@ -1306,8 +1317,8 @@ turlar upstream'e iki kat yük bindirirdi.
1306
1317
  `accept-encoding: br, gzip` başlıklarıyla gider; ikincisi sıkıştırılmış gövdenin
1307
1318
  de önbelleğe girmesi için.
1308
1319
 
1309
- `DEV_TOKEN` ayarlıysa ısıtma token'ı çerez olarak taşır; yoksa dev gate tüm
1310
- sayfalara 404 döner ve önbellek hiç dolmaz.
1320
+ Dev gate açıksa ısıtma token'ı çerez olarak taşır; yoksa gate tüm sayfalara
1321
+ 404 döner ve önbellek hiç dolmaz. `DEV_TOKEN` tek başına gate'i açmaz.
1311
1322
 
1312
1323
  Dev panelindeki istek listesi ve terminal, `prewarmUserAgent` taşıyan istekleri
1313
1324
  filtreler: yüzlerce ısıtma isteği görünümü doldurmasın. İlerleme baloncuğun
@@ -51,7 +51,7 @@ export default {
51
51
  lang: "tr",
52
52
  },
53
53
 
54
- layout: "views/layout.ejs",
54
+ layout: "views/layout.jsk",
55
55
  routes: ["./routes/10-pages.mjs", "./routes/99-catch-all.mjs"],
56
56
  trailingSlash: false,
57
57
 
@@ -208,26 +208,32 @@ session id taşımak için handoff köprüsünü açar.
208
208
 
209
209
  | Alan | Tip | Varsayılan | Anlamı |
210
210
  | --- | --- | --- | --- |
211
- | `crossSubdomainHandoff` | `boolean \| object` | `false` | `true` veya `{ ttlSeconds?, path?, maxValueBytes? }` → `POST /_jskelet/auth/handoff` + `?handoff=` redeem |
211
+ | `crossSubdomainHandoff` | `boolean \| object` | `false` | Açıkken `POST /_jskelet/auth/handoff` + `?handoff=` redeem. Object: `allowedCookieNames` (zorunlu), `ttlSeconds?`, `path?`, `maxValueBytes?`, `maxPendingTickets?`, `maxMintsPerIpPerMinute?` |
212
212
 
213
213
  ```js
214
214
  auth: {
215
- crossSubdomainHandoff: { ttlSeconds: 60 },
215
+ crossSubdomainHandoff: {
216
+ allowedCookieNames: ["sid"],
217
+ ttlSeconds: 60,
218
+ },
216
219
  },
217
220
  ```
218
221
 
219
- Ayrıntı ve `window.name` yedeği: [12-panel-ve-oturum.md](./12-panel-ve-oturum.md).
222
+ Mint uç noktası CSRF middleware'inden **sonra** mount edilir (origin kontrolü).
223
+ Cookie adı allowlist dışındaysa veya RFC 6265 token değilse 400. Ayrıntı:
224
+ [12-panel-ve-oturum.md](./12-panel-ve-oturum.md).
220
225
 
221
226
  ## `layout`
222
227
 
223
228
  **Tip:** `string` — **Varsayılan:** yok (otomatik çözüm)
224
229
 
225
- Layout `.ejs` dosyasının yolu. Verilen değer **views dizininin üst dizinine**
226
- göre çözülür, yani varsayılan `views` ile `"views/ozel.ejs"` →
227
- `<root>/views/ozel.ejs`.
230
+ Layout dosyasının yolu (`.jsk` veya legacy `.ejs`). Verilen değer **views
231
+ dizininin üst dizinine** göre çözülür, yani varsayılan `views` ile
232
+ `"views/ozel.jsk"` → `<root>/views/ozel.jsk`.
228
233
 
229
- Verilmezse sırayla: `views/layout.jsk`, `views/layout.ejs`, yoksa framework'ün
230
- minimal layout'u. Ayrıntı: [04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md).
234
+ Verilmezse sırayla: `views/layout.jsk`, `views/layout.ejs` (legacy), yoksa
235
+ framework'ün `src/templates/layout.jsk` varsayılanı. Ayrıntı:
236
+ [04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md).
231
237
 
232
238
  ## `routes`
233
239
 
@@ -287,14 +293,28 @@ static: {
287
293
  }
288
294
  ```
289
295
 
296
+ ## `devGate`
297
+
298
+ **Tip:** `boolean` — **Varsayılan:** `false`
299
+
300
+ Yayına açılmamış ortamı gizler. **`DEV_TOKEN` tek başına siteyi kilitlemez.**
301
+ Paylaşılan bir task tanımı production'a da aynı değişkeni taşıyabilir; o
302
+ durumda ziyaretçi token vermek zorunda kalmaz, site açık kalır.
303
+
304
+ Gate'i açmak için `devGate: true` ya da `DEV_GATE=1`. İkisi de varken token
305
+ taşımayan isteğe 404 döner. `DEV_GATE=0` config'teki açığı da kapatır. Token
306
+ boşsa gate açık olsa da istekler geçer.
307
+
308
+ Ayrıntı: [09-dev-araclari.md](./09-dev-araclari.md).
309
+
290
310
  ## `devGateBypass`
291
311
 
292
312
  **Tip:** `string[]` — **Varsayılan:**
293
313
  `["/api/healthcheck", "/robots.txt", "/sitemap.xml", "/site.webmanifest", "/favicon.ico"]`
294
314
 
295
315
  Dev gate'in hiçbir koşulda kapatmadığı **tam** yollar (önek değil, birebir
296
- eşleşme). `DEV_TOKEN` ayarlı bir ortamda sağlık kontrolünün ve robots
297
- dosyalarının erişilebilir kalması için. Verilirse varsayılanın yerine geçer.
316
+ eşleşme). Gate açıkken sağlık kontrolünün ve robots dosyalarının erişilebilir
317
+ kalması için. Verilirse varsayılanın yerine geçer.
298
318
 
299
319
  Ayrıntı: [09-dev-araclari.md](./09-dev-araclari.md).
300
320
 
@@ -328,7 +348,7 @@ var.
328
348
  | `trustProxy` | `boolean` | `true` | Express'in `trust proxy` ayarı. Ters proxy arkasında doğru protokol ve istemci IP'si için gerekli. |
329
349
  | `cookieSecret` | `string \| null` | `null` | İmzalı cookie sırrı. Verilmezse `JSKELET_SECRET` okunur. |
330
350
  | `csrf.enabled` | `boolean` | `true` | Origin/`Sec-Fetch-Site` kontrolü. |
331
- | `csrf.token` | `boolean` | `false` | Çift gönderim token'ı katmanı. |
351
+ | `csrf.token` | `boolean` | `false` | Çift gönderim token'ı katmanı. Cookie oturumlu formlarda **açın**. |
332
352
  | `csrf.allowedOrigins` | `string[]` | `[]` | Kendi host'umuzun yanında kabul edilen origin'ler. |
333
353
  | `csrf.exclude` | `string[]` | `[]` | Kontrolden muaf yollar; `source` desen sözdizimi. |
334
354
  | `csrf.cookieName` | `string` | `"csrf_token"` | Token cookie'sinin adı. |
@@ -336,14 +356,17 @@ var.
336
356
  | `csrf.headerName` | `string` | `"x-csrf-token"` | Token'ın kabul edildiği başlık. |
337
357
 
338
358
  `trustProxy` doğrudan internete açık bir sunucuda **kapatılmalı**: açıkken
339
- istemci kendi `X-Forwarded-For` başlığını uydurabilir ve rate limit ile audit
340
- log yanlış adresi görür.
359
+ istemci kendi `X-Forwarded-For` / `X-Forwarded-Proto` / Host başlığını
360
+ uydurabilir; rate limit, admin IP allowlist, Secure cookie ve cache `vary.host`
361
+ yanlış adresi görür. Ters proxy (nginx, Caddy, Cloudflare) arkasındaysa `true`
362
+ doğru varsayılandır.
341
363
 
342
364
  CSRF kontrolü yalnızca çapraz site olduğu **belli** olan istekleri reddeder —
343
365
  `Origin` uyuşmuyorsa ya da `Sec-Fetch-Site: cross-site` geldiyse. İkisi de yoksa
344
366
  istek geçer, çünkü tarayıcılar çapraz origin bir POST'ta `Origin`'i her zaman
345
- gönderirken webhook'lar hiç göndermez. Yine de tarayıcıdan gelmeyen uçları
346
- `csrf.exclude` listesine yazmak niyeti okunur kılıyor.
367
+ gönderirken webhook'lar hiç göndermez. Cookie ile oturum açan panel/form
368
+ uygulamalarında `csrf.token: true` + `csrfField()` ikinci katmandır; webhook
369
+ uçlarını `csrf.exclude` listesine yazın.
347
370
 
348
371
  ## `navigation`
349
372
 
@@ -420,7 +443,9 @@ body > footer { view-transition-name: site-footer; }
420
443
  ::view-transition-new(root) { animation-duration: 180ms; }
421
444
  ```
422
445
 
423
- Çalışan hâli `examples/marketing/styles/globals.css` içinde.
446
+ Çalışan bir örnek için Tailwind `@source` ve view-transition CSS'ini kendi
447
+ uygulamanızın `styles/globals.css` dosyasına taşıyın; yukarıdaki bloklar
448
+ başlangıç noktasıdır.
424
449
 
425
450
  **CSP kullanıyorsanız** kurallar satır içi bir `<script type="speculationrules">`
426
451
  olarak basılır; `script-src` politikanızın buna izin vermesi gerekir.
@@ -540,7 +565,9 @@ icons: {
540
565
 
541
566
  `false` verilirse görsel adımı hiç çalışmaz. Build adımı `sharp` gerektirir ve
542
567
  watch turunda hiç çalışmaz. Remote açıksa `sharp` **runtime**'da da gerekir;
543
- yoksa optimizer kaynak URL'ye 302 yönlendirir. Ayrıntı: [08-build.md](./08-build.md).
568
+ yoksa optimizer kaynak URL'ye 302 yönlendirir. Fetch, redirect'leri otomatik
569
+ takip etmez: her hop `allowHosts` ve private adres kontrolünden geçer.
570
+ Ayrıntı: [08-build.md](./08-build.md).
544
571
 
545
572
  ```js
546
573
  images: {
@@ -573,6 +600,9 @@ clientEnv: ["PUBLIC_WS_URL", "PUBLIC_CDN_ORIGIN"]
573
600
  ```
574
601
 
575
602
  **Buraya gizli anahtar koymayın** — değerler bundle'da düz metin olarak durur.
603
+ İsimlerinde `SECRET`, `PASSWORD`, `TOKEN`, `API_KEY`, `PRIVATE` vb. geçen
604
+ anahtarlar build sırasında **reddeder** (`PUBLIC` / `PUBLISHABLE` içerenler
605
+ muaf).
576
606
 
577
607
  ## `headers()`
578
608
 
@@ -581,7 +611,8 @@ clientEnv: ["PUBLIC_WS_URL", "PUBLIC_CDN_ORIGIN"]
581
611
 
582
612
  Yol desenine göre yanıt başlıkları. Framework yalnızca statik dosyalara uzun
583
613
  ömürlü cache yazar; bunun dışındaki her başlık (CSP, COOP, HSTS,
584
- X-Frame-Options…) buradan gelir ve varsayılanların üstüne biner.
614
+ X-Frame-Options…) buradan gelir ve varsayılanların üstüne biner. Üretim
615
+ sitelerinde en azından aşağıdaki güvenlik başlıklarını tanımlayın.
585
616
 
586
617
  Eşleşen **tüm** kurallar uygulanır (redirect'lerin aksine ilk eşleşmede
587
618
  durulmaz), sırayla; aynı başlığı iki kural yazarsa sonraki kazanır.
@@ -596,11 +627,18 @@ async headers() {
596
627
  source: "/:path*",
597
628
  headers: [
598
629
  { key: "X-Frame-Options", value: "SAMEORIGIN" },
630
+ { key: "X-Content-Type-Options", value: "nosniff" },
599
631
  { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
632
+ {
633
+ key: "Permissions-Policy",
634
+ value: "camera=(), microphone=(), geolocation=()",
635
+ },
600
636
  {
601
637
  key: "Content-Security-Policy",
602
- value: "default-src 'self'; img-src 'self' https://cdn.ornek.com data:",
638
+ value: "default-src 'self'; img-src 'self' https://cdn.ornek.com data:; script-src 'self'",
603
639
  },
640
+ // Yalnızca HTTPS terminasyonu sizin kontrolünüzdeyse:
641
+ // { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains" },
604
642
  ],
605
643
  },
606
644
  {
@@ -733,13 +771,16 @@ HTML önbelleğinin girdi sınırı. Girdi başına yüz kilobayt düştüğü i
733
771
  yükseltmek belleği hızla tüketir; on binlerce yollu bir siteyi buradan çözmeye
734
772
  çalışmak yanlış katman, doğru yer `cache().data`.
735
773
 
774
+ **Tavan 800.** Daha yükseği yüklemede uyarıyla 800'e çekilir. Süreç içi HTML +
775
+ sıkıştırılmış gövde ayrıca 256 MB'yi geçemez; bu bütçe config'den yükseltilmez.
776
+
736
777
  ### `cache().data`
737
778
 
738
779
  Upstream veri önbelleği (`withDataCache`). Ayrıntı: [06-cache.md](./06-cache.md).
739
780
 
740
781
  | Alan | Tip | Varsayılan | Anlamı |
741
782
  | --- | --- | --- | --- |
742
- | `maxEntries` | `number` | `10000` | LRU girdi sınırı. JSON, HTML'e göre onlarca kat küçük olduğu için sınır yüksek. |
783
+ | `maxEntries` | `number` | `10000` | LRU girdi sınırı. JSON, HTML'e göre onlarca kat küçük olduğu için sınır yüksek. **Tavan 20000**; üstü uyarıyla kesilir. |
743
784
  | `staleFactor` | `number` | `10` | TTL dolduktan sonra girdinin kaç TTL boyunca daha kullanılabileceği. `0` → bayat servis yok. |
744
785
 
745
786
  ### `cache().trackUpstream`
@@ -979,13 +1020,13 @@ prewarm: {
979
1020
  | Alan | Tip | Varsayılan | Anlamı |
980
1021
  | --- | --- | --- | --- |
981
1022
  | `onVisit` | `true \| false \| object` | kapalı | Ziyaret tabanlı ısıtma |
982
- | `onVisit.perPage` | `number` | `20` | Sayfa başına üstten alta en fazla link |
983
- | `onVisit.concurrency` | `number` | klasik ile aynı | Paralel işçi |
984
- | `onVisit.rps` | `number` | klasik ile aynı | Saniyedeki tavan; `0` sınırsız |
1023
+ | `onVisit.perPage` | `number` | `20` | Sayfa başına üstten alta en fazla link. **Tavan 20** |
1024
+ | `onVisit.concurrency` | `number` | `2` | Paralel işçi. **Tavan 2** |
1025
+ | `onVisit.rps` | `number` | `2` | Saniyedeki tavan. **Tavan 2**; `0` da 2'ye çekilir |
985
1026
 
986
1027
  ```js
987
1028
  prewarm: {
988
- onVisit: { perPage: 20, rps: 4 },
1029
+ onVisit: { perPage: 20, rps: 2 },
989
1030
  }
990
1031
  ```
991
1032
 
@@ -1081,10 +1122,11 @@ basılmaz.
1081
1122
  | Değişken | Kim okur | Varsayılan | Anlamı |
1082
1123
  | --- | --- | --- | --- |
1083
1124
  | `NODE_ENV` | her yer | `production` (start/build), `development` (dev) | Dev overlay, EJS cache, manifest yeniden okuma, route hata davranışı ve prewarm varsayılanlarını belirler. `jskelet dev` bunu kendisi ayarlar — `cross-env` gerekmez. |
1084
- | `PORT` | `startServer` | `3000` | Dinlenecek port |
1125
+ | `PORT` | `startServer` | `3000` | Dinlenecek port. Doluysa süreç başlamaz; `jskelet start|dev --murder` dinleyiciyi öldürür |
1085
1126
  | `HOST` | `startServer` | `::` | Bağlanılacak arayüz. Varsayılan çift yığın dinler (IPv6 + IPv4); IPv6 yoksa `0.0.0.0`'a düşer |
1086
1127
  | `JSKELET_SECRET` | `jskelet/cookies` | — | İmzalı cookie sırrı. `security.cookieSecret` verilmediğinde buradan okunur; ikisi de yoksa imzalı cookie API'si hata verir. [12](./12-panel-ve-oturum.md) |
1087
- | `DEV_TOKEN` | `devGate`, `prewarm` | — | Ayarlıysa token taşımayan her isteğe 404 döner. Isıtma token'ı çerez olarak taşır. [09](./09-dev-araclari.md) |
1128
+ | `DEV_GATE` | `devGate` | kapalı | `1` gate'i açar, `0` config'te açık olsa da kapatır. `DEV_TOKEN` tek başına açmaz. [09](./09-dev-araclari.md) |
1129
+ | `DEV_TOKEN` | `devGate`, `prewarm` | — | Gate açıkken beklenen sır. Yoksa veya gate kapalıysa site açık kalır. Isıtma, gate açıkken token'ı çerez olarak taşır. [09](./09-dev-araclari.md) |
1088
1130
  | `JSKELET_ADMIN` | `createApp` | — | Ayarlıysa yönetim panelini açar; `0` config'te açık olan paneli kapatır. Env config'i ezer, çünkü panel genelde bir arıza sırasında tek seferlik açılır. [06](./06-cache.md) |
1089
1131
  | `JSKELET_LOG_BUCKET` | `logs.s3` | — | Log hedefi: bucket ya da `bucket/prefix` yolu. Credential ile birlikte varsa sink otomatik açılır |
1090
1132
  | `JSKELET_S3_BUCKET` | `logs.s3` | — | `JSKELET_LOG_BUCKET` yoksa bucket; `JSKELET_S3_KEY_PREFIX` ile birleşir |
package/docs/08-build.md CHANGED
@@ -167,8 +167,9 @@ etmezdi. Değişiklikler 120 ms birleştirilir.
167
167
 
168
168
  ## Client JS — esbuild
169
169
 
170
- `client/entries/*.js` içindeki her `.js` dosyası bir entry'dir. Dizin yoksa ya da
171
- boşsa adım atlanır.
170
+ `client/entries/*.{js,ts,mts}` içindeki her kaynak dosya bir entry'dir (`.tsx`
171
+ yok). Manifest anahtarı her zaman `*.js` olur (`main.ts` → `main.js`). Aynı stem
172
+ için birden fazla uzantı build hatasıdır. Dizin yoksa ya da boşsa adım atlanır.
172
173
 
173
174
  esbuild ayarları:
174
175
 
@@ -178,7 +179,7 @@ esbuild ayarları:
178
179
  | `format` | `esm` | `type="module"` script'ler |
179
180
  | `target` | `chrome111`, `edge111`, `firefox111`, `safari16.4` | ESM + dinamik import + `IntersectionObserver` island modelinin alt sınırı; daha eskisine transpile etmek çıktıyı büyütüp hiçbir ziyaretçi kazandırmıyor |
180
181
  | `minify` | `true` | — |
181
- | `sourcemap` | `true` | Tarayıcıda teşhis |
182
+ | `sourcemap` | yalnızca `NODE_ENV=development` | Prod'da `.map` dosyaları `public/assets` altında yayınlanmaz |
182
183
  | `entryNames` | `[name].[hash]` | `immutable` cache |
183
184
  | `chunkNames` | `chunks/[name].[hash]` | — |
184
185
  | `legalComments` | `none` | — |
@@ -189,16 +190,19 @@ esbuild ayarları:
189
190
  ### `@/` alias'ı
190
191
 
191
192
  esbuild tarafında `@/` proje köküne çözülür ve uzantı tamamlama yapılır
192
- (`.js`, `.mjs`, `.json`, `/index.js`). Node tarafındaki `alias-hooks.mjs` ile
193
- aynı davranış, böylece `lib/` altındaki modüller hem sunucuda hem tarayıcıda
194
- aynı import stilini kullanabilir.
193
+ (`.js`, `.mjs`, `.ts`, `.mts`, `.json`, `/index.js`, `/index.ts`). Node
194
+ `alias-hooks.mjs` sunucuda yalnızca `.js` / `.mjs` / `.json` çözer; paylaşılan
195
+ `@/lib` dosyaları bu yüzden `.js` kalmalıdır. Client-only `.ts` import'ları
196
+ esbuild hattında çalışır.
195
197
 
196
198
  ### `clientEnv` gömülmesi
197
199
 
198
200
  Tarayıcıda `process` yoktur; sunucuyla paylaşılan modüller yine de `process.env`
199
201
  okur. `config.clientEnv` ile bildirilen anahtarlar ve `NODE_ENV` build zamanında
200
202
  tek nesne olarak define edilir, yani listede olmayan bir anahtar okunduğunda
201
- çökme yerine `undefined` döner. Ayrıntı: [07-yapilandirma.md](./07-yapilandirma.md).
203
+ çökme yerine `undefined` döner. İsimleri secret benzeri olan anahtarlar
204
+ (`SECRET`, `API_KEY`, …) build'i düşürür; `PUBLIC` / `PUBLISHABLE` içerenler
205
+ muaf. Ayrıntı: [07-yapilandirma.md](./07-yapilandirma.md).
202
206
 
203
207
  ### Manifest anahtarları
204
208
 
@@ -274,7 +278,7 @@ Yerel dosya adları:
274
278
  (Phosphor ve `icon()` ile uyum için önerilen kutu).
275
279
  - Taranan dizinler varsayılan olarak `views`, `client`, `routes`, `lib`,
276
280
  `features`, `shared`; `icons.scan` ile değiştirilebilir. Taranan uzantılar:
277
- `.ejs`, `.jsk`, `.js`, `.mjs`.
281
+ `.ejs`, `.jsk`, `.js`, `.mjs`, `.ts`, `.mts`.
278
282
  - Ağırlıklar: `thin`, `light`, `regular`, `bold`, `fill`, `duotone`. Tanınmayan
279
283
  bir ağırlık `regular` sayılır.
280
284
 
@@ -339,7 +343,9 @@ orijinal dosyaya döner. Watch turunda hiç çalışmaz.
339
343
  `images.remote.allowHosts` verilirse `createApp` `/_jskelet/image` ucunu
340
344
  mount eder. CMS / CDN kapakları build'e girmediği için `image()` bu host'lardaki
341
345
  URL'leri `?url=&w=` biçiminde yeniden yazar; uç sharp ile webp üretir ve
342
- `.jskelet/image-cache/` altına yazar. Ayrıntı: [07-yapilandirma.md](./07-yapilandirma.md).
346
+ `.jskelet/image-cache/` altına yazar. Upstream fetch redirect'leri elle takip
347
+ edilir: her hop allowlist + private IP / DNS kontrolünden geçer (açık redirect
348
+ SSRF kapalı). Ayrıntı: [07-yapilandirma.md](./07-yapilandirma.md).
343
349
 
344
350
  ## Precompress
345
351
 
@@ -21,6 +21,10 @@ jskelet dev
21
21
  bastırır) ve TTY varsa `JSKELET_COLOR=1` (borulanmış çıktıda renk zorlar)
22
22
  geçirilir.
23
23
 
24
+ Port (`PORT`, varsayılan `3000`) doluysa sunucu **başlamaz**; hata satırında
25
+ PID ve `--murder` ipucu vardır. `jskelet dev --murder` dinleyiciyi öldürüp aynı
26
+ porta bağlanır (başka bir terminalde unutulmuş süreç için).
27
+
24
28
  Açılış sırası: banner → build adımları → sunucu hazır → `Ready` özeti. Özet hem
25
29
  build hem sunucu hazır olduğunda basılır; aksi hâlde arkadan gelen build
26
30
  satırlarının arasında kalıyordu.
@@ -70,7 +74,7 @@ WATCH_DIRS = [
70
74
  Ayrıca `jskelet.config.mjs` dosyasının kendisi izlenir: config değişince hem
71
75
  sunucu hem build yeni ayarlarla açılmalı.
72
76
 
73
- İzlenen uzantılar: `.js`, `.mjs`, `.json`, `.ejs`.
77
+ İzlenen uzantılar: `.js`, `.mjs`, `.json`, `.jsk`, `.ejs`.
74
78
 
75
79
  `views` de izlenir çünkü bileşenlerin çoğu `views/components/**.js` içinde ve bu
76
80
  modüller sunucuya bir kez import edildiği için, restart olmadan yapılan
@@ -294,11 +298,19 @@ hiçbir şey yüklenmez.
294
298
 
295
299
  ## Dev gate — `DEV_TOKEN`
296
300
 
297
- Yayına açılmamış bir ortamı gizlemek için: `DEV_TOKEN` ayarlıyken token
298
- taşımayan **her** isteğe 404 döner.
301
+ Yayına açılmamış bir ortamı gizlemek için. **Framework token'ı zorunlu tutmaz:**
302
+ `DEV_TOKEN` ortamda durması siteyi kilitlemez. Gate'i siz açarsınız.
299
303
 
300
304
  ```bash
301
- DEV_TOKEN=uzun-rastgele-bir-dize npm start
305
+ DEV_GATE=1 DEV_TOKEN=uzun-rastgele-bir-dize npm start
306
+ ```
307
+
308
+ Aynı şey config ile:
309
+
310
+ ```js
311
+ export default {
312
+ devGate: true,
313
+ };
302
314
  ```
303
315
 
304
316
  Erişim:
@@ -318,10 +330,12 @@ Davranış:
318
330
  `/api/healthcheck`, `/robots.txt`, `/sitemap.xml`, `/site.webmanifest`,
319
331
  `/favicon.ico`. Sağlık kontrolünüz farklı bir yolda ise bu listeye eklemeyi
320
332
  unutmayın, aksi hâlde orkestratör 404 görür.
321
- - `DEV_TOKEN` yoksa middleware tamamen devre dışıdır ve üretimde hiçbir maliyeti
322
- olmaz.
323
- - Isıtma kendi sunucusuna istek attığı için token'ı çerez olarak taşır; yoksa tüm
324
- sayfalar 404 alır ve önbellek hiç dolmaz ([06-cache.md](./06-cache.md)).
333
+ - `devGate` kapalıyken (varsayılan) veya `DEV_TOKEN` boşken middleware isteği
334
+ olduğu gibi geçirir. Production task'ına sızmış bir `DEV_TOKEN` ziyaretçiden
335
+ token istemez; açılışta bir uyarı basılır.
336
+ - `DEV_GATE=0` config'te `devGate: true` olsa da gate'i kapatır.
337
+ - Isıtma, gate açıkken token'ı çerez olarak taşır; yoksa tüm sayfalar 404 alır
338
+ ve önbellek hiç dolmaz ([06-cache.md](./06-cache.md)).
325
339
 
326
340
  Gate middleware zincirinde `headers`tan sonra, `redirects`ten **önce** durur:
327
341
  yayına açılmamış bir ortam yönlendirme kurallarını bile dışarıya sızdırmamalı.