jskelet 0.6.2 → 0.6.4

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 (43) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +2 -0
  3. package/docs/02-mimari.md +1 -0
  4. package/docs/04-render-ve-sablonlar.md +9 -3
  5. package/docs/06-cache.md +53 -9
  6. package/docs/07-yapilandirma.md +1208 -1191
  7. package/docs/08-build.md +2 -1
  8. package/docs/10-dagitim.md +16 -6
  9. package/docs/12-panel-ve-oturum.md +2 -1
  10. package/docs/en/02-architecture.md +2 -1
  11. package/docs/en/04-rendering.md +9 -3
  12. package/docs/en/06-caching.md +54 -9
  13. package/docs/en/07-configuration.md +24 -9
  14. package/docs/en/08-build.md +2 -1
  15. package/docs/en/10-deployment.md +17 -6
  16. package/docs/en/12-dashboards-and-sessions.md +2 -1
  17. package/package.json +1 -1
  18. package/src/config/defaults.js +541 -518
  19. package/src/config/index.js +1500 -1456
  20. package/src/init.mjs +2 -0
  21. package/src/server/cache-blob.js +70 -0
  22. package/src/server/cache-control.js +45 -0
  23. package/src/server/data-cache.js +118 -27
  24. package/src/server/disk-cache.js +233 -0
  25. package/src/server/html-cache.js +90 -16
  26. package/src/server/image-optimizer.js +95 -2
  27. package/src/server/logs/file-sink.js +159 -32
  28. package/src/server/logs/pipeline.js +10 -3
  29. package/src/server/middleware/static-precompressed.js +31 -10
  30. package/src/server/og-image.js +17 -4
  31. package/src/server/prewarm.js +25 -1
  32. package/src/server/redis.js +31 -12
  33. package/src/server/render.js +910 -910
  34. package/types/config/defaults.d.ts +21 -1
  35. package/types/config/index.d.ts +14 -0
  36. package/types/server/cache-blob.d.ts +13 -0
  37. package/types/server/cache-control.d.ts +28 -0
  38. package/types/server/data-cache.d.ts +9 -0
  39. package/types/server/disk-cache.d.ts +36 -0
  40. package/types/server/html-cache.d.ts +26 -3
  41. package/types/server/logs/file-sink.d.ts +16 -5
  42. package/types/server/og-image.d.ts +5 -0
  43. package/types/server/redis.d.ts +2 -1
@@ -131,6 +131,12 @@ export declare const CLASSIC_PREWARM_KEYS: string[];
131
131
  * `vary.host` kopyası sayı tavanının altında da RSS'i şişirir.
132
132
  */
133
133
  export declare const DEFAULT_HTML_CACHE_MAX_ENTRIES = 500;
134
+ /**
135
+ * Edge taze penceresi bittikten sonra eski HTML'in sunulacağı süre (saniye).
136
+ * `cache().staleWhileRevalidate`. 0 ise `stale-while-revalidate` direktifi
137
+ * basılmaz. Süreç içi HTML cache'in stale penceresinden bağımsızdır.
138
+ */
139
+ export declare const DEFAULT_STALE_WHILE_REVALIDATE = 60;
134
140
  /** `cache().maxEntries` için sert tavan. Üstü uyarıyla bu değere çekilir. */
135
141
  export declare const HTML_CACHE_MAX_ENTRIES_CEILING = 800;
136
142
  /**
@@ -139,6 +145,17 @@ export declare const HTML_CACHE_MAX_ENTRIES_CEILING = 800;
139
145
  * saklanmaz, yanıt yine gider.
140
146
  */
141
147
  export declare const HTML_CACHE_BYTE_BUDGET: number;
148
+ /**
149
+ * Süreç içi veri önbelleğinin JSON bayt tavanı (64 MB). Sayı tavanı
150
+ * şişman gövdeleri tutmaz; config yükseltemez. Tek değer bütçeden büyükse
151
+ * saklanmaz, çağıran sonucu yine alır.
152
+ */
153
+ export declare const DATA_CACHE_BYTE_BUDGET: number;
154
+ /**
155
+ * Uzak görsel disk önbelleğinin tavanı (256 MB). `.jskelet/image-cache/`
156
+ * bu boyutu aşınca en eski dosya düşer. Config yükseltemez.
157
+ */
158
+ export declare const IMAGE_CACHE_BYTE_BUDGET: number;
142
159
  /** `cache().data.maxEntries` için sert tavan. Uzun kuyruk burada durur, HTML'de değil. */
