jskelet 0.7.2 → 0.7.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.
- package/CHANGELOG.md +10 -0
- package/docs/02-mimari.md +11 -3
- package/docs/04-render-ve-sablonlar.md +32 -3
- package/docs/06-cache.md +35 -16
- package/docs/07-yapilandirma.md +10 -8
- package/docs/08-build.md +5 -2
- package/docs/en/02-architecture.md +10 -3
- package/docs/en/04-rendering.md +36 -4
- package/docs/en/06-caching.md +34 -16
- package/docs/en/07-configuration.md +7 -4
- package/docs/en/08-build.md +7 -4
- package/package.json +1 -1
- package/src/build/tasks/css.mjs +2 -1
- package/src/client/admin/i18n.js +4 -0
- package/src/client/admin/panel.js +8 -2
- package/src/config/defaults.js +10 -2
- package/src/config/index.js +7 -1
- package/src/server/html-cache.js +90 -35
- package/src/server/redis.js +332 -10
- package/src/views/helpers/tags.js +38 -9
- package/types/config/defaults.d.ts +10 -2
- package/types/config/index.d.ts +7 -0
- package/types/server/dev/report.d.ts +2 -0
- package/types/server/redis.d.ts +43 -3
- package/types/views/helpers/tags.d.ts +7 -1
|
@@ -324,28 +324,57 @@ export function toKebab(name) {
|
|
|
324
324
|
* build yokken 404 link'i istememek için. `.jsk` ifade dilinde `asset()` /
|
|
325
325
|
* `hasAsset()` çağrılamadığı için layout bu etiketi kullanır.
|
|
326
326
|
*
|
|
327
|
-
*
|
|
327
|
+
* `blocking` varsayılan `true`: `<link rel="stylesheet">` boyamayı bekletir.
|
|
328
|
+
* Ölçümde bu, sheet geç gelince oluşan CLS'ten daha ucuz. `false` yalnızca
|
|
329
|
+
* açık boolean'dır (`:blocking="false"`); atlamak veya `true` aynı çıktıyı
|
|
330
|
+
* verir.
|
|
331
|
+
*
|
|
332
|
+
* @param {{ styles?: string[], blocking?: boolean }} [props]
|
|
328
333
|
* @returns {string}
|
|
329
334
|
*/
|
|
330
335
|
export function stylesheets(props = {}) {
|
|
331
336
|
const styles = Array.isArray(props.styles) ? props.styles : [];
|
|
337
|
+
const blocking = props.blocking !== false;
|
|
332
338
|
/** @type {string[]} */
|
|
333
339
|
const parts = [];
|
|
334
340
|
|
|
335
|
-
|
|
336
|
-
parts.push(
|
|
337
|
-
`<link rel="stylesheet" href="${esc(asset("app.css"))}" data-jskelet-css="app.css">`,
|
|
338
|
-
);
|
|
339
|
-
}
|
|
341
|
+
pushStylesheet(parts, "app.css", blocking);
|
|
340
342
|
|
|
341
343
|
for (const sheet of styles) {
|
|
342
|
-
if (!sheet
|
|
344
|
+
if (!sheet) continue;
|
|
345
|
+
pushStylesheet(parts, sheet, blocking);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return parts.join("\n ");
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Tek bir manifest anahtarı için stylesheet linki.
|
|
353
|
+
*
|
|
354
|
+
* `blocking: false` iken `media="print"`: eşleşmeyen media tarayıcıda
|
|
355
|
+
* render-blocking sayılmaz, indirme boyamayı bekletmez. `onload` sheet
|
|
356
|
+
* inince `media`'yı `all` yapar. JS kapalıyken `onload` çalışmaz ve link
|
|
357
|
+
* print'te kalır; `<noscript>` içindeki normal link o yolu kapatır.
|
|
358
|
+
*
|
|
359
|
+
* @param {string[]} parts
|
|
360
|
+
* @param {string} name Manifest anahtarı (`app.css`, `home.css`, …)
|
|
361
|
+
* @param {boolean} blocking
|
|
362
|
+
*/
|
|
363
|
+
function pushStylesheet(parts, name, blocking) {
|
|
364
|
+
if (!hasAsset(name)) return;
|
|
365
|
+
|
|
366
|
+
const href = esc(asset(name));
|
|
367
|
+
const id = esc(name);
|
|
368
|
+
if (blocking) {
|
|
343
369
|
parts.push(
|
|
344
|
-
`<link rel="stylesheet" href="${
|
|
370
|
+
`<link rel="stylesheet" href="${href}" data-jskelet-css="${id}">`,
|
|
345
371
|
);
|
|
372
|
+
return;
|
|
346
373
|
}
|
|
347
374
|
|
|
348
|
-
|
|
375
|
+
parts.push(
|
|
376
|
+
`<link rel="stylesheet" href="${href}" media="print" onload="this.media='all'" data-jskelet-css="${id}">\n <noscript><link rel="stylesheet" href="${href}" data-jskelet-css="${id}"></noscript>`,
|
|
377
|
+
);
|
|
349
378
|
}
|
|
350
379
|
|
|
351
380
|
/**
|
|
@@ -260,11 +260,19 @@ export declare const DEFAULT_REDIS: {
|
|
|
260
260
|
/** pub/sub üzerinden invalidation yayını. */
|
|
261
261
|
events: boolean;
|
|
262
262
|
/**
|
|
263
|
-
*
|
|
263
|
+
* Veri, yayın ve SCAN için tek komut tavanı. Önbellek okuması isteği
|
|
264
264
|
* bloklayan bir adım: Redis takıldığında render'a düşmek, ağı beklemekten
|
|
265
|
-
* iyidir.
|
|
265
|
+
* iyidir. HTML gövdesi bu süreye sığmaz; o bağlantının tavanı
|
|
266
|
+
* `htmlCommandTimeoutMs`.
|
|
266
267
|
*/
|
|
267
268
|
commandTimeoutMs: number;
|
|
269
|
+
/**
|
|
270
|
+
* Yalnızca HTML bağlantısı. ioredis `commandTimeout` istemci genelinde
|
|
271
|
+
* olduğu için gövde ayrı bağlantıda durur. Verilmezse 2000: uygulama
|
|
272
|
+
* config'i değiştirmek zorunda kalmasın. Parçalı yazma normalde bunun
|
|
273
|
+
* altında biter; tavan, gövde beklenmedik büyürse diye durur.
|
|
274
|
+
*/
|
|
275
|
+
htmlCommandTimeoutMs: number;
|
|
268
276
|
};
|
|
269
277
|
/**
|
|
270
278
|
* Kalıcı log sink'leri (dosya + S3).
|
package/types/config/index.d.ts
CHANGED
|
@@ -34,7 +34,14 @@ export type RedisConfig = {
|
|
|
34
34
|
* pub/sub invalidation yayını.
|
|
35
35
|
*/
|
|
36
36
|
events: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Veri, yayın ve SCAN tavanı.
|
|
39
|
+
*/
|
|
37
40
|
commandTimeoutMs: number;
|
|
41
|
+
/**
|
|
42
|
+
* Yalnızca HTML bağlantısının tavanı.
|
|
43
|
+
*/
|
|
44
|
+
htmlCommandTimeoutMs: number;
|
|
38
45
|
};
|
|
39
46
|
export type LogKind = "http" | "event" | "error";
|
|
40
47
|
export type LogsConfig = {
|
package/types/server/redis.d.ts
CHANGED
|
@@ -48,6 +48,40 @@ export declare function redisSharesEncoded(): boolean;
|
|
|
48
48
|
* @returns {string}
|
|
49
49
|
*/
|
|
50
50
|
export declare function cacheKey(kind: "html" | "data", key: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* HTML kaydını parçalı yazar. Meta küçük JSON'dur; gövde ham brotli baytıdır
|
|
53
|
+
* (base64 yok, JSON içinde ikinci brotli yok). `encoded` varsa her kodlama
|
|
54
|
+
* `:enc:` anahtarına olduğu gibi gider.
|
|
55
|
+
*
|
|
56
|
+
* Ateşle-unut ve tek sayaç adımı: üç SET'ten biri düşerse bu bir hatadır,
|
|
57
|
+
* veri devre kesicisine yazılmaz.
|
|
58
|
+
*
|
|
59
|
+
* @param {string} key Önbellek anahtarı (`yol?query`), öneksiz.
|
|
60
|
+
* @param {Record<string, unknown>} meta
|
|
61
|
+
* @param {Buffer} body
|
|
62
|
+
* @param {Map<string, Buffer> | null} encoded
|
|
63
|
+
* @param {number} ttlMs
|
|
64
|
+
*/
|
|
65
|
+
export declare function redisShareHtml(key: string, meta: Record<string, unknown>, body: Buffer, encoded: Map<string, Buffer> | null, ttlMs: number): void;
|
|
66
|
+
/**
|
|
67
|
+
* Meta + gövde (+ açıksa kodlamalar) tek pipeline. Parça eksikse kayıt yok
|
|
68
|
+
* sayılır; bu bir hata değildir. Bağlantı hatası HTML sayacına yazılır.
|
|
69
|
+
*
|
|
70
|
+
* @param {string} key Önbellek anahtarı (`yol?query`), öneksiz.
|
|
71
|
+
* @returns {Promise<{ html: string, status: unknown, storedAt: unknown,
|
|
72
|
+
* expiresAt: unknown, staleUntil: unknown, produceMs: unknown, deps: unknown,
|
|
73
|
+
* encoded: Map<string, Buffer> } | null>}
|
|
74
|
+
*/
|
|
75
|
+
export declare function redisGetHtml(key: string): Promise<{
|
|
76
|
+
html: string;
|
|
77
|
+
status: unknown;
|
|
78
|
+
storedAt: unknown;
|
|
79
|
+
expiresAt: unknown;
|
|
80
|
+
staleUntil: unknown;
|
|
81
|
+
produceMs: unknown;
|
|
82
|
+
deps: unknown;
|
|
83
|
+
encoded: Map<string, Buffer>;
|
|
84
|
+
} | null>;
|
|
51
85
|
/**
|
|
52
86
|
* @param {string} key
|
|
53
87
|
* @returns {Promise<any | null>} Girdi yoksa, ayrıştırılamıyorsa ya da Redis
|
|
@@ -85,7 +119,8 @@ export declare function redisDropMatching(kind: "html" | "data", match?: (key: s
|
|
|
85
119
|
* Dev raporu için durum özeti. Bağlantı yoksa da güvenle çağrılabilir.
|
|
86
120
|
*
|
|
87
121
|
* @returns {{ enabled: boolean, connected: boolean, keyPrefix: string,
|
|
88
|
-
* buildId: string, errors: number, bypassed: boolean
|
|
122
|
+
* buildId: string, errors: number, bypassed: boolean, htmlErrors: number,
|
|
123
|
+
* htmlBypassed: boolean }}
|
|
89
124
|
*/
|
|
90
125
|
export declare function getRedisStatus(): {
|
|
91
126
|
enabled: boolean;
|
|
@@ -94,6 +129,8 @@ export declare function getRedisStatus(): {
|
|
|
94
129
|
buildId: string;
|
|
95
130
|
errors: number;
|
|
96
131
|
bypassed: boolean;
|
|
132
|
+
htmlErrors: number;
|
|
133
|
+
htmlBypassed: boolean;
|
|
97
134
|
};
|
|
98
135
|
/**
|
|
99
136
|
* Bağlantının **nereye** kurulduğu ve hangi ayarlarla çalıştığı.
|
|
@@ -106,7 +143,7 @@ export declare function getRedisStatus(): {
|
|
|
106
143
|
* @returns {{ address: string, secure: boolean, db: string | null,
|
|
107
144
|
* namespace: string, keyPrefix: string, html: boolean, data: boolean,
|
|
108
145
|
* storeEncoded: boolean, events: boolean, commandTimeoutMs: number,
|
|
109
|
-
* subscribed: boolean }}
|
|
146
|
+
* htmlCommandTimeoutMs: number, subscribed: boolean }}
|
|
110
147
|
*/
|
|
111
148
|
export declare function getRedisDetails(): {
|
|
112
149
|
address: string;
|
|
@@ -119,6 +156,7 @@ export declare function getRedisDetails(): {
|
|
|
119
156
|
storeEncoded: boolean;
|
|
120
157
|
events: boolean;
|
|
121
158
|
commandTimeoutMs: number;
|
|
159
|
+
htmlCommandTimeoutMs: number;
|
|
122
160
|
subscribed: boolean;
|
|
123
161
|
};
|
|
124
162
|
/**
|
|
@@ -152,8 +190,10 @@ export declare function disconnectRedis(): Promise<void>;
|
|
|
152
190
|
*
|
|
153
191
|
* @param {any} fake `null` → katman kapatılır.
|
|
154
192
|
* @param {Partial<RedisConfig>} [overrides]
|
|
193
|
+
* @param {any} [htmlFake] Verilmezse `fake` hem veri hem HTML istemcisidir.
|
|
194
|
+
* HTML zaman aşımını veri sayacından ayırmak için ayrı bir sahte verilir.
|
|
155
195
|
*/
|
|
156
|
-
export declare function setRedisClientForTests(fake: any, overrides?: Partial<RedisConfig
|
|
196
|
+
export declare function setRedisClientForTests(fake: any, overrides?: Partial<RedisConfig>, htmlFake?: any): void;
|
|
157
197
|
/**
|
|
158
198
|
* Testler için: abone kanalından gelmiş gibi olay besler. `originId`
|
|
159
199
|
* verilmezse uzak bir node varsayılır; kendi kimliğini taşıyan bir yayını
|
|
@@ -102,11 +102,17 @@ export declare function toKebab(name: string): string;
|
|
|
102
102
|
* build yokken 404 link'i istememek için. `.jsk` ifade dilinde `asset()` /
|
|
103
103
|
* `hasAsset()` çağrılamadığı için layout bu etiketi kullanır.
|
|
104
104
|
*
|
|
105
|
-
*
|
|
105
|
+
* `blocking` varsayılan `true`: `<link rel="stylesheet">` boyamayı bekletir.
|
|
106
|
+
* Ölçümde bu, sheet geç gelince oluşan CLS'ten daha ucuz. `false` yalnızca
|
|
107
|
+
* açık boolean'dır (`:blocking="false"`); atlamak veya `true` aynı çıktıyı
|
|
108
|
+
* verir.
|
|
109
|
+
*
|
|
110
|
+
* @param {{ styles?: string[], blocking?: boolean }} [props]
|
|
106
111
|
* @returns {string}
|
|
107
112
|
*/
|
|
108
113
|
export declare function stylesheets(props?: {
|
|
109
114
|
styles?: string[];
|
|
115
|
+
blocking?: boolean;
|
|
110
116
|
}): string;
|
|
111
117
|
/**
|
|
112
118
|
* Layout gövde sonu script'leri: `main.js`, controller `entries`, isteğe
|