kreftjs 0.0.7-beta → 0.0.10-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.
Files changed (96) hide show
  1. package/README.md +5 -31
  2. package/bin/artisan-more.js +2 -0
  3. package/bin/artisan.js +51 -49
  4. package/bin/backend/config.js +2 -2
  5. package/bin/backend/http.js +5 -5
  6. package/bin/backend/index.js +6 -2
  7. package/bin/backend/mcp.js +3 -5
  8. package/bin/backend/migrator.js +1 -3
  9. package/bin/backend/query.js +1 -1
  10. package/bin/backend/queue.js +8 -9
  11. package/bin/backend/redis.js +1 -1
  12. package/bin/backend/typescript.js +1 -1
  13. package/bin/build.js +24 -19
  14. package/bin/db-api.js +2 -2
  15. package/bin/db.js +4 -4
  16. package/bin/deps.js +1 -1
  17. package/bin/electron.js +3 -5
  18. package/bin/kreftjs-config.js +1 -6
  19. package/bin/kreftjs.js +34 -35
  20. package/bin/layout.js +1 -1
  21. package/bin/no-auth.js +18 -18
  22. package/bin/prerender.js +1 -1
  23. package/bin/ssr.js +3 -3
  24. package/bin/update.js +10 -10
  25. package/docs/{Docs.kreftjs → Docs.kreft} +1 -1
  26. package/docs/README.md +102 -104
  27. package/editors/vscode/README.md +3 -3
  28. package/editors/vscode/package.json +3 -4
  29. package/editors/vscode/snippets/kreftjs.json +2 -2
  30. package/kreftjs.d.ts +15 -27
  31. package/kreftjs.js +82 -79
  32. package/package.json +4 -4
  33. package/templates/app/README.md +10 -10
  34. package/templates/app/_env.example +7 -6
  35. package/templates/app/_vscode/settings.json +3 -2
  36. package/templates/app/backend/app/Http/Controllers/Admin/DashboardController.js +2 -2
  37. package/templates/app/backend/app/Http/Controllers/Admin/UserController.js +1 -1
  38. package/templates/app/backend/app/Http/Controllers/Auth/ApiTokenController.js +1 -1
  39. package/templates/app/backend/app/Http/Controllers/Auth/AuthenticatedSessionController.js +1 -1
  40. package/templates/app/backend/app/Http/Controllers/Auth/ConfirmablePasswordController.js +1 -1
  41. package/templates/app/backend/app/Http/Controllers/Auth/EmailVerificationController.js +1 -1
  42. package/templates/app/backend/app/Http/Controllers/Auth/NewPasswordController.js +2 -2
  43. package/templates/app/backend/app/Http/Controllers/Auth/PasswordResetLinkController.js +1 -1
  44. package/templates/app/backend/app/Http/Controllers/Auth/RegisteredUserController.js +2 -2
  45. package/templates/app/backend/app/Http/Controllers/Auth/SessionController.js +1 -1
  46. package/templates/app/backend/app/Http/Controllers/Auth/TwoFactorController.js +1 -1
  47. package/templates/app/backend/app/Http/Controllers/ProfileController.js +2 -2
  48. package/templates/app/backend/app/Http/Middleware/RequirePassword.js +1 -1
  49. package/templates/app/backend/lang/ar/validation.json +2 -2
  50. package/templates/app/backend/lang/en/validation.json +2 -2
  51. package/templates/app/frontend/{App.kreftjs → App.kreft} +1 -1
  52. package/templates/app/frontend/components/profile/{ApiTokens.kreftjs → ApiTokens.kreft} +1 -1
  53. package/templates/app/frontend/components/profile/{Sessions.kreftjs → Sessions.kreft} +1 -1
  54. package/templates/app/frontend/components/profile/{TwoFactor.kreftjs → TwoFactor.kreft} +1 -1
  55. package/templates/app/frontend/errors/{ErrorMonitor.kreftjs → ErrorMonitor.kreft} +3 -3
  56. package/templates/app/frontend/index.html +8 -8
  57. package/templates/app/frontend/kreftjs.d.ts +15 -27
  58. package/templates/app/frontend/kreftjs.js +82 -79
  59. package/templates/app/frontend/layouts/{docs.kreftjs → docs.kreft} +1 -1
  60. package/templates/app/frontend/pages/{Dashboard.kreftjs → Dashboard.kreft} +1 -1
  61. package/templates/app/frontend/pages/{ErrorMonitor.kreftjs → ErrorMonitor.kreft} +2 -2
  62. package/templates/app/frontend/pages/{Home.kreftjs → Home.kreft} +2 -2
  63. package/templates/app/frontend/pages/{Profile.kreftjs → Profile.kreft} +4 -4
  64. package/templates/app/frontend/pages/auth/{Register.kreftjs → Register.kreft} +1 -1
  65. package/templates/app/frontend/pages/auth/{ResetPassword.kreftjs → ResetPassword.kreft} +1 -1
  66. package/templates/app/frontend/routes/web.kreft +34 -0
  67. package/templates/app/frontend/tests/components/{Counter.kreftjs → Counter.kreft} +1 -1
  68. package/templates/app/frontend/tests/pages/About.kreft +12 -0
  69. package/templates/app/frontend/tests/pages/{Test.kreftjs → Test.kreft} +1 -1
  70. package/templates/app/lang/ar/validation.json +1 -1
  71. package/templates/app/lang/en/validation.json +1 -1
  72. package/templates/errors/{401.kreftjs → 401.kreft} +2 -2
  73. package/templates/errors/{402.kreftjs → 402.kreft} +2 -2
  74. package/templates/errors/{403.kreftjs → 403.kreft} +2 -2
  75. package/templates/errors/{404.kreftjs → 404.kreft} +2 -2
  76. package/templates/errors/{419.kreftjs → 419.kreft} +2 -2
  77. package/templates/errors/{429.kreftjs → 429.kreft} +2 -2
  78. package/templates/errors/{500.kreftjs → 500.kreft} +2 -2
  79. package/templates/errors/{503.kreftjs → 503.kreft} +2 -2
  80. package/templates/errors/{ErrorMonitor.kreftjs → ErrorMonitor.kreft} +13 -12
  81. package/templates/errors/{error.kreftjs → error.kreft} +2 -2
  82. package/templates/errors/{minimal.kreftjs → minimal.kreft} +1 -1
  83. package/tools/dev-client.js +2 -2
  84. package/tools/vite-plugin-kreftjs.d.ts +3 -5
  85. package/tools/vite-plugin-kreftjs.js +12 -14
  86. package/templates/app/frontend/routes/web.kreftjs +0 -34
  87. package/templates/app/frontend/tests/pages/About.kreftjs +0 -12
  88. /package/templates/app/frontend/components/{Field.kreftjs → Field.kreft} +0 -0
  89. /package/templates/app/frontend/components/{StatCard.kreftjs → StatCard.kreft} +0 -0
  90. /package/templates/app/frontend/layouts/{app.kreftjs → app.kreft} +0 -0
  91. /package/templates/app/frontend/layouts/{guest.kreftjs → guest.kreft} +0 -0
  92. /package/templates/app/frontend/pages/{Users.kreftjs → Users.kreft} +0 -0
  93. /package/templates/app/frontend/pages/auth/{ConfirmPassword.kreftjs → ConfirmPassword.kreft} +0 -0
  94. /package/templates/app/frontend/pages/auth/{ForgotPassword.kreftjs → ForgotPassword.kreft} +0 -0
  95. /package/templates/app/frontend/pages/auth/{Login.kreftjs → Login.kreft} +0 -0
  96. /package/templates/app/frontend/pages/auth/{VerifyEmail.kreftjs → VerifyEmail.kreft} +0 -0
