jskelet 0.6.3 → 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.
- package/AGENTS.md +136 -136
- package/CHANGELOG.md +628 -620
- package/LICENSE +21 -21
- package/README.md +2 -0
- package/bin/jskelet.mjs +130 -130
- package/docs/01-baslangic.md +291 -291
- package/docs/02-mimari.md +310 -310
- package/docs/03-routing.md +515 -515
- package/docs/04-render-ve-sablonlar.md +667 -661
- package/docs/05-islands.md +486 -486
- package/docs/06-cache.md +1467 -1443
- package/docs/07-yapilandirma.md +1208 -1197
- package/docs/08-build.md +429 -429
- package/docs/09-dev-araclari.md +364 -364
- package/docs/10-dagitim.md +348 -338
- package/docs/12-panel-ve-oturum.md +479 -478
- package/docs/README.md +83 -83
- package/docs/en/01-getting-started.md +298 -298
- package/docs/en/02-architecture.md +329 -329
- package/docs/en/03-routing.md +531 -531
- package/docs/en/04-rendering.md +675 -669
- package/docs/en/05-islands.md +497 -497
- package/docs/en/06-caching.md +1476 -1453
- package/docs/en/07-configuration.md +1229 -1219
- package/docs/en/08-build.md +447 -447
- package/docs/en/09-dev-tools.md +373 -373
- package/docs/en/10-deployment.md +351 -340
- package/docs/en/11-migration.md +398 -398
- package/docs/en/12-dashboards-and-sessions.md +489 -488
- package/docs/en/README.md +87 -87
- package/package.json +137 -137
- package/src/build/ensure-build.mjs +19 -19
- package/src/build/paths.mjs +153 -153
- package/src/build/resolve-peer.mjs +36 -36
- package/src/build/tasks/client.mjs +349 -349
- package/src/build/tasks/css.mjs +235 -235
- package/src/build/tasks/fonts.mjs +146 -146
- package/src/build/tasks/icons.mjs +357 -357
- package/src/build/tasks/images.mjs +244 -244
- package/src/build/tasks/precompress.mjs +78 -78
- package/src/build/tasks/templates.mjs +20 -20
- package/src/client/admin/i18n.js +764 -764
- package/src/client/admin/login.html +74 -74
- package/src/client/admin/panel.css +809 -809
- package/src/client/admin/panel.html +495 -495
- package/src/client/admin/panel.js +1251 -1251
- package/src/client/devtools/report.html +185 -185
- package/src/client/devtools/report.js +745 -745
- package/src/client/devtools/seo.js +628 -628
- package/src/client/dom.js +95 -95
- package/src/client/form.js +192 -192
- package/src/client/index.js +45 -45
- package/src/client/registry.js +305 -305
- package/src/client/safe-image.js +91 -91
- package/src/client/shared-cookie.js +225 -225
- package/src/client/store.js +36 -36
- package/src/client/swap.js +188 -188
- package/src/compile/codegen.js +336 -336
- package/src/compile/compile-all.js +149 -149
- package/src/compile/errors.js +66 -66
- package/src/compile/expr.js +409 -409
- package/src/compile/index.js +17 -17
- package/src/compile/parse.js +541 -541
- package/src/compile/resolve.js +211 -211
- package/src/compile/scan-exports.js +51 -51
- package/src/config/defaults.js +541 -534
- package/src/config/index.js +1500 -1469
- package/src/config/pattern.js +107 -107
- package/src/generate.mjs +163 -163
- package/src/http/control-flow.js +71 -71
- package/src/http/cookies-entry.js +21 -21
- package/src/http/cookies.js +277 -277
- package/src/http/request-cache.js +46 -46
- package/src/http/request-context.js +165 -165
- package/src/http/shared-cookie.js +178 -178
- package/src/index.js +101 -101
- package/src/init.mjs +232 -230
- package/src/migrate/apply.mjs +262 -262
- package/src/migrate/babel.mjs +79 -79
- package/src/migrate/classify.mjs +155 -155
- package/src/migrate/config.mjs +126 -126
- package/src/migrate/fs-walk.mjs +191 -191
- package/src/migrate/parse.mjs +26 -26
- package/src/migrate/scan.mjs +177 -177
- package/src/migrate/transform/expr-source.mjs +168 -168
- package/src/migrate/transform/island.mjs +67 -67
- package/src/migrate/transform/jsx-to-component.mjs +302 -302
- package/src/migrate/transform/jsx-to-jsk.mjs +330 -330
- package/src/migrate/transform/page-split.mjs +435 -435
- package/src/migrate/write.mjs +81 -81
- package/src/migrate.mjs +171 -171
- package/src/runtime/alias-hooks.mjs +119 -119
- package/src/runtime/register.mjs +4 -4
- package/src/server/admin/actions.js +229 -229
- package/src/server/admin/auth.js +125 -125
- package/src/server/admin/event-log.js +151 -151
- package/src/server/admin/gate.js +209 -209
- package/src/server/admin/inventory.js +188 -188
- package/src/server/admin/mount.js +56 -56
- package/src/server/admin/router.js +216 -216
- package/src/server/admin/snapshot.js +241 -241
- package/src/server/assets.js +147 -147
- package/src/server/auth/handoff.js +309 -309
- package/src/server/cache-blob.js +70 -70
- package/src/server/cache-control.js +45 -0
- package/src/server/cache-deps.js +42 -42
- package/src/server/cache-vary.js +113 -113
- package/src/server/cloudflare.js +607 -607
- package/src/server/create-app.js +366 -366
- package/src/server/data-cache.js +553 -553
- package/src/server/dev/report.js +485 -485
- package/src/server/dev/socket.js +170 -170
- package/src/server/dev/version-check.mjs +139 -139
- package/src/server/disk-cache.js +233 -233
- package/src/server/ejs-adapter.js +59 -59
- package/src/server/html-cache.js +1196 -1196
- package/src/server/image-optimizer.js +500 -500
- package/src/server/logs/access-middleware.js +66 -66
- package/src/server/logs/file-sink.js +193 -193
- package/src/server/logs/pipeline.js +165 -165
- package/src/server/logs/s3-put.js +214 -214
- package/src/server/logs/s3-sink.js +112 -112
- package/src/server/metadata.js +102 -102
- package/src/server/middleware/compression.js +205 -205
- package/src/server/middleware/csrf.js +134 -134
- package/src/server/middleware/dev-gate.js +75 -75
- package/src/server/middleware/headers.js +37 -37
- package/src/server/middleware/redirects.js +32 -32
- package/src/server/middleware/robots-txt.js +341 -341
- package/src/server/middleware/static-precompressed.js +121 -121
- package/src/server/middleware/trailing-slash.js +53 -53
- package/src/server/middleware/upstream-proxy.js +141 -141
- package/src/server/og-image.js +369 -356
- package/src/server/port-guard.js +255 -255
- package/src/server/prewarm.js +1082 -1082
- package/src/server/redis.js +588 -588
- package/src/server/render.js +910 -910
- package/src/server/router.js +157 -157
- package/src/server/status-page.js +265 -265
- package/src/server/upstream-limiter.js +376 -376
- package/src/server/upstream-tracking.js +166 -166
- package/src/shared/cookie-domain.js +66 -66
- package/src/start.mjs +22 -22
- package/src/templates/layout.ejs +30 -30
- package/src/templates/layout.jsk +30 -30
- package/src/version.mjs +31 -31
- package/src/views/components/loader.js +101 -101
- package/src/views/helpers/html.js +102 -102
- package/src/views/helpers/tags.js +375 -375
- package/types/config/defaults.d.ts +6 -0
- package/types/config/index.d.ts +6 -0
- package/types/server/cache-control.d.ts +28 -0
- package/types/server/og-image.d.ts +5 -0
package/src/server/router.js
CHANGED
|
@@ -1,157 +1,157 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Route modüllerini yükler ve Express'e bağlar.
|
|
3
|
-
*
|
|
4
|
-
* Dosya sistemine dayalı otomatik URL türetme **yok**: her modül kendi
|
|
5
|
-
* yollarını `app.get(...)` ile açıkça yazar. Sebep, Next.js'ten taşınırken
|
|
6
|
-
* öğrenilen bir şey — sıra önemli. `/:slug` gibi tek segmentli bir yakalayıcı
|
|
7
|
-
* `/about` rotasından önce kaydedilirse "about" bir slug sanılır. Sırayı
|
|
8
|
-
* dosya adına gizlemek yerine görünür kılmak, teşhisi kolaylaştırıyor.
|
|
9
|
-
*
|
|
10
|
-
* Sıra iki şekilde belirlenir:
|
|
11
|
-
* 1. `jskelet.config.mjs` → `routes: ["./routes/api.js", …]` (açık liste)
|
|
12
|
-
* 2. Liste yoksa `routes/` alfabetik taranır, ardından her feature'ın
|
|
13
|
-
* `index.js` dosyası alfabetik eklenir. Catch-all'lar için sayısal önek.
|
|
14
|
-
*
|
|
15
|
-
* Modül sözleşmesi: default export ya da `register` adlı named export,
|
|
16
|
-
* `(app, api) => void | Promise<void>` imzasıyla. `api` içinde `route`,
|
|
17
|
-
* `fragment`, `renderView`, `renderPage`, `notFound`/`redirect` ve
|
|
18
|
-
* `ogHandler` hazır gelir, böylece route dosyaları framework'ten tek tek
|
|
19
|
-
* import yapmak zorunda kalmaz.
|
|
20
|
-
*/
|
|
21
|
-
import fs from "node:fs";
|
|
22
|
-
import path from "node:path";
|
|
23
|
-
import process from "node:process";
|
|
24
|
-
import { pathToFileURL } from "node:url";
|
|
25
|
-
import { getConfig } from "../config/index.js";
|
|
26
|
-
import { fragment, renderPage, renderView, route } from "./render.js";
|
|
27
|
-
import {
|
|
28
|
-
notFound,
|
|
29
|
-
permanentRedirect,
|
|
30
|
-
redirect,
|
|
31
|
-
seeOther,
|
|
32
|
-
} from "../http/control-flow.js";
|
|
33
|
-
import { ImageResponse, ogHandler, ogImage, sendOgImage } from "./og-image.js";
|
|
34
|
-
|
|
35
|
-
const isDev = process.env.NODE_ENV === "development";
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @param {string} dir
|
|
39
|
-
* @param {string[]} [out]
|
|
40
|
-
* @returns {string[]}
|
|
41
|
-
*/
|
|
42
|
-
function discover(dir, out = []) {
|
|
43
|
-
if (!fs.existsSync(dir)) return out;
|
|
44
|
-
|
|
45
|
-
const entries = fs
|
|
46
|
-
.readdirSync(dir, { withFileTypes: true })
|
|
47
|
-
.sort((a, b) => a.name.localeCompare(b.name));
|
|
48
|
-
|
|
49
|
-
for (const entry of entries) {
|
|
50
|
-
const full = path.join(dir, entry.name);
|
|
51
|
-
|
|
52
|
-
if (entry.isDirectory()) {
|
|
53
|
-
discover(full, out);
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (!/\.(js|mjs)$/.test(entry.name)) continue;
|
|
58
|
-
if (entry.name.startsWith("_")) continue;
|
|
59
|
-
|
|
60
|
-
out.push(full);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return out;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* `features/<name>/index.js` (veya `.mjs`) — feature-first kayıt noktası.
|
|
68
|
-
* @param {string} featuresDir
|
|
69
|
-
* @returns {string[]}
|
|
70
|
-
*/
|
|
71
|
-
function discoverFeatures(featuresDir) {
|
|
72
|
-
if (!featuresDir || !fs.existsSync(featuresDir)) return [];
|
|
73
|
-
|
|
74
|
-
return fs
|
|
75
|
-
.readdirSync(featuresDir, { withFileTypes: true })
|
|
76
|
-
.filter((e) => e.isDirectory())
|
|
77
|
-
.map((e) => e.name)
|
|
78
|
-
.sort((a, b) => a.localeCompare(b))
|
|
79
|
-
.flatMap((name) => {
|
|
80
|
-
const dir = path.join(featuresDir, name);
|
|
81
|
-
for (const file of ["index.js", "index.mjs"]) {
|
|
82
|
-
const full = path.join(dir, file);
|
|
83
|
-
if (fs.existsSync(full)) return [full];
|
|
84
|
-
}
|
|
85
|
-
return [];
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Route dosyalarına geçilen framework yüzeyi.
|
|
91
|
-
*/
|
|
92
|
-
const api = {
|
|
93
|
-
route,
|
|
94
|
-
fragment,
|
|
95
|
-
renderView,
|
|
96
|
-
renderPage,
|
|
97
|
-
notFound,
|
|
98
|
-
redirect,
|
|
99
|
-
permanentRedirect,
|
|
100
|
-
seeOther,
|
|
101
|
-
ogHandler,
|
|
102
|
-
ogImage,
|
|
103
|
-
sendOgImage,
|
|
104
|
-
ImageResponse,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* @param {import('express').Express} app
|
|
109
|
-
* @returns {Promise<number>} Bağlanan modül sayısı.
|
|
110
|
-
*/
|
|
111
|
-
export async function registerRoutes(app) {
|
|
112
|
-
const config = getConfig();
|
|
113
|
-
|
|
114
|
-
const files = config.routes
|
|
115
|
-
? config.routes.map((entry) => path.resolve(config.root, entry))
|
|
116
|
-
: [...discover(config.dirs.routes), ...discoverFeatures(config.dirs.features)];
|
|
117
|
-
|
|
118
|
-
if (!files.length) {
|
|
119
|
-
console.warn(
|
|
120
|
-
`[router] no route modules found — is ${path.relative(config.root, config.dirs.routes)}/ empty?`,
|
|
121
|
-
);
|
|
122
|
-
return 0;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
let registered = 0;
|
|
126
|
-
|
|
127
|
-
for (const file of files) {
|
|
128
|
-
/** @type {Record<string, unknown>} */
|
|
129
|
-
let module;
|
|
130
|
-
|
|
131
|
-
try {
|
|
132
|
-
module = await import(pathToFileURL(file).href);
|
|
133
|
-
} catch (error) {
|
|
134
|
-
// Dev'de eksik/bozuk bir modül tüm sunucuyu düşürmesin: uyar ve devam
|
|
135
|
-
// et. Üretimde fırlat — yarım route tablosuyla yayına çıkmak,
|
|
136
|
-
// sessizce 404 dönen sayfalar demek.
|
|
137
|
-
if (isDev) {
|
|
138
|
-
console.warn(`[router] ${path.basename(file)} failed to load, skipped`, error);
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
throw error;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
const register = module.default ?? module.register;
|
|
145
|
-
if (typeof register !== "function") {
|
|
146
|
-
console.warn(
|
|
147
|
-
`[router] ${path.basename(file)} exports neither a default nor a 'register' function, skipped`,
|
|
148
|
-
);
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
await register(app, api);
|
|
153
|
-
registered += 1;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return registered;
|
|
157
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Route modüllerini yükler ve Express'e bağlar.
|
|
3
|
+
*
|
|
4
|
+
* Dosya sistemine dayalı otomatik URL türetme **yok**: her modül kendi
|
|
5
|
+
* yollarını `app.get(...)` ile açıkça yazar. Sebep, Next.js'ten taşınırken
|
|
6
|
+
* öğrenilen bir şey — sıra önemli. `/:slug` gibi tek segmentli bir yakalayıcı
|
|
7
|
+
* `/about` rotasından önce kaydedilirse "about" bir slug sanılır. Sırayı
|
|
8
|
+
* dosya adına gizlemek yerine görünür kılmak, teşhisi kolaylaştırıyor.
|
|
9
|
+
*
|
|
10
|
+
* Sıra iki şekilde belirlenir:
|
|
11
|
+
* 1. `jskelet.config.mjs` → `routes: ["./routes/api.js", …]` (açık liste)
|
|
12
|
+
* 2. Liste yoksa `routes/` alfabetik taranır, ardından her feature'ın
|
|
13
|
+
* `index.js` dosyası alfabetik eklenir. Catch-all'lar için sayısal önek.
|
|
14
|
+
*
|
|
15
|
+
* Modül sözleşmesi: default export ya da `register` adlı named export,
|
|
16
|
+
* `(app, api) => void | Promise<void>` imzasıyla. `api` içinde `route`,
|
|
17
|
+
* `fragment`, `renderView`, `renderPage`, `notFound`/`redirect` ve
|
|
18
|
+
* `ogHandler` hazır gelir, böylece route dosyaları framework'ten tek tek
|
|
19
|
+
* import yapmak zorunda kalmaz.
|
|
20
|
+
*/
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
import process from "node:process";
|
|
24
|
+
import { pathToFileURL } from "node:url";
|
|
25
|
+
import { getConfig } from "../config/index.js";
|
|
26
|
+
import { fragment, renderPage, renderView, route } from "./render.js";
|
|
27
|
+
import {
|
|
28
|
+
notFound,
|
|
29
|
+
permanentRedirect,
|
|
30
|
+
redirect,
|
|
31
|
+
seeOther,
|
|
32
|
+
} from "../http/control-flow.js";
|
|
33
|
+
import { ImageResponse, ogHandler, ogImage, sendOgImage } from "./og-image.js";
|
|
34
|
+
|
|
35
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} dir
|
|
39
|
+
* @param {string[]} [out]
|
|
40
|
+
* @returns {string[]}
|
|
41
|
+
*/
|
|
42
|
+
function discover(dir, out = []) {
|
|
43
|
+
if (!fs.existsSync(dir)) return out;
|
|
44
|
+
|
|
45
|
+
const entries = fs
|
|
46
|
+
.readdirSync(dir, { withFileTypes: true })
|
|
47
|
+
.sort((a, b) => a.name.localeCompare(b.name));
|
|
48
|
+
|
|
49
|
+
for (const entry of entries) {
|
|
50
|
+
const full = path.join(dir, entry.name);
|
|
51
|
+
|
|
52
|
+
if (entry.isDirectory()) {
|
|
53
|
+
discover(full, out);
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!/\.(js|mjs)$/.test(entry.name)) continue;
|
|
58
|
+
if (entry.name.startsWith("_")) continue;
|
|
59
|
+
|
|
60
|
+
out.push(full);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* `features/<name>/index.js` (veya `.mjs`) — feature-first kayıt noktası.
|
|
68
|
+
* @param {string} featuresDir
|
|
69
|
+
* @returns {string[]}
|
|
70
|
+
*/
|
|
71
|
+
function discoverFeatures(featuresDir) {
|
|
72
|
+
if (!featuresDir || !fs.existsSync(featuresDir)) return [];
|
|
73
|
+
|
|
74
|
+
return fs
|
|
75
|
+
.readdirSync(featuresDir, { withFileTypes: true })
|
|
76
|
+
.filter((e) => e.isDirectory())
|
|
77
|
+
.map((e) => e.name)
|
|
78
|
+
.sort((a, b) => a.localeCompare(b))
|
|
79
|
+
.flatMap((name) => {
|
|
80
|
+
const dir = path.join(featuresDir, name);
|
|
81
|
+
for (const file of ["index.js", "index.mjs"]) {
|
|
82
|
+
const full = path.join(dir, file);
|
|
83
|
+
if (fs.existsSync(full)) return [full];
|
|
84
|
+
}
|
|
85
|
+
return [];
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Route dosyalarına geçilen framework yüzeyi.
|
|
91
|
+
*/
|
|
92
|
+
const api = {
|
|
93
|
+
route,
|
|
94
|
+
fragment,
|
|
95
|
+
renderView,
|
|
96
|
+
renderPage,
|
|
97
|
+
notFound,
|
|
98
|
+
redirect,
|
|
99
|
+
permanentRedirect,
|
|
100
|
+
seeOther,
|
|
101
|
+
ogHandler,
|
|
102
|
+
ogImage,
|
|
103
|
+
sendOgImage,
|
|
104
|
+
ImageResponse,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @param {import('express').Express} app
|
|
109
|
+
* @returns {Promise<number>} Bağlanan modül sayısı.
|
|
110
|
+
*/
|
|
111
|
+
export async function registerRoutes(app) {
|
|
112
|
+
const config = getConfig();
|
|
113
|
+
|
|
114
|
+
const files = config.routes
|
|
115
|
+
? config.routes.map((entry) => path.resolve(config.root, entry))
|
|
116
|
+
: [...discover(config.dirs.routes), ...discoverFeatures(config.dirs.features)];
|
|
117
|
+
|
|
118
|
+
if (!files.length) {
|
|
119
|
+
console.warn(
|
|
120
|
+
`[router] no route modules found — is ${path.relative(config.root, config.dirs.routes)}/ empty?`,
|
|
121
|
+
);
|
|
122
|
+
return 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let registered = 0;
|
|
126
|
+
|
|
127
|
+
for (const file of files) {
|
|
128
|
+
/** @type {Record<string, unknown>} */
|
|
129
|
+
let module;
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
module = await import(pathToFileURL(file).href);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
// Dev'de eksik/bozuk bir modül tüm sunucuyu düşürmesin: uyar ve devam
|
|
135
|
+
// et. Üretimde fırlat — yarım route tablosuyla yayına çıkmak,
|
|
136
|
+
// sessizce 404 dönen sayfalar demek.
|
|
137
|
+
if (isDev) {
|
|
138
|
+
console.warn(`[router] ${path.basename(file)} failed to load, skipped`, error);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
throw error;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const register = module.default ?? module.register;
|
|
145
|
+
if (typeof register !== "function") {
|
|
146
|
+
console.warn(
|
|
147
|
+
`[router] ${path.basename(file)} exports neither a default nor a 'register' function, skipped`,
|
|
148
|
+
);
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
await register(app, api);
|
|
153
|
+
registered += 1;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return registered;
|
|
157
|
+
}
|