jskelet 0.6.2 → 0.6.3

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 (155) hide show
  1. package/AGENTS.md +136 -136
  2. package/CHANGELOG.md +620 -596
  3. package/LICENSE +21 -21
  4. package/bin/jskelet.mjs +130 -130
  5. package/docs/01-baslangic.md +291 -291
  6. package/docs/02-mimari.md +310 -309
  7. package/docs/03-routing.md +515 -515
  8. package/docs/04-render-ve-sablonlar.md +661 -661
  9. package/docs/05-islands.md +486 -486
  10. package/docs/06-cache.md +1443 -1423
  11. package/docs/07-yapilandirma.md +12 -6
  12. package/docs/08-build.md +429 -428
  13. package/docs/09-dev-araclari.md +364 -364
  14. package/docs/10-dagitim.md +338 -338
  15. package/docs/12-panel-ve-oturum.md +478 -478
  16. package/docs/README.md +83 -83
  17. package/docs/en/01-getting-started.md +298 -298
  18. package/docs/en/02-architecture.md +329 -328
  19. package/docs/en/03-routing.md +531 -531
  20. package/docs/en/04-rendering.md +669 -669
  21. package/docs/en/05-islands.md +497 -497
  22. package/docs/en/06-caching.md +1453 -1431
  23. package/docs/en/07-configuration.md +1219 -1214
  24. package/docs/en/08-build.md +447 -446
  25. package/docs/en/09-dev-tools.md +373 -373
  26. package/docs/en/10-deployment.md +340 -340
  27. package/docs/en/11-migration.md +398 -398
  28. package/docs/en/12-dashboards-and-sessions.md +488 -488
  29. package/docs/en/README.md +87 -87
  30. package/package.json +137 -137
  31. package/src/build/ensure-build.mjs +19 -19
  32. package/src/build/paths.mjs +153 -153
  33. package/src/build/resolve-peer.mjs +36 -36
  34. package/src/build/tasks/client.mjs +349 -349
  35. package/src/build/tasks/css.mjs +235 -235
  36. package/src/build/tasks/fonts.mjs +146 -146
  37. package/src/build/tasks/icons.mjs +357 -357
  38. package/src/build/tasks/images.mjs +244 -244
  39. package/src/build/tasks/precompress.mjs +78 -78
  40. package/src/build/tasks/templates.mjs +20 -20
  41. package/src/client/admin/i18n.js +764 -764
  42. package/src/client/admin/login.html +74 -74
  43. package/src/client/admin/panel.css +809 -809
  44. package/src/client/admin/panel.html +495 -495
  45. package/src/client/admin/panel.js +1251 -1251
  46. package/src/client/devtools/report.html +185 -185
  47. package/src/client/devtools/report.js +745 -745
  48. package/src/client/devtools/seo.js +628 -628
  49. package/src/client/dom.js +95 -95
  50. package/src/client/form.js +192 -192
  51. package/src/client/index.js +45 -45
  52. package/src/client/registry.js +305 -305
  53. package/src/client/safe-image.js +91 -91
  54. package/src/client/shared-cookie.js +225 -225
  55. package/src/client/store.js +36 -36
  56. package/src/client/swap.js +188 -188
  57. package/src/compile/codegen.js +336 -336
  58. package/src/compile/compile-all.js +149 -149
  59. package/src/compile/errors.js +66 -66
  60. package/src/compile/expr.js +409 -409
  61. package/src/compile/index.js +17 -17
  62. package/src/compile/parse.js +541 -541
  63. package/src/compile/resolve.js +211 -211
  64. package/src/compile/scan-exports.js +51 -51
  65. package/src/config/defaults.js +17 -1
  66. package/src/config/index.js +13 -0
  67. package/src/config/pattern.js +107 -107
  68. package/src/generate.mjs +163 -163
  69. package/src/http/control-flow.js +71 -71
  70. package/src/http/cookies-entry.js +21 -21
  71. package/src/http/cookies.js +277 -277
  72. package/src/http/request-cache.js +46 -46
  73. package/src/http/request-context.js +165 -165
  74. package/src/http/shared-cookie.js +178 -178
  75. package/src/index.js +101 -101
  76. package/src/init.mjs +230 -230
  77. package/src/migrate/apply.mjs +262 -262
  78. package/src/migrate/babel.mjs +79 -79
  79. package/src/migrate/classify.mjs +155 -155
  80. package/src/migrate/config.mjs +126 -126
  81. package/src/migrate/fs-walk.mjs +191 -191
  82. package/src/migrate/parse.mjs +26 -26
  83. package/src/migrate/scan.mjs +177 -177
  84. package/src/migrate/transform/expr-source.mjs +168 -168
  85. package/src/migrate/transform/island.mjs +67 -67
  86. package/src/migrate/transform/jsx-to-component.mjs +302 -302
  87. package/src/migrate/transform/jsx-to-jsk.mjs +330 -330
  88. package/src/migrate/transform/page-split.mjs +435 -435
  89. package/src/migrate/write.mjs +81 -81
  90. package/src/migrate.mjs +171 -171
  91. package/src/runtime/alias-hooks.mjs +119 -119
  92. package/src/runtime/register.mjs +4 -4
  93. package/src/server/admin/actions.js +229 -229
  94. package/src/server/admin/auth.js +125 -125
  95. package/src/server/admin/event-log.js +151 -151
  96. package/src/server/admin/gate.js +209 -209
  97. package/src/server/admin/inventory.js +188 -188
  98. package/src/server/admin/mount.js +56 -56
  99. package/src/server/admin/router.js +216 -216
  100. package/src/server/admin/snapshot.js +241 -241
  101. package/src/server/assets.js +147 -147
  102. package/src/server/auth/handoff.js +309 -309
  103. package/src/server/cache-blob.js +70 -0
  104. package/src/server/cache-deps.js +42 -42
  105. package/src/server/cache-vary.js +113 -113
  106. package/src/server/cloudflare.js +607 -607
  107. package/src/server/create-app.js +366 -366
  108. package/src/server/data-cache.js +553 -462
  109. package/src/server/dev/report.js +485 -485
  110. package/src/server/dev/socket.js +170 -170
  111. package/src/server/dev/version-check.mjs +139 -139
  112. package/src/server/disk-cache.js +233 -0
  113. package/src/server/ejs-adapter.js +59 -59
  114. package/src/server/html-cache.js +1196 -1122
  115. package/src/server/image-optimizer.js +500 -407
  116. package/src/server/logs/access-middleware.js +66 -66
  117. package/src/server/logs/file-sink.js +193 -66
  118. package/src/server/logs/pipeline.js +165 -158
  119. package/src/server/logs/s3-put.js +214 -214
  120. package/src/server/logs/s3-sink.js +112 -112
  121. package/src/server/metadata.js +102 -102
  122. package/src/server/middleware/compression.js +205 -205
  123. package/src/server/middleware/csrf.js +134 -134
  124. package/src/server/middleware/dev-gate.js +75 -75
  125. package/src/server/middleware/headers.js +37 -37
  126. package/src/server/middleware/redirects.js +32 -32
  127. package/src/server/middleware/robots-txt.js +341 -341
  128. package/src/server/middleware/static-precompressed.js +121 -100
  129. package/src/server/middleware/trailing-slash.js +53 -53
  130. package/src/server/middleware/upstream-proxy.js +141 -141
  131. package/src/server/og-image.js +356 -356
  132. package/src/server/port-guard.js +255 -255
  133. package/src/server/prewarm.js +1082 -1058
  134. package/src/server/redis.js +588 -569
  135. package/src/server/render.js +4 -4
  136. package/src/server/router.js +157 -157
  137. package/src/server/status-page.js +265 -265
  138. package/src/server/upstream-limiter.js +376 -376
  139. package/src/server/upstream-tracking.js +166 -166
  140. package/src/shared/cookie-domain.js +66 -66
  141. package/src/start.mjs +22 -22
  142. package/src/templates/layout.ejs +30 -30
  143. package/src/templates/layout.jsk +30 -30
  144. package/src/version.mjs +31 -31
  145. package/src/views/components/loader.js +101 -101
  146. package/src/views/helpers/html.js +102 -102
  147. package/src/views/helpers/tags.js +375 -375
  148. package/types/config/defaults.d.ts +15 -1
  149. package/types/config/index.d.ts +8 -0
  150. package/types/server/cache-blob.d.ts +13 -0
  151. package/types/server/data-cache.d.ts +9 -0
  152. package/types/server/disk-cache.d.ts +36 -0
  153. package/types/server/html-cache.d.ts +26 -3
  154. package/types/server/logs/file-sink.d.ts +16 -5
  155. package/types/server/redis.d.ts +2 -1
