kreftjs 0.0.17-beta → 0.0.20-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/README.md CHANGED
@@ -42,10 +42,30 @@ Open the address in the terminal (normally `http://localhost:8000`). A new proje
42
42
  | **Authentication** | Cookie sessions with CSRF protection, API tokens with permissions, device list, two-factor codes, email verification, account lockout. |
43
43
  | **Tooling** | `kreft dev` with hot reload, DevTools, an error monitor, `kreft build` (CSP-safe), prerendering, TypeScript, Vite and Electron support, a safer `kreft add`, an MCP server for AI agents. |
44
44
 
45
+ ## Desktop apps (Electron)
46
+
47
+ ```bash
48
+ kreft new my-app --electron # or: kreft electron:init in an existing app
49
+ npm install
50
+ kreft electron # opens the app in its own window (no browser, no URL)
51
+ ```
52
+
53
+ Make installers (build each system on that system; `.deb` and `.rpm` need Linux):
54
+
55
+ ```bash
56
+ npm run electron:build:mac # .dmg and .zip
57
+ npm run electron:build:win # NSIS installer and portable .exe
58
+ npm run electron:build:linux # AppImage, .deb and .rpm
59
+ npm run electron:build:all # all three (same as: kreft electron:build --all)
60
+ ```
61
+
62
+ The app icon is `build/icon.png`, and `ELECTRON_MENU=show|auto|hide` controls the window menu. Details: [Desktop apps with Electron](docs/README.md#desktop-apps-with-electron).
63
+
45
64
  ## Learn more
46
65
 
47
66
  | I want to… | Read |
48
67
  |---|---|
68
+ | Learn Kreft in Arabic, from basics to advanced tested examples | [كتاب Kreft بالعربية](book/ar/README.md) |
49
69
  | Build my first page | [Your first app](docs/README.md#your-first-app) and [Components](docs/README.md#components-and-the-kreft-file) |
50
70
  | Fetch data and handle forms | [Fetching data](docs/README.md#fetching-data), [Forms](docs/README.md#forms-and-validation) |
51
71
  | Add an API and a database | [Routing](docs/README.md#routing), [Models](docs/README.md#models-and-the-database), [Migrations](docs/README.md#migrations-seeders-and-factories) |
package/bin/build.js CHANGED
@@ -34,12 +34,13 @@ const SERVER_DIRS = new Set();
34
34
  const SKIP = new Set(['node_modules', 'dist', 'dist-electron', '.git', '.vscode', '.idea', 'package.json', 'package-lock.json', '.DS_Store']);
35
35
 
36
36
  module.exports = function build(args) {
37
- let folder = null, out = null, base = null, prerender = null, urlsFile = null, htaccess = true;
37
+ let folder = null, out = null, base = null, prerender = null, urlsFile = null, htaccess = true, minify = true;
38
38
  const include = [];
39
39
  for (let i = 0; i < args.length; i++) {
40
40
  if (args[i] === '--out' || args[i] === '-o') out = args[++i];
41
41
  else if (args[i] === '--base') base = args[++i];
42
42
  else if (args[i] === '--no-htaccess') htaccess = false;
43
+ else if (args[i] === '--no-minify') minify = false; // keep kreftjs.js readable (for debugging)
43
44
  else if (args[i] === '--include') include.push(args[++i]); // another folder to copy in, like the docs
44
45
  else if (args[i] === '--prerender') prerender = args[i + 1] && !args[i + 1].startsWith('-') && args[i + 1].includes('/') ? args[++i].split(',') : [];
45
46
  else if (args[i] === '--urls') urlsFile = args[++i]; // a file with more addresses to prerender (pages from your data)
@@ -154,7 +155,17 @@ ${indent(components.join('\n\n'))}
154
155
  }
155
156
  }
156
157
  }
157
- fs.copyFileSync(path.join(__dirname, '..', 'kreftjs.js'), path.join(dist, 'kreftjs.js'));
158
+ // the framework file is minified when esbuild is installed (about 40% smaller); without it, it is copied as it is
159
+ const runtimeSrc = path.join(__dirname, '..', 'kreftjs.js'), runtimeOut = path.join(dist, 'kreftjs.js');
160
+ const esb = minify ? deps.loadEsbuild(root) : null;
161
+ let minified = false;
162
+ if (esb) {
163
+ try {
164
+ fs.writeFileSync(runtimeOut, esb.transformSync(fs.readFileSync(runtimeSrc, 'utf8'), { minify: true, target: 'es2020', legalComments: 'none' }).code);
165
+ minified = true;
166
+ } catch (_) { /* fall back to the plain copy */ }
167
+ }
168
+ if (!minified) fs.copyFileSync(runtimeSrc, runtimeOut);
158
169
  for (const dir of include) {
159
170
  const from = path.resolve(dir);
160
171
  if (!fs.existsSync(from)) fail(`--include: ${dir} does not exist.`);
package/bin/electron.js CHANGED
@@ -54,11 +54,21 @@ function getDevToolsConfig() {
54
54
  // ELECTRON_MENU=hide no menu at all
55
55
  // Change it while running from the page: window.kreftDesktop.setMenu('show' | 'auto' | 'hide')
56
56
  let menuMode = String(process.env.ELECTRON_MENU || 'show').toLowerCase();
57
- const defaultMenu = Menu.getApplicationMenu();
57
+ let defaultMenu = null; // Electron's own menu, read once the app is ready
58
58
  function applyMenu(mode) {
59
59
  menuMode = ['show', 'auto', 'hide'].includes(mode) ? mode : 'show';
60
- Menu.setApplicationMenu(menuMode === 'hide' ? null : (Menu.getApplicationMenu() || defaultMenu));
60
+ if (!defaultMenu) defaultMenu = Menu.getApplicationMenu();
61
+ if (menuMode === 'hide') {
62
+ // macOS keeps one app menu (with Quit) because the system needs it; Windows and Linux lose the bar
63
+ Menu.setApplicationMenu(process.platform === 'darwin'
64
+ ? Menu.buildFromTemplate([{ role: 'appMenu' }])
65
+ : null);
66
+ } else {
67
+ Menu.setApplicationMenu(defaultMenu);
68
+ }
61
69
  if (mainWindow && process.platform !== 'darwin') {
70
+ if (menuMode === 'hide') mainWindow.removeMenu();
71
+ else mainWindow.setMenu(defaultMenu);
62
72
  mainWindow.setAutoHideMenuBar(menuMode === 'auto');
63
73
  mainWindow.setMenuBarVisibility(menuMode === 'show');
64
74
  }
@@ -235,6 +245,7 @@ ipcMain.handle('kreft:dialog:save', async (_, options) => {
235
245
  });
236
246
 
237
247
  app.whenReady().then(() => {
248
+ applyMenu(menuMode);
238
249
  createWindow();
239
250
 
240
251
  app.on('activate', () => {
@@ -431,7 +442,52 @@ function freePort(start) {
431
442
  });
432
443
  }
433
444
 
445
+ function help() {
446
+ console.log(`
447
+ Kreft + Electron: your app as a desktop program (Windows, macOS, Linux)
448
+
449
+ Commands
450
+ kreft new <name> --electron A new app with desktop support
451
+ kreft electron:init Add desktop support to an existing app (alias: kreft make:electron)
452
+ Writes electron/main.js, electron/preload.js, build/icon.png and the build block
453
+ in package.json. Files that exist are never overwritten.
454
+ kreft electron Open the app in its own window: no browser, no URL (alias: kreft electron:dev)
455
+ --devtools[=right|bottom|left|detach] Open DevTools --no-devtools Do not
456
+ --port <number> Private port for the hidden dev server (default: the next free one)
457
+ kreft electron:build Build the app (kreft build --base ./) and make installers in dist-electron/
458
+ --mac --win --linux Choose the systems (more electron-builder flags work: --arm64, --x64, --dir)
459
+ npm run electron:build:mac .dmg and .zip
460
+ npm run electron:build:win NSIS installer and portable .exe
461
+ npm run electron:build:linux AppImage, .deb and .rpm
462
+ npm run electron:build:all All three
463
+ kreft electron:help This text
464
+
465
+ Window menu ELECTRON_MENU=show (default) | auto (Alt shows it) | hide
466
+ From a page: kreftDesktop.setMenu('hide'), kreftDesktop.getMenu()
467
+ (macOS always keeps one app menu with Quit)
468
+ DevTools ELECTRON_DEVTOOLS=right|bottom|left|detach|false, or F12 / Ctrl+Shift+I
469
+ App icon build/icon.png, a square PNG of 512x512 or more (.icns and .ico are made from it)
470
+ App name build.productName and build.appId in package.json
471
+ Installer info description, homepage, author (with e-mail) and build.linux.maintainer in package.json
472
+ (missing ones are filled in from git when you build; check them)
473
+ From a page if (Kreftjs.isElectron) kreftDesktop.getInfo(), minimize(), maximize(), close(),
474
+ showMessageBox(), showOpenDialog(), showSaveDialog(), openDevTools()
475
+
476
+ Good to know
477
+ - Build each system on that system. On a Mac, .deb and .rpm fail: build them on Linux.
478
+ - npm run build makes the website (paths start at /). electron:build makes the desktop build (--base ./).
479
+ - The packaged app has no backend: frontend-only apps work, full-stack ones (login, database) need a server.
480
+ - Unsigned apps show a warning on macOS and Windows: https://www.electron.build/code-signing
481
+ - Errors: "Electron is not installed locally" -> kreft add -D electron
482
+ "electron-builder is not installed" -> kreft add -D electron-builder
483
+ White window in the app -> run electron:build again (it needs --base ./)
484
+
485
+ Full guide: docs/README.md, "Desktop apps with Electron"
486
+ `);
487
+ }
488
+
434
489
  function dev(args = []) {
490
+ if (['help', '--help', '-h'].includes(args[0])) return help();
435
491
  const asked = args.findIndex((a) => a === '--port' || a === '-p');
436
492
  if (asked >= 0 && Number(args[asked + 1])) return startDev(args, Number(args[asked + 1]));
437
493
  return freePort(Number(process.env.PORT) || 8000).then((port) => startDev(args, port));
@@ -521,6 +577,8 @@ function startDev(args, port) {
521
577
  }
522
578
 
523
579
  function build(args = []) {
580
+ // --all is a Kreft shortcut for --mac --win --linux (electron-builder has no such flag)
581
+ if (args.includes('--all')) args = [...args.filter((a) => a !== '--all'), ...['--mac', '--win', '--linux'].filter((p) => !args.includes(p))];
524
582
  const root = getProjectRoot();
525
583
  const electronMain = path.join(root, 'electron', 'main.js');
526
584
  if (!fs.existsSync(electronMain)) {
@@ -574,6 +632,7 @@ function build(args = []) {
574
632
 
575
633
  module.exports = {
576
634
  init,
635
+ help,
577
636
  dev,
578
637
  run: dev,
579
638
  build,
package/bin/kreftjs.js CHANGED
@@ -46,6 +46,7 @@ const commands = {
46
46
  'electron:dev': (a) => require('./electron.js').dev(a),
47
47
  'electron:build': (a) => require('./electron.js').build(a),
48
48
  'electron:init': (a) => require('./electron.js').init(a),
49
+ 'electron:help': () => require('./electron.js').help(),
49
50
  'make:electron': (a) => require('./electron.js').init(a),
50
51
  vite: (a) => require('./vite.js').dev(a),
51
52
  'vite:dev': (a) => require('./vite.js').dev(a),
@@ -117,10 +118,10 @@ function help() {
117
118
  kreft vite:init Add Vite configuration to an existing project (alias: kreft make:vite)
118
119
 
119
120
  Desktop (Electron.js):
120
- kreft electron Start dev server and launch desktop window (alias: kreft electron:dev)
121
- kreft electron:dev Start dev server and launch desktop window
122
- kreft electron:build Build static bundle and package desktop app with electron-builder
121
+ kreft electron Open the app in a desktop window only: no browser, no URL (alias: kreft electron:dev)
122
+ kreft electron:build Build and make installers (--mac, --win, --linux; or npm run electron:build:all)
123
123
  kreft electron:init Add Electron support to an existing project (alias: kreft make:electron)
124
+ kreft electron:help Everything about desktop apps: menu, icon, installers, errors
124
125
 
125
126
  The backend (kreft list shows every command, yours too):
126
127
  kreft key:generate Set the application encryption key in .env (--show: print only)
@@ -164,6 +165,7 @@ function help() {
164
165
  --prerender [paths] Also save every page as ready HTML (needs: npm i -D jsdom)
165
166
  --include <folder> Also copy this folder into the output (for example docs)
166
167
  --no-htaccess Do not write dist/.htaccess (page-address rules for Apache and Hostinger)
168
+ --no-minify Copy kreftjs.js as it is (by default it is minified when esbuild is installed)
167
169
  kreft add <packages...> Install npm packages with strict security gatekeeper (alias: kreft install, kreft i)
168
170
  -D, --dev Install as devDependency
169
171
  -y, --yes Auto-confirm unverified community packages in CI/CD
@@ -0,0 +1,169 @@
1
+ # الفصل الأول: البداية
2
+
3
+ ## ما هو Kreft؟
4
+
5
+ Kreft (يُكتب `kreftjs`) إطار عمل صغير، تفاعلي (reactive)، له لغة مكوّنات خاصة به: ملفات `.kreft`. تكتب في الملف الواحد حالتك وقيمك المشتقة وأفعالك بكلمات بسيطة، ثم تصف الصفحة في `<view>`. ويأتي مع واجهة خلفية كاملة على Node.js (مسارات، ومتحكمات، ونماذج، وترحيلات، وطوابير، وبريد)، فيغطي المشروع الواحد التطبيق بأكمله.
6
+
7
+ > **ملاحظة:** الإصدار الحالي تجريبي (`0.0.x-beta`). كل ما في هذا الكتاب جُرِّب على الإصدار الذي صدر معه، لكن واجهات الإطار قد تتغير بين الإصدارات التجريبية. راجع `kreft --version` وملف `docs/README.md` (بالإنجليزية) عند الشك.
8
+
9
+ لماذا قد تختاره؟
10
+
11
+ - **لغة واحدة للمكوّن:** HTML ومنطق وتنسيق في ملف واحد، بلا ديكورات ولا وحدات (modules) تتعلمها.
12
+ - **بدون إعداد:** `kreft new` ثم `kreft dev`. لا ملف إعداد لأداة تجميع.
13
+ - **واجهة خلفية جاهزة:** تسجيل دخول، وتحقق من البريد، واستعادة كلمة المرور، ولوحة إدارة، ومصادقة ثنائية.
14
+ - **تطبيقات سطح المكتب:** `kreft new --electron` ثم تبني مثبّتات لـ Windows وmacOS وLinux.
15
+ - **دعم RTL من الأساس:** تبديل اللغة واتجاه الصفحة من دالة واحدة (مهم لنا نحن العرب، وله فصل كامل).
16
+
17
+ ## التثبيت
18
+
19
+ المتطلبات: Node.js (يُفضَّل 22 أو أحدث) وnpm.
20
+
21
+ ```bash
22
+ npm install -g kreftjs
23
+ kreft --version # مثال: 0.0.19-beta
24
+ ```
25
+
26
+ للتحقق من أن كل شيء سليم:
27
+
28
+ ```bash
29
+ kreft about
30
+ ```
31
+
32
+ وللحصول على تلوين الملفات وملفات المقتطفات (snippets) في VS Code أو Cursor:
33
+
34
+ ```bash
35
+ kreft vscode
36
+ ```
37
+
38
+ ## أول تطبيق
39
+
40
+ ```bash
41
+ kreft new my-app # يسألك: JavaScript أم TypeScript؟
42
+ cd my-app
43
+ npm run dev
44
+ ```
45
+
46
+ افتح العنوان الذي يطبعه الطرفية (عادة `http://localhost:8000`؛ وإن كان المنفذ مشغولًا يُستخدم التالي).
47
+
48
+ خيارات مفيدة عند الإنشاء:
49
+
50
+ ```bash
51
+ kreft new shop --db mysql --ts # TypeScript وقاعدة MySQL
52
+ kreft new site --ui tailwind --no-auth # Tailwind بدون صفحات تسجيل الدخول
53
+ kreft new desk --electron # مع دعم تطبيقات سطح المكتب
54
+ kreft new app-name --ui bootstrap --no-auth
55
+ ```
56
+
57
+ > **تنبيه:** اكتب قيم الخيارات كما هي بالضبط: `bootstrap` و`tailwind` و`bulma` و`pico`. أي قيمة أخرى توقف الأمر مع رسالة تعرض القيم المسموحة.
58
+
59
+ يأتي المشروع الجديد (إن لم تستعمل `--no-auth`) بصفحات الدخول والتسجيل واستعادة كلمة المرور وتأكيد البريد والملف الشخصي ولوحة الإدارة. وعند تشغيل `npm run dev` تُنشأ الجداول ومستخدم تجريبي:
60
+
61
+ - البريد: `test@example.com`
62
+ - كلمة المرور: `password`
63
+
64
+ > **تحذير:** هذا المستخدم للتطوير المحلي فقط. احذفه أو لا تشغّل `--seed` أبدًا على قاعدة بيانات حقيقية.
65
+
66
+ رسائل البريد (تأكيد، استعادة) تُطبع في الطرفية إلى أن تضبط `MAIL_URL`.
67
+
68
+ ## أصغر تطبيق ممكن
69
+
70
+ يمكنك استعمال Kreft بلا مشروع كامل. التطبيق صفحة HTML وملفات `.kreft`:
71
+
72
+ ```html
73
+ <!-- index.html -->
74
+ <div id="app"></div>
75
+ <script src="kreftjs.js"></script>
76
+ <script>
77
+ Kreftjs.app('App.kreft').mount('#app')
78
+ </script>
79
+ ```
80
+
81
+ ```html
82
+ <!-- App.kreft -->
83
+ state name = 'العالم'
84
+
85
+ <view>
86
+ <h1>مرحبًا يا {name}</h1>
87
+ <input k-model="name">
88
+ </view>
89
+ ```
90
+
91
+ > **تحذير:** ملفات `.kreft` تحتاج خادمًا. المتصفحات ترفض تحميل الملفات من `file://`، فافتح التطبيق دائمًا عبر `npm run dev` أو أي خادم.
92
+
93
+ ## بنية المشروع
94
+
95
+ ينشئ `kreft new` مجلدين لا يختلطان أبدًا: `frontend/` هو ما يصل المتصفح، و`backend/` هو الخادم ولا يمكن الوصول إليه عبر HTTP.
96
+
97
+ ```text
98
+ my-app/
99
+ ├── frontend/
100
+ │ ├── index.html نقطة الدخول
101
+ │ ├── App.kreft المكوّن الجذر وحاوية الموجِّه
102
+ │ ├── routes/web.kreft مسارات الصفحات
103
+ │ ├── layouts/ app.kreft (بعد الدخول)، guest.kreft (صفحات الدخول)
104
+ │ ├── pages/ ملف .kreft لكل شاشة
105
+ │ ├── components/ مكوّنات قابلة لإعادة الاستخدام
106
+ │ ├── ui.css نظام التصميم
107
+ │ └── tests/ اختبارات المكوّنات
108
+ ├── backend/
109
+ │ ├── config/ app.js, auth.js, database.js, redis.js, session.js
110
+ │ ├── app/
111
+ │ │ ├── Http/ Controllers, Middleware, Requests, Resources
112
+ │ │ ├── Models/ User, PersonalAccessToken
113
+ │ │ └── Auth/ مساعدات الجلسات
114
+ │ ├── database/ migrations, seeders, factories
115
+ │ └── routes/ api.js, auth.js, console.js
116
+ ├── .env الأسرار والإعدادات (لا ترفعه إلى Git أبدًا)
117
+ ├── package.json
118
+ └── kreftjs.config.json خيارات سطر الأوامر
119
+ ```
120
+
121
+ لماذا الفصل مهم؟
122
+
123
+ - `kreft dev` و`kreft build` يقدّمان `frontend/` فقط. أما `backend/` وملفات قاعدة البيانات و`.env` فلا عنوان ويب لها.
124
+ - على macOS وLinux يمنح `kreft new` المجلد `backend/` والملف `.env` صلاحيات يقرؤها المالك فقط.
125
+ - ملفات مثل `.env` و`*.db` و`*.pem` و`package.json` مرفوضة حتى لو طُلبت بالاسم.
126
+
127
+ ## إضافة مكتبة CSS
128
+
129
+ أي مكتبة تعمل. أضف `<link>` في `index.html`، أو ثبّتها واستورد ملفها من ملف `.kreft`:
130
+
131
+ ```html
132
+ import 'bootstrap/dist/css/bootstrap.min.css' // npm i bootstrap
133
+ import './theme.css' // ملفك الخاص بجانب هذا الملف
134
+ ```
135
+
136
+ ## حزم npm في المتصفح
137
+
138
+ ```bash
139
+ kreft add dayjs nanoid lodash
140
+ kreft add -D esbuild # مرة واحدة لكل مشروع: يجهّز الحزم للمتصفح
141
+ ```
142
+
143
+ ```html
144
+ import dayjs from 'dayjs'
145
+ import { nanoid } from 'nanoid'
146
+
147
+ state id = nanoid()
148
+
149
+ <view>
150
+ <p>{dayjs().format('YYYY-MM-DD')}</p>
151
+ </view>
152
+ ```
153
+
154
+ الأمر `kreft add` نسخة أكثر أمانًا من `npm install`: يمنع سكربتات التثبيت افتراضيًا، ويتحقق من أخطاء الكتابة المتعمدة في أسماء الحزم (typosquatting)، وينبّه إلى الحزم التي نُشرت قبل أقل من 14 يومًا، ثم يشغّل `npm audit`.
155
+
156
+ ## أوامر ستستخدمها كل يوم
157
+
158
+ | الأمر | وظيفته |
159
+ |---|---|
160
+ | `kreft new my-app` | ينشئ مشروعًا |
161
+ | `kreft dev` | خادم التطوير مع إعادة تحميل فورية |
162
+ | `kreft build` | يصرّف التطبيق إلى ملفات عادية في `dist/` |
163
+ | `kreft serve dist` | يشغّل التطبيق المبني للمستخدمين الحقيقيين |
164
+ | `kreft list` | يعرض كل أوامر نسختك |
165
+ | `kreft help` | خيارات الأوامر الرئيسية |
166
+ | `kreft tinker` | طرفية تفاعلية مع نماذجك (`await User.count()`) |
167
+ | `kreft update` | يحدّث الحزم وملف `kreftjs.js` |
168
+
169
+ تدريب سريع: أنشئ مشروعًا، وغيّر كلمة في `frontend/pages/` وراقب الصفحة تتبدل في المتصفح دون إعادة تحميل وبدون ضياع الحالة. هذه هي إعادة التحميل الفورية (hot reload).