package/bin/build.js CHANGED
@@ -11,7 +11,7 @@
11
11
  * kreft build --no-htaccess do not write dist/.htaccess (the Apache / Hostinger page-address rules)
12
12
  *
13
13
  * What it does:
14
- * 1. Compiles every .kreftjs file ahead of time into app.js (no .kreftjs files are downloaded in production).
14
+ * 1. Compiles every .kreft file ahead of time into app.js (no .kreft files are downloaded in production).
15
15
  * 2. Turns every expression in the views into a real function, so the app runs without
16
16
  * eval / new Function — it works under a strict Content-Security-Policy.
17
17
  * 3. Collects all <style> blocks (scoped ones already scoped) into app.css.
@@ -28,8 +28,8 @@ const { expandBlocks, prepareTemplate, splitKreft, splitInterp, exactBrace, stri
28
28
  scopeCss, hashString, propType, simplePathRE, fnExpRE, forAliasRE, stripTypeScript } = Kreftjs.__internal;
29
29
 
30
30
  const deps = require('./deps.js');
31
- // component files: .kreftjs, or .kreft / .som in an older project
32
- const isComp = (f) => /\.(?:kreftjs|kreft|som)$/i.test(f);
31
+ // component files: .kreft, or .kreftjs in a project from the 0.0.x betas
32
+ const isComp = (f) => /\.(?:kreftjs|kreft)$/i.test(f);
33
33
  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
 