143
160
  export declare const DATA_CACHE_MAX_ENTRIES_CEILING = 20000;
144
161
  /**
@@ -262,7 +279,10 @@ export declare const DEFAULT_LOGS: {
262
279
  enabled: boolean;
263
280
  /** Proje köküne göre relative. */
264
281
  dir: string;
265
- /** Yalnızca günlük rotasyon. */
282
+ /**
283
+ * Artık kullanılmıyor. Parçalar en fazla 5 dakika durur; alan çözülen
284
+ * config'te durur ki eski okuyucular kırılmasın.
285
+ */
266
286
  rotate: "daily";
267
287
  };
268
288
  s3: {
@@ -45,11 +45,19 @@ export type LogsConfig = {
45
45
  * Sink'lere giden kayıt türleri.
46
46
  */
47
47
  kinds: LogKind[];
48
+ /**
49
+ * `rotate` durur; dosya parçaları en fazla 5 dakika tutulur.
50
+ */
48
51
  file: {
49
52
  enabled: boolean;
50
53
  dir: string;
51
54
  rotate: "daily";
52
55
  };
56
+ /**
57
+ * Mühürlenen zstd parçasını uygulamanın seçtiği yere aktarır. Hata
58
+ * siteyi düşürmez.
59
+ */
60
+ drainLog: import('../server/logs/file-sink.js').DrainLog | null;
53
61
  s3: {
54
62
  enabled: boolean;
55
63
  bucket: string | null;
@@ -116,6 +124,12 @@ export type ResolvedConfig = {
116
124
  * HTML önbelleğinin girdi sınırı.
117
125
  */
118
126
  htmlMaxEntries: number;
127
+ /**
128
+ * Edge taze penceresi bittikten sonra
129
+ * eski HTML'in sunulacağı süre (saniye). 0 ise direktif basılmaz. Süreç içi
130
+ * HTML cache'in stale penceresinden bağımsızdır.
131
+ */
132
+ staleWhileRevalidate: number;
119
133
  /**
120
134
  * Upstream veri önbelleği ayarları.
121
135
  */
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Küçük gövde düz `string` döner (çağıran senkron yazabilsin). Büyük gövde
3
+ * brotli bitince çözülen bir Promise.
4
+ *
5
+ * @param {unknown} value
6
+ * @returns {string | Buffer | Promise<string | Buffer> | null}
7
+ */
8
+ export declare function encodeCacheValue(value: unknown): string | Buffer | Promise<string | Buffer> | null;
9
+ /**
10
+ * @param {Buffer | string} raw
11
+ * @returns {unknown}
12
+ */
13
+ export declare function decodeCacheValue(raw: Buffer | string): unknown;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Tarayıcıya `max-age=0`, edge'e `CDN-Cache-Control`.
3
+ *
4
+ * `s-maxage` yazılmaz: Cloudflare `max-age=0` ile birlikte görünce nesneyi
5
+ * EXPIRED sayar. `must-revalidate`, `proxy-revalidate` ve `no-cache` aynı
6
+ * yanıtta stale penceresini keser; burada üretilmez. `s-maxage`'e dönen bir
7
+ * anahtar da yok — o mod aynı EXPIRED sonucunu geri getirir.
8
+ *
9
+ * Süreç içi HTML cache (`X-JSkelet-Cache: STALE`) ayrı katmandır; bu modül
10
+ * ona dokunmaz. Görsel optimizer kendi `max-age` + `stale-while-revalidate`
11
+ * yolunu kullanır.
12
+ */
13
+ /**
14
+ * @param {number} maxAge Edge'in taze penceresi (saniye). HTML'de route TTL.
15
+ * @param {number} staleWhileRevalidate Taze pencere bitince eski kopyanın
16
+ * sunulacağı süre. 0 ise direktif basılmaz.
17
+ * @returns {{ cacheControl: string, cdnCacheControl: string }}
18
+ */
19
+ export declare function edgeCacheControl(maxAge: number, staleWhileRevalidate: number): {
20
+ cacheControl: string;
21
+ cdnCacheControl: string;
22
+ };
23
+ /**
24
+ * @param {import('express').Response} res
25
+ * @param {number} maxAge
26
+ * @param {number} staleWhileRevalidate
27
+ */
28
+ export declare function setEdgeCacheHeaders(res: import('express').Response, maxAge: number, staleWhileRevalidate: number): void;
@@ -2,6 +2,7 @@ export type DataEntry = {
2
2
  value: unknown;
3
3
  expiresAt: number;
4
4
  staleUntil: number;
5
+ bytes: number;
5
6
  };
6
7
  /**
7
8
  * Süreç ömrü boyunca biriken sayaçlar.
@@ -90,6 +91,14 @@ export declare function clearDataCache(prefix?: string): number;
90
91
  export declare function dropDataCacheKey(key: string): boolean;
91
92
  /** @returns {number} */
92
93
  export declare function getDataCacheSize(): number;
94
+ /**
95
+ * Bellek freninin bayt tavanını geçici olarak değiştirir. Testler LRU
96
+ * tahliyesini küçük bir değerle doğrular; `null` üretim tavanına döner.
97
+ *
98
+ * @param {number | null} bytes
99
+ * @returns {void}
100
+ */
101
+ export declare function setDataCacheByteBudget(bytes: number | null): void;
93
102
  /**
94
103
  * Süreç başından beri biriken sayaçlar. `produced` kotaya yazılan tek sayıdır:
95
104
  * geri kalan her şey upstream'e hiç gitmemiş bir okuma.
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @param {string | null} root Mutlak dizin, ya da config yoluna dönmek için `null`.
3
+ */
4
+ export declare function setDiskCacheRootForTests(root: string | null): void;
5
+ /**
6
+ * @param {"html" | "data"} kind
7
+ * @returns {boolean}
8
+ */
9
+ export declare function diskShares(kind: "html" | "data"): boolean;
10
+ /**
11
+ * @param {"html" | "data"} kind
12
+ * @param {string} key
13
+ * @returns {Promise<unknown | null>}
14
+ */
15
+ export declare function diskGetJson(kind: "html" | "data", key: string): Promise<unknown | null>;
16
+ /**
17
+ * Ateşle-unut. Dönüş değeri testler bekleyebilsin diye durur; istek yolu
18
+ * beklemez.
19
+ *
20
+ * @param {"html" | "data"} kind
21
+ * @param {string} key
22
+ * @param {unknown} value
23
+ * @returns {Promise<void>}
24
+ */
25
+ export declare function diskSetJson(kind: "html" | "data", key: string, value: unknown): Promise<void>;
26
+ /**
27
+ * @param {"html" | "data"} kind
28
+ * @param {string[]} keys
29
+ */
30
+ export declare function diskDrop(kind: "html" | "data", keys: string[]): void;
31
+ /**
32
+ * @param {"html" | "data"} kind
33
+ * @param {(key: string) => boolean} [match] Verilmezse türün tamamı silinir.
34
+ * @returns {Promise<number>}
35
+ */
36
+ export declare function diskDropMatching(kind: "html" | "data", match?: (key: string) => boolean): Promise<number>;
@@ -26,8 +26,8 @@
26
26
  * (L1) **birincil kalır**: `read()` senkron, sıkıştırılmış gövdeler girdiyle
27
27
  * birlikte ve tutarlılık makinesi (`tokens`, `purgedDeps`) tek proseste. Redis
28
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.
29
+ * diğer node'lara duyurur. Redis yoksa aynı kayıt `.jskelet/cache/<buildId>/`
30
+ * altına yazılır; bu tek makinenin yeniden açılışını karşılar, kümeyi değil.
31
31
  */
32
32
  export type HtmlEntry = {
33
33
  html: string;
@@ -144,9 +144,10 @@ export declare function dropHtmlCacheKey(key: string): boolean;
144
144
  * açılmaz.
145
145
  *
146
146
  * @param {string} [onlyHost]
147
- * @returns {{ path: string, host: string }[]}
147
+ * @returns {{ key: string, path: string, host: string }[]}
148
148
  */
149
149
  export declare function takeInvalidatedTargets(onlyHost?: string): {
150
+ key: string;
150
151
  path: string;
151
152
  host: string;
152
153
  }[];
@@ -190,11 +191,33 @@ export declare function isHtmlCacheFresh(pathname: string, req?: {
190
191
  headers?: Record<string, unknown>;
191
192
  get?: (name: string) => string | undefined;
192
193
  }): boolean;
194
+ /**
195
+ * Bu anahtarın girdisi hâlâ taze mi? Süre dolumu ısıtması anahtarı bildiği
196
+ * için yol taraması yapmaz. Soft-bayat (`expiresAt === 0`) taze sayılmaz:
197
+ * ziyaretçi arada yenilediyse yeni `expiresAt` taze döner ve HTTP atlanır.
198
+ *
199
+ * @param {string} key
200
+ * @returns {boolean}
201
+ */
202
+ export declare function isHtmlCacheKeyFresh(key: string): boolean;
203
+ /**
204
+ * Girdide en fazla bir sıkıştırılmış gövde durur. Yeni kodlama eskisinin
205
+ * yerini alır; ham HTML kalır. Bayt sayacı `noteHtmlCacheGrowth` ile işlenir.
206
+ *
207
+ * @param {Map<string, Buffer>} encoded
208
+ * @param {string} encoding
209
+ * @param {Buffer} buffer
210
+ * @returns {void}
211
+ */
212
+ export declare function rememberHtmlEncoding(encoded: Map<string, Buffer>, encoding: string, buffer: Buffer): void;
193
213
  /**
194
214
  * Erken tazeleme penceresine girmiş (veya TTL'i dolmuş) trafiksiz girdileri
195
215
  * soft-bayatlatır ve ısıtma kuyruğuna alır. HTTP ısıtması producer'sız
196
216
  * çalıştığı için soft-bayat şart: taze HIT yenileme tetiklemez.
197
217
  *
218
+ * Tur başına en fazla `EARLY_SWEEP_MARK_BUDGET` girdi. Önce süresi en yakın
219
+ * dolacak olan; kota dolunca kalanlar bir sonraki tura kalır.
220
+ *
198
221
  * @returns {number} İşaretlenen girdi sayısı.
199
222
  */
200
223
  export declare function sweepEarlyExpiry(): number;
@@ -1,17 +1,28 @@
1
+ export type LogChunk = {
2
+ body: Buffer;
3
+ encoding: "zstd";
4
+ bytes: number;
5
+ lines: number;
6
+ at: number;
7
+ };
1
8
  export type LogSink = {
2
9
  write: (entry: Record<string, unknown>) => Promise<void>;
3
10
  flush: () => Promise<void>;
4
11
  close: () => Promise<void>;
5
12
  };
13
+ export type DrainLog = (chunk: LogChunk) => void | Promise<void>;
14
+ /** Diskteki parçaların ömrü. Config yükseltemez. */
15
+ export declare const FILE_LOG_RETENTION_MS: number;
6
16
  /**
7
- * @typedef {{ write: (entry: Record<string, unknown>) => Promise<void>,
8
- * flush: () => Promise<void>, close: () => Promise<void> }} LogSink
9
- */
10
- /**
11
- * @param {{ root: string, dir: string }} options
17
+ * @param {{ root: string, dir: string, persist?: boolean,
18
+ * retentionMs?: number, drainLog?: DrainLog | null }} options
19
+ * `persist: false` diske yazmaz; yalnız `drainLog` çağrılır.
12
20
  * @returns {LogSink}
13
21
  */
14
22
  export declare function createFileSink(options: {
15
23
  root: string;
16
24
  dir: string;
25
+ persist?: boolean;
26
+ retentionMs?: number;
27
+ drainLog?: DrainLog | null;
17
28
  }): LogSink;
@@ -94,6 +94,11 @@ export declare function buildOgSvg(options?: OgCardOptions & {
94
94
  export declare function ogImage(options?: OgImageOptions): Promise<OgImageResult>;
95
95
  /**
96
96
  * Express yanıtına OG görseli basar.
97
+ *
98
+ * Varsayılan edge penceresi 86400 / 604800'tür ve HTML TTL'ye bağlı değildir.
99
+ * `cacheControl` verilirse yalnızca `Cache-Control` yazılır;
100
+ * `CDN-Cache-Control` basılmaz.
101
+ *
97
102
  * @param {import('express').Response} res
98
103
  * @param {OgImageOptions} [options]
99
104
  * @returns {Promise<OgImageResult>}
@@ -56,7 +56,8 @@ export declare function cacheKey(kind: "html" | "data", key: string): string;
56
56
  export declare function redisGetJson(key: string): Promise<any | null>;
57
57
  /**
58
58
  * Ateşle-unut yazma. İsteğin yanıt yolunda beklenmez: HTML zaten L1'e
59
- * yazıldı, Redis kopyası yalnızca diğer node'lar için.
59
+ * yazıldı, Redis kopyası yalnızca diğer node'lar için. 1 KB ve üstü gövdeler
60
+ * brotli ile yazılır; okuma düz JSON'u da kabul eder.
60
61
  *
61
62
  * @param {string} key
62
63
  * @param {unknown} value