@@ -1,211 +1,211 @@
1
- /**
2
- * View kökleri ve `.jsk` dosya keşfi.
3
- *
4
- * Sıra: views, sonra shared/views, sonra her feature altındaki views.
5
- * Aynı view id birden fazla kökte varsa son bulunan kazanır.
6
- */
7
- import fs from "node:fs";
8
- import path from "node:path";
9
- import { toPascalCase } from "./codegen.js";
10
- import { CompileError } from "./errors.js";
11
- import { scanNamedExports } from "./scan-exports.js";
12
-
13
- /**
14
- * Runtime'ın camelCase → PascalCase alias'ı ile aynı kural.
15
- * @param {string} name
16
- * @returns {string}
17
- */
18
- export function toComponentTag(name) {
19
- return name.charAt(0).toUpperCase() + name.slice(1);
20
- }
21
-
22
- /**
23
- * @param {{ root: string, dirs: Record<string, string> }} config
24
- * @returns {string[]} Mutlak view kökleri (var olanlar).
25
- */
26
- export function getViewRoots(config) {
27
- /** @type {string[]} */
28
- const roots = [];
29
- const { dirs, root } = config;
30
-
31
- if (dirs.views && fs.existsSync(dirs.views)) {
32
- roots.push(dirs.views);
33
- }
34
-
35
- const sharedViews = dirs.shared
36
- ? path.join(dirs.shared, "views")
37
- : path.join(root, "shared", "views");
38
- if (fs.existsSync(sharedViews)) roots.push(sharedViews);
39
-
40
- const featuresDir = dirs.features ?? path.join(root, "features");
41
- if (fs.existsSync(featuresDir)) {
42
- const features = fs
43
- .readdirSync(featuresDir, { withFileTypes: true })
44
- .filter((e) => e.isDirectory())
45
- .map((e) => e.name)
46
- .sort((a, b) => a.localeCompare(b));
47
-
48
- for (const name of features) {
49
- const views = path.join(featuresDir, name, "views");
50
- if (fs.existsSync(views)) roots.push(views);
51
- }
52
- }
53
-
54
- return roots;
55
- }
56
-
57
- /**
58
- * Bileşen dizinleri: her view kökü altındaki `components/`.
59
- * @param {{ root: string, dirs: Record<string, string> }} config
60
- * @returns {string[]}
61
- */
62
- export function getComponentDirs(config) {
63
- return getViewRoots(config)
64
- .map((root) => path.join(root, "components"))
65
- .filter((dir) => fs.existsSync(dir));
66
- }
67
-
68
- /**
69
- * @param {string[]} viewRoots
70
- * @returns {Map<string, string>} viewId → mutlak `.jsk` yolu
71
- */
72
- export function discoverJskFiles(viewRoots) {
73
- /** @type {Map<string, string>} */
74
- const map = new Map();
75
-
76
- for (const root of viewRoots) {
77
- collectJsk(root, root, map);
78
- }
79
-
80
- return map;
81
- }
82
-
83
- /**
84
- * @param {string} dir
85
- * @param {string} root
86
- * @param {Map<string, string>} out
87
- */
88
- function collectJsk(dir, root, out) {
89
- if (!fs.existsSync(dir)) return;
90
-
91
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
92
- const full = path.join(dir, entry.name);
93
- if (entry.isDirectory()) {
94
- collectJsk(full, root, out);
95
- continue;
96
- }
97
- if (!entry.name.endsWith(".jsk")) continue;
98
- const rel = path.relative(root, full).split(path.sep).join("/");
99
- const viewId = rel.replace(/\.jsk$/i, "");
100
- out.set(viewId, full);
101
- }
102
- }
103
-
104
- /**
105
- * `components/foo-bar.jsk` → `FooBar`
106
- * @param {string} viewId
107
- * @returns {string | null}
108
- */
109
- export function componentNameFromViewId(viewId) {
110
- const parts = viewId.split("/");
111
- if (parts[0] !== "components" || parts.length < 2) return null;
112
- const base = parts[parts.length - 1];
113
- return toPascalCase(base);
114
- }
115
-
116
- /**
117
- * Bilinen bileşen adları: JS named export'lar + derlenecek `.jsk` bileşenleri
118
- * + yerleşik etiketler.
119
- *
120
- * JS tarafında dosya adı varsayılmaz; kaynak metinden `export` adları okunur.
121
- * Aynı export (veya aynı PascalCase etiket) iki dosyada varsa derleme hatası.
122
- *
123
- * @param {string[]} componentDirs
124
- * @param {Map<string, string>} jskFiles
125
- * @returns {Set<string>}
126
- */
127
- export function collectKnownComponents(componentDirs, jskFiles) {
128
- const known = new Set([
129
- "Link",
130
- "Image",
131
- "Icon",
132
- "CsrfField",
133
- "PreloadImage",
134
- "Stylesheets",
135
- "BodyScripts",
136
- "JsonLd",
137
- ]);
138
-
139
- /** @type {Map<string, string>} export adı → göreli yol */
140
- const byName = new Map();
141
- /** @type {Map<string, string>} PascalCase etiket → göreli yol */
142
- const byTag = new Map();
143
-
144
- for (const [viewId] of jskFiles) {
145
- const name = componentNameFromViewId(viewId);
146
- if (!name) continue;
147
- known.add(name);
148
- byTag.set(name, `${viewId}.jsk`);
149
- }
150
-
151
- for (const dir of componentDirs) {
152
- collectJsComponentNames(dir, known, byName, byTag);
153
- }
154
-
155
- return known;
156
- }
157
-
158
- /**
159
- * @param {string} name
160
- * @param {string} origin
161
- * @param {Map<string, string>} byName
162
- * @param {Map<string, string>} byTag
163
- */
164
- function registerExportOrigin(name, origin, byName, byTag) {
165
- const previousName = byName.get(name);
166
- if (previousName && previousName !== origin) {
167
- throw new CompileError(
168
- `Component '${name}' is defined twice: ${previousName} and ${origin}`,
169
- );
170
- }
171
- byName.set(name, origin);
172
-
173
- const tag = toComponentTag(name);
174
- const previousTag = byTag.get(tag);
175
- if (previousTag && previousTag !== origin) {
176
- throw new CompileError(
177
- `Component '${tag}' is defined twice: ${previousTag} and ${origin}`,
178
- );
179
- }
180
- byTag.set(tag, origin);
181
- }
182
-
183
- /**
184
- * @param {string} dir
185
- * @param {Set<string>} out
186
- * @param {Map<string, string>} byName
187
- * @param {Map<string, string>} byTag
188
- */
189
- function collectJsComponentNames(dir, out, byName, byTag) {
190
- if (!fs.existsSync(dir)) return;
191
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
192
- const full = path.join(dir, entry.name);
193
- if (entry.isDirectory()) {
194
- collectJsComponentNames(full, out, byName, byTag);
195
- continue;
196
- }
197
- if (!entry.name.endsWith(".js")) continue;
198
- if (entry.name === "loader.js" || entry.name === "index.js") continue;
199
-
200
- // Kimlik mutlak yol: çoklu kökte iki `list.js` aynı göreli ada sahip olabilir.
201
- const origin = full.split(path.sep).join("/");
202
- const source = fs.readFileSync(full, "utf8");
203
- const exports = scanNamedExports(source);
204
-
205
- for (const name of exports) {
206
- registerExportOrigin(name, origin, byName, byTag);
207
- out.add(name);
208
- out.add(toComponentTag(name));
209
- }
210
- }
211
- }
1
+ /**
2
+ * View kökleri ve `.jsk` dosya keşfi.
3
+ *
4
+ * Sıra: views, sonra shared/views, sonra her feature altındaki views.
5
+ * Aynı view id birden fazla kökte varsa son bulunan kazanır.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { toPascalCase } from "./codegen.js";
10
+ import { CompileError } from "./errors.js";
11
+ import { scanNamedExports } from "./scan-exports.js";
12
+
13
+ /**
14
+ * Runtime'ın camelCase → PascalCase alias'ı ile aynı kural.
15
+ * @param {string} name
16
+ * @returns {string}
17
+ */
18
+ export function toComponentTag(name) {
19
+ return name.charAt(0).toUpperCase() + name.slice(1);
20
+ }
21
+
22
+ /**
23
+ * @param {{ root: string, dirs: Record<string, string> }} config
24
+ * @returns {string[]} Mutlak view kökleri (var olanlar).
25
+ */
26
+ export function getViewRoots(config) {
27
+ /** @type {string[]} */
28
+ const roots = [];
29
+ const { dirs, root } = config;
30
+
31
+ if (dirs.views && fs.existsSync(dirs.views)) {
32
+ roots.push(dirs.views);
33
+ }
34
+
35
+ const sharedViews = dirs.shared
36
+ ? path.join(dirs.shared, "views")
37
+ : path.join(root, "shared", "views");
38
+ if (fs.existsSync(sharedViews)) roots.push(sharedViews);
39
+
40
+ const featuresDir = dirs.features ?? path.join(root, "features");
41
+ if (fs.existsSync(featuresDir)) {
42
+ const features = fs
43
+ .readdirSync(featuresDir, { withFileTypes: true })
44
+ .filter((e) => e.isDirectory())
45
+ .map((e) => e.name)
46
+ .sort((a, b) => a.localeCompare(b));
47
+
48
+ for (const name of features) {
49
+ const views = path.join(featuresDir, name, "views");
50
+ if (fs.existsSync(views)) roots.push(views);
51
+ }
52
+ }
53
+
54
+ return roots;
55
+ }
56
+
57
+ /**
58
+ * Bileşen dizinleri: her view kökü altındaki `components/`.
59
+ * @param {{ root: string, dirs: Record<string, string> }} config
60
+ * @returns {string[]}
61
+ */
62
+ export function getComponentDirs(config) {
63
+ return getViewRoots(config)
64
+ .map((root) => path.join(root, "components"))
65
+ .filter((dir) => fs.existsSync(dir));
66
+ }
67
+
68
+ /**
69
+ * @param {string[]} viewRoots
70
+ * @returns {Map<string, string>} viewId → mutlak `.jsk` yolu
71
+ */
72
+ export function discoverJskFiles(viewRoots) {
73
+ /** @type {Map<string, string>} */
74
+ const map = new Map();
75
+
76
+ for (const root of viewRoots) {
77
+ collectJsk(root, root, map);
78
+ }
79
+
80
+ return map;
81
+ }
82
+
83
+ /**
84
+ * @param {string} dir
85
+ * @param {string} root
86
+ * @param {Map<string, string>} out
87
+ */
88
+ function collectJsk(dir, root, out) {
89
+ if (!fs.existsSync(dir)) return;
90
+
91
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
92
+ const full = path.join(dir, entry.name);
93
+ if (entry.isDirectory()) {
94
+ collectJsk(full, root, out);
95
+ continue;
96
+ }
97
+ if (!entry.name.endsWith(".jsk")) continue;
98
+ const rel = path.relative(root, full).split(path.sep).join("/");
99
+ const viewId = rel.replace(/\.jsk$/i, "");
100
+ out.set(viewId, full);
101
+ }
102
+ }
103
+
104
+ /**
105
+ * `components/foo-bar.jsk` → `FooBar`
106
+ * @param {string} viewId
107
+ * @returns {string | null}
108
+ */
109
+ export function componentNameFromViewId(viewId) {
110
+ const parts = viewId.split("/");
111
+ if (parts[0] !== "components" || parts.length < 2) return null;
112
+ const base = parts[parts.length - 1];
113
+ return toPascalCase(base);
114
+ }
115
+
116
+ /**
117
+ * Bilinen bileşen adları: JS named export'lar + derlenecek `.jsk` bileşenleri
118
+ * + yerleşik etiketler.
119
+ *
120
+ * JS tarafında dosya adı varsayılmaz; kaynak metinden `export` adları okunur.
121
+ * Aynı export (veya aynı PascalCase etiket) iki dosyada varsa derleme hatası.
122
+ *
123
+ * @param {string[]} componentDirs
124
+ * @param {Map<string, string>} jskFiles
125
+ * @returns {Set<string>}
126
+ */
127
+ export function collectKnownComponents(componentDirs, jskFiles) {
128
+ const known = new Set([
129
+ "Link",
130
+ "Image",
131
+ "Icon",
132
+ "CsrfField",
133
+ "PreloadImage",
134
+ "Stylesheets",
135
+ "BodyScripts",
136
+ "JsonLd",
137
+ ]);
138
+
139
+ /** @type {Map<string, string>} export adı → göreli yol */
140
+ const byName = new Map();
141
+ /** @type {Map<string, string>} PascalCase etiket → göreli yol */
142
+ const byTag = new Map();
143
+
144
+ for (const [viewId] of jskFiles) {
145
+ const name = componentNameFromViewId(viewId);
146
+ if (!name) continue;
147
+ known.add(name);
148
+ byTag.set(name, `${viewId}.jsk`);
149
+ }
150
+
151
+ for (const dir of componentDirs) {
152
+ collectJsComponentNames(dir, known, byName, byTag);
153
+ }
154
+
155
+ return known;
156
+ }
157
+
158
+ /**
159
+ * @param {string} name
160
+ * @param {string} origin
161
+ * @param {Map<string, string>} byName
162
+ * @param {Map<string, string>} byTag
163
+ */
164
+ function registerExportOrigin(name, origin, byName, byTag) {
165
+ const previousName = byName.get(name);
166
+ if (previousName && previousName !== origin) {
167
+ throw new CompileError(
168
+ `Component '${name}' is defined twice: ${previousName} and ${origin}`,
169
+ );
170
+ }
171
+ byName.set(name, origin);
172
+
173
+ const tag = toComponentTag(name);
174
+ const previousTag = byTag.get(tag);
175
+ if (previousTag && previousTag !== origin) {
176
+ throw new CompileError(
177
+ `Component '${tag}' is defined twice: ${previousTag} and ${origin}`,
178
+ );
179
+ }
180
+ byTag.set(tag, origin);
181
+ }
182
+
183
+ /**
184
+ * @param {string} dir
185
+ * @param {Set<string>} out
186
+ * @param {Map<string, string>} byName
187
+ * @param {Map<string, string>} byTag
188
+ */
189
+ function collectJsComponentNames(dir, out, byName, byTag) {
190
+ if (!fs.existsSync(dir)) return;
191
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
192
+ const full = path.join(dir, entry.name);
193
+ if (entry.isDirectory()) {
194
+ collectJsComponentNames(full, out, byName, byTag);
195
+ continue;
196
+ }
197
+ if (!entry.name.endsWith(".js")) continue;
198
+ if (entry.name === "loader.js" || entry.name === "index.js") continue;
199
+
200
+ // Kimlik mutlak yol: çoklu kökte iki `list.js` aynı göreli ada sahip olabilir.
201
+ const origin = full.split(path.sep).join("/");
202
+ const source = fs.readFileSync(full, "utf8");
203
+ const exports = scanNamedExports(source);
204
+
205
+ for (const name of exports) {
206
+ registerExportOrigin(name, origin, byName, byTag);
207
+ out.add(name);
208
+ out.add(toComponentTag(name));
209
+ }
210
+ }
211
+ }
@@ -1,51 +1,51 @@
1
- /**
2
- * Kaynak metinden named export adlarını çıkarır — modülü çalıştırmadan.
3
- * Compile-time bilinen bileşen listesi için; `default` yok sayılır.
4
- */
5
-
6
- /**
7
- * Yorumları kaba şekilde siler; string içindeki sahte eşleşmeler nadirdir.
8
- * @param {string} source
9
- * @returns {string}
10
- */
11
- function stripComments(source) {
12
- return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
13
- }
14
-
15
- /**
16
- * `export { a, b as C, default as X }` listesinden dışa verilen adları toplar.
17
- * @param {string} clause
18
- * @param {Set<string>} out
19
- */
20
- function addExportList(clause, out) {
21
- for (const part of clause.split(",")) {
22
- const trimmed = part.trim();
23
- if (!trimmed) continue;
24
- const bits = trimmed.split(/\s+as\s+/i);
25
- const exported = (bits[1] ?? bits[0]).trim();
26
- if (!exported || exported === "default") continue;
27
- out.add(exported);
28
- }
29
- }
30
-
31
- /**
32
- * @param {string} source
33
- * @returns {string[]}
34
- */
35
- export function scanNamedExports(source) {
36
- const text = stripComments(source);
37
- /** @type {Set<string>} */
38
- const names = new Set();
39
-
40
- for (const match of text.matchAll(
41
- /\bexport\s+(?:async\s+)?(?:function\*?|class|const|let|var)\s+([A-Za-z_$][\w$]*)/g,
42
- )) {
43
- names.add(match[1]);
44
- }
45
-
46
- for (const match of text.matchAll(/\bexport\s*\{([^}]+)\}/g)) {
47
- addExportList(match[1], names);
48
- }
49
-
50
- return [...names];
51
- }
1
+ /**
2
+ * Kaynak metinden named export adlarını çıkarır — modülü çalıştırmadan.
3
+ * Compile-time bilinen bileşen listesi için; `default` yok sayılır.
4
+ */
5
+
6
+ /**
7
+ * Yorumları kaba şekilde siler; string içindeki sahte eşleşmeler nadirdir.
8
+ * @param {string} source
9
+ * @returns {string}
10
+ */
11
+ function stripComments(source) {
12
+ return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
13
+ }
14
+
15
+ /**
16
+ * `export { a, b as C, default as X }` listesinden dışa verilen adları toplar.
17
+ * @param {string} clause
18
+ * @param {Set<string>} out
19
+ */
20
+ function addExportList(clause, out) {
21
+ for (const part of clause.split(",")) {
22
+ const trimmed = part.trim();
23
+ if (!trimmed) continue;
24
+ const bits = trimmed.split(/\s+as\s+/i);
25
+ const exported = (bits[1] ?? bits[0]).trim();
26
+ if (!exported || exported === "default") continue;
27
+ out.add(exported);
28
+ }
29
+ }
30
+
31
+ /**
32
+ * @param {string} source
33
+ * @returns {string[]}
34
+ */
35
+ export function scanNamedExports(source) {
36
+ const text = stripComments(source);
37
+ /** @type {Set<string>} */
38
+ const names = new Set();
39
+
40
+ for (const match of text.matchAll(
41
+ /\bexport\s+(?:async\s+)?(?:function\*?|class|const|let|var)\s+([A-Za-z_$][\w$]*)/g,
42
+ )) {
43
+ names.add(match[1]);
44
+ }
45
+
46
+ for (const match of text.matchAll(/\bexport\s*\{([^}]+)\}/g)) {
47
+ addExportList(match[1], names);
48
+ }
49
+
50
+ return [...names];
51
+ }
@@ -169,6 +169,19 @@ export const HTML_CACHE_MAX_ENTRIES_CEILING = 800;
169
169
  */
170
170
  export const HTML_CACHE_BYTE_BUDGET = 256 * 1024 * 1024;
171
171
 
172
+ /**
173
+ * Süreç içi veri önbelleğinin JSON bayt tavanı (64 MB). Sayı tavanı
174
+ * şişman gövdeleri tutmaz; config yükseltemez. Tek değer bütçeden büyükse
175
+ * saklanmaz, çağıran sonucu yine alır.
176
+ */
177
+ export const DATA_CACHE_BYTE_BUDGET = 64 * 1024 * 1024;
178
+
179
+ /**
180
+ * Uzak görsel disk önbelleğinin tavanı (256 MB). `.jskelet/image-cache/`
181
+ * bu boyutu aşınca en eski dosya düşer. Config yükseltemez.
182
+ */
183
+ export const IMAGE_CACHE_BYTE_BUDGET = 256 * 1024 * 1024;
184
+
172
185
  /** `cache().data.maxEntries` için sert tavan. Uzun kuyruk burada durur, HTML'de değil. */
173
186
  export const DATA_CACHE_MAX_ENTRIES_CEILING = 20_000;
174
187
 
@@ -297,7 +310,10 @@ export const DEFAULT_LOGS = {
297
310
  enabled: false,
298
311
  /** Proje köküne göre relative. */
299
312
  dir: "logs",
300
- /** Yalnızca günlük rotasyon. */
313
+ /**
314
+ * Artık kullanılmıyor. Parçalar en fazla 5 dakika durur; alan çözülen
315
+ * config'te durur ki eski okuyucular kırılmasın.
316
+ */
301
317
  rotate: /** @type {"daily"} */ ("daily"),
302
318
  },
303
319
  s3: {
@@ -97,6 +97,10 @@ const CONFIG_FILE = "jskelet.config.mjs";
97
97
  * basılsın mı (banner/build satırları etkilenmez).
98
98
  * @property {LogKind[]} kinds Sink'lere giden kayıt türleri.
99
99
  * @property {{ enabled: boolean, dir: string, rotate: "daily" }} file
100
+ * `rotate` durur; dosya parçaları en fazla 5 dakika tutulur.
101
+ * @property {import('../server/logs/file-sink.js').DrainLog | null} drainLog
102
+ * Mühürlenen zstd parçasını uygulamanın seçtiği yere aktarır. Hata
103
+ * siteyi düşürmez.
100
104
  * @property {{ enabled: boolean, bucket: string | null, prefix: string,
101
105
  * region: string | null, endpoint: string | null, flushIntervalMs: number,
102
106
  * maxBatch: number }} s3
@@ -578,6 +582,14 @@ export function normalizeLogs(raw) {
578
582
  envText(process.env.JSKELET_S3_REGION) ??
579
583
  "auto";
580
584
 
585
+ /** @type {import('../server/logs/file-sink.js').DrainLog | null} */
586
+ let drainLog = null;
587
+ if (typeof source.drainLog === "function") {
588
+ drainLog = source.drainLog;
589
+ } else if (source.drainLog != null) {
590
+ console.warn("[config] logs.drainLog must be a function, ignoring it");
591
+ }
592
+
581
593
  const credentials = readS3CredentialsFromEnv();
582
594
  // `JSKELET_LOG_BUCKET` (veya S3 bucket) + credential varsa config'te
583
595
  // `enabled: true` unutulmuş olsa bile aç. Açık `enabled: false` ezer.
@@ -603,6 +615,7 @@ export function normalizeLogs(raw) {
603
615
  : DEFAULT_LOGS.file.dir,
604
616
  rotate: "daily",
605
617
  },
618
+ drainLog,
606
619
  s3: {
607
620
  enabled,
608
621
  bucket: bucketPath.bucket,