@@ -59,9 +59,9 @@ module.exports = function build(args) {
59
59
  // server code never goes into the built site: server/, backend app/ and routes/
60
60
  if (!lay.split) for (const dir of [root, project]) ['server', 'app', 'routes'].forEach((d) => SERVER_DIRS.add(path.join(dir, d)));
61
61
  SERVER_DIRS.add(lay.backend === lay.project ? path.join(project, 'server') : lay.backend);
62
- const bare = new Set(), cssLinks = []; // npm packages used by the .kreftjs files, and imported CSS files
62
+ const bare = new Set(), cssLinks = []; // npm packages used by the .kreft files, and imported CSS files
63
63
 
64
- // ---- 1. find and compile every .kreftjs file
64
+ // ---- 1. find and compile every .kreft file
65
65
  const kreftFiles = walk(root, dist).filter((f) => isComp(f));
66
66
  const fns = new Map(); // precompiled expression functions: key → source
67
67
  const components = [];
@@ -70,7 +70,7 @@ module.exports = function build(args) {
70
70
 
71
71
  addRouterTemplates(fns); // the router's own <kreft-link> and <kreft-view> templates
72
72
 
73
- // .kreftjs files in --include folders too: they land in the output as <folder>/…, so that is their path there
73
+ // .kreft files in --include folders too: they land in the output as <folder>/…, so that is their path there
74
74
  const jobs = kreftFiles.map((file) => [file, toUrlPath(path.relative(root, file)), root]);
75
75
  for (const dir of include) {
76
76
  const from = path.resolve(dir);
@@ -84,7 +84,7 @@ module.exports = function build(args) {
84
84
  const templateBar = createProgressBar(jobs.length, { label: 'Compiling templates' });
85
85
  for (const [file, rel, base] of jobs) {
86
86
  templateBar.tick(rel);
87
- // routes/web.kreftjs and other route files: plain JavaScript with Route in scope, kept as a function
87
+ // routes/web.kreft and other route files: plain JavaScript with Route in scope, kept as a function
88
88
  if (/^routes\//.test(rel)) {
89
89
  const src = stripTypeScript(fs.readFileSync(file, 'utf8'));
90
90
  try { new Function('Route', src); } catch (e) { errors.push(` ${rel}: ${e.message}`); continue; }
@@ -115,7 +115,7 @@ module.exports = function build(args) {
115
115
  const langInject = Object.keys(langData).length ? `Kreftjs.translations(${JSON.stringify(langData)});\n` : '';
116
116
 
117
117
  const precompiled = [...fns].map(([key, src]) => `F[${JSON.stringify(key)}] = ${src};`).join('\n');
118
- const appJs = `/* Built by kreft build — do not edit. Rebuild from your .kreftjs files instead. */
118
+ const appJs = `/* Built by kreft build — do not edit. Rebuild from your .kreft files instead. */
119
119
  ${env.envScript(env.publicEnv())}
120
120
  (function (Kreftjs) {
121
121
  if (!Kreftjs) throw new Error('Load kreftjs.js before app.js');
@@ -168,7 +168,7 @@ ${indent(components.join('\n\n'))}
168
168
 
169
169
  // ---- 3. index.html: kreftjs.js + app.js + app.css, inline scripts moved to main.js
170
170
  let html = fs.readFileSync(path.join(root, 'index.html'), 'utf8');
171
- // an included folder that sits next to the app ('../docs/Docs.kreftjs') is inside the output: 'docs/Docs.kreftjs'
171
+ // an included folder that sits next to the app ('../docs/Docs.kreft') is inside the output: 'docs/Docs.kreft'
172
172
  for (const dir of include) {
173
173
  const up = toUrlPath(path.relative(root, path.resolve(dir)));
174
174
  if (up.startsWith('../')) html = html.split(`'${up}/`).join(`'${path.basename(up)}/`).split(`"${up}/`).join(`"${path.basename(up)}/`);
@@ -177,7 +177,7 @@ ${indent(components.join('\n\n'))}
177
177
  let sawKreft = false, placedMain = false;
178
178
  html = html.replace(/<script\b([^>]*)>([\s\S]*?)<\/script>/gi, (tag, attrs, body) => {
179
179
  const src = (attrs.match(/\bsrc\s*=\s*["']([^"']+)["']/i) || [])[1];
180
- if (src && /(^|\/)(?:kreftjs|kreft|som)(\.min)?\.js$/i.test(src)) {
180
+ if (src && /(^|\/)(?:kreftjs|kreft)(\.min)?\.js$/i.test(src)) {
181
181
  sawKreft = true;
182
182
  return '<script src="kreftjs.js"></script>\n <script src="app.js"></script>';
183
183
  }
@@ -252,8 +252,11 @@ ${indent(components.join('\n\n'))}
252
252
  report();
253
253
  };
254
254
 
255
- // Apache (Hostinger, cPanel …) answers /docs with a 404, because only index.html exists on disk. These rules send every address
256
- // that is not a real file or folder to index.html, so reloading a page works. An .htaccess you keep in public/ is left alone;
255
+ // Apache (Hostinger, cPanel …) answers /docs with a 404, because only index.html exists on disk. These rules send every page address
256
+ // (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
+ // 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
258
+ // app.js, or an /api/ address the host cannot answer, stays a real 404: sending it index.html would hand the page's HTML to code
259
+ // that expects data (a list, JSON). An .htaccess you keep in public/ is left alone;
257
260
  // a relative base (./, as the desktop build uses) has no server and gets no file.
258
261
  function writeHtaccess(dist, html) {
259
262
  const m = /<base\b[^>]*\bhref="([^"]*)"/i.exec(html);
@@ -265,7 +268,9 @@ function writeHtaccess(dist, html) {
265
268
  RewriteBase ${base}
266
269
  RewriteRule ^index\\.html$ - [L]
267
270
  RewriteCond %{REQUEST_FILENAME} !-f
268
- RewriteCond %{REQUEST_FILENAME} !-d
271
+ RewriteCond %{REQUEST_FILENAME}/index.html !-f
272
+ RewriteCond %{REQUEST_URI} !^${base}api/
273
+ RewriteCond %{REQUEST_URI} !\\.[A-Za-z0-9]+$
269
274
  RewriteRule . ${base}index.html [L]
270
275
  </IfModule>
271
276
  `);
@@ -278,12 +283,12 @@ function tsToJs(file, project) {
278
283
  return code.replace(/((?:from|import)\s*\(?\s*['"])(\.{1,2}\/[^'"]+?)\.ts(['"])/g, '$1$2.js$3');
279
284
  }
280
285
 
281
- /* ------------------------------------------------------------------ one .kreftjs file → JS */
286
+ /* ------------------------------------------------------------------ one .kreft file → JS */
282
287
  function compileFile(file, rel, root) {
283
288
  const sp = splitKreft(fs.readFileSync(file, 'utf8'), rel);
284
289
  const name = sp.name;
285
290
 
286
- // the script must parse; report the .kreftjs line if it doesn't
291
+ // the script must parse; report the .kreft line if it doesn't
287
292
  const run = `function ($scope, $h) { with ($scope) {\n${sp.code}\n} }`;
288
293
  try { new Function('return ' + run); } catch (e) { throw new Error(`script error: ${e.message}`); }
289
294
 
@@ -297,13 +302,13 @@ function compileFile(file, rel, root) {
297
302
  return `${JSON.stringify(p)}: { ${type ? `type: ${type.name}, ` : ''}default: function () { return (${expr}); } }`;
298
303
  });
299
304
 
300
- // imports: other .kreftjs files become component references; .js modules load with import()
305
+ // imports: other .kreft files become component references; .js modules load with import()
301
306
  const comps = [], values = [], bare = [], cssImports = [];
302
307
  for (const stmt of sp.imports) {
303
308
  const m = stmt.match(/^import\s+(?:([\s\S]+?)\s+from\s+)?(['"])(.+?)\2/);
304
309
  if (!m) throw new Error(`can't read import: ${stmt}`);
305
310
  const [, what, , spec] = m;
306
- if (/^(?:kreftjs|kreft|som)(\.js)?$/.test(spec)) continue;
311
+ if (/^(?:kreftjs|kreft)(\.js)?$/.test(spec)) continue;
307
312
  let target = /^\.{1,2}\//.test(spec) ? toUrlPath(path.relative(root, path.resolve(path.dirname(file), spec))) : spec;
308
313
  if (/^\.{1,2}\//.test(spec) && /\.ts$/i.test(spec)) target = target.replace(/\.ts$/i, '.js'); // TypeScript files are built into .js
309
314
  if (isComp(spec)) {
@@ -351,7 +356,7 @@ function compileFile(file, rel, root) {
351
356
  // `import { a, b as c } from './x.js'` → loaded with import() when the component is first used
352
357
  function loadValuesSource(values) {
353
358
  const lines = values.map(({ what, target, local }, i) => {
354
- // files in the app resolve from <base href>, like .kreftjs paths; URLs and package names stay as written
359
+ // files in the app resolve from <base href>, like .kreft paths; URLs and package names stay as written
355
360
  const url = local ? `new URL(${JSON.stringify(target)}, document.baseURI).href` : JSON.stringify(target);
356
361
  const picks = [];
357
362
  if (what) what.split(/,(?![^{]*\})/).map((s) => s.trim()).forEach((part) => {
@@ -540,7 +545,7 @@ function walk(dir, exclude) {
540
545
  if (SKIP.has(entry.name)) continue;
541
546
  if (entry.name === 'storage' && (entry.isSymbolicLink() || entry.isDirectory())) continue;
542
547
  // the database, its settings and its migrations stay on the server, never in the built site
543
- if (/\.(db|sqlite3?)(-wal|-shm)?$/i.test(entry.name) || entry.name === 'kreftjs.config.json' || entry.name === 'kreft.config.json' || entry.name === 'som.config.json' || (entry.isDirectory() && entry.name === 'database')) continue;
548
+ if (/\.(db|sqlite3?)(-wal|-shm)?$/i.test(entry.name) || entry.name === 'kreftjs.config.json' || entry.name === 'kreft.config.json' || (entry.isDirectory() && entry.name === 'database')) continue;
544
549
  const full = path.join(dir, entry.name);
545
550
  if (exclude && full === exclude) continue;
546
551
  if (SERVER_DIRS.has(full)) continue; // server/ code runs on the server only
package/bin/db-api.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * A REST API made from the tables of a database (used by `kreft dev --db` and `kreft serve --db`).
3
3
  *
4
4
  * GET /api the tables you can use
5
- * GET /api/posts rows ?userId=3 ?title_like=som ?likes_gte=5 ?q=text
5
+ * GET /api/posts rows ?userId=3 ?title_like=news ?likes_gte=5 ?q=text
6
6
  * ?_sort=-created_at,title ?_limit=20&_page=2 (header X-Total-Count)
7
7
  * GET /api/posts/1 one row
8
8
  * POST /api/posts create (201, the new row)
@@ -28,7 +28,7 @@ function createDbApi(db, { tables: allow = null, production = false, prefix = '/
28
28
  const all = await db.tables();
29
29
  const out = new Map();
30
30
  for (const t of all) {
31
- if (t.name === 'som_migrations') continue;
31
+ if (t.name === 'kreft_migrations') continue;
32
32
  let rules = allow ? allow[t.name] : true;
33
33
  if (rules == null || rules === false) continue;
34
34
  if (rules === true) rules = {};
package/bin/db.js CHANGED
@@ -250,14 +250,14 @@ function splitSql(sql) {
250
250
 
251
251
  /* ---------------------------------------------------------------- migrations
252
252
  * database/migrations/001_create_posts.sql, 002_add_likes.sql … run once each, in name order,
253
- * remembered in the table som_migrations (TODO 3.1: rename to kreft_migrations, reading the old name as a fallback).
253
+ * remembered in the table kreft_migrations .
254
254
  * database/seed.sql fills in starting data.
255
255
  */
256
256
  async function migrate(db, dir, log = () => {}) {
257
257
  if (!fs.existsSync(dir)) return [];
258
258
  const idType = db.kind === 'postgres' ? 'TEXT' : 'VARCHAR(255)';
259
- await db.exec(`CREATE TABLE IF NOT EXISTS som_migrations (name ${idType} PRIMARY KEY, ran_at ${idType} NOT NULL)`);
260
- const done = new Set((await db.query('SELECT name FROM som_migrations')).map((r) => r.name));
259
+ await db.exec(`CREATE TABLE IF NOT EXISTS kreft_migrations (name ${idType} PRIMARY KEY, ran_at ${idType} NOT NULL)`);
260
+ const done = new Set((await db.query('SELECT name FROM kreft_migrations')).map((r) => r.name));
261
261
  const files = fs.readdirSync(dir).filter((f) => f.endsWith('.sql')).sort();
262
262
  const ran = [];
263
263
  for (const f of files) {
@@ -265,7 +265,7 @@ async function migrate(db, dir, log = () => {}) {
265
265
  const sql = fs.readFileSync(path.join(dir, f), 'utf8');
266
266
  try { await db.exec(sql); }
267
267
  catch (e) { throw new Error(`Migration ${f} failed: ${e.message}`); }
268
- await db.run('INSERT INTO som_migrations (name, ran_at) VALUES (?, ?)', [f, new Date().toISOString()]);
268
+ await db.run('INSERT INTO kreft_migrations (name, ran_at) VALUES (?, ?)', [f, new Date().toISOString()]);
269
269
  log(f);
270
270
  ran.push(f);
271
271
  }
package/bin/deps.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * npm packages in the browser.
3
3
  *
4
- * import dayjs from 'dayjs' (in a .kreftjs file)
4
+ * import dayjs from 'dayjs' (in a .kreft file)
5
5
  * import { debounce } from 'lodash'
6
6
  * import 'bootstrap/dist/css/bootstrap.min.css'
7
7
  *
package/bin/electron.js CHANGED
@@ -38,7 +38,7 @@ function getDevToolsConfig() {
38
38
  (process.argv.includes('--devtools') ? 'right' : null) ||
39
39
  (process.argv.includes('--no-devtools') ? 'false' : null) ||
40
40
  process.env.ELECTRON_DEVTOOLS ||
41
- (process.env.KREFT_ELECTRON_DEVTOOLS || process.env.SOM_ELECTRON_DEVTOOLS) ||
41
+ process.env.KREFT_ELECTRON_DEVTOOLS ||
42
42
  '';
43
43
  const val = String(raw).trim().toLowerCase();
44
44
  if (!val) return { show: false, mode: 'right' };
@@ -225,7 +225,7 @@ app.on('window-all-closed', () => {
225
225
 
226
226
  preload: () => `const { contextBridge, ipcRenderer } = require('electron');
227
227
 
228
- // Expose safe desktop bridge onto window.kreftDesktop (window.somDesktop is the same object: the Som.js name)
228
+ // Expose safe desktop bridge onto window.kreftDesktop
229
229
  const desktop = {
230
230
  isElectron: true,
231
231
  getInfo: () => ipcRenderer.invoke('kreft:app-info'),
@@ -240,10 +240,8 @@ const desktop = {
240
240
  showSaveDialog: (options) => ipcRenderer.invoke('kreft:dialog:save', options),
241
241
  };
242
242
  contextBridge.exposeInMainWorld('kreftDesktop', desktop);
243
- contextBridge.exposeInMainWorld('somDesktop', desktop);
244
243
 
245
244
  contextBridge.exposeInMainWorld('__KREFT_ELECTRON__', true);
246
- contextBridge.exposeInMainWorld('__SOM_ELECTRON__', true);
247
245
  `,
248
246
  };
249
247
 
@@ -388,7 +386,7 @@ function startDev(args, port) {
388
386
  const bin = resolveElectronBinary(root);
389
387
 
390
388
  // Extract devtools settings from CLI args or environment
391
- let devToolsEnv = process.env.ELECTRON_DEVTOOLS || (process.env.KREFT_ELECTRON_DEVTOOLS || process.env.SOM_ELECTRON_DEVTOOLS) || '';
389
+ let devToolsEnv = process.env.ELECTRON_DEVTOOLS || process.env.KREFT_ELECTRON_DEVTOOLS || '';
392
390
  const devToolsArg = args.find((a) => a === '--devtools' || a.startsWith('--devtools=') || a === '--no-devtools');
393
391
  if (devToolsArg) {
394
392
  if (devToolsArg === '--devtools') devToolsEnv = 'right';
@@ -14,17 +14,12 @@ function readConfig(start) {
14
14
  path.join(dir, 'config', 'kreftjs.json'),
15
15
  path.join(dir, 'Config', 'kreftjs.config.json'),
16
16
  path.join(dir, 'Config', 'kreftjs.json'),
17
- // the earlier names: kreft.config.json, then Som.js's som.config.json
17
+ // the earlier name: kreft.config.json
18
18
  path.join(dir, 'kreft.config.json'),
19
19
  path.join(dir, 'config', 'kreft.config.json'),
20
20
  path.join(dir, 'config', 'kreft.json'),
21
21
  path.join(dir, 'Config', 'kreft.config.json'),
22
22
  path.join(dir, 'Config', 'kreft.json'),
23
- path.join(dir, 'som.config.json'),
24
- path.join(dir, 'config', 'som.config.json'),
25
- path.join(dir, 'config', 'som.json'),
26
- path.join(dir, 'Config', 'som.config.json'),
27
- path.join(dir, 'Config', 'som.json'),
28
23
  ];
29
24
  for (const file of candidates) {
30
25
  if (fs.existsSync(file)) {
package/bin/kreftjs.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * kreft dev --port 3000 another port
8
8
  * kreft dev ./site another folder
9
9
  * kreft build build this folder for production into ./dist
10
- * kreft vscode install colors and snippets for .kreftjs files in VS Code
10
+ * kreft vscode install colors and snippets for .kreft files in VS Code
11
11
  * kreft serve dist run the built app in production (with --db: its database API)
12
12
  * kreft db migrate run new database/migrations/*.sql (also: seed, tables, sql "…")
13
13
  * kreft help show this help
@@ -87,7 +87,7 @@ function help() {
87
87
  --no-auth …without login, register, profile and users (--auth: with them, the default)
88
88
  --redis …configure Redis for caching, background queues and pub/sub
89
89
  --ui <library> …with a CSS library from a CDN: tailwind, bootstrap, bulma or pico
90
- --ts …use TypeScript across frontend (.kreftjs, .ts) and backend (.ts)
90
+ --ts …use TypeScript across frontend (.kreft, .ts) and backend (.ts)
91
91
  --js …use JavaScript (default when non-interactive)
92
92
  --electron …with Electron desktop app support (main.js, preload.js, packaging)
93
93
  --vite …with Vite.js bundling & instant HMR (vite.config.js, npm run vite)
@@ -140,7 +140,7 @@ function help() {
140
140
  kreft make:request StorePostRequest app/Http/Requests/StorePostRequest.js (--model Post)
141
141
  kreft make:resource PostResource app/Http/Resources/PostResource.js
142
142
  kreft make:rule Uppercase app/Rules/Uppercase.js
143
- kreft make:page Post frontend/pages/Post.kreftjs (--model Post, -r, --route=file, --auth)
143
+ kreft make:page Post frontend/pages/Post.kreft (--model Post, -r, --route=file, --auth)
144
144
  kreft make:factory PostFactory database/factories/PostFactory.js (--model Post)
145
145
  kreft make:migration create_posts_table
146
146
  kreft make:seeder PostSeeder
@@ -155,7 +155,7 @@ function help() {
155
155
  kreft make:command SendReport app/Console/Commands/SendReport.js (--command report:send)
156
156
  kreft make:errors The error pages in errors/ (401, 403, 404, 419, 429, 500, 503…)
157
157
  kreft make:admin <email> Let that user open the admin panel at /admin (--remove: take it away)
158
- kreft make:routes admin A new route file for pages: frontend/routes/admin.kreftjs (--api: backend/routes/admin.js)
158
+ kreft make:routes admin A new route file for pages: frontend/routes/admin.kreft (--api: backend/routes/admin.js)
159
159
  kreft db tables List tables and columns
160
160
  kreft db sql "<SQL>" Run one SQL statement and print the result
161
161
  kreft build [folder] Build for production (default: this folder)
@@ -175,7 +175,7 @@ function help() {
175
175
  --check Check for outdated packages (npm outdated)
176
176
  --core Update only Kreft runtime files (kreftjs.js, kreftjs.d.ts, server.d.ts)
177
177
  --npm Update only npm dependencies
178
- kreft vscode Install .kreftjs colors and snippets in VS Code (also Cursor, VSCodium)
178
+ kreft vscode Install .kreft colors and snippets in VS Code (also Cursor, VSCodium)
179
179
 
180
180
  Examples:
181
181
  kreft new shop
@@ -256,7 +256,7 @@ async function createProject(args) {
256
256
  fs.copyFileSync(path.join(__dirname, '..', 'kreftjs.js'), path.join(front, 'kreftjs.js'));
257
257
  fs.copyFileSync(path.join(__dirname, '..', 'kreftjs.d.ts'), path.join(front, 'kreftjs.d.ts')); // editor hints
258
258
  fs.copyFileSync(path.join(__dirname, '..', 'server.d.ts'), path.join(target, 'backend', 'server.d.ts')); // hints for require('kreftjs/server')
259
- // the documentation pages, in their own folder: docs/Docs.kreftjs, its Markdown reader and the README.md manual
259
+ // the documentation pages, in their own folder: docs/Docs.kreft, its Markdown reader and the README.md manual
260
260
  copyFolder(path.join(__dirname, '..', 'docs'), path.join(front, 'docs'));
261
261
 
262
262
  const projectName = path.basename(target).toLowerCase().replace(/[^a-z0-9-]+/g, '-');
@@ -307,7 +307,7 @@ ${auth ? ` Then log in as test@example.com with the password "password", or reg
307
307
  ` : ' Created without authentication (--no-auth): there is no login, registration or users table.\n'}`);
308
308
  }
309
309
 
310
- // kreft new my-app --ts → TypeScript across backend (.ts) and frontend (.kreftjs, .ts), tsconfig.json, and npm run typecheck
310
+ // kreft new my-app --ts → TypeScript across backend (.ts) and frontend (.kreft, .ts), tsconfig.json, and npm run typecheck
311
311
  function toTypeScript(target, projectPkg) {
312
312
  const { toTs, TSCONFIG } = require('./to-ts.js');
313
313
  const walk = (dir) => {
@@ -323,8 +323,8 @@ function toTypeScript(target, projectPkg) {
323
323
  projectPkg.devDependencies = { esbuild: '^0.25.0', typescript: '^5.8.0', '@types/node': '^22.13.0' };
324
324
  projectPkg.allowScripts = { esbuild: true };
325
325
  // Shared TypeScript interfaces for the frontend
326
- fs.writeFileSync(path.join(target, 'frontend', 'types.ts'), `// Shared TypeScript interfaces for your .kreftjs pages and frontend modules.
327
- // Import in any .kreftjs file or .ts module: import type { User } from '../types.ts'
326
+ fs.writeFileSync(path.join(target, 'frontend', 'types.ts'), `// Shared TypeScript interfaces for your .kreft pages and frontend modules.
327
+ // Import in any .kreft file or .ts module: import type { User } from '../types.ts'
328
328
 
329
329
  export interface User {
330
330
  id: number
@@ -355,10 +355,10 @@ export function ago(date: string | Date): string {
355
355
  return 'just now'
356
356
  }
357
357
  `);
358
- // Upgrade Counter.kreftjs to showcase TypeScript in .kreftjs components
359
- const counterKreft = path.join(target, 'frontend', 'tests', 'components', 'Counter.kreftjs');
358
+ // Upgrade Counter.kreft to showcase TypeScript in .kreft components
359
+ const counterKreft = path.join(target, 'frontend', 'tests', 'components', 'Counter.kreft');
360
360
  if (fs.existsSync(counterKreft)) {
361
- fs.writeFileSync(counterKreft, `<!-- A TypeScript .kreftjs component: a button that counts. Used by tests/pages/Test.kreftjs as <counter>. -->
361
+ fs.writeFileSync(counterKreft, `<!-- A TypeScript .kreft component: a button that counts. Used by tests/pages/Test.kreft as <counter>. -->
362
362
  prop start: number = 0
363
363
 
364
364
  state count: number = start
@@ -377,8 +377,8 @@ button { font-variant-numeric: tabular-nums; justify-self: start; }
377
377
  </style>
378
378
  `);
379
379
  }
380
- // If --db created Todos.kreftjs, upgrade it with TypeScript interfaces & typed actions
381
- const todosKreft = path.join(target, 'frontend', 'pages', 'Todos.kreftjs');
380
+ // If --db created Todos.kreft, upgrade it with TypeScript interfaces & typed actions
381
+ const todosKreft = path.join(target, 'frontend', 'pages', 'Todos.kreft');
382
382
  if (fs.existsSync(todosKreft)) {
383
383
  const src = fs.readFileSync(todosKreft, 'utf8');
384
384
  fs.writeFileSync(todosKreft, src
@@ -391,9 +391,9 @@ button { font-variant-numeric: tabular-nums; justify-self: start; }
391
391
 
392
392
  // kreft new my-app --ui bootstrap → the library's CDN links in index.html
393
393
  function uiKits() { return {
394
- tailwind: ['<!-- Tailwind CSS: use its classes in any .kreftjs file -->', '<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>'],
395
- bootstrap: ['<!-- Bootstrap: its classes and components (data-bs-toggle…) work in any .kreftjs file -->', '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">', '<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>'],
396
- bulma: ['<!-- Bulma: its classes work in any .kreftjs file -->', '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css">'],
394
+ tailwind: ['<!-- Tailwind CSS: use its classes in any .kreft file -->', '<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>'],
395
+ bootstrap: ['<!-- Bootstrap: its classes and components (data-bs-toggle…) work in any .kreft file -->', '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">', '<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" defer></script>'],
396
+ bulma: ['<!-- Bulma: its classes work in any .kreft file -->', '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.2/css/bulma.min.css">'],
397
397
  pico: ['<!-- Pico CSS: plain HTML gets styled by itself -->', '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css">'],
398
398
  }; }
399
399
  function addUiKit(target, ui) {
@@ -508,7 +508,7 @@ module.exports = TodoSeeder
508
508
  const setUrl = (f, u) => fs.writeFileSync(f, fs.readFileSync(f, 'utf8').replace(/^DATABASE_URL=.*$/m, () => 'DATABASE_URL=' + u));
509
509
  setUrl(path.join(target, '.env'), url);
510
510
  setUrl(path.join(target, '.env.example'), url.replace(/\/\/[^:@\s]+:[^@\s]+@/, '//user:password@'));
511
- fs.writeFileSync(path.join(front, 'pages', 'Todos.kreftjs'), `<!-- the todos table, through routes/api.js and app/Http/Controllers/TodoController.js -->
511
+ fs.writeFileSync(path.join(front, 'pages', 'Todos.kreft'), `<!-- the todos table, through routes/api.js and app/Http/Controllers/TodoController.js -->
512
512
  load todos = api.get('/api/todos')
513
513
  // rules are checked here first, so a todo with mistakes is never sent; the server's 422 errors land here too
514
514
  state draft = form({ title: '' }, { title: 'required|max:200' })
@@ -565,9 +565,9 @@ label { display: flex; align-items: center; gap: 10px; }
565
565
  .done { color: var(--muted); text-decoration: line-through; }
566
566
  </style>
567
567
  `);
568
- const webFile = path.join(front, 'routes', 'web.kreftjs');
569
- fs.writeFileSync(webFile, fs.readFileSync(webFile, 'utf8').replace(/( Route\.view\('\/profile'[^\n]*\n)/, "$1 Route.view('/todos', 'pages/Todos.kreftjs').name('todos').title('Todos')\n"));
570
- const layout = path.join(front, 'layouts', 'app.kreftjs');
568
+ const webFile = path.join(front, 'routes', 'web.kreft');
569
+ fs.writeFileSync(webFile, fs.readFileSync(webFile, 'utf8').replace(/( Route\.view\('\/profile'[^\n]*\n)/, "$1 Route.view('/todos', 'pages/Todos.kreft').name('todos').title('Todos')\n"));
570
+ const layout = path.join(front, 'layouts', 'app.kreft');
571
571
  fs.writeFileSync(layout, fs.readFileSync(layout, 'utf8').replace(/(<kreft-link k-if="\$store\.auth\.token" to="\/dashboard"[^>]*>[^<]*<\/kreft-link>)/, '$1\n <kreft-link k-if="$store.auth.token" to="/todos" exact-class="here">Todos</kreft-link>'));
572
572
  }
573
573
  function copyFolder(from, to) {
@@ -591,11 +591,11 @@ function installVscode() {
591
591
  for (const home of homes) {
592
592
  const dir = path.join(home, 'extensions');
593
593
  fs.mkdirSync(dir, { recursive: true });
594
- fs.readdirSync(dir).filter((n) => n.startsWith('kreft.kreftjs-') || n.startsWith('kreft.kreft-') || n.startsWith('somjs.som-')) /* the older extensions go too */.forEach((n) => fs.rmSync(path.join(dir, n), { recursive: true, force: true }));
594
+ fs.readdirSync(dir).filter((n) => n.startsWith('kreft.kreftjs-') || n.startsWith('kreft.kreft-')) /* the older extensions go too */.forEach((n) => fs.rmSync(path.join(dir, n), { recursive: true, force: true }));
595
595
  copyFolder(from, path.join(dir, `kreft.kreftjs-${ext.version}`));
596
596
  console.log(` Installed in ${path.join(dir, `kreft.kreftjs-${ext.version}`)}`);
597
597
  }
598
- // Ensure current project .vscode/settings.json maps .kreftjs files to Kreft and configures formatter
598
+ // Ensure current project .vscode/settings.json maps .kreft files to Kreft and configures formatter
599
599
  const settingsDir = path.join(process.cwd(), '.vscode');
600
600
  const settings = path.join(settingsDir, 'settings.json');
601
601
  fs.mkdirSync(settingsDir, { recursive: true });
@@ -603,11 +603,11 @@ function installVscode() {
603
603
  if (fs.existsSync(settings)) {
604
604
  try { cfg = JSON.parse(fs.readFileSync(settings, 'utf8')); } catch {}
605
605
  }
606
- cfg['files.associations'] = { ...(cfg['files.associations'] || {}), '*.kreftjs': 'kreftjs' };
606
+ cfg['files.associations'] = { ...(cfg['files.associations'] || {}), '*.kreft': 'kreftjs', '*.kreftjs': 'kreftjs' };
607
607
  cfg['[kreftjs]'] = { ...(cfg['[kreftjs]'] || {}), 'editor.defaultFormatter': 'kreft.kreftjs' };
608
608
  fs.writeFileSync(settings, JSON.stringify(cfg, null, 2) + '\n');
609
- console.log(' Updated .vscode/settings.json: .kreftjs files use Kreft language and kreft.kreftjs formatter');
610
- console.log('\n Restart VS Code (or run "Reload Window") to see updated colors and formatting in .kreftjs files.\n');
609
+ console.log(' Updated .vscode/settings.json: .kreft files use Kreft language and kreft.kreftjs formatter');
610
+ console.log('\n Restart VS Code (or run "Reload Window") to see updated colors and formatting in .kreft files.\n');
611
611
  }
612
612
 
613
613
  /* ------------------------------------------------------------------ kreft dev */
@@ -670,7 +670,7 @@ async function devServer(args, { production = false } = {}) {
670
670
  installAlias(); // require('kreftjs/server') and .ts files work in migrations and seeders
671
671
  require('./backend/model.js').setBaseDir(backendDir);
672
672
  const dir = migrations || migrationsDir(backendDir, config.dir, root);
673
- const isNew = !(await db.tables()).some((t) => t.name === 'som_migrations'); // nothing migrated yet
673
+ const isNew = !(await db.tables()).some((t) => t.name === 'kreft_migrations'); // nothing migrated yet
674
674
  const ran = dir ? await migrator.migrate(db, dir, (f) => console.log(` migrated ${f}`)) : [];
675
675
  // --seed: a brand-new database gets database/seeders/DatabaseSeeder.js
676
676
  if (seedNew && isNew && ran.length) await migrator.seed(db, backendDir, { log: (n) => console.log(` seeded ${n}`) });
@@ -731,7 +731,7 @@ async function devServer(args, { production = false } = {}) {
731
731
  const npmMap = () => (production ? null : deps.importMap(project));
732
732
 
733
733
  const types = {
734
- '.html': 'text/html', '.js': 'text/javascript', '.mjs': 'text/javascript', '.kreftjs': 'text/plain', '.kreft': 'text/plain', '.som': 'text/plain',
734
+ '.html': 'text/html', '.js': 'text/javascript', '.mjs': 'text/javascript', '.kreft': 'text/plain', '.kreftjs': 'text/plain',
735
735
  '.css': 'text/css', '.json': 'application/json', '.svg': 'image/svg+xml', '.png': 'image/png',
736
736
  '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.webp': 'image/webp',
737
737
  '.ico': 'image/x-icon', '.woff2': 'font/woff2', '.woff': 'font/woff', '.txt': 'text/plain', '.md': 'text/markdown',
@@ -830,8 +830,8 @@ async function devServer(args, { production = false } = {}) {
830
830
  if (!isFile(full)) return;
831
831
  const urlPath = '/' + rel.split(path.sep).join('/');
832
832
  const ext = path.extname(full).toLowerCase();
833
- const isComp = ext === '.kreftjs' || ext === '.kreft' || ext === '.som'; // .kreft / .som: files of an older project
834
- const routeFile = isComp && /^routes[\/\\]/.test(rel); // routes/web.kreftjs: the whole page loads again
833
+ const isComp = ext === '.kreft' || ext === '.kreftjs'; // .kreftjs: files of a project from the 0.0.x betas
834
+ const routeFile = isComp && /^routes[\/\\]/.test(rel); // routes/web.kreft: the whole page loads again
835
835
  const msg = { type: isComp && !routeFile ? 'kreft' : ext === '.css' ? 'css' : 'reload', path: urlPath };
836
836
  clients.forEach((c) => c.write(`data: ${JSON.stringify(msg)}\n\n`));
837
837
  if (clients.size) console.log(` ${msg.type === 'reload' ? 'reload' : 'update'} ${urlPath}`);
@@ -862,7 +862,7 @@ async function devServer(args, { production = false } = {}) {
862
862
  if (!isFile(full)) return;
863
863
  const urlPath = '/admin/' + rel.split(path.sep).join('/');
864
864
  const ext = path.extname(full).toLowerCase();
865
- const isComp = ext === '.kreftjs' || ext === '.kreft' || ext === '.som';
865
+ const isComp = ext === '.kreft' || ext === '.kreftjs';
866
866
  const routeFile = /^routes[\/\\]/.test(rel);
867
867
  const msg = { type: isComp && !routeFile ? 'kreft' : ext === '.css' ? 'css' : 'reload', path: urlPath };
868
868
  clients.forEach((c) => c.write(`data: ${JSON.stringify(msg)}\n\n`));
@@ -904,7 +904,7 @@ async function devServer(args, { production = false } = {}) {
904
904
  clients.forEach((c) => c.write(`data: ${JSON.stringify({ type: 'reload', path: '/.env' })}\n\n`));
905
905
  });
906
906
  // files a browser must never get: the database itself, its settings and password, hidden files, locks, dumps
907
- const secret = (p) => /(^|\/)\.|\.(db|sqlite3?|db-wal|db-shm|sqlite-wal|sqlite-shm|sql|bak|dump|key|pem|crt)$|(^|\/)((?:kreftjs|kreft|som)\.config\.json|package(-lock)?\.json|pnpm-lock\.yaml|yarn\.lock|bun\.lockb|composer\.(json|lock)|docker-compose.*\.ya?ml|Dockerfile|node_modules|vendor)(\/|$)/i.test(p)
907
+ const secret = (p) => /(^|\/)\.|\.(db|sqlite3?|db-wal|db-shm|sqlite-wal|sqlite-shm|sql|bak|dump|key|pem|crt)$|(^|\/)((?:kreftjs|kreft)\.config\.json|package(-lock)?\.json|pnpm-lock\.yaml|yarn\.lock|bun\.lockb|composer\.(json|lock)|docker-compose.*\.ya?ml|Dockerfile|node_modules|vendor)(\/|$)/i.test(p)
908
908
  || (production && /(^|\/)(database|app|routes)\//i.test(p));
909
909
  setInterval(() => clients.forEach((c) => c.write(': ping\n\n')), 25000).unref();
910
910
  // a page of the app: index.html, with the SEO tags of backend/routes/seo.js for this address (and its status)
@@ -989,7 +989,7 @@ async function devServer(args, { production = false } = {}) {
989
989
  const down = downInfo();
990
990
  if (!down) return false;
991
991
  const { same, cookieSecure } = require('./backend/http.js');
992
- const cookie = (req.headers.cookie || '').match(/(?:^|;\s*)(?:kreft|som)_bypass=([^;]+)/); // som_bypass: set before the rename, still accepted
992
+ const cookie = (req.headers.cookie || '').match(/(?:^|;\s*)kreft_bypass=([^;]+)/);
993
993
  let cookieVal = null;
994
994
  if (cookie) { try { cookieVal = decodeURIComponent(cookie[1]); } catch (_) { cookieVal = cookie[1]; } }
995
995
  if (down.secret && cookieVal && same(cookieVal, String(down.secret))) return false;
@@ -1018,7 +1018,7 @@ async function devServer(args, { production = false } = {}) {
1018
1018
  // therefore only answers the names of this computer (add more with KREFT_ALLOWED_HOSTS=my-tunnel.example).
1019
1019
  const hostOnly = (h) => String(h || '').toLowerCase().replace(/:\d+$/, '').replace(/^\[|\]$/g, '');
1020
1020
  const isLocalName = (n) => n === 'localhost' || n === '127.0.0.1' || n === '::1' || n.endsWith('.localhost');
1021
- const allowedHosts = new Set(String((process.env.KREFT_ALLOWED_HOSTS || process.env.SOM_ALLOWED_HOSTS) || '').split(',').map((x) => x.trim().toLowerCase()).filter(Boolean));
1021
+ const allowedHosts = new Set(String(process.env.KREFT_ALLOWED_HOSTS || '').split(',').map((x) => x.trim().toLowerCase()).filter(Boolean));
1022
1022
  const loopbackBind = !production && (host === 'localhost' || host === '::1' || /^127\./.test(host));
1023
1023
  // a request from another web site (Origin) that changes data in the unauthenticated API (--api, --db)
1024
1024
  const crossSiteWrite = (req) => {
@@ -1068,7 +1068,6 @@ async function devServer(args, { production = false } = {}) {
1068
1068
  let urlPath;
1069
1069
  try { urlPath = decodeURIComponent(new URL(req.url, 'http://x').pathname); }
1070
1070
  catch (_) { res.writeHead(400); return res.end('Bad request'); }
1071
- if (urlPath.startsWith('/__som/')) urlPath = '/__kreft/' + urlPath.slice('/__som/'.length); // the Som.js address of the dev files
1072
1071
  // a backslash or a NUL in the path is never a real page, and on Windows a backslash would act as a folder separator
1073
1072
  if (/[\\\0]/.test(urlPath)) { res.writeHead(400); return res.end('Bad request'); }
1074
1073
  if (maintenance(req, res, urlPath)) return;
package/bin/layout.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Where a project's parts are.
3
3
  *
4
4
  * New projects (kreft new) keep frontend and backend apart:
5
- * frontend/ the only folder a browser can reach: index.html, pages, components, routes/web.kreftjs …
5
+ * frontend/ the only folder a browser can reach: index.html, pages, components, routes/web.kreft …
6
6
  * backend/ never served: routes/api.js, app/, database/ (and server/)
7
7
  * .env, package.json, node_modules/ at the top, next to both
8
8
  *
package/bin/no-auth.js CHANGED
@@ -11,8 +11,8 @@ const path = require('path');
11
11
 
12
12
  const TO_REMOVE = [
13
13
  // frontend: the sign-in pages, the profile, the admin pages and what only they use
14
- 'frontend/pages/auth', 'frontend/pages/Profile.kreftjs', 'frontend/pages/Users.kreftjs', 'frontend/pages/Dashboard.kreftjs',
15
- 'frontend/components/profile', 'frontend/components/StatCard.kreftjs', 'frontend/layouts/guest.kreftjs',
14
+ 'frontend/pages/auth', 'frontend/pages/Profile.kreft', 'frontend/pages/Users.kreft', 'frontend/pages/Dashboard.kreft',
15
+ 'frontend/components/profile', 'frontend/components/StatCard.kreft', 'frontend/layouts/guest.kreft',
16
16
  // backend: the auth routes, controllers, middleware, models and the users table
17
17
  'backend/routes/auth.js', 'backend/app/Auth',
18
18
  'backend/app/Http/Controllers/Auth', 'backend/app/Http/Controllers/Admin', 'backend/app/Http/Controllers/ProfileController.js',
@@ -62,15 +62,15 @@ module.exports = DatabaseSeeder
62
62
  const WEB = (todos) => `// Application Web Routes (this app was created without sign-in: --no-auth).
63
63
 
64
64
  // Welcome page
65
- Route.view('/', 'pages/Home.kreftjs').layout('none').name('home').title('Welcome')
66
- Route.view('/welcome', 'pages/Home.kreftjs').layout('none').name('welcome').title('Welcome')
67
- ${todos ? "\nRoute.view('/todos', 'pages/Todos.kreftjs').name('todos').title('Todos')\n" : ''}
65
+ Route.view('/', 'pages/Home.kreft').layout('none').name('home').title('Welcome')
66
+ Route.view('/welcome', 'pages/Home.kreft').layout('none').name('welcome').title('Welcome')
67
+ ${todos ? "\nRoute.view('/todos', 'pages/Todos.kreft').name('todos').title('Todos')\n" : ''}
68
68
  // Documentation (docs/) and test suite (tests/)
69
- Route.view('/docs', 'docs/Docs.kreftjs').name('docs').title('Documentation').layout('docs') // its own slim bar
70
- Route.view('/error-monitor', 'pages/ErrorMonitor.kreftjs').name('error-monitor').title('Error Monitor')
69
+ Route.view('/docs', 'docs/Docs.kreft').name('docs').title('Documentation').layout('docs') // its own slim bar
70
+ Route.view('/error-monitor', 'pages/ErrorMonitor.kreft').name('error-monitor').title('Error Monitor')
71
71
  Route.prefix('/tests').name('tests.').group(() => {
72
- Route.view('/', 'tests/pages/Test.kreftjs').name('index').title('Test Suite')
73
- Route.view('/about', 'tests/pages/About.kreftjs').name('about').title('About · Tests')
72
+ Route.view('/', 'tests/pages/Test.kreft').name('index').title('Test Suite')
73
+ Route.view('/about', 'tests/pages/About.kreft').name('about').title('About · Tests')
74
74
  })
75
75
  `;
76
76
 
@@ -127,18 +127,18 @@ function removeAuth(target) {
127
127
  write('backend/routes/api.js', API(todos));
128
128
  write('backend/app/Providers/AppServiceProvider.js', PROVIDER);
129
129
  write('backend/database/seeders/DatabaseSeeder.js', SEEDER(todos));
130
- write('frontend/routes/web.kreftjs', WEB(todos));
131
- write('frontend/layouts/app.kreftjs', LAYOUT(todos));
130
+ write('frontend/routes/web.kreft', WEB(todos));
131
+ write('frontend/layouts/app.kreft', LAYOUT(todos));
132
132
 
133
133
  // index.html: no auth store, no guards, no "signed out" handling; the router keeps its pages and layout
134
134
  let html = read('frontend/index.html');
135
135
  const from = html.indexOf(' // Who is signed in.');
136
- const to = html.indexOf(" Kreftjs.app('App.kreftjs')");
136
+ const to = html.indexOf(" Kreftjs.app('App.kreft')");
137
137
  if (from >= 0 && to > from) {
138
138
  html = html.slice(0, from) + ` const router = Kreftjs.router({
139
- routes: ['routes/web.kreftjs'], // the pages are in routes/web.kreftjs; add more files: kreft make:routes admin
140
- layout: 'app', // every page goes inside layouts/app.kreftjs…
141
- errors: 'errors', // error pages: errors/404.kreftjs for unknown addresses, abort(403) → errors/403.kreftjs
139
+ routes: ['routes/web.kreft'], // the pages are in routes/web.kreft; add more files: kreft make:routes admin
140
+ layout: 'app', // every page goes inside layouts/app.kreft…
141
+ errors: 'errors', // error pages: errors/404.kreft for unknown addresses, abort(403) → errors/403.kreft
142
142
  })
143
143
 
144
144
  ` + html.slice(to);
@@ -147,12 +147,12 @@ function removeAuth(target) {
147
147
  write('frontend/index.html', html);
148
148
 
149
149
  // the welcome page loses its Log in / Sign up / Dashboard links
150
- const home = read('frontend/pages/Home.kreftjs')
150
+ const home = read('frontend/pages/Home.kreft')
151
151
  .replace(/[ \t]*<kreft-link k-if="!?\$store\.auth\.user"[^>]*>[\s\S]*?<\/kreft-link>[ \t]*\r?\n/g, '');
152
- write('frontend/pages/Home.kreftjs', home);
152
+ write('frontend/pages/Home.kreft', home);
153
153
 
154
154
  // the docs bar went back to "the app" when signed in
155
- write('frontend/layouts/docs.kreftjs', read('frontend/layouts/docs.kreftjs')
155
+ write('frontend/layouts/docs.kreft', read('frontend/layouts/docs.kreft')
156
156
  .replace(/<kreft-link to=\{\$store\.auth\.user \? '\/dashboard' : '\/'\} class="back">← \{\$store\.auth\.user \? 'Back to the app' : 'Home'\}<\/kreft-link>/,
157
157
  '<kreft-link to="/" class="back">← Home</kreft-link>'));
158
158
 
package/bin/prerender.js CHANGED
@@ -131,7 +131,7 @@ function createRenderer({ jsdom, origin, basePath, maxWait = 10000, userAgent, e
131
131
  return {
132
132
  problems,
133
133
  path: router ? router.route.path : route,
134
- errorStatus: router && router.route.error ? Number(router.route.error.status) || 500 : 0, // the app showed errors/404.kreftjs (or another)
134
+ errorStatus: router && router.route.error ? Number(router.route.error.status) || 500 : 0, // the app showed errors/404.kreft (or another)
135
135
  title: w.document.title,
136
136
  tags: seoTags(w.document, origin),
137
137
  htmlAttrs: ['lang', 'dir', 'data-kreft-orig-lang', 'data-kreft-orig-dir'].filter((a) => w.document.documentElement.hasAttribute(a)).map((a) => [a, w.document.documentElement.getAttribute(a)]),
package/bin/ssr.js CHANGED
@@ -11,7 +11,7 @@
11
11
  * KREFT_SSR_TTL seconds a drawn page is kept (default 300)
12
12
  *
13
13
  * Needs jsdom (npm i -D jsdom). Without it, or when a page fails or is too slow, the normal page is sent.
14
- * If the app answers with its 404 page (errors/404.kreftjs), the response status is 404 too.
14
+ * If the app answers with its 404 page (errors/404.kreft), the response status is 404 too.
15
15
  *
16
16
  * The simulated browser asks this same server, so its requests carry a secret User-Agent (new on every start):
17
17
  * the server never draws them again, and lets them through the HTTPS redirect.
@@ -32,8 +32,8 @@ const decode = (p) => { try { return decodeURIComponent(p); } catch (_) { return
32
32
  const trimSlash = (p) => (p.length > 1 ? p.replace(/\/+$/, '') : p);
33
33
 
34
34
  function create({ root, origin, log = () => { }, cached = true }) {
35
- const mode = String((process.env.KREFT_SSR || process.env.SOM_SSR) || 'bots').toLowerCase();
36
- const ttl = cached ? (Number((process.env.KREFT_SSR_TTL || process.env.SOM_SSR_TTL)) || 300) * 1000 : 0; // kreftjs dev: always the latest files
35
+ const mode = String(process.env.KREFT_SSR || 'bots').toLowerCase();
36
+ const ttl = cached ? (Number(process.env.KREFT_SSR_TTL) || 300) * 1000 : 0; // kreftjs dev: always the latest files
37
37
  const userAgent = 'kreft-ssr/' + crypto.randomBytes(16).toString('hex');
38
38
  const cache = new Map(); // address → { at, html, status }
39
39
  const failed = new Map(); // address → when it failed