kreftjs 0.0.23-beta.0 → 0.0.23-beta.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.
@@ -0,0 +1,278 @@
1
+ /*
2
+ * Home pages made for apps, not for the web:
3
+ *
4
+ * kreft new my-app --mobile the home page is a phone screen: top bar, cards, big touch targets, bottom tab bar
5
+ * kreft new my-app --electron the home page is a desktop workspace: sidebar, toolbar, cards, shortcuts
6
+ * kreft make:home --mobile | --desktop (re)write them in an existing project (replaces pages/Home.kreft)
7
+ *
8
+ * Both together: pages/Home.kreft shows the desktop one inside the Electron window and the phone one everywhere else.
9
+ * Add ?platform=mobile or ?platform=desktop to the address to preview either in a normal browser.
10
+ *
11
+ * The generated files are plain .kreft files in the project: change them freely.
12
+ */
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ // what the project has: no-auth projects have no dashboard, users or profile pages
17
+ function features(front) {
18
+ const has = (f) => fs.existsSync(path.join(front, f));
19
+ return { dashboard: has('pages/Dashboard.kreft'), users: has('pages/Users.kreft'), profile: has('pages/Profile.kreft'), docs: has('docs/Docs.kreft'), auth: has('pages/auth') };
20
+ }
21
+
22
+ const js = (v) => JSON.stringify(v).replace(/</g, '\\u003c');
23
+
24
+ function mobileSource(f) {
25
+ const tiles = [
26
+ f.dashboard && { icon: '▦', label: 'Dashboard', to: '/dashboard' },
27
+ f.users && { icon: '☺', label: 'Users', to: '/users' },
28
+ f.profile && { icon: '⚙', label: 'Profile', to: '/profile' },
29
+ f.docs && { icon: '☰', label: 'Docs', to: '/docs' },
30
+ { icon: '!', label: 'Errors', to: '/error-monitor' },
31
+ ].filter(Boolean);
32
+ const tabs = [{ icon: '⌂', label: 'Home', to: '/' }, ...tiles.filter((t) => t.to !== '/error-monitor').slice(0, 3)];
33
+ return `<!-- The home page of the phone app: a top bar, cards and a bottom tab bar, all sized for a thumb.
34
+ @tap, @swipeleft and @longpress are Kreft's touch events. Add ?platform=mobile in a browser to preview it. -->
35
+
36
+ state app = Kreftjs.env.PUBLIC_APP_NAME || 'My app'
37
+ state tiles = ${js(tiles)}
38
+ state tabs = ${js(tabs)}
39
+ state taps = 0
40
+ state note = 'Tap the card. Swipe left to reset. Hold to double.'
41
+
42
+ action hit() { taps++; note = 'Tapped ' + taps + (taps === 1 ? ' time' : ' times') }
43
+ action reset() { taps = 0; note = 'Reset by swipe' }
44
+ action boost() { taps = taps * 2; note = 'Doubled by long press' }
45
+
46
+ <view>
47
+ <div class="phone">
48
+ <header class="bar">
49
+ <img src="logo-mark.svg" alt="" width="28" height="28">
50
+ <h1>{app}</h1>
51
+ </header>
52
+
53
+ <main>
54
+ <section class="hello">
55
+ <p class="small">Welcome back</p>
56
+ <h2>What do you want to do?</h2>
57
+ </section>
58
+
59
+ <section class="grid" aria-label="Shortcuts">
60
+ <kreft-link k-for="t in tiles" to={t.to} class="tile">
61
+ <span class="ico" aria-hidden="true">{t.icon}</span>
62
+ <span class="lbl">{t.label}</span>
63
+ </kreft-link>
64
+ </section>
65
+
66
+ <section class="card try" @tap={hit} @swipeleft={reset} @longpress={boost}>
67
+ <p class="small">Touch events</p>
68
+ <p class="count">{taps}</p>
69
+ <p class="note">{note}</p>
70
+ </section>
71
+
72
+ <section class="card">
73
+ <p class="small">This app</p>
74
+ <p>One Kreft codebase: the website, the phone app and the desktop app.</p>
75
+ </section>
76
+ </main>
77
+
78
+ <nav class="tabs" aria-label="Main">
79
+ <kreft-link k-for="t in tabs" to={t.to} class="tab" active-class="on" exact-active-class="on">
80
+ <span class="ico" aria-hidden="true">{t.icon}</span>
81
+ <span class="lbl">{t.label}</span>
82
+ </kreft-link>
83
+ </nav>
84
+ </div>
85
+ </view>
86
+
87
+ <style scoped>
88
+ .phone { min-height: 100vh; display: flex; flex-direction: column; background: var(--accent); }
89
+ .bar { position: sticky; top: 0; z-index: 5; display: flex; align-items: center; gap: 10px; padding: 14px 16px; background: var(--background); border-bottom: 1px solid var(--border); }
90
+ .bar h1 { margin: 0; font-size: 18px; font-weight: 700; letter-spacing: -0.02em; }
91
+ main { flex: 1; padding: 16px 16px 96px; display: flex; flex-direction: column; gap: 16px; }
92
+ .small { margin: 0 0 4px; font-size: 13px; color: var(--muted); }
93
+ .hello h2 { margin: 0; font-size: 26px; line-height: 1.2; letter-spacing: -0.03em; }
94
+ .grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
95
+ .tile { display: flex; flex-direction: column; justify-content: space-between; gap: 18px; min-height: 104px; padding: 16px; background: var(--card); border: 1px solid var(--card-border); border-radius: 16px; color: var(--foreground); text-decoration: none; }
96
+ .tile:active { background: var(--accent-strong); }
97
+ .tile .ico { font-size: 26px; line-height: 1; }
98
+ .tile .lbl { font-weight: 600; font-size: 16px; }
99
+ .card { padding: 18px; background: var(--card); border: 1px solid var(--card-border); border-radius: 16px; }
100
+ .card p:last-child { margin-bottom: 0; }
101
+ .try { user-select: none; -webkit-user-select: none; text-align: center; }
102
+ .try:active { background: var(--accent-strong); }
103
+ .count { margin: 4px 0; font-size: 56px; font-weight: 700; letter-spacing: -0.04em; }
104
+ .note { margin: 0; color: var(--muted); font-size: 14px; }
105
+ .tabs { position: fixed; left: 0; right: 0; bottom: 0; z-index: 10; display: flex; padding: 6px 8px calc(6px + env(safe-area-inset-bottom)); background: var(--background); border-top: 1px solid var(--border); }
106
+ .tab { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 6px 0; min-height: 48px; color: var(--muted); text-decoration: none; font-size: 12px; border-radius: 12px; }
107
+ .tab .ico { font-size: 22px; line-height: 1.1; }
108
+ .tab.on { color: var(--foreground); font-weight: 700; }
109
+ @media (min-width: 700px) { .phone { max-width: 520px; margin: 0 auto; border-inline: 1px solid var(--border); } .tabs { max-width: 520px; margin: 0 auto; } }
110
+ </style>
111
+ `;
112
+ }
113
+
114
+ function desktopSource(f) {
115
+ const nav = [
116
+ { label: 'Home', to: '/' },
117
+ f.dashboard && { label: 'Dashboard', to: '/dashboard' },
118
+ f.users && { label: 'Users', to: '/users' },
119
+ f.profile && { label: 'Profile', to: '/profile' },
120
+ f.docs && { label: 'Docs', to: '/docs' },
121
+ { label: 'Error monitor', to: '/error-monitor' },
122
+ ].filter(Boolean);
123
+ return `<!-- The home page of the desktop app: a sidebar, a toolbar and a workspace, like a real desktop program.
124
+ Inside the Electron window window.kreftDesktop gives the app name, version and system.
125
+ Add ?platform=desktop in a browser to preview it. -->
126
+
127
+ state app = Kreftjs.env.PUBLIC_APP_NAME || 'My app'
128
+ state nav = ${js(nav)}
129
+ state query = ''
130
+ state info = { name: app, version: '', platform: 'browser' }
131
+ state shortcuts = [
132
+ { keys: 'F12', does: 'Open or close the developer tools' },
133
+ { keys: 'Ctrl / ⌘ + R', does: 'Reload the window' },
134
+ { keys: 'Ctrl / ⌘ + + / −', does: 'Zoom in and out' },
135
+ { keys: 'F11', does: 'Full screen' },
136
+ ]
137
+ derive shown = nav.filter((n) => n.label.toLowerCase().includes(query.trim().toLowerCase()))
138
+
139
+ on ready {
140
+ if (window.kreftDesktop && window.kreftDesktop.getInfo) {
141
+ window.kreftDesktop.getInfo().then((i) => { info = { name: i.name, version: i.version, platform: i.platform + ' ' + i.arch } }).catch(() => {})
142
+ }
143
+ }
144
+
145
+ <view>
146
+ <div class="shell">
147
+ <aside class="side">
148
+ <div class="brand"><img src="logo-mark.svg" alt="" width="22" height="22"><span>{app}</span></div>
149
+ <nav aria-label="Main">
150
+ <kreft-link k-for="n in nav" to={n.to} class="item" active-class="on" exact-active-class="on">{n.label}</kreft-link>
151
+ </nav>
152
+ <p class="foot">{info.name} {info.version}<br>{info.platform}</p>
153
+ </aside>
154
+
155
+ <section class="work">
156
+ <header class="toolbar">
157
+ <h1>Home</h1>
158
+ <input type="search" placeholder="Search pages…" k-model="query" aria-label="Search pages">
159
+ </header>
160
+
161
+ <div class="content">
162
+ <div class="cards">
163
+ <article class="card"><p class="small">Application</p><p class="big">{info.name}</p></article>
164
+ <article class="card"><p class="small">Version</p><p class="big">{info.version || 'dev'}</p></article>
165
+ <article class="card"><p class="small">System</p><p class="big">{info.platform}</p></article>
166
+ </div>
167
+
168
+ <h2>Open</h2>
169
+ <div class="list">
170
+ <kreft-link k-for="n in shown" to={n.to} class="row"><span>{n.label}</span><span class="arrow">→</span></kreft-link>
171
+ <p k-if="shown.length === 0" class="empty">No page matches “{query}”.</p>
172
+ </div>
173
+
174
+ <h2>Shortcuts</h2>
175
+ <table class="keys">
176
+ <tr k-for="s in shortcuts"><td><kbd>{s.keys}</kbd></td><td>{s.does}</td></tr>
177
+ </table>
178
+ </div>
179
+ </section>
180
+ </div>
181
+ </view>
182
+
183
+ <style scoped>
184
+ .shell { display: grid; grid-template-columns: 232px 1fr; height: 100vh; background: var(--background); color: var(--foreground); }
185
+ .side { display: flex; flex-direction: column; gap: 8px; padding: 16px 12px; background: var(--accent); border-right: 1px solid var(--border); overflow: auto; }
186
+ .brand { display: flex; align-items: center; gap: 8px; padding: 4px 8px 12px; font-weight: 700; letter-spacing: -0.02em; }
187
+ .item { display: block; padding: 8px 10px; border-radius: 6px; color: var(--muted); text-decoration: none; font-size: 14px; }
188
+ .item:hover { background: var(--accent-strong); color: var(--foreground); }
189
+ .item.on { background: var(--accent-strong); color: var(--foreground); font-weight: 600; }
190
+ .foot { margin: auto 0 0; padding: 8px; font-size: 12px; color: var(--muted); }
191
+ .work { display: flex; flex-direction: column; min-width: 0; }
192
+ .toolbar { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 12px 24px; border-bottom: 1px solid var(--border); }
193
+ .toolbar h1 { margin: 0; font-size: 18px; }
194
+ .toolbar input { width: 260px; max-width: 50%; }
195
+ .content { padding: 24px; overflow: auto; }
196
+ .content h2 { margin: 28px 0 12px; font-size: 14px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
197
+ .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 16px; }
198
+ .card { padding: 16px; background: var(--card); border: 1px solid var(--card-border); border-radius: var(--radius-lg); }
199
+ .small { margin: 0 0 4px; font-size: 12px; color: var(--muted); }
200
+ .big { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -0.02em; overflow-wrap: anywhere; }
201
+ .list { border: 1px solid var(--card-border); border-radius: var(--radius-lg); overflow: hidden; }
202
+ .row { display: flex; justify-content: space-between; padding: 12px 16px; color: var(--foreground); text-decoration: none; border-bottom: 1px solid var(--border-subtle); }
203
+ .row:last-child { border-bottom: 0; }
204
+ .row:hover { background: var(--accent); }
205
+ .arrow { color: var(--muted); }
206
+ .empty { margin: 0; padding: 12px 16px; color: var(--muted); }
207
+ .keys { border-collapse: collapse; }
208
+ .keys td { padding: 6px 24px 6px 0; font-size: 14px; }
209
+ kbd { padding: 2px 6px; border: 1px solid var(--border); border-radius: 4px; background: var(--accent); font-size: 12px; }
210
+ @media (max-width: 720px) { .shell { grid-template-columns: 1fr; height: auto; } .side { border-right: 0; border-bottom: 1px solid var(--border); } }
211
+ </style>
212
+ `;
213
+ }
214
+
215
+ // pages/Home.kreft: the platform switch when both exist, otherwise the one that exists
216
+ function homeSource(mobile, desktop) {
217
+ if (mobile && desktop) {
218
+ return `<!-- The home page: the desktop workspace inside the Electron window, the phone screen everywhere else.
219
+ Preview in a browser with ?platform=desktop or ?platform=mobile. -->
220
+ state desktop = (function () {
221
+ const asked = new URLSearchParams(location.search).get('platform')
222
+ if (asked) return asked === 'desktop'
223
+ return Boolean(window.kreftDesktop || window.__KREFT_ELECTRON__)
224
+ })()
225
+
226
+ <view>
227
+ <home-desktop k-if="desktop"></home-desktop>
228
+ <home-mobile k-else></home-mobile>
229
+ </view>
230
+ `;
231
+ }
232
+ return `<!-- The home page of the ${mobile ? 'phone' : 'desktop'} app. Its design is in components/${mobile ? 'HomeMobile' : 'HomeDesktop'}.kreft -->
233
+ <view>
234
+ <home-${mobile ? 'mobile' : 'desktop'}></home-${mobile ? 'mobile' : 'desktop'}>
235
+ </view>
236
+ `;
237
+ }
238
+
239
+ // index.html lists every component: .component('Field', 'components/Field.kreft')
240
+ function register(front, names) {
241
+ const file = path.join(front, 'index.html');
242
+ if (!fs.existsSync(file)) return;
243
+ let html = fs.readFileSync(file, 'utf8');
244
+ const add = names.filter((n) => !html.includes(`.component('${n}'`));
245
+ if (!add.length) return;
246
+ const lines = add.map((n) => `.component('${n}', 'components/${n}.kreft')`);
247
+ const m = html.match(/^([ \t]*)\.component\(/m) || html.match(/^([ \t]*)\.use\(router\)/m);
248
+ if (!m) { console.warn(' Could not find where components are listed in index.html. Add: ' + lines.join(' ')); return; }
249
+ const indent = m[1];
250
+ html = html.replace(m[0], lines.map((l) => indent + l + '\n').join('') + m[0]);
251
+ fs.writeFileSync(file, html);
252
+ }
253
+
254
+ // existing: what a project that already had one of them keeps when the other is added
255
+ function apply(target, { mobile = false, desktop = false } = {}) {
256
+ const lay = require('./layout.js').layout(target);
257
+ const front = lay.frontend;
258
+ const f = features(front);
259
+ fs.mkdirSync(path.join(front, 'components'), { recursive: true });
260
+ fs.mkdirSync(path.join(front, 'pages'), { recursive: true });
261
+ const has = (n) => fs.existsSync(path.join(front, 'components', n));
262
+ const wantMobile = mobile || has('HomeMobile.kreft');
263
+ const wantDesktop = desktop || has('HomeDesktop.kreft');
264
+ if (mobile) fs.writeFileSync(path.join(front, 'components', 'HomeMobile.kreft'), mobileSource(f));
265
+ if (desktop) fs.writeFileSync(path.join(front, 'components', 'HomeDesktop.kreft'), desktopSource(f));
266
+ fs.writeFileSync(path.join(front, 'pages', 'Home.kreft'), homeSource(wantMobile, wantDesktop));
267
+ register(front, [wantMobile && 'HomeMobile', wantDesktop && 'HomeDesktop'].filter(Boolean));
268
+ return { mobile: wantMobile, desktop: wantDesktop };
269
+ }
270
+
271
+ function make(args = []) {
272
+ const mobile = args.includes('--mobile'), desktop = args.includes('--desktop') || args.includes('--electron');
273
+ if (!mobile && !desktop) { console.error(' Use kreft make:home --mobile or --desktop (or both).'); process.exit(1); }
274
+ const r = apply(process.cwd(), { mobile, desktop });
275
+ console.log(` Wrote the ${[r.mobile && 'phone', r.desktop && 'desktop'].filter(Boolean).join(' and ')} home page (pages/Home.kreft and components/).`);
276
+ }
277
+
278
+ module.exports = { apply, make, mobileSource, desktopSource, homeSource, features };
package/bin/kreftjs.js CHANGED
@@ -48,6 +48,7 @@ const commands = {
48
48
  'electron:init': (a) => require('./electron.js').init(a),
49
49
  'electron:help': () => require('./electron.js').help(),
50
50
  'make:electron': (a) => require('./electron.js').init(a),
51
+ 'make:home': (a) => require('./home-variants.js').make(a),
51
52
  'mobile:init': (a) => require('./mobile.js').init(a[0]),
52
53
  'mobile:build': (a) => require('./mobile.js').build(a),
53
54
  'mobile:open': (a) => require('./mobile.js').open(a),
@@ -128,6 +129,7 @@ function help() {
128
129
  kreft electron Open the app in a desktop window only: no browser, no URL (alias: kreft electron:dev)
129
130
  kreft electron:build Build and make installers (--mac, --win, --linux; or npm run electron:build:all)
130
131
  kreft electron:init Add Electron support to an existing project (alias: kreft make:electron)
132
+ kreft make:home Write an app-style home page: --mobile (phone screen) or --desktop (sidebar workspace)
131
133
  kreft mobile:build Build for iOS / Android with Capacitor (--android, --ios, --api-url; see kreft mobile:help)
132
134
  kreft electron:help Everything about desktop apps: menu, icon, installers, errors
133
135
 
@@ -305,6 +307,7 @@ async function createProject(args) {
305
307
  fs.writeFileSync(path.join(target, 'package.json'), JSON.stringify(projectPkg, null, 2) + '\n');
306
308
  if (electron) require('./electron.js').init(target);
307
309
  if (mobile) require('./mobile.js').init(target);
310
+ if (mobile || electron) require('./home-variants.js').apply(target, { mobile, desktop: electron }); // a home page made for the app, not the web
308
311
  if (vite) require('./vite.js').init(target, { ts });
309
312
 
310
313
  console.log(`
package/bin/mobile.js CHANGED
@@ -40,6 +40,7 @@ function configFor(root) {
40
40
  appName: String(name),
41
41
  webDir: 'dist',
42
42
  server: { androidScheme: 'https' },
43
+ android: { adjustMarginsForEdgeToEdge: 'force' }, // Android 15+ draws apps under the status bar: keep the page below it
43
44
  };
44
45
  }
45
46
 
package/docs/README.md CHANGED
@@ -2243,6 +2243,8 @@ kreft mobile:open --android # Android Studio (--ios: Xcode, needs a Mac)
2243
2243
  | `kreft mobile:open` | Opens the native project |
2244
2244
  | `kreft mobile:dev` | Runs on a device or emulator with live reload from your dev server (same Wi-Fi) |
2245
2245
 
2246
+ **Building the Android app needs Java 21** (Capacitor 7). Android Studio includes it; on a command line set `JAVA_HOME` to it, for example on a Mac `export JAVA_HOME="/Applications/Android Studio.app/Contents/jbr/Contents/Home"`. Running from Android Studio ( `kreft mobile:open --android` ) needs no extra setup. The iOS Simulator needs a full Xcode install, not only the command line tools.
2247
+
2246
2248
  **The backend does not run inside the phone.** Run it on a server and give the app its address with `--api-url` (written to `.env` as `PUBLIC_API_URL`), then in your code:
2247
2249
 
2248
2250
  ```js
@@ -2251,6 +2253,17 @@ Kreftjs.api.setup({ base: Kreftjs.env.PUBLIC_API_URL, token: () => Kreftjs.stora
2251
2253
 
2252
2254
  Use API tokens for sign-in in the app, not cookie sessions.
2253
2255
 
2256
+ ### Home pages made for apps
2257
+
2258
+ A website's welcome page is not what an app should open on. `kreft new my-app --mobile` writes a **phone home screen** (top bar, shortcut cards, a bottom tab bar, a card that shows the touch events), and `kreft new my-app --electron` writes a **desktop workspace** (sidebar, toolbar with search, info cards, shortcuts). With both flags, `pages/Home.kreft` shows the desktop one inside the Electron window and the phone one everywhere else.
2259
+
2260
+ ```bash
2261
+ kreft make:home --mobile # in an existing project: phone home screen (replaces pages/Home.kreft)
2262
+ kreft make:home --desktop # desktop workspace
2263
+ ```
2264
+
2265
+ They are normal files (`components/HomeMobile.kreft`, `components/HomeDesktop.kreft`), so change them freely. Preview either in a browser with `?platform=mobile` or `?platform=desktop`. Links to the dashboard, users and profile appear only when the project has them (not with `--no-auth`).
2266
+
2254
2267
  ### Touch events
2255
2268
 
2256
2269
  ```html
package/kreftjs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Kreft v0.0.22-beta — reactive by nature
2
+ * Kreft v0.0.23-beta.1 — 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.
@@ -5648,7 +5648,7 @@
5648
5648
  stores, storeLog, busLog,
5649
5649
  };
5650
5650
 
5651
- const VERSION = '0.0.22-beta';
5651
+ const VERSION = '0.0.23-beta.1';
5652
5652
  const Kreftjs = {
5653
5653
  version: VERSION,
5654
5654
  // 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.23-beta.0",
3
+ "version": "0.0.23-beta.1",
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/kreftjs-com --base / --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 test/headline.test.js test/menu.test.js test/electron-all.test.js test/build-minify.test.js test/stream.test.js test/syntax.test.js test/memory.test.js test/shield.test.js test/mcp-client.test.js test/dbapi-secrets.test.js test/auth-csrf.test.js test/not-a-project.test.js test/mobile.test.js test/gestures.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 test/menu.test.js test/electron-all.test.js test/build-minify.test.js test/stream.test.js test/syntax.test.js test/memory.test.js test/shield.test.js test/mcp-client.test.js test/dbapi-secrets.test.js test/auth-csrf.test.js test/not-a-project.test.js test/mobile.test.js test/gestures.test.js test/home-variants.test.js",
18
18
  "electron": "kreftjs electron",
19
19
  "electron:dev": "kreftjs electron:dev",
20
20
  "electron:build": "kreftjs electron:build"
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Kreft v0.0.22-beta — reactive by nature
2
+ * Kreft v0.0.23-beta.1 — 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.
@@ -5648,7 +5648,7 @@
5648
5648
  stores, storeLog, busLog,
5649
5649
  };
5650
5650
 
5651
- const VERSION = '0.0.22-beta';
5651
+ const VERSION = '0.0.23-beta.1';
5652
5652
  const Kreftjs = {
5653
5653
  version: VERSION,
5654
5654
  // PUBLIC_ values from .env (kreft dev and kreft build put them here); never secrets