kreftjs 0.0.10-beta → 0.0.12-beta
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/bin/build.js +24 -0
- package/docs/README.md +2 -2
- package/kreftjs.d.ts +1 -1
- package/kreftjs.js +2 -2
- package/package.json +2 -2
- package/templates/app/frontend/errors/ErrorMonitor.kreft +2 -2
- package/templates/app/frontend/kreftjs.d.ts +1 -1
- package/templates/app/frontend/kreftjs.js +2 -2
- package/templates/app/frontend/pages/Dashboard.kreft +1 -1
- package/templates/app/frontend/pages/Home.kreft +47 -6
- package/templates/errors/ErrorMonitor.kreft +1 -1
package/bin/build.js
CHANGED
|
@@ -229,6 +229,7 @@ ${indent(components.join('\n\n'))}
|
|
|
229
229
|
: html.replace(/<head>/i, `<head>\n <base href="${b}">`);
|
|
230
230
|
}
|
|
231
231
|
write(dist, 'index.html', html);
|
|
232
|
+
addCacheBusters(dist);
|
|
232
233
|
if (htaccess) writeHtaccess(dist, html);
|
|
233
234
|
|
|
234
235
|
const report = () => {
|
|
@@ -252,6 +253,22 @@ ${indent(components.join('\n\n'))}
|
|
|
252
253
|
report();
|
|
253
254
|
};
|
|
254
255
|
|
|
256
|
+
// A host keeps .js and .css for days (Hostinger: 7), and a new build keeps the same file names, so visitors would run the old
|
|
257
|
+
// runtime and old pages after an upgrade (the welcome page still saying "Kreft 0.0.6-beta"). A short hash of each file goes into its
|
|
258
|
+
// address (kreftjs.js?v=3f2a9c1b): a changed file is a new address, an unchanged one stays cached.
|
|
259
|
+
function addCacheBusters(dist) {
|
|
260
|
+
const file = path.join(dist, 'index.html');
|
|
261
|
+
const html = fs.readFileSync(file, 'utf8');
|
|
262
|
+
const out = html.replace(/(<(?:script|link)\b[^>]*?\b(?:src|href)=)(["'])([^"']+)\2/gi, (m, pre, q, url) => {
|
|
263
|
+
if (/^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(url) || /[?#]/.test(url) || !/\.(?:m?js|css)$/i.test(url)) return m;
|
|
264
|
+
const target = path.join(dist, url.replace(/^\//, ''));
|
|
265
|
+
if (!target.startsWith(dist + path.sep) || !fs.existsSync(target) || !fs.statSync(target).isFile()) return m;
|
|
266
|
+
const hash = require('crypto').createHash('sha1').update(fs.readFileSync(target)).digest('hex').slice(0, 8);
|
|
267
|
+
return pre + q + url + '?v=' + hash + q;
|
|
268
|
+
});
|
|
269
|
+
if (out !== html) fs.writeFileSync(file, out);
|
|
270
|
+
}
|
|
271
|
+
|
|
255
272
|
// Apache (Hostinger, cPanel …) answers /docs with a 404, because only index.html exists on disk. These rules send every page address
|
|
256
273
|
// (no file extension, not under /api/) that is not a real file, or a folder with its own index.html (a prerendered page), to index.html,
|
|
257
274
|
// so reloading a page works even when a folder has the page's name (the docs/ folder next to the /docs page). A missing file such as
|
|
@@ -273,6 +290,13 @@ function writeHtaccess(dist, html) {
|
|
|
273
290
|
RewriteCond %{REQUEST_URI} !\\.[A-Za-z0-9]+$
|
|
274
291
|
RewriteRule . ${base}index.html [L]
|
|
275
292
|
</IfModule>
|
|
293
|
+
|
|
294
|
+
# index.html names the other files with their hashes, so it must always be asked for again
|
|
295
|
+
<IfModule mod_headers.c>
|
|
296
|
+
<FilesMatch "^index\\.html$">
|
|
297
|
+
Header set Cache-Control "no-cache"
|
|
298
|
+
</FilesMatch>
|
|
299
|
+
</IfModule>
|
|
276
300
|
`);
|
|
277
301
|
}
|
|
278
302
|
|
package/docs/README.md
CHANGED
|
@@ -82,7 +82,7 @@ npx kreftjs dev
|
|
|
82
82
|
### Check that it works
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
|
-
kreft --version # for example 0.0.
|
|
85
|
+
kreft --version # for example 0.0.12-beta
|
|
86
86
|
kreft about # Kreft and Node.js versions, this project's settings and drivers
|
|
87
87
|
kreft list # every command your version has
|
|
88
88
|
```
|
|
@@ -1751,7 +1751,7 @@ RewriteCond %{REQUEST_URI} !\.[A-Za-z0-9]+$
|
|
|
1751
1751
|
RewriteRule . /index.html [L]
|
|
1752
1752
|
```
|
|
1753
1753
|
|
|
1754
|
-
Apache only knows the files on disk, so without these rules `/docs` or any other clean address gives a 404 when someone opens or reloads it. With them, every page address (no file extension, not under `/api/`) that is not a real file, or a folder with its own `index.html`, opens `index.html` and the router takes over. A missing file such as `app.js`, or an `/api/` address, stays a plain 404, so code that asks for data never receives the page's HTML. Upload the file too (it starts with a dot, so some file managers hide it; turn on "show hidden files"). If the site lives in a folder, build with `--base /folder/` and the rules follow it. An `.htaccess` you keep in `public/` is used as it is. A relative base (`--base ./`, used by the desktop build) gets no file.
|
|
1754
|
+
Apache only knows the files on disk, so without these rules `/docs` or any other clean address gives a 404 when someone opens or reloads it. With them, every page address (no file extension, not under `/api/`) that is not a real file, or a folder with its own `index.html`, opens `index.html` and the router takes over. A missing file such as `app.js`, or an `/api/` address, stays a plain 404, so code that asks for data never receives the page's HTML. Upload the file too (it starts with a dot, so some file managers hide it; turn on "show hidden files"). If the site lives in a folder, build with `--base /folder/` and the rules follow it. An `.htaccess` you keep in `public/` is used as it is. `kreft build` also puts a short hash into the address of each script and style sheet (`app.js?v=28a965f6`), and the `.htaccess` tells the host never to keep `index.html`. Hosts cache `.js` and `.css` for days, so without the hash visitors would keep running the old runtime and old pages after you upload a new build. A relative base (`--base ./`, used by the desktop build) gets no file.
|
|
1755
1755
|
|
|
1756
1756
|
> [!NOTE]
|
|
1757
1757
|
> This hosts the front end only. Login, the database and everything under `/api` need the Node.js server, which Apache does not run.
|
package/kreftjs.d.ts
CHANGED
package/kreftjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.12-beta — reactive by nature
|
|
3
3
|
* The .kreft component language (state · derive · action · when · watch · on),
|
|
4
4
|
* { } views with k-if / k-each / k-model, components, slots, router, stores,
|
|
5
5
|
* share / receive, event bus and a template engine.
|
|
@@ -5036,7 +5036,7 @@
|
|
|
5036
5036
|
stores, storeLog, busLog,
|
|
5037
5037
|
};
|
|
5038
5038
|
|
|
5039
|
-
const VERSION = '0.0.
|
|
5039
|
+
const VERSION = '0.0.12-beta';
|
|
5040
5040
|
const Kreftjs = {
|
|
5041
5041
|
version: VERSION,
|
|
5042
5042
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kreftjs",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12-beta",
|
|
4
4
|
"description": "A tiny reactive framework with its own component language (.kreft files): router with nested routes, stores, saved data, animations, an API client, hot reload, DevTools and a template engine.",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"main": "kreftjs.js",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"start": "node bin/kreftjs.js dev --api demo/db.json --db sqlite:demo/database/demo.db --migrations demo/database/migrations --server demo/server --backend demo --seed",
|
|
15
15
|
"build": "node bin/kreftjs.js build demo --out dist/demo --include docs",
|
|
16
16
|
"preview": "node bin/kreftjs.js dev dist --api demo/db.json --db sqlite:demo/database/demo.db --migrations demo/database/migrations --server demo/server --backend demo --seed",
|
|
17
|
-
"test": "node --test test/security.test.js test/prerender.test.js test/seo.test.js test/rebrand.test.js test/noauth.test.js test/winspawn.test.js test/htaccess.test.js test/cookie-secure.test.js test/password-rule.test.js",
|
|
17
|
+
"test": "node --test test/security.test.js test/prerender.test.js test/seo.test.js test/rebrand.test.js test/noauth.test.js test/winspawn.test.js test/htaccess.test.js test/cookie-secure.test.js test/password-rule.test.js test/headline.test.js",
|
|
18
18
|
"electron": "kreftjs electron",
|
|
19
19
|
"electron:dev": "kreftjs electron:dev",
|
|
20
20
|
"electron:build": "kreftjs electron:build"
|
|
@@ -92,7 +92,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
92
92
|
<div class="badges">
|
|
93
93
|
<span class="badge danger-badge">HTTP {status}</span>
|
|
94
94
|
<span class="badge solid">{currentTitle}</span>
|
|
95
|
-
<span class="badge">Kreft {Kreftjs.version || '0.0.
|
|
95
|
+
<span class="badge">Kreft {Kreftjs.version || '0.0.12-beta'}</span>
|
|
96
96
|
</div>
|
|
97
97
|
<div class="actions">
|
|
98
98
|
<button class="sm" @click={copyReport}>{copied ? 'Copied Markdown' : 'Copy Report'}</button>
|
|
@@ -189,7 +189,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
189
189
|
<h3>Kreft Runtime</h3>
|
|
190
190
|
<table>
|
|
191
191
|
<tbody>
|
|
192
|
-
<tr><th>Engine</th><td><code>Kreft v{Kreftjs.version || '0.0.
|
|
192
|
+
<tr><th>Engine</th><td><code>Kreft v{Kreftjs.version || '0.0.12-beta'}</code></td></tr>
|
|
193
193
|
<tr><th>Sanitizer</th><td><code>Active (cleanHtml / SafeHtml)</code></td></tr>
|
|
194
194
|
<tr><th>Environment</th><td><code>development (APP_DEBUG=true)</code></td></tr>
|
|
195
195
|
</tbody>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Kreft v0.0.
|
|
2
|
+
* Kreft v0.0.12-beta — reactive by nature
|
|
3
3
|
* The .kreft component language (state · derive · action · when · watch · on),
|
|
4
4
|
* { } views with k-if / k-each / k-model, components, slots, router, stores,
|
|
5
5
|
* share / receive, event bus and a template engine.
|
|
@@ -5036,7 +5036,7 @@
|
|
|
5036
5036
|
stores, storeLog, busLog,
|
|
5037
5037
|
};
|
|
5038
5038
|
|
|
5039
|
-
const VERSION = '0.0.
|
|
5039
|
+
const VERSION = '0.0.12-beta';
|
|
5040
5040
|
const Kreftjs = {
|
|
5041
5041
|
version: VERSION,
|
|
5042
5042
|
// PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets
|
|
@@ -112,7 +112,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
112
112
|
<div class="info-list">
|
|
113
113
|
<div class="info-item">
|
|
114
114
|
<span class="info-label">Framework Engine</span>
|
|
115
|
-
<span class="info-value">Kreft {Kreftjs.version || '0.0.
|
|
115
|
+
<span class="info-value">Kreft {Kreftjs.version || '0.0.12-beta'}</span>
|
|
116
116
|
</div>
|
|
117
117
|
<div class="info-item">
|
|
118
118
|
<span class="info-label">Active Database</span>
|
|
@@ -4,6 +4,22 @@
|
|
|
4
4
|
state name = 'Enterprise User'
|
|
5
5
|
state count = 0
|
|
6
6
|
state copied = false
|
|
7
|
+
|
|
8
|
+
// the headline changes every few seconds: each line slides in from the right with a flash of red light (not for people who asked for less motion)
|
|
9
|
+
state rotating = [
|
|
10
|
+
'Build full-stack apps in plain words.',
|
|
11
|
+
'The JavaScript framework that reads like English.',
|
|
12
|
+
'Components, backend and database in one small framework.',
|
|
13
|
+
'A small framework for the whole stack.',
|
|
14
|
+
]
|
|
15
|
+
state rotIndex = 0
|
|
16
|
+
derive rotWord = [rotating[rotIndex]]
|
|
17
|
+
let rotTimer
|
|
18
|
+
on ready {
|
|
19
|
+
const calm = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
20
|
+
if (!calm) rotTimer = setInterval(() => { rotIndex = (rotIndex + 1) % rotating.length }, 3800)
|
|
21
|
+
}
|
|
22
|
+
on destroy { clearInterval(rotTimer) }
|
|
7
23
|
derive double = count * 2
|
|
8
24
|
|
|
9
25
|
state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$/, '') // where "Documentation" links go: PUBLIC_DOCS_URL in .env
|
|
@@ -64,10 +80,9 @@ action copy() {
|
|
|
64
80
|
<section class="hero-grid">
|
|
65
81
|
<!-- Left Column: Copy, Headlines & CTA Badges -->
|
|
66
82
|
<div class="hero-copy">
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
Framework.
|
|
83
|
+
<p class="version-pill"><span class="version-dot" aria-hidden="true"></span>Kreft v{Kreftjs.version}</p>
|
|
84
|
+
<h1 class="hero-headline" aria-label="Build full-stack apps in plain words.">
|
|
85
|
+
<span aria-hidden="true">{for w in rotWord key w}<span class="rotator">{w}</span>{/for}</span>
|
|
71
86
|
</h1>
|
|
72
87
|
|
|
73
88
|
<p class="hero-tagline">Built for scale, speed, and safety.</p>
|
|
@@ -275,8 +290,34 @@ action copy() {
|
|
|
275
290
|
.hero-copy {
|
|
276
291
|
max-width: 540px;
|
|
277
292
|
}
|
|
293
|
+
.version-pill {
|
|
294
|
+
display: inline-flex;
|
|
295
|
+
align-items: center;
|
|
296
|
+
gap: 8px;
|
|
297
|
+
margin: 0 0 20px;
|
|
298
|
+
padding: 5px 12px;
|
|
299
|
+
font-family: var(--font-mono, ui-monospace, monospace);
|
|
300
|
+
font-size: 12.5px;
|
|
301
|
+
font-weight: 500;
|
|
302
|
+
color: var(--foreground);
|
|
303
|
+
background: var(--accent);
|
|
304
|
+
border: 1px solid var(--border);
|
|
305
|
+
border-radius: 9999px;
|
|
306
|
+
}
|
|
307
|
+
.version-dot { width: 7px; height: 7px; border-radius: 50%; background: #10b981; }
|
|
308
|
+
|
|
309
|
+
/* the changing headline: each line slides in from the right (a marquee) with a flash of red light, then settles */
|
|
310
|
+
.rotator { display: block; animation: rotator-flash 0.9s ease-out; }
|
|
311
|
+
@keyframes rotator-flash {
|
|
312
|
+
0% { opacity: 0; transform: translateX(1.4em); filter: blur(6px); color: #ef4444; text-shadow: 0 0 0.7em rgba(239, 68, 68, 0.95); }
|
|
313
|
+
35% { opacity: 1; filter: blur(0); color: #ef4444; text-shadow: 0 0 0.55em rgba(239, 68, 68, 0.85); }
|
|
314
|
+
100% { opacity: 1; transform: none; filter: none; color: var(--foreground); text-shadow: none; }
|
|
315
|
+
}
|
|
316
|
+
@media (prefers-reduced-motion: reduce) { .rotator { animation: none; } }
|
|
278
317
|
.hero-headline {
|
|
279
|
-
font-size: clamp(
|
|
318
|
+
font-size: clamp(30px, 3.9vw, 48px);
|
|
319
|
+
min-height: 3.3em; /* three lines for the longest headline, so the page below does not jump */
|
|
320
|
+
overflow: hidden;
|
|
280
321
|
line-height: 1.05;
|
|
281
322
|
letter-spacing: -0.04em;
|
|
282
323
|
font-weight: 800;
|
|
@@ -605,7 +646,7 @@ dd { margin: 0; color: var(--muted); }
|
|
|
605
646
|
}
|
|
606
647
|
@media (max-width: 640px) {
|
|
607
648
|
.welcome-container { padding: 24px 0 48px; }
|
|
608
|
-
.hero-headline { font-size:
|
|
649
|
+
.hero-headline { font-size: 32px; }
|
|
609
650
|
.hero-tagline { font-size: 20px; }
|
|
610
651
|
.cta-actions { flex-direction: column; width: 100%; }
|
|
611
652
|
.pill-btn { width: 100%; text-align: center; }
|
|
@@ -118,7 +118,7 @@ state docs = (Kreftjs.env.PUBLIC_DOCS_URL || 'http://kreftjs.com').replace(/\/+$
|
|
|
118
118
|
<div class="hero-badges">
|
|
119
119
|
<span class="badge-exception">{currentTitle}</span>
|
|
120
120
|
<span class="badge-env">Node.js {typeof process !== 'undefined' ? process.version : 'v22.0.0'}</span>
|
|
121
|
-
<span class="badge-env">Kreft v0.0.
|
|
121
|
+
<span class="badge-env">Kreft v0.0.12-beta</span>
|
|
122
122
|
</div>
|
|
123
123
|
<h1 class="hero-error-message">{currentMessage}</h1>
|
|
124
124
|
</div>
|