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
@@ -0,0 +1,116 @@
1
+ export type DataEntry = {
2
+ value: unknown;
3
+ expiresAt: number;
4
+ staleUntil: number;
5
+ };
6
+ /**
7
+ * Süreç ömrü boyunca biriken sayaçlar.
8
+ *
9
+ * Isıtma turunun kotayı ne kadar harcadığı ancak buradan görülüyor: tur
10
+ * bittiğinde `produced` kaç gerçek upstream çağrısı yapıldığını, `hits` kaçının
11
+ * hiç gitmediğini söyler. Oran düşükse çözüm hız freni değil, TTL'i uzatmak —
12
+ * fren çağrıları yavaşlatır, sayısını azaltmaz.
13
+ */
14
+ declare const stats: {
15
+ /** Taze girdiden servis edildi. */
16
+ hits: number;
17
+ /** Bayat girdiden servis edildi; tazeleme arkada koştu. */
18
+ stale: number;
19
+ /** Girdi yoktu, çağıran bekledi. */
20
+ misses: number;
21
+ /** Aynı anahtarı eşzamanlı isteyen çağrılar tek üretime düştü. */
22
+ coalesced: number;
23
+ /** Paylaşımlı kademeden geldi; upstream'e gitmedi. */
24
+ shared: number;
25
+ /** `producer` gerçekten çalıştı — kotaya yazılan tek sayı. */
26
+ produced: number;
27
+ /** `ttlSeconds: 0` ile önbellek tamamen atlandı. */
28
+ bypassed: number;
29
+ };
30
+ /**
31
+ * Veriyi önbellekten döner, gerekiyorsa `producer` ile üretir.
32
+ *
33
+ * @param {string} key Anahtar tamamen uygulamanın; sürüm/dil gibi ayrımlar
34
+ * anahtara yazılır (`quote:v2:${symbol}`).
35
+ * @param {number} ttlSeconds 0 → önbellek yok, `producer` her çağrıda çalışır.
36
+ * @param {() => Promise<T>} producer
37
+ * @param {{ storeEmpty?: boolean, staleFactor?: number }} [options]
38
+ * `storeEmpty` boş cevabı da saklar, `staleFactor` bu anahtar için bayat
39
+ * penceresini ayarlar (0 → bayat servis yok).
40
+ * @returns {Promise<T>}
41
+ * @template T
42
+ */
43
+ export declare function withDataCache<T>(key: string, ttlSeconds: number, producer: () => Promise<T>, options?: {
44
+ storeEmpty?: boolean;
45
+ staleFactor?: number;
46
+ }): Promise<T>;
47
+ /**
48
+ * `withDataCache`'in fonksiyon sarmalayıcısı: argümanlardan anahtar üretir.
49
+ * `cache()` (istek içi memoizasyon) ile aynı kullanım biçimi, ama istekler
50
+ * arasında ve TTL'li.
51
+ *
52
+ * @param {F} fn
53
+ * @param {{ key: string, revalidate: number, storeEmpty?: boolean,
54
+ * staleFactor?: number }} options `key` önektir; argümanlar sonuna eklenir.
55
+ * @returns {F}
56
+ * @template {(...args: any[]) => Promise<any>} F
57
+ */
58
+ export declare function dataCache<F extends (...args: any[]) => Promise<any>>(fn: F, options: {
59
+ key: string;
60
+ revalidate: number;
61
+ storeEmpty?: boolean;
62
+ staleFactor?: number;
63
+ }): F;
64
+ /**
65
+ * Bir anahtarı ya da önek eşleşen tüm anahtarları düşürür. Webhook ile
66
+ * "bu haber güncellendi" bilgisi geldiğinde kullanılır.
67
+ *
68
+ * Düşen anahtarları **render sırasında okumuş** HTML girdileri de bayatlar:
69
+ * uygulamanın ayrıca `invalidateHtmlCache()` çağırması gerekmez ve aynı veriyi
70
+ * gösteren liste sayfalarını unutmak mümkün değildir (bkz. `cache-deps.js`).
71
+ *
72
+ * `cache.redis` açıkken çağrı ayrıca paylaşımlı kademeden siler ve diğer
73
+ * node'lara duyurulur — bugün bir webhook yalnızca isteği alan node'un
74
+ * önbelleğini tazeliyor, diğerleri TTL'i bekliyordu.
75
+ *
76
+ * @param {string} [prefix] Verilmezse tüm önbellek boşaltılır.
77
+ * @returns {number} Silinen girdi sayısı.
78
+ */
79
+ export declare function clearDataCache(prefix?: string): number;
80
+ /**
81
+ * Tek bir veri anahtarını düşürür.
82
+ *
83
+ * `clearDataCache()` **önek** eşleştiriyor: `quote:v2:AAPL` verildiğinde
84
+ * `quote:v2:AAPLX` de düşer. Yönetim panelinde listeden seçilen satır tam
85
+ * olarak o anahtar olmalı, komşusu değil.
86
+ *
87
+ * @param {string} key
88
+ * @returns {boolean} Girdi var mıydı.
89
+ */
90
+ export declare function dropDataCacheKey(key: string): boolean;
91
+ /** @returns {number} */
92
+ export declare function getDataCacheSize(): number;
93
+ /**
94
+ * Süreç başından beri biriken sayaçlar. `produced` kotaya yazılan tek sayıdır:
95
+ * geri kalan her şey upstream'e hiç gitmemiş bir okuma.
96
+ *
97
+ * @returns {typeof stats & { reads: number, hitRatio: number }}
98
+ * `reads` önbellekten geçen toplam okuma, `hitRatio` bunların kaçının
99
+ * upstream'e gitmediği (0–1).
100
+ */
101
+ export declare function getDataCacheStats(): typeof stats & {
102
+ reads: number;
103
+ hitRatio: number;
104
+ };
105
+ /**
106
+ * Dev raporu ve yönetim uçları için döküm. Değerin kendisi dönmez: JSON'un
107
+ * tamamını bir teşhis ucundan dışa vermek istenmez.
108
+ *
109
+ * @returns {{ key: string, stale: boolean, expiresIn: number }[]}
110
+ */
111
+ export declare function getDataCacheEntries(): {
112
+ key: string;
113
+ stale: boolean;
114
+ expiresIn: number;
115
+ }[];
116
+ export {};
@@ -0,0 +1,44 @@
1
+ export type ServerError = {
2
+ id: number;
3
+ level: string;
4
+ message: string;
5
+ stack: string | null;
6
+ url: string | null;
7
+ page: string | null;
8
+ island: string | null;
9
+ details: unknown;
10
+ at: number;
11
+ };
12
+ /**
13
+ * @param {string} level
14
+ * @param {string} message
15
+ * @param {{
16
+ * stack?: string | null,
17
+ * url?: string | null,
18
+ * page?: string | null,
19
+ * island?: string | null,
20
+ * details?: unknown,
21
+ * }} [extra]
22
+ */
23
+ export declare function recordServerError(level: string, message: string, extra?: {
24
+ stack?: string | null;
25
+ url?: string | null;
26
+ page?: string | null;
27
+ island?: string | null;
28
+ details?: unknown;
29
+ }): void;
30
+ /**
31
+ * Dev araçlarını uygulamaya bağlar.
32
+ * @param {import('express').Express} app
33
+ */
34
+ export declare function mountDevtools(app: import('express').Express): void;
35
+ /**
36
+ * Canlı kanalı HTTP sunucusuna bağlar.
37
+ *
38
+ * Express uygulamasına takılamıyor: WebSocket el sıkışması `upgrade` olayında
39
+ * geçiyor ve o olay middleware zincirine hiç uğramıyor. Bu yüzden `listen`
40
+ * sonrası ayrı bir adım.
41
+ *
42
+ * @param {import('node:http').Server} server
43
+ */
44
+ export declare function attachDevSocket(server: import('node:http').Server): void;
@@ -0,0 +1,229 @@
1
+ export type PageReport = {
2
+ url: string;
3
+ title: string | null;
4
+ at: number;
5
+ visits: number;
6
+ metrics: Record<string, number | null>;
7
+ resources: {
8
+ count: number;
9
+ bytes: number;
10
+ byType: Record<string, {
11
+ count: number;
12
+ bytes: number;
13
+ }>;
14
+ };
15
+ islands: {
16
+ total: number;
17
+ ready: number;
18
+ names: string[];
19
+ };
20
+ api: {
21
+ url: string;
22
+ ms: number;
23
+ status: number;
24
+ bytes: number;
25
+ initiator: string;
26
+ }[];
27
+ html: {
28
+ bytes: number | null;
29
+ cache: string | null;
30
+ ms: number | null;
31
+ };
32
+ };
33
+ /** Tarayıcıdan gelen ölçüm paketini saklar. En yeni paket öncekini ezer. */
34
+ export declare function recordPageReport(payload: any): void;
35
+ /** Ölçümler tarayıcı sekmesinde değil sunucuda durur; sıfırlama da buradan. */
36
+ export declare function clearPageReports(): void;
37
+ export type ServerApiCall = {
38
+ url: string;
39
+ host: string;
40
+ method: string;
41
+ status: number;
42
+ ms: number;
43
+ bytes: number;
44
+ at: number;
45
+ error: string | null;
46
+ page: string | null;
47
+ details: unknown;
48
+ };
49
+ export type ApiFailure = {
50
+ url: string;
51
+ method: string;
52
+ status: number;
53
+ ms: number;
54
+ bytes: number;
55
+ error: string | null;
56
+ page: string | null;
57
+ details: unknown;
58
+ };
59
+ /**
60
+ * @typedef {{
61
+ * url: string,
62
+ * method: string,
63
+ * status: number,
64
+ * ms: number,
65
+ * bytes: number,
66
+ * error: string | null,
67
+ * page: string | null,
68
+ * details: unknown,
69
+ * }} ApiFailure
70
+ */
71
+ /**
72
+ * SSR sırasında yapılan dış çağrıları ölçer. `globalThis.fetch` sarılır;
73
+ * yalnızca dev'de çağrıldığı için üretim yolu dokunulmaz kalır.
74
+ *
75
+ * Başarısız cevaplar (4xx/5xx ya da ağ) isteğe bağlı `onFailure` ile
76
+ * overlay hata günlüğüne de düşer — uygulama kendi logger'ıyla stderr'e
77
+ * yazsa bile panel "hangi sayfa hangi API" bilgisini görsün.
78
+ *
79
+ * @param {{ onFailure?: (call: ApiFailure) => void }} [options]
80
+ */
81
+ export declare function trackServerFetch(options?: {
82
+ onFailure?: (call: ApiFailure) => void;
83
+ }): void;
84
+ /**
85
+ * Rapor sayfasının tek veri kaynağı.
86
+ * @param {{ requests: object[], errors: object[] }} devtools
87
+ */
88
+ export declare function buildReport(devtools: {
89
+ requests: object[];
90
+ errors: object[];
91
+ }): {
92
+ generatedAt: number;
93
+ process: {
94
+ pid: number;
95
+ node: string;
96
+ uptime: number;
97
+ memory: {
98
+ rss: number;
99
+ heapUsed: number;
100
+ };
101
+ env: string;
102
+ };
103
+ pages: {
104
+ url: string;
105
+ title: string | null;
106
+ at: number;
107
+ visits: number;
108
+ metrics: Record<string, number | null>;
109
+ resources: {
110
+ count: number;
111
+ bytes: number;
112
+ byType: Record<string, {
113
+ count: number;
114
+ bytes: number;
115
+ }>;
116
+ };
117
+ islands: {
118
+ total: number;
119
+ ready: number;
120
+ names: string[];
121
+ };
122
+ api: {
123
+ url: string;
124
+ ms: number;
125
+ status: number;
126
+ bytes: number;
127
+ initiator: string;
128
+ }[];
129
+ html: {
130
+ bytes: number | null;
131
+ cache: string | null;
132
+ ms: number | null;
133
+ };
134
+ }[];
135
+ serverApi: ServerApiCall[];
136
+ build: {
137
+ available: boolean;
138
+ outputs: {
139
+ file: string;
140
+ entry: any;
141
+ isChunk: boolean;
142
+ bytes: any;
143
+ gzip: number | null;
144
+ brotli: number | null;
145
+ imports: any;
146
+ inputs: {
147
+ source: string;
148
+ bytes: any;
149
+ }[];
150
+ inputCount: number;
151
+ }[];
152
+ groups: {
153
+ name: string;
154
+ bytes: number;
155
+ }[];
156
+ assets: {
157
+ name: string;
158
+ url: string;
159
+ kind: string;
160
+ bytes: number | null;
161
+ gzip: number | null;
162
+ brotli: number | null;
163
+ }[];
164
+ };
165
+ cache: {
166
+ size: number;
167
+ entries: {
168
+ key: string;
169
+ bytes: number;
170
+ status: number;
171
+ stale: boolean;
172
+ expiresIn: number;
173
+ encodings: string[];
174
+ deps: number;
175
+ }[];
176
+ data: number;
177
+ dataStats: {
178
+ hits: number;
179
+ stale: number;
180
+ misses: number;
181
+ coalesced: number;
182
+ shared: number;
183
+ produced: number;
184
+ bypassed: number;
185
+ } & {
186
+ reads: number;
187
+ hitRatio: number;
188
+ };
189
+ redis: {
190
+ enabled: boolean;
191
+ connected: boolean;
192
+ keyPrefix: string;
193
+ buildId: string;
194
+ errors: number;
195
+ bypassed: boolean;
196
+ };
197
+ };
198
+ upstream: {
199
+ host: string;
200
+ rate: number;
201
+ maxRate: number;
202
+ concurrency: number;
203
+ active: number;
204
+ throttled: number;
205
+ rejected: number;
206
+ bypassed: boolean;
207
+ blockedMs: number;
208
+ bypassedMs: number;
209
+ }[];
210
+ prewarm: {
211
+ active: boolean;
212
+ done: number;
213
+ total: number;
214
+ ok: number;
215
+ failed: number;
216
+ startedAt: number | null;
217
+ finishedAt: number | null;
218
+ entries: {
219
+ path: string;
220
+ status: number;
221
+ ms: number;
222
+ bytes: number;
223
+ cache: string | null;
224
+ error: string | null;
225
+ }[];
226
+ };
227
+ requests: object[];
228
+ errors: object[];
229
+ };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * HTTP upgrade isteğini WebSocket bağlantısına çevirir.
3
+ *
4
+ * @param {import('node:http').IncomingMessage} req
5
+ * @param {import('node:net').Socket} socket
6
+ * @param {Buffer} head Node'un istekle birlikte okuduğu artakalan baytlar.
7
+ * @param {(send: (payload: object) => void) => void} onOpen
8
+ * Bağlantı kurulunca çağrılır; ilk paketi göndermek için kullanılır.
9
+ */
10
+ export declare function upgradeToSocket(req: import('node:http').IncomingMessage, socket: import('node:net').Socket, head: Buffer, onOpen: (send: (payload: object) => void) => void): void;
11
+ /**
12
+ * Bağlı tüm panellere gönderir.
13
+ * @param {object} payload
14
+ */
15
+ export declare function broadcastSocket(payload: object): void;
16
+ /** @returns {number} açık panel sayısı */
17
+ export declare function socketCount(): number;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Kontrolü başlatır. Beklenmez; sonuç geldiğinde `versionStatus()` günceldir.
3
+ * `JSKELET_VERSION_CHECK=0` ile tamamen kapatılabilir (çevrimdışı çalışma,
4
+ * kurumsal ağlar).
5
+ */
6
+ export declare function startVersionCheck(): void;
7
+ /**
8
+ * @returns {{ current: string, latest: string | null, outdated: boolean, checkedAt: number | null }}
9
+ */
10
+ export declare function versionStatus(): {
11
+ current: string;
12
+ latest: string | null;
13
+ outdated: boolean;
14
+ checkedAt: number | null;
15
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @returns {Promise<import('ejs')>}
3
+ */
4
+ export declare function loadEjs(): Promise<import('ejs')>;
5
+ /**
6
+ * @param {string} file
7
+ * @param {Record<string, unknown>} data
8
+ * @param {object} options
9
+ * @returns {Promise<string>}
10
+ */
11
+ export declare function renderEjsFile(file: string, data: Record<string, unknown>, options: object): Promise<string>;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * `jskelet.config.mjs` → `preconnect: ["https://cdn.example.com"]`.
3
+ * Üçüncü taraf kaynaklar (görsel CDN'i, API origin'i, font host'u) buraya
4
+ * yazılır. Boş liste geçerli bir yapılandırmadır.
5
+ *
6
+ * @returns {string}
7
+ */
8
+ export declare function preconnectHints(): string;
9
+ /**
10
+ * Speculation Rules gövdesini üretir. `getConfig()`ten ayrı tutulmasının
11
+ * sebebi test edilebilirlik: kural üretimi saf bir dönüşüm.
12
+ *
13
+ * @param {import('../config/index.js').NavigationConfig} navigation
14
+ * @returns {object | null} Hiç kural yoksa `null`.
15
+ */
16
+ export declare function buildSpeculationRules(navigation: import('../config/index.js').NavigationConfig): object | null;
17
+ /**
18
+ * Site içi gezinme ipuçları: Speculation Rules + cross-document view
19
+ * transition. İkisi de her sayfada aynı olduğu için bir kez hesaplanır.
20
+ *
21
+ * Bunlar bilinçli olarak client runtime'ı değil: tarayıcı bağlantı üzerinde
22
+ * duraksamayı, önceliklendirmeyi ve iptali kendisi yönetiyor. Aynı davranışı
23
+ * JS ile yazmak hem daha fazla bayt hem daha kötü bir tahmin demek.
24
+ *
25
+ * @returns {string}
26
+ */
27
+ export declare function navigationHints(): string;
28
+ /**
29
+ * İlk ekrandaki görselin preload'ı. Preconnect'leri layout zaten her sayfaya
30
+ * bastığı için burada tekrarlanmaz.
31
+ *
32
+ * @param {{ href?: string | null, imageSrcSet?: string,
33
+ * imageSizes?: string }} [lcpImage]
34
+ * @returns {string}
35
+ */
36
+ export declare function headHints(lcpImage?: {
37
+ href?: string | null;
38
+ imageSrcSet?: string;
39
+ imageSizes?: string;
40
+ }): string;
@@ -0,0 +1,207 @@
1
+ /**
2
+ * ISR ikamesi: route + query anahtarlı, TTL'li LRU HTML cache.
3
+ *
4
+ * TTL dolduğunda girdi hemen atılmaz: `stale` pencerede eski HTML anında
5
+ * döner ve tazeleme arkada çalışır. Böylece ilk ısıtmadan sonra hiçbir istek
6
+ * render'ı beklemez; buna karşılık HTML'deki veri en fazla `revalidate + bir
7
+ * tazeleme turu` kadar geride olabilir. Fiyat gibi canlı alanlar istemcide
8
+ * WebSocket'ten güncellendiği için bu gecikme ekranda görünmez.
9
+ *
10
+ * TTL dolmadan önce de tazelenir (**erken tazeleme**): son başarılı üretimin
11
+ * süresi (`produceMs`) kadar önden arka plan refresh başlar, böylece yavaş
12
+ * bir sayfa TTL anında hâlâ soğuk render'a düşmez. Trafik yoksa sweeper
13
+ * girdiyi soft-bayatlatır ve ısıtma kuyruğuna alır.
14
+ *
15
+ * TTL'in yanında ikinci bir tazelik kaynağı daha var: **hedefli
16
+ * invalidation**. Bir içerik güncellendiğinde tüm önbelleği boşaltmak
17
+ * (`clearHtmlCache()`) o an sıcak olan her sayfayı soğuk render'a çevirir;
18
+ * TTL'i beklemek ise güncellemeyi dakikalarca geciktirir.
19
+ * `invalidateHtmlCache()` ikisinin arasını açar ve varsayılan davranışı
20
+ * **bayatlatmaktır**: girdi silinmez, süresi geçmiş sayılır. Ziyaretçi eski
21
+ * HTML'i beklemeden alır, tazeleme arkada tek seferde koşar.
22
+ *
23
+ * ## Paylaşımlı kademe
24
+ *
25
+ * `cache.redis` açıkken store'un ikinci bir kademesi olur. Bellek içi store
26
+ * (L1) **birincil kalır**: `read()` senkron, sıkıştırılmış gövdeler girdiyle
27
+ * birlikte ve tutarlılık makinesi (`tokens`, `purgedDeps`) tek proseste. Redis
28
+ * yalnızca L1'de bulunmayan bir yol için render'ı atlatır ve invalidation'ı
29
+ * diğer node'lara duyurur. Redis erişilemez olduğunda bu modül birebir eskisi
30
+ * gibi çalışır.
31
+ */
32
+ export type HtmlEntry = {
33
+ html: string;
34
+ status: number;
35
+ expiresAt: number;
36
+ staleUntil: number;
37
+ encoded: Map<string, Buffer>;
38
+ deps: Set<string>;
39
+ storedAt: number;
40
+ sharedEncodings: number;
41
+ produceMs: number;
42
+ };
43
+ /**
44
+ * Erken tazeleme lead'i: son render süresinin 2 katı (en az 250 ms), TTL'in
45
+ * yarısından fazla olamaz — kısa TTL'lerde sürekli refresh döngüsü olmasın.
46
+ *
47
+ * @param {number} produceMs
48
+ * @param {number} ttlMs
49
+ * @returns {number}
50
+ */
51
+ export declare function earlyRefreshLeadMs(produceMs: number, ttlMs: number): number;
52
+ /**
53
+ * Sıkıştırılmış gövde `install()`'dan sonra, ilk brotli/gzip yanıtında
54
+ * girdinin `encoded` haritasına eklenir. Sayacı delta ile büyütmek, o sıra
55
+ * LRU'dan düşmüş bir haritaya yazınca bir daha inmeyen bir artık bırakır;
56
+ * store'dan yeniden okumak o artığı taşımaz.
57
+ *
58
+ * @returns {void}
59
+ */
60
+ export declare function noteHtmlCacheGrowth(): void;
61
+ /**
62
+ * Bellek freninin bayt tavanını geçici olarak değiştirir. Testler LRU
63
+ * tahliyesini küçük bir değerle doğrular; `null` üretim tavanına döner.
64
+ *
65
+ * @param {number | null} bytes
66
+ * @returns {void}
67
+ */
68
+ export declare function setHtmlCacheByteBudget(bytes: number | null): void;
69
+ /**
70
+ * @param {string} key
71
+ * @param {number} ttlSeconds 0 → cache yok
72
+ * @param {() => Promise<{ html: string, status: number }>} producer
73
+ * @returns {Promise<{ html: string, status: number, cached: boolean,
74
+ * stale?: boolean, early?: boolean, encoded?: Map<string, Buffer> }>}
75
+ */
76
+ export declare function withHtmlCache(key: string, ttlSeconds: number, producer: () => Promise<{
77
+ html: string;
78
+ status: number;
79
+ }>): Promise<{
80
+ html: string;
81
+ status: number;
82
+ cached: boolean;
83
+ stale?: boolean;
84
+ early?: boolean;
85
+ encoded?: Map<string, Buffer>;
86
+ }>;
87
+ /**
88
+ * Store'u tamamen boşaltır. Dev sunucusu manifest her değiştiğinde bunu
89
+ * çağırır: saklanan HTML artık var olmayan hash'li varlıkları işaret ediyor,
90
+ * yani gerçekten **geçersiz** — bayatlatmak yetmez.
91
+ */
92
+ export declare function clearHtmlCache(): void;
93
+ export declare function getHtmlCacheSize(): number;
94
+ /**
95
+ * Hedefli invalidation: TTL'i beklemeden, ama tüm önbelleği boşaltmadan.
96
+ *
97
+ * Varsayılan **yumuşaktır** (`hard: false`): girdi silinmez, süresi geçmiş
98
+ * sayılır. Bir webhook beş yüz sayfayı birden düşürdüğünde sert silme, tam da
99
+ * içeriğin güncellendiği anda beş yüz soğuk render başlatır ve upstream'i
100
+ * döver. Bayatlatmada ise ziyaretçi eski HTML'i beklemeden alır, tazeleme
101
+ * arkada ve anahtar başına tek seferde koşar. `hard: true` yalnızca eski
102
+ * HTML'in gerçekten geçersiz olduğu durumlar için.
103
+ *
104
+ * Anahtar `yol?query` (isteğe bağlı `vary|` önekiyle) olduğundan eşleştirme
105
+ * **yol kısmına** yapılır: bir yolun bütün query / host varyantları tek
106
+ * çağrıyla düşer.
107
+ *
108
+ * @param {string | RegExp | (string | RegExp)[]} target
109
+ * @param {{ hard?: boolean }} [options]
110
+ * @returns {number} Etkilenen girdi sayısı (uçuştaki render'lar dahil).
111
+ */
112
+ export declare function invalidateHtmlCache(target: string | RegExp | (string | RegExp)[], options?: {
113
+ hard?: boolean;
114
+ }): number;
115
+ /**
116
+ * Verilen veri anahtarlarını render sırasında okumuş sayfaları bayatlatır.
117
+ * `clearDataCache()` bunu çağırır; uygulamanın hiçbir şey bildirmesi gerekmez.
118
+ *
119
+ * Burada **yayın yapılmaz**: çağıran `clearDataCache()` zaten bir
120
+ * `data:clear` olayı yayınlıyor ve uzak node'lar aynı zinciri kendi ters
121
+ * indeksleri üzerinden çalıştırıyor. Ters indeks node'a özel olduğu için
122
+ * doğru olan da bu — bir sayfa yalnızca onu render etmiş node'da kayıtlı.
123
+ *
124
+ * @param {Iterable<string>} dataKeys
125
+ * @returns {number} Etkilenen HTML girdisi sayısı.
126
+ */
127
+ export declare function invalidateHtmlByDependency(dataKeys: Iterable<string>): number;
128
+ /**
129
+ * Tek bir önbellek **anahtarını** düşürür.
130
+ *
131
+ * `invalidateHtmlCache()` yol deseniyle çalışıyor ve bir yolun bütün query
132
+ * varyantlarını birlikte düşürüyor. Yönetim paneli listedeki tek satırı
133
+ * silebilmek istiyor: `/liste?sayfa=2` düşerken `/liste?sayfa=3` sıcak
134
+ * kalmalı. Desen sözdiziminde `?` kaçırılamadığı için ayrı bir yüzey.
135
+ *
136
+ * @param {string} key `yol?query` biçiminde tam anahtar.
137
+ * @returns {boolean} Girdi var mıydı.
138
+ */
139
+ export declare function dropHtmlCacheKey(key: string): boolean;
140
+ /**
141
+ * Invalidate edilmiş yollar. Okuma yıkıcıdır; iki tur aynı yolu tekrar
142
+ * ısıtmasın. `onlyHost` verilirse başka host'ların anahtarları kuyrukta
143
+ * kalır — süre dolumu onları kendi host'uyla ısıtır, `127.0.0.1` anahtarı
144
+ * açılmaz.
145
+ *
146
+ * @param {string} [onlyHost]
147
+ * @returns {{ path: string, host: string }[]}
148
+ */
149
+ export declare function takeInvalidatedTargets(onlyHost?: string): {
150
+ path: string;
151
+ host: string;
152
+ }[];
153
+ /**
154
+ * Yol listesi. Vary öneki düşülür; host ayrımı `takeInvalidatedTargets`.
155
+ *
156
+ * @returns {string[]}
157
+ */
158
+ export declare function takeInvalidatedPaths(): string[];
159
+ /**
160
+ * Dev raporu için önbellek dökümü: hangi sayfa ne kadar HTML tutuyor, ne
161
+ * zaman bayatlıyor, kaç veri anahtarına bağlı. HTML gövdesi dönmez, yalnızca
162
+ * boyutu.
163
+ *
164
+ * @returns {{ key: string, bytes: number, status: number, stale: boolean,
165
+ * expiresIn: number, encodings: string[], deps: number }[]}
166
+ */
167
+ export declare function getHtmlCacheEntries(): {
168
+ key: string;
169
+ bytes: number;
170
+ status: number;
171
+ stale: boolean;
172
+ expiresIn: number;
173
+ encodings: string[];
174
+ deps: number;
175
+ }[];
176
+ /**
177
+ * Yol (query'siz) için taze bir HTML girdisi var mı? Ziyaret ısıtması yalnızca
178
+ * soğuk / bayat hedefleri kuyruğa alır; HIT'leri yeniden çekmez.
179
+ *
180
+ * Gerçek anahtar `h=host|/yol?` biçimindedir: düz `store.get(pathname)` hem
181
+ * vary önekini hem sondaki `?` işaretini kaçırır ve sıcak sayfayı yeniden
182
+ * ısıtır. `vary.host` açıkken yalnızca bu isteğin host'u sayılır; diğer
183
+ * locale'in kopyası bu yolu sıcak yapmaz.
184
+ *
185
+ * @param {string} pathname
186
+ * @param {{ headers?: Record<string, unknown>, get?: (name: string) => string | undefined }} [req]
187
+ * @returns {boolean}
188
+ */
189
+ export declare function isHtmlCacheFresh(pathname: string, req?: {
190
+ headers?: Record<string, unknown>;
191
+ get?: (name: string) => string | undefined;
192
+ }): boolean;
193
+ /**
194
+ * Erken tazeleme penceresine girmiş (veya TTL'i dolmuş) trafiksiz girdileri
195
+ * soft-bayatlatır ve ısıtma kuyruğuna alır. HTTP ısıtması producer'sız
196
+ * çalıştığı için soft-bayat şart: taze HIT yenileme tetiklemez.
197
+ *
198
+ * @returns {number} İşaretlenen girdi sayısı.
199
+ */
200
+ export declare function sweepEarlyExpiry(): number;
201
+ /**
202
+ * Trafiksiz sayfaların TTL öncesi soft-bayatlatılması. `startPrewarm` açar;
203
+ * `PREWARM=0` iken hiç kurulmaz. `unref` — süreç kapanışını geciktirmez.
204
+ *
205
+ * @returns {void}
206
+ */
207
+ export declare function startEarlyExpirySweep(): void;