jskelet 0.5.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/AGENTS.md +18 -13
  2. package/CHANGELOG.md +387 -385
  3. package/README.md +9 -7
  4. package/bin/jskelet.mjs +24 -10
  5. package/docs/01-baslangic.md +4 -3
  6. package/docs/02-mimari.md +4 -3
  7. package/docs/03-routing.md +11 -6
  8. package/docs/04-render-ve-sablonlar.md +35 -43
  9. package/docs/05-islands.md +12 -8
  10. package/docs/07-yapilandirma.md +53 -25
  11. package/docs/08-build.md +40 -18
  12. package/docs/09-dev-araclari.md +5 -1
  13. package/docs/10-dagitim.md +6 -1
  14. package/docs/11-tasima.md +51 -17
  15. package/docs/12-panel-ve-oturum.md +10 -4
  16. package/docs/README.md +7 -5
  17. package/docs/en/01-getting-started.md +4 -3
  18. package/docs/en/02-architecture.md +5 -5
  19. package/docs/en/03-routing.md +12 -7
  20. package/docs/en/04-rendering.md +47 -59
  21. package/docs/en/05-islands.md +13 -8
  22. package/docs/en/07-configuration.md +55 -27
  23. package/docs/en/08-build.md +43 -21
  24. package/docs/en/09-dev-tools.md +6 -1
  25. package/docs/en/10-deployment.md +6 -1
  26. package/docs/en/11-migration.md +51 -16
  27. package/docs/en/12-dashboards-and-sessions.md +9 -4
  28. package/docs/en/README.md +7 -5
  29. package/package.json +49 -14
  30. package/src/build/tasks/client.mjs +91 -10
  31. package/src/build/tasks/icons.mjs +152 -18
  32. package/src/client/index.js +2 -2
  33. package/src/compile/codegen.js +4 -0
  34. package/src/compile/compile-all.js +12 -21
  35. package/src/compile/expr.js +5 -0
  36. package/src/compile/parse.js +64 -8
  37. package/src/compile/resolve.js +3 -0
  38. package/src/config/defaults.js +12 -2
  39. package/src/config/index.js +31 -3
  40. package/src/dev-server.mjs +26 -3
  41. package/src/http/cookies-entry.js +1 -0
  42. package/src/http/cookies.js +18 -0
  43. package/src/logo.png +0 -0
  44. package/src/migrate/apply.mjs +262 -0
  45. package/src/migrate/babel.mjs +79 -0
  46. package/src/migrate/classify.mjs +155 -0
  47. package/src/migrate/config.mjs +126 -0
  48. package/src/migrate/fs-walk.mjs +191 -0
  49. package/src/migrate/parse.mjs +26 -0
  50. package/src/migrate/scan.mjs +177 -0
  51. package/src/migrate/transform/expr-source.mjs +168 -0
  52. package/src/migrate/transform/island.mjs +67 -0
  53. package/src/migrate/transform/jsx-to-component.mjs +302 -0
  54. package/src/migrate/transform/jsx-to-jsk.mjs +330 -0
  55. package/src/migrate/transform/page-split.mjs +435 -0
  56. package/src/migrate/write.mjs +81 -0
  57. package/src/migrate.mjs +171 -0
  58. package/src/server/auth/handoff.js +94 -11
  59. package/src/server/create-app.js +28 -10
  60. package/src/server/ejs-adapter.js +59 -0
  61. package/src/server/image-optimizer.js +94 -26
  62. package/src/server/port-guard.js +255 -0
  63. package/src/server/render.js +27 -9
  64. package/src/server/status-page.js +105 -4
  65. package/src/start.mjs +18 -3
  66. package/src/templates/layout.ejs +8 -28
  67. package/src/templates/layout.jsk +30 -0
  68. package/src/templates/layout.render.js +41 -0
  69. package/src/views/helpers/tags.js +86 -3
  70. package/types/build/resolve-peer.d.mts +13 -0
  71. package/types/client/dom.d.ts +55 -0
  72. package/types/client/form.d.ts +19 -0
  73. package/types/client/index.d.ts +20 -0
  74. package/types/client/registry.d.ts +53 -0
  75. package/types/client/safe-image.d.ts +19 -0
  76. package/types/client/shared-cookie.d.ts +82 -0
  77. package/types/client/store.d.ts +18 -0
  78. package/types/client/swap.d.ts +46 -0
  79. package/types/compile/codegen.d.ts +32 -0
  80. package/types/compile/compile-all.d.ts +42 -0
  81. package/types/compile/errors.d.ts +30 -0
  82. package/types/compile/expr.d.ts +67 -0
  83. package/types/compile/index.d.ts +10 -0
  84. package/types/compile/parse.d.ts +82 -0
  85. package/types/compile/resolve.d.ts +46 -0
  86. package/types/compile/scan-exports.d.ts +9 -0
  87. package/types/config/defaults.d.ts +449 -0
  88. package/types/config/index.d.ts +299 -0
  89. package/types/config/pattern.d.ts +38 -0
  90. package/types/http/control-flow.d.ts +45 -0
  91. package/types/http/cookies-entry.d.ts +5 -0
  92. package/types/http/cookies.d.ts +113 -0
  93. package/types/http/request-cache.d.ts +13 -0
  94. package/types/http/request-context.d.ts +67 -0
  95. package/types/http/shared-cookie.d.ts +73 -0
  96. package/types/index.d.ts +30 -0
  97. package/types/log.d.mts +153 -0
  98. package/types/server/admin/actions.d.ts +16 -0
  99. package/types/server/admin/auth.d.ts +52 -0
  100. package/types/server/admin/event-log.d.ts +38 -0
  101. package/types/server/admin/gate.d.ts +43 -0
  102. package/types/server/admin/inventory.d.ts +40 -0
  103. package/types/server/admin/mount.d.ts +6 -0
  104. package/types/server/admin/router.d.ts +6 -0
  105. package/types/server/admin/snapshot.d.ts +6 -0
  106. package/types/server/assets.d.ts +47 -0
  107. package/types/server/auth/handoff.d.ts +12 -0
  108. package/types/server/cache-deps.d.ts +16 -0
  109. package/types/server/cache-vary.d.ts +30 -0
  110. package/types/server/cloudflare.d.ts +163 -0
  111. package/types/server/create-app.d.ts +25 -0
  112. package/types/server/data-cache.d.ts +116 -0
  113. package/types/server/dev/devtools.d.ts +44 -0
  114. package/types/server/dev/report.d.ts +229 -0
  115. package/types/server/dev/socket.d.ts +17 -0
  116. package/types/server/dev/version-check.d.mts +15 -0
  117. package/types/server/ejs-adapter.d.ts +11 -0
  118. package/types/server/head-hints.d.ts +40 -0
  119. package/types/server/html-cache.d.ts +173 -0
  120. package/types/server/image-optimizer.d.ts +68 -0
  121. package/types/server/logs/access-middleware.d.ts +7 -0
  122. package/types/server/logs/file-sink.d.ts +17 -0
  123. package/types/server/logs/pipeline.d.ts +37 -0
  124. package/types/server/logs/s3-put.d.ts +85 -0
  125. package/types/server/logs/s3-sink.d.ts +26 -0
  126. package/types/server/metadata.d.ts +38 -0
  127. package/types/server/middleware/compression.d.ts +17 -0
  128. package/types/server/middleware/csrf.d.ts +4 -0
  129. package/types/server/middleware/dev-gate.d.ts +2 -0
  130. package/types/server/middleware/headers.d.ts +2 -0
  131. package/types/server/middleware/redirects.d.ts +2 -0
  132. package/types/server/middleware/static-precompressed.d.ts +5 -0
  133. package/types/server/middleware/trailing-slash.d.ts +11 -0
  134. package/types/server/middleware/upstream-proxy.d.ts +21 -0
  135. package/types/server/og-image.d.ts +149 -0
  136. package/types/server/port-guard.d.ts +50 -0
  137. package/types/server/prewarm.d.ts +128 -0
  138. package/types/server/redis.d.ts +163 -0
  139. package/types/server/render.d.ts +101 -0
  140. package/types/server/router.d.ts +5 -0
  141. package/types/server/status-page.d.ts +24 -0
  142. package/types/server/upstream-limiter.d.ts +123 -0
  143. package/types/server/upstream-tracking.d.ts +42 -0
  144. package/types/shared/cookie-domain.d.ts +29 -0
  145. package/types/templates/layout.render.d.ts +7 -0
  146. package/types/version.d.mts +10 -0
  147. package/types/views/components/loader.d.ts +5 -0
  148. package/types/views/helpers/html.d.ts +39 -0
  149. 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,173 @@
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
+ * @param {string} key
54
+ * @param {number} ttlSeconds 0 → cache yok
55
+ * @param {() => Promise<{ html: string, status: number }>} producer
56
+ * @returns {Promise<{ html: string, status: number, cached: boolean,
57
+ * stale?: boolean, early?: boolean, encoded?: Map<string, Buffer> }>}
58
+ */
59
+ export declare function withHtmlCache(key: string, ttlSeconds: number, producer: () => Promise<{
60
+ html: string;
61
+ status: number;
62
+ }>): Promise<{
63
+ html: string;
64
+ status: number;
65
+ cached: boolean;
66
+ stale?: boolean;
67
+ early?: boolean;
68
+ encoded?: Map<string, Buffer>;
69
+ }>;
70
+ /**
71
+ * Store'u tamamen boşaltır. Dev sunucusu manifest her değiştiğinde bunu
72
+ * çağırır: saklanan HTML artık var olmayan hash'li varlıkları işaret ediyor,
73
+ * yani gerçekten **geçersiz** — bayatlatmak yetmez.
74
+ */
75
+ export declare function clearHtmlCache(): void;
76
+ export declare function getHtmlCacheSize(): number;
77
+ /**
78
+ * Hedefli invalidation: TTL'i beklemeden, ama tüm önbelleği boşaltmadan.
79
+ *
80
+ * Varsayılan **yumuşaktır** (`hard: false`): girdi silinmez, süresi geçmiş
81
+ * sayılır. Bir webhook beş yüz sayfayı birden düşürdüğünde sert silme, tam da
82
+ * içeriğin güncellendiği anda beş yüz soğuk render başlatır ve upstream'i
83
+ * döver. Bayatlatmada ise ziyaretçi eski HTML'i beklemeden alır, tazeleme
84
+ * arkada ve anahtar başına tek seferde koşar. `hard: true` yalnızca eski
85
+ * HTML'in gerçekten geçersiz olduğu durumlar için.
86
+ *
87
+ * Anahtar `yol?query` (isteğe bağlı `vary|` önekiyle) olduğundan eşleştirme
88
+ * **yol kısmına** yapılır: bir yolun bütün query / host varyantları tek
89
+ * çağrıyla düşer.
90
+ *
91
+ * @param {string | RegExp | (string | RegExp)[]} target
92
+ * @param {{ hard?: boolean }} [options]
93
+ * @returns {number} Etkilenen girdi sayısı (uçuştaki render'lar dahil).
94
+ */
95
+ export declare function invalidateHtmlCache(target: string | RegExp | (string | RegExp)[], options?: {
96
+ hard?: boolean;
97
+ }): number;
98
+ /**
99
+ * Verilen veri anahtarlarını render sırasında okumuş sayfaları bayatlatır.
100
+ * `clearDataCache()` bunu çağırır; uygulamanın hiçbir şey bildirmesi gerekmez.
101
+ *
102
+ * Burada **yayın yapılmaz**: çağıran `clearDataCache()` zaten bir
103
+ * `data:clear` olayı yayınlıyor ve uzak node'lar aynı zinciri kendi ters
104
+ * indeksleri üzerinden çalıştırıyor. Ters indeks node'a özel olduğu için
105
+ * doğru olan da bu — bir sayfa yalnızca onu render etmiş node'da kayıtlı.
106
+ *
107
+ * @param {Iterable<string>} dataKeys
108
+ * @returns {number} Etkilenen HTML girdisi sayısı.
109
+ */
110
+ export declare function invalidateHtmlByDependency(dataKeys: Iterable<string>): number;
111
+ /**
112
+ * Tek bir önbellek **anahtarını** düşürür.
113
+ *
114
+ * `invalidateHtmlCache()` yol deseniyle çalışıyor ve bir yolun bütün query
115
+ * varyantlarını birlikte düşürüyor. Yönetim paneli listedeki tek satırı
116
+ * silebilmek istiyor: `/liste?sayfa=2` düşerken `/liste?sayfa=3` sıcak
117
+ * kalmalı. Desen sözdiziminde `?` kaçırılamadığı için ayrı bir yüzey.
118
+ *
119
+ * @param {string} key `yol?query` biçiminde tam anahtar.
120
+ * @returns {boolean} Girdi var mıydı.
121
+ */
122
+ export declare function dropHtmlCacheKey(key: string): boolean;
123
+ /**
124
+ * Invalidate edilmiş ve henüz kimsenin istemediği yolları döner ve kuyruğu
125
+ * boşaltır. Isıtma turu bunları başa alır; iki tur aynı yolu tekrar
126
+ * ısıtmasın diye okuma yıkıcıdır.
127
+ *
128
+ * Vary öneki (`h=…|`) düşülür — HTTP ısıtması yalnızca yolu ister; host
129
+ * ayrımı `prewarm.origins` / istek Host'u ile yapılır.
130
+ *
131
+ * @returns {string[]}
132
+ */
133
+ export declare function takeInvalidatedPaths(): string[];
134
+ /**
135
+ * Dev raporu için önbellek dökümü: hangi sayfa ne kadar HTML tutuyor, ne
136
+ * zaman bayatlıyor, kaç veri anahtarına bağlı. HTML gövdesi dönmez, yalnızca
137
+ * boyutu.
138
+ *
139
+ * @returns {{ key: string, bytes: number, status: number, stale: boolean,
140
+ * expiresIn: number, encodings: string[], deps: number }[]}
141
+ */
142
+ export declare function getHtmlCacheEntries(): {
143
+ key: string;
144
+ bytes: number;
145
+ status: number;
146
+ stale: boolean;
147
+ expiresIn: number;
148
+ encodings: string[];
149
+ deps: number;
150
+ }[];
151
+ /**
152
+ * Yol (query'siz) için taze bir HTML girdisi var mı? Ziyaret ısıtması yalnızca
153
+ * soğuk / bayat hedefleri kuyruğa alır; HIT'leri yeniden çekmez.
154
+ *
155
+ * @param {string} pathname
156
+ * @returns {boolean}
157
+ */
158
+ export declare function isHtmlCacheFresh(pathname: string): boolean;
159
+ /**
160
+ * Erken tazeleme penceresine girmiş (veya TTL'i dolmuş) trafiksiz girdileri
161
+ * soft-bayatlatır ve ısıtma kuyruğuna alır. HTTP ısıtması producer'sız
162
+ * çalıştığı için soft-bayat şart: taze HIT yenileme tetiklemez.
163
+ *
164
+ * @returns {number} İşaretlenen girdi sayısı.
165
+ */
166
+ export declare function sweepEarlyExpiry(): number;
167
+ /**
168
+ * Trafiksiz sayfaların TTL öncesi soft-bayatlatılması. `startPrewarm` açar;
169
+ * `PREWARM=0` iken hiç kurulmaz. `unref` — süreç kapanışını geciktirmez.
170
+ *
171
+ * @returns {void}
172
+ */
173
+ export declare function startEarlyExpirySweep(): void;