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.
- package/AGENTS.md +19 -15
- package/CHANGELOG.md +165 -15
- package/README.md +16 -21
- package/bin/jskelet.mjs +23 -9
- package/docs/01-baslangic.md +4 -3
- package/docs/02-mimari.md +10 -4
- package/docs/03-routing.md +14 -7
- package/docs/04-render-ve-sablonlar.md +60 -43
- package/docs/05-islands.md +12 -8
- package/docs/06-cache.md +18 -7
- package/docs/07-yapilandirma.md +69 -27
- package/docs/08-build.md +15 -9
- package/docs/09-dev-araclari.md +22 -8
- package/docs/10-dagitim.md +14 -13
- package/docs/11-tasima.md +51 -17
- package/docs/12-panel-ve-oturum.md +10 -4
- package/docs/README.md +10 -33
- package/docs/en/01-getting-started.md +4 -3
- package/docs/en/02-architecture.md +12 -6
- package/docs/en/03-routing.md +15 -8
- package/docs/en/04-rendering.md +71 -59
- package/docs/en/05-islands.md +13 -8
- package/docs/en/06-caching.md +21 -7
- package/docs/en/07-configuration.md +69 -29
- package/docs/en/08-build.md +16 -10
- package/docs/en/09-dev-tools.md +24 -8
- package/docs/en/10-deployment.md +14 -14
- package/docs/en/11-migration.md +51 -16
- package/docs/en/12-dashboards-and-sessions.md +9 -4
- package/docs/en/README.md +10 -35
- package/package.json +48 -13
- package/src/build/tasks/client.mjs +91 -10
- package/src/build/tasks/icons.mjs +11 -1
- package/src/client/index.js +2 -2
- package/src/compile/codegen.js +4 -0
- package/src/compile/compile-all.js +12 -21
- package/src/compile/expr.js +5 -0
- package/src/compile/parse.js +64 -8
- package/src/compile/resolve.js +3 -0
- package/src/config/defaults.js +48 -5
- package/src/config/index.js +138 -27
- package/src/dev-server.mjs +26 -3
- package/src/http/cookies-entry.js +1 -0
- package/src/http/cookies.js +18 -0
- package/src/logo.png +0 -0
- package/src/migrate/apply.mjs +262 -0
- package/src/migrate/babel.mjs +79 -0
- package/src/migrate/classify.mjs +155 -0
- package/src/migrate/config.mjs +126 -0
- package/src/migrate/fs-walk.mjs +191 -0
- package/src/migrate/parse.mjs +26 -0
- package/src/migrate/scan.mjs +177 -0
- package/src/migrate/transform/expr-source.mjs +168 -0
- package/src/migrate/transform/island.mjs +67 -0
- package/src/migrate/transform/jsx-to-component.mjs +302 -0
- package/src/migrate/transform/jsx-to-jsk.mjs +330 -0
- package/src/migrate/transform/page-split.mjs +435 -0
- package/src/migrate/write.mjs +81 -0
- package/src/migrate.mjs +171 -0
- package/src/server/auth/handoff.js +94 -11
- package/src/server/create-app.js +37 -10
- package/src/server/ejs-adapter.js +59 -0
- package/src/server/html-cache.js +178 -32
- package/src/server/image-optimizer.js +94 -26
- package/src/server/middleware/dev-gate.js +21 -8
- package/src/server/middleware/robots-txt.js +341 -0
- package/src/server/port-guard.js +255 -0
- package/src/server/prewarm.js +137 -51
- package/src/server/render.js +30 -10
- package/src/server/status-page.js +105 -4
- package/src/start.mjs +18 -3
- package/src/templates/layout.ejs +8 -28
- package/src/templates/layout.jsk +30 -0
- package/src/templates/layout.render.js +41 -0
- package/src/views/helpers/tags.js +86 -3
- package/types/build/resolve-peer.d.mts +13 -0
- package/types/client/dom.d.ts +55 -0
- package/types/client/form.d.ts +19 -0
- package/types/client/index.d.ts +20 -0
- package/types/client/registry.d.ts +53 -0
- package/types/client/safe-image.d.ts +19 -0
- package/types/client/shared-cookie.d.ts +82 -0
- package/types/client/store.d.ts +18 -0
- package/types/client/swap.d.ts +46 -0
- package/types/compile/codegen.d.ts +32 -0
- package/types/compile/compile-all.d.ts +42 -0
- package/types/compile/errors.d.ts +30 -0
- package/types/compile/expr.d.ts +67 -0
- package/types/compile/index.d.ts +10 -0
- package/types/compile/parse.d.ts +82 -0
- package/types/compile/resolve.d.ts +46 -0
- package/types/compile/scan-exports.d.ts +9 -0
- package/types/config/defaults.d.ts +477 -0
- package/types/config/index.d.ts +304 -0
- package/types/config/pattern.d.ts +38 -0
- package/types/http/control-flow.d.ts +45 -0
- package/types/http/cookies-entry.d.ts +5 -0
- package/types/http/cookies.d.ts +113 -0
- package/types/http/request-cache.d.ts +13 -0
- package/types/http/request-context.d.ts +67 -0
- package/types/http/shared-cookie.d.ts +73 -0
- package/types/index.d.ts +30 -0
- package/types/log.d.mts +153 -0
- package/types/server/admin/actions.d.ts +16 -0
- package/types/server/admin/auth.d.ts +52 -0
- package/types/server/admin/event-log.d.ts +38 -0
- package/types/server/admin/gate.d.ts +43 -0
- package/types/server/admin/inventory.d.ts +40 -0
- package/types/server/admin/mount.d.ts +6 -0
- package/types/server/admin/router.d.ts +6 -0
- package/types/server/admin/snapshot.d.ts +6 -0
- package/types/server/assets.d.ts +47 -0
- package/types/server/auth/handoff.d.ts +12 -0
- package/types/server/cache-deps.d.ts +16 -0
- package/types/server/cache-vary.d.ts +30 -0
- package/types/server/cloudflare.d.ts +163 -0
- package/types/server/create-app.d.ts +25 -0
- package/types/server/data-cache.d.ts +116 -0
- package/types/server/dev/devtools.d.ts +44 -0
- package/types/server/dev/report.d.ts +229 -0
- package/types/server/dev/socket.d.ts +17 -0
- package/types/server/dev/version-check.d.mts +15 -0
- package/types/server/ejs-adapter.d.ts +11 -0
- package/types/server/head-hints.d.ts +40 -0
- package/types/server/html-cache.d.ts +207 -0
- package/types/server/image-optimizer.d.ts +68 -0
- package/types/server/logs/access-middleware.d.ts +7 -0
- package/types/server/logs/file-sink.d.ts +17 -0
- package/types/server/logs/pipeline.d.ts +37 -0
- package/types/server/logs/s3-put.d.ts +85 -0
- package/types/server/logs/s3-sink.d.ts +26 -0
- package/types/server/metadata.d.ts +38 -0
- package/types/server/middleware/compression.d.ts +17 -0
- package/types/server/middleware/csrf.d.ts +4 -0
- package/types/server/middleware/dev-gate.d.ts +2 -0
- package/types/server/middleware/headers.d.ts +2 -0
- package/types/server/middleware/redirects.d.ts +2 -0
- package/types/server/middleware/robots-txt.d.ts +33 -0
- package/types/server/middleware/static-precompressed.d.ts +5 -0
- package/types/server/middleware/trailing-slash.d.ts +11 -0
- package/types/server/middleware/upstream-proxy.d.ts +21 -0
- package/types/server/og-image.d.ts +149 -0
- package/types/server/port-guard.d.ts +50 -0
- package/types/server/prewarm.d.ts +131 -0
- package/types/server/redis.d.ts +163 -0
- package/types/server/render.d.ts +101 -0
- package/types/server/router.d.ts +5 -0
- package/types/server/status-page.d.ts +24 -0
- package/types/server/upstream-limiter.d.ts +123 -0
- package/types/server/upstream-tracking.d.ts +42 -0
- package/types/shared/cookie-domain.d.ts +29 -0
- package/types/templates/layout.render.d.ts +7 -0
- package/types/version.d.mts +10 -0
- package/types/views/components/loader.d.ts +5 -0
- package/types/views/helpers/html.d.ts +39 -0
- 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;
|