kreftjs 0.0.2-beta → 0.0.4-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 +12 -12
- package/bin/add.js +14 -14
- package/bin/artisan-more.js +41 -41
- package/bin/artisan.js +41 -41
- package/bin/backend/command.js +1 -1
- package/bin/backend/factory.js +1 -1
- package/bin/backend/index.js +3 -3
- package/bin/backend/model.js +2 -2
- package/bin/backend/notifications.js +1 -1
- package/bin/backend/queue.js +2 -2
- package/bin/backend/schedule.js +2 -2
- package/bin/backend/seo-pages.js +1 -1
- package/bin/backend/storage.js +1 -1
- package/bin/backend/support.js +4 -4
- package/bin/backend/typescript.js +1 -1
- package/bin/build.js +11 -11
- package/bin/db-api.js +3 -3
- package/bin/db.js +1 -1
- package/bin/deps.js +6 -6
- package/bin/electron.js +12 -12
- package/bin/env.js +2 -2
- package/bin/guard.js +2 -2
- package/bin/kreftjs-config.js +1 -1
- package/bin/kreftjs.js +105 -109
- package/bin/layout.js +1 -1
- package/bin/no-auth.js +4 -4
- package/bin/prerender.js +4 -4
- package/bin/server-routes.js +2 -2
- package/bin/ssr.js +2 -2
- package/bin/terminal.js +1 -1
- package/bin/to-ts.js +1 -1
- package/bin/update.js +17 -17
- package/bin/urls-file.js +1 -1
- package/bin/vite.js +11 -11
- package/bin/win-spawn.js +39 -0
- package/docs/Docs.kreftjs +1 -1
- package/docs/README.md +140 -123
- package/kreftjs.d.ts +1 -1
- package/kreftjs.js +18 -18
- package/package.json +3 -4
- package/templates/app/README.md +20 -20
- package/templates/app/backend/database/migrations/0001_01_01_000000_create_users_table.js +1 -1
- package/templates/app/backend/database/migrations/0001_01_01_000002_create_jobs_table.js +1 -1
- package/templates/app/backend/database/seeders/DatabaseSeeder.js +1 -1
- package/templates/app/backend/routes/api.js +1 -1
- package/templates/app/backend/routes/console.js +2 -2
- package/templates/app/frontend/errors/ErrorMonitor.kreftjs +2 -2
- package/templates/app/frontend/index.html +1 -1
- package/templates/app/frontend/kreftjs.d.ts +1 -1
- package/templates/app/frontend/kreftjs.js +18 -18
- package/templates/app/frontend/pages/Dashboard.kreftjs +1 -1
- package/templates/app/frontend/pages/ErrorMonitor.kreftjs +1 -1
- package/templates/app/frontend/pages/Home.kreftjs +2 -2
- package/templates/errors/ErrorMonitor.kreftjs +1 -1
package/bin/kreftjs.js
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
/*
|
|
3
3
|
* The kreftjs command
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
5
|
+
* kreft new my-app create a new Kreft project
|
|
6
|
+
* kreft dev run the dev server in this folder (http://localhost:8000)
|
|
7
|
+
* kreft dev --port 3000 another port
|
|
8
|
+
* kreft dev ./site another folder
|
|
9
|
+
* kreft build build this folder for production into ./dist
|
|
10
|
+
* kreft vscode install colors and snippets for .kreftjs files in VS Code
|
|
11
|
+
* kreft serve dist run the built app in production (with --db: its database API)
|
|
12
|
+
* kreft db migrate run new database/migrations/*.sql (also: seed, tables, sql "…")
|
|
13
|
+
* kreft help show this help
|
|
14
14
|
*
|
|
15
15
|
* No dependencies — only Node.js.
|
|
16
16
|
*/
|
|
@@ -35,10 +35,6 @@ if (require.main === module && (process.argv.includes('--gc') || process.env.AUT
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
const rawArgs = process.argv.slice(2).filter((a) => a !== '--gc');
|
|
38
|
-
// `som` (and `somjs`) still run this file, so an existing global install keeps working
|
|
39
|
-
if (require.main === module && /^(som|somjs)(\.cmd|\.js)?$/i.test(path.basename(process.argv[1] || ''))) {
|
|
40
|
-
console.error(' The "som" command is now "kreftjs" (Som.js is now Kreft). "som" still works for now: use "kreftjs" from here on.');
|
|
41
|
-
}
|
|
42
38
|
const [command = 'help', ...rest] = rawArgs;
|
|
43
39
|
|
|
44
40
|
const commands = {
|
|
@@ -75,7 +71,7 @@ guard.checkStart(command);
|
|
|
75
71
|
if (['queue:work', 'queue:start', 'schedule:work'].includes(command)) guard.watch([process.cwd()]);
|
|
76
72
|
if (commands[command]) commands[command](rest);
|
|
77
73
|
else if (command && !command.startsWith('-')) {
|
|
78
|
-
// your own commands: app/Console/Commands (
|
|
74
|
+
// your own commands: app/Console/Commands (kreft make:command SendReport)
|
|
79
75
|
require('./artisan-more.js').runCustom(command, rest).then((found) => { if (!found) unknown(); }, (e) => { console.error(' ' + (e.stack || e)); process.exitCode = 1; });
|
|
80
76
|
} else unknown();
|
|
81
77
|
|
|
@@ -85,7 +81,7 @@ function help() {
|
|
|
85
81
|
Kreft ${pkg.version}
|
|
86
82
|
|
|
87
83
|
Usage:
|
|
88
|
-
|
|
84
|
+
kreft new <name> Create a new project in a folder called <name>, with login, register,
|
|
89
85
|
password reset, email verification and profile pages (on SQLite)
|
|
90
86
|
--db <kind> …on another database (sqlite, mysql or postgres), plus a Todos example
|
|
91
87
|
--no-auth …without login, register, profile and users (--auth: with them, the default)
|
|
@@ -95,7 +91,7 @@ function help() {
|
|
|
95
91
|
--js …use JavaScript (default when non-interactive)
|
|
96
92
|
--electron …with Electron desktop app support (main.js, preload.js, packaging)
|
|
97
93
|
--vite …with Vite.js bundling & instant HMR (vite.config.js, npm run vite)
|
|
98
|
-
|
|
94
|
+
kreft dev [folder] Start the dev server (default: this folder)
|
|
99
95
|
--port <number> Port to use (default: 8000, or the next free one)
|
|
100
96
|
--host <address> Who may open it (default: 127.0.0.1, only this computer; 0.0.0.0: your network)
|
|
101
97
|
--api <file.json> Serve a REST API from a JSON file at /api (GET, POST, PUT, PATCH, DELETE)
|
|
@@ -108,83 +104,83 @@ function help() {
|
|
|
108
104
|
--server <dir> Your own Node.js code for /api (default: server/): server/hello.js → /api/hello
|
|
109
105
|
--db <database> Serve the tables of a database at /api (new migrations run first):
|
|
110
106
|
sqlite:database/app.db (built in, nothing to install)
|
|
111
|
-
mysql://user:pass@localhost:3306/shop (
|
|
112
|
-
postgres://user:pass@localhost:5432/shop (
|
|
113
|
-
|
|
107
|
+
mysql://user:pass@localhost:3306/shop (kreft add mysql2)
|
|
108
|
+
postgres://user:pass@localhost:5432/shop (kreft add pg)
|
|
109
|
+
kreft serve [folder] Run a built app for real users (folder: dist). Same --port and --db;
|
|
114
110
|
only the tables listed in kreftjs.config.json are served
|
|
115
111
|
|
|
116
112
|
Bundler & Dev Server (Vite.js):
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
113
|
+
kreft vite Start Vite dev server and proxy backend API (alias: kreft vite:dev)
|
|
114
|
+
kreft vite:dev Start Vite dev server with instant HMR and backend proxy
|
|
115
|
+
kreft vite:build Build production bundle with Vite and Rollup
|
|
116
|
+
kreft vite:preview Preview production build locally with Vite
|
|
117
|
+
kreft vite:init Add Vite configuration to an existing project (alias: kreft make:vite)
|
|
122
118
|
|
|
123
119
|
Desktop (Electron.js):
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
The backend (
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
|
123
|
+
kreft electron:init Add Electron support to an existing project (alias: kreft make:electron)
|
|
124
|
+
|
|
125
|
+
The backend (kreft list shows every command, yours too):
|
|
126
|
+
kreft key:generate Set the application encryption key in .env (--show: print only)
|
|
127
|
+
kreft migrate Run new migrations in database/migrations (.js or .sql)
|
|
128
|
+
kreft migrate:rollback Undo the last batch of migrations (--step 2: the last two)
|
|
129
|
+
kreft migrate:fresh Drop every table and migrate again (--seed: then seed)
|
|
130
|
+
kreft migrate:status Which migrations ran
|
|
131
|
+
kreft db:seed Run database/seeders/DatabaseSeeder.js (--class PostSeeder: another one)
|
|
132
|
+
kreft route:list The routes in routes/api.js
|
|
133
|
+
kreft storage:link Connect public/storage to storage/app/public (--force) (alias: kreft link:storage)
|
|
134
|
+
kreft storage:unlink Remove the storage link (alias: kreft unlink:storage)
|
|
135
|
+
kreft sitemap Generate public/sitemap.xml and robots.txt
|
|
136
|
+
kreft log Tail recent log entries from storage/logs/kreft.log (--lines 50, --level error)
|
|
137
|
+
kreft log:clear Clear the log file
|
|
138
|
+
kreft make:model Post app/Models/Post.js (-m -f -s -c -p -r, --route=file, --auth, --all)
|
|
139
|
+
kreft make:controller PostController (--api, --model Post, -r, --route=file, --auth)
|
|
140
|
+
kreft make:request StorePostRequest app/Http/Requests/StorePostRequest.js (--model Post)
|
|
141
|
+
kreft make:resource PostResource app/Http/Resources/PostResource.js
|
|
142
|
+
kreft make:rule Uppercase app/Rules/Uppercase.js
|
|
143
|
+
kreft make:page Post frontend/pages/Post.kreftjs (--model Post, -r, --route=file, --auth)
|
|
144
|
+
kreft make:factory PostFactory database/factories/PostFactory.js (--model Post)
|
|
145
|
+
kreft make:migration create_posts_table
|
|
146
|
+
kreft make:seeder PostSeeder
|
|
147
|
+
kreft make:middleware EnsureIsAdmin
|
|
148
|
+
kreft make:job SendWelcomeEmail app/Jobs/SendWelcomeEmail.js
|
|
149
|
+
kreft make:event OrderShipped app/Events/OrderShipped.js
|
|
150
|
+
kreft make:listener SendShipmentNotice app/Listeners/SendShipmentNotice.js (--event OrderShipped)
|
|
151
|
+
kreft make:mail WelcomeMail app/Mail/WelcomeMail.js
|
|
152
|
+
kreft make:notification InvoicePaid app/Notifications/InvoicePaid.js
|
|
153
|
+
kreft make:policy PostPolicy app/Policies/PostPolicy.js (--model Post)
|
|
154
|
+
kreft make:observer PostObserver app/Observers/PostObserver.js (--model Post)
|
|
155
|
+
kreft make:command SendReport app/Console/Commands/SendReport.js (--command report:send)
|
|
156
|
+
kreft make:errors The error pages in errors/ (401, 403, 404, 419, 429, 500, 503…)
|
|
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)
|
|
159
|
+
kreft db tables List tables and columns
|
|
160
|
+
kreft db sql "<SQL>" Run one SQL statement and print the result
|
|
161
|
+
kreft build [folder] Build for production (default: this folder)
|
|
166
162
|
--out <folder> Where to write it (default: dist)
|
|
167
163
|
--base <path> Change the <base href> (for example /)
|
|
168
164
|
--prerender [paths] Also save every page as ready HTML (needs: npm i -D jsdom)
|
|
169
165
|
--include <folder> Also copy this folder into the output (for example docs)
|
|
170
|
-
|
|
166
|
+
kreft add <packages...> Install npm packages with strict security gatekeeper (alias: kreft install, kreft i)
|
|
171
167
|
-D, --dev Install as devDependency
|
|
172
168
|
-y, --yes Auto-confirm unverified community packages in CI/CD
|
|
173
169
|
--dry-run, --check Inspect package security report without installing
|
|
174
170
|
--allow-scripts Permit postinstall lifecycle scripts (default: sandboxed with --ignore-scripts)
|
|
175
171
|
--force Bypass redundancy blocks, typosquat traps and security warnings
|
|
176
|
-
|
|
172
|
+
kreft update [packages] Update project packages (npm update) and Kreft runtime files
|
|
177
173
|
--latest Upgrade packages to their latest versions
|
|
178
174
|
--check Check for outdated packages (npm outdated)
|
|
179
175
|
--core Update only Kreft runtime files (kreftjs.js, kreftjs.d.ts, server.d.ts)
|
|
180
176
|
--npm Update only npm dependencies
|
|
181
|
-
|
|
177
|
+
kreft vscode Install .kreftjs colors and snippets in VS Code (also Cursor, VSCodium)
|
|
182
178
|
|
|
183
179
|
Examples:
|
|
184
|
-
|
|
180
|
+
kreft new shop
|
|
185
181
|
cd shop
|
|
186
182
|
npm run dev
|
|
187
|
-
|
|
183
|
+
kreft update
|
|
188
184
|
npm run build
|
|
189
185
|
`);
|
|
190
186
|
}
|
|
@@ -195,7 +191,7 @@ function unknown() {
|
|
|
195
191
|
process.exit(1);
|
|
196
192
|
}
|
|
197
193
|
|
|
198
|
-
/* ------------------------------------------------------------------
|
|
194
|
+
/* ------------------------------------------------------------------ kreft new */
|
|
199
195
|
async function createProject(args) {
|
|
200
196
|
let name = null, dbKind = null, ui = null, ts = false, langChosen = false, electron = false, vite = false, redis = false, auth = true, authChosen = false;
|
|
201
197
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -221,7 +217,7 @@ async function createProject(args) {
|
|
|
221
217
|
process.exit(1);
|
|
222
218
|
}
|
|
223
219
|
if (!name) {
|
|
224
|
-
console.error(' Give the project a name:
|
|
220
|
+
console.error(' Give the project a name: kreft new my-app (or: kreft new my-app --ts)');
|
|
225
221
|
process.exit(1);
|
|
226
222
|
}
|
|
227
223
|
const target = path.resolve(name);
|
|
@@ -268,8 +264,8 @@ async function createProject(args) {
|
|
|
268
264
|
version: '0.1.0',
|
|
269
265
|
private: true,
|
|
270
266
|
scripts: {
|
|
271
|
-
dev: '
|
|
272
|
-
migrate: '
|
|
267
|
+
dev: 'kreft dev --seed', start: 'kreft dev --seed', build: 'kreft build', preview: 'kreft dev dist', serve: 'kreft serve dist',
|
|
268
|
+
migrate: 'kreft migrate', 'db:seed': 'kreft db:seed', 'migrate:fresh': 'kreft migrate:fresh --seed',
|
|
273
269
|
},
|
|
274
270
|
};
|
|
275
271
|
// .env: the project's own settings (from .env.example, with its name filled in)
|
|
@@ -302,7 +298,7 @@ async function createProject(args) {
|
|
|
302
298
|
Created ${name}/
|
|
303
299
|
|
|
304
300
|
Next:
|
|
305
|
-
cd ${name}${ts ? '\n npm install (TypeScript, its Node.js types and esbuild)' : ''}${vite ? '\n npm install (install vite)\n
|
|
301
|
+
cd ${name}${ts ? '\n npm install (TypeScript, its Node.js types and esbuild)' : ''}${vite ? '\n npm install (install vite)\n kreft vite:dev (launch Vite dev server with instant HMR)' : ''}${electron ? '\n npm install (install electron & electron-builder)\n kreft electron:dev (launch desktop window)' : ''}${dbKind === 'mysql' ? '\n kreft add mysql2 (the MySQL driver, verified & sandboxed)' : dbKind === 'postgres' ? '\n kreft add pg (the PostgreSQL driver, verified & sandboxed)' : ''}${dbKind && dbKind !== 'sqlite' ? '\n (set DATABASE_URL in .env to your database)' : ''}
|
|
306
302
|
npm run dev
|
|
307
303
|
|
|
308
304
|
${auth ? ` Then log in as test@example.com with the password "password", or register.
|
|
@@ -310,7 +306,7 @@ ${auth ? ` Then log in as test@example.com with the password "password", or reg
|
|
|
310
306
|
` : ' Created without authentication (--no-auth): there is no login, registration or users table.\n'}`);
|
|
311
307
|
}
|
|
312
308
|
|
|
313
|
-
//
|
|
309
|
+
// kreft new my-app --ts → TypeScript across backend (.ts) and frontend (.kreftjs, .ts), tsconfig.json, and npm run typecheck
|
|
314
310
|
function toTypeScript(target, projectPkg) {
|
|
315
311
|
const { toTs, TSCONFIG } = require('./to-ts.js');
|
|
316
312
|
const walk = (dir) => {
|
|
@@ -345,7 +341,7 @@ export interface ApiList<T> {
|
|
|
345
341
|
// a typed helper for the frontend, used like any module: import { money } from '../logic/format.ts'
|
|
346
342
|
fs.mkdirSync(path.join(target, 'frontend', 'logic'), { recursive: true });
|
|
347
343
|
fs.writeFileSync(path.join(target, 'frontend', 'logic', 'format.ts'), `// A TypeScript module for the pages: import { money, ago } from '../logic/format.ts'
|
|
348
|
-
//
|
|
344
|
+
// kreft dev turns it into JavaScript as it is sent; kreft build writes it as format.js
|
|
349
345
|
|
|
350
346
|
export function money(amount: number, currency: string = 'USD'): string {
|
|
351
347
|
return new Intl.NumberFormat('en', { style: 'currency', currency }).format(amount)
|
|
@@ -392,7 +388,7 @@ button { font-variant-numeric: tabular-nums; justify-self: start; }
|
|
|
392
388
|
}
|
|
393
389
|
}
|
|
394
390
|
|
|
395
|
-
//
|
|
391
|
+
// kreft new my-app --ui bootstrap → the library's CDN links in index.html
|
|
396
392
|
function uiKits() { return {
|
|
397
393
|
tailwind: ['<!-- Tailwind CSS: use its classes in any .kreftjs file -->', '<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>'],
|
|
398
394
|
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>'],
|
|
@@ -415,14 +411,14 @@ function addUiKit(target, ui) {
|
|
|
415
411
|
fs.writeFileSync(file, updated);
|
|
416
412
|
}
|
|
417
413
|
|
|
418
|
-
//
|
|
414
|
+
// kreft new my-app --db sqlite → database/migrations, a seed, kreftjs.config.json and a Todos page
|
|
419
415
|
function addDatabase(target, kind, projectName) {
|
|
420
416
|
const back = path.join(target, 'backend'), front = path.join(target, 'frontend');
|
|
421
417
|
const file = (rel, text) => { fs.mkdirSync(path.dirname(path.join(back, rel)), { recursive: true }); fs.writeFileSync(path.join(back, rel), text); };
|
|
422
418
|
const d = new Date(), p2 = (n) => String(n).padStart(2, '0');
|
|
423
419
|
const stamp = `${d.getFullYear()}_${p2(d.getMonth() + 1)}_${p2(d.getDate())}_000001`;
|
|
424
420
|
// A migration, a model, a controller, a seeder and a route
|
|
425
|
-
file(`database/migrations/${stamp}_create_todos_table.js`, `//
|
|
421
|
+
file(`database/migrations/${stamp}_create_todos_table.js`, `// kreft dev runs new migrations by itself (or: kreft migrate). kreft migrate:rollback runs down().
|
|
426
422
|
module.exports = {
|
|
427
423
|
up(schema) {
|
|
428
424
|
schema.create('todos', (table) => {
|
|
@@ -488,7 +484,7 @@ module.exports = TodoController
|
|
|
488
484
|
file('database/seeders/TodoSeeder.js', `const { Seeder } = require('kreftjs/server')
|
|
489
485
|
const Todo = require('../../app/Models/Todo')
|
|
490
486
|
|
|
491
|
-
// DatabaseSeeder calls this one (or on its own:
|
|
487
|
+
// DatabaseSeeder calls this one (or on its own: kreft db:seed --class TodoSeeder)
|
|
492
488
|
class TodoSeeder extends Seeder {
|
|
493
489
|
async run() {
|
|
494
490
|
await Todo.create({ title: 'Learn Kreft', done: true })
|
|
@@ -583,7 +579,7 @@ function copyFolder(from, to) {
|
|
|
583
579
|
}
|
|
584
580
|
}
|
|
585
581
|
|
|
586
|
-
/* ------------------------------------------------------------------
|
|
582
|
+
/* ------------------------------------------------------------------ kreft vscode */
|
|
587
583
|
function installVscode() {
|
|
588
584
|
const os = require('os');
|
|
589
585
|
const from = path.join(__dirname, '..', 'editors', 'vscode');
|
|
@@ -613,12 +609,12 @@ function installVscode() {
|
|
|
613
609
|
console.log('\n Restart VS Code (or run "Reload Window") to see updated colors and formatting in .kreftjs files.\n');
|
|
614
610
|
}
|
|
615
611
|
|
|
616
|
-
/* ------------------------------------------------------------------
|
|
612
|
+
/* ------------------------------------------------------------------ kreft dev */
|
|
617
613
|
async function devServer(args, { production = false } = {}) {
|
|
618
614
|
const isProd = Boolean(production || process.env.APP_ENV === 'production' || process.env.NODE_ENV === 'production');
|
|
619
615
|
let port = production ? Number(process.env.PORT) || 8000 : 8000, folder = production ? 'dist' : '.', apiFile = null, delay = 0, saveApi = true, hot = !production, dbUrl = null, migrations = null, serverFolder = null, backendFolder = null, seedNew = false;
|
|
620
|
-
//
|
|
621
|
-
//
|
|
616
|
+
// kreft dev only answers this computer; --host 0.0.0.0 shares it on your network.
|
|
617
|
+
// kreft serve answers everyone (HOST in the environment can narrow it).
|
|
622
618
|
let host = production ? process.env.HOST || '0.0.0.0' : '127.0.0.1';
|
|
623
619
|
for (let i = 0; i < args.length; i++) {
|
|
624
620
|
if (args[i] === '--port' || args[i] === '-p') port = Number(args[++i]) || port;
|
|
@@ -639,7 +635,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
639
635
|
const lay = require('./layout.js').layout(folder === 'dist' || folder === '.' ? '.' : folder);
|
|
640
636
|
const root = !production && folder === '.' ? lay.frontend : path.resolve(folder);
|
|
641
637
|
if (production && !fs.existsSync(root)) {
|
|
642
|
-
console.error(` Nothing to serve in ${root}. Build first:
|
|
638
|
+
console.error(` Nothing to serve in ${root}. Build first: kreft build`);
|
|
643
639
|
process.exit(1);
|
|
644
640
|
}
|
|
645
641
|
const mockApi = apiFile && !production ? createMockApi(path.resolve(apiFile), delay, saveApi) : null;
|
|
@@ -658,7 +654,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
658
654
|
const hasBackend = Boolean(apiRoutesFile);
|
|
659
655
|
// kreftjs serve: the backend must not sit inside the folder that is served, or its files could be downloaded
|
|
660
656
|
if (production && hasBackend && (backendDir === root || backendDir.startsWith(root + path.sep))) {
|
|
661
|
-
console.error(` The backend (${backendDir}) is inside the folder being served (${root}).\n Serve the built site instead:
|
|
657
|
+
console.error(` The backend (${backendDir}) is inside the folder being served (${root}).\n Serve the built site instead: kreft build, then kreft serve dist`);
|
|
662
658
|
process.exit(1);
|
|
663
659
|
}
|
|
664
660
|
if (production && hasBackend && !process.env.APP_KEY) console.warn(' Warning: no APP_KEY in .env. Signed links (email verification) stop working on every restart.');
|
|
@@ -668,7 +664,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
668
664
|
const { createDbApi } = require('./db-api.js');
|
|
669
665
|
try {
|
|
670
666
|
db = await connect(dbUrl, { root: config.dir });
|
|
671
|
-
if (!production) { //
|
|
667
|
+
if (!production) { // kreft dev runs new migrations by itself; for kreft serve, run `kreft migrate`
|
|
672
668
|
const { migrator, installAlias } = require('./backend/index.js');
|
|
673
669
|
installAlias(); // require('kreftjs/server') and .ts files work in migrations and seeders
|
|
674
670
|
require('./backend/model.js').setBaseDir(backendDir);
|
|
@@ -697,7 +693,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
697
693
|
const n = backend.routes().length;
|
|
698
694
|
backendRoutesCount = n;
|
|
699
695
|
// queued jobs, mails and notifications run in the background here, and routes/console.js runs on schedule
|
|
700
|
-
// (QUEUE_WORKER=off or SCHEDULER=off in .env when a separate `
|
|
696
|
+
// (QUEUE_WORKER=off or SCHEDULER=off in .env when a separate `kreft queue:work` / cron does it)
|
|
701
697
|
if (db) {
|
|
702
698
|
const queue = require('./backend/queue.js');
|
|
703
699
|
const queues = String(process.env.QUEUE_NAMES || 'high,default,low').split(',').map((x) => x.trim());
|
|
@@ -713,7 +709,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
713
709
|
}
|
|
714
710
|
if (process.env.SCHEDULER !== 'off') require('./backend/schedule.js').startScheduler(backendDir);
|
|
715
711
|
}
|
|
716
|
-
backendNote = `\n Routes: ${path.relative(process.cwd(), apiRoutesFile) || 'routes/api.js'} → ${n} route${n === 1 ? '' : 's'} at /api (
|
|
712
|
+
backendNote = `\n Routes: ${path.relative(process.cwd(), apiRoutesFile) || 'routes/api.js'} → ${n} route${n === 1 ? '' : 's'} at /api (kreft route:list)`;
|
|
717
713
|
}
|
|
718
714
|
|
|
719
715
|
// ----- your own server code: server/hello.js → /api/hello (any Node.js package can be used there)
|
|
@@ -730,7 +726,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
730
726
|
console.error(` --server: ${serverFolder} does not exist.`);
|
|
731
727
|
process.exit(1);
|
|
732
728
|
}
|
|
733
|
-
// npm packages in the browser (
|
|
729
|
+
// npm packages in the browser (kreft dev only; kreft build puts them in dist/deps)
|
|
734
730
|
const npmMap = () => (production ? null : deps.importMap(project));
|
|
735
731
|
|
|
736
732
|
const types = {
|
|
@@ -743,7 +739,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
743
739
|
|
|
744
740
|
const prodHeaders = isProd ? { 'Referrer-Policy': 'same-origin', 'X-Frame-Options': 'SAMEORIGIN', 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains; preload' } : {};
|
|
745
741
|
function send(res, file, opts = {}) { // opts.seo: tags for <head> (pages from seo.js), opts.status: 404 for a page that does not exist
|
|
746
|
-
// a TypeScript module for the browser: its JavaScript (
|
|
742
|
+
// a TypeScript module for the browser: its JavaScript (kreft build writes it as .js)
|
|
747
743
|
if (!production && /\.(m|c)?ts$/i.test(file) && !file.endsWith('.d.ts')) {
|
|
748
744
|
const { transpileTs } = require('./backend/typescript.js');
|
|
749
745
|
res.writeHead(200, { 'Content-Type': 'text/javascript; charset=utf-8', 'Cache-Control': 'no-store', 'X-Content-Type-Options': 'nosniff' });
|
|
@@ -763,7 +759,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
763
759
|
});
|
|
764
760
|
if (!production && type === 'text/html') {
|
|
765
761
|
let html = fs.readFileSync(file, 'utf8');
|
|
766
|
-
// PUBLIC_ values from .env, as Kreftjs.env (
|
|
762
|
+
// PUBLIC_ values from .env, as Kreftjs.env (kreft build puts them in app.js)
|
|
767
763
|
const envTag = `<script>${env.envScript(env.publicEnv())}</script>`;
|
|
768
764
|
const langHelper = require('./lang.js');
|
|
769
765
|
const langDirs = langHelper.findLangDirs(root);
|
|
@@ -903,7 +899,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
903
899
|
if (cur.mtimeMs === prev.mtimeMs) return; // not a real change (the file may not exist at all)
|
|
904
900
|
const before = process.env.DATABASE_URL;
|
|
905
901
|
env.loadEnv(envDir);
|
|
906
|
-
console.log(' .env changed' + (process.env.DATABASE_URL !== before ? ' (restart
|
|
902
|
+
console.log(' .env changed' + (process.env.DATABASE_URL !== before ? ' (restart kreft dev to use the new DATABASE_URL)' : ''));
|
|
907
903
|
clients.forEach((c) => c.write(`data: ${JSON.stringify({ type: 'reload', path: '/.env' })}\n\n`));
|
|
908
904
|
});
|
|
909
905
|
// files a browser must never get: the database itself, its settings and password, hidden files, locks, dumps
|
|
@@ -918,7 +914,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
918
914
|
try { seo = await require('./backend/seo-pages.js').resolve(backendDir, urlPath, req); } catch (e) { console.log(' routes/seo.js: ' + (e && e.message || e)); }
|
|
919
915
|
}
|
|
920
916
|
// a crawler or link preview gets the page already drawn (and a 404 when the app shows its 404 page)
|
|
921
|
-
if (ssr.wants(req) && (!seo || seo.status === 200) && !fs.readFileSync(file, 'utf8').includes('data-kreft-ssg')) { // a page
|
|
917
|
+
if (ssr.wants(req) && (!seo || seo.status === 200) && !fs.readFileSync(file, 'utf8').includes('data-kreft-ssg')) { // a page kreft build --prerender already drew is sent as it is
|
|
922
918
|
const page = await ssr.render(urlPath, search);
|
|
923
919
|
if (page) {
|
|
924
920
|
res.writeHead(page.status, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': isProd ? 'no-cache' : 'no-store', 'Vary': 'User-Agent', 'X-Content-Type-Options': 'nosniff', ...prodHeaders });
|
|
@@ -964,7 +960,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
964
960
|
}
|
|
965
961
|
if (urlPath.startsWith('/__kreft/npm/')) {
|
|
966
962
|
const file = deps.packageFile(project, urlPath.slice('/__kreft/npm/'.length));
|
|
967
|
-
if (!file) { res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' }); return res.end('Not in node_modules: ' + urlPath.slice(11) + ' (
|
|
963
|
+
if (!file) { res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' }); return res.end('Not in node_modules: ' + urlPath.slice(11) + ' (kreft add ' + (urlPath.slice(11).match(deps.NAME) || [''])[0] + ')'); }
|
|
968
964
|
return send(res, file);
|
|
969
965
|
}
|
|
970
966
|
const spec = urlPath.slice('/__kreft/deps/'.length).replace(/\/$/, '');
|
|
@@ -977,7 +973,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
977
973
|
const privateDirs = [serverDir, ...(hasBackend ? ['app', 'routes', 'database', 'config', 'storage'].map((d) => path.join(backendDir, d)) : []), path.join(root, 'config')];
|
|
978
974
|
const insideServerDir = (file) => privateDirs.some((d) => file === d || file.startsWith(d + path.sep));
|
|
979
975
|
|
|
980
|
-
// kreftjs down: storage/framework/down.json → a 503 for everyone, except with the secret (
|
|
976
|
+
// kreftjs down: storage/framework/down.json → a 503 for everyone, except with the secret (kreft down --secret=…)
|
|
981
977
|
const downPath = path.join(backendDir, 'storage', 'framework', 'down.json');
|
|
982
978
|
let downCache = { at: 0, data: null };
|
|
983
979
|
const downInfo = () => {
|
|
@@ -1017,7 +1013,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
1017
1013
|
}
|
|
1018
1014
|
|
|
1019
1015
|
// DNS rebinding: a web page can make its own name (evil.example) point at 127.0.0.1 and then read everything
|
|
1020
|
-
//
|
|
1016
|
+
// kreft dev serves, with the browser believing it is the same site. A server that only answers this computer
|
|
1021
1017
|
// therefore only answers the names of this computer (add more with KREFT_ALLOWED_HOSTS=my-tunnel.example).
|
|
1022
1018
|
const hostOnly = (h) => String(h || '').toLowerCase().replace(/:\d+$/, '').replace(/^\[|\]$/g, '');
|
|
1023
1019
|
const isLocalName = (n) => n === 'localhost' || n === '127.0.0.1' || n === '::1' || n.endsWith('.localhost');
|
|
@@ -1101,7 +1097,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
1101
1097
|
}
|
|
1102
1098
|
if (hot && urlPath.startsWith('/__kreft/')) return devFiles(req, res, urlPath);
|
|
1103
1099
|
if (adminDir && (urlPath === '/admin' || urlPath.startsWith('/admin/'))) return adminFiles(req, res, urlPath);
|
|
1104
|
-
// /storage/…: files on the public disk (backend/storage/app/public), connected by
|
|
1100
|
+
// /storage/…: files on the public disk (backend/storage/app/public), connected by kreft storage:link.
|
|
1105
1101
|
// They are sent as downloads of plain data: an uploaded .html or .svg can't run scripts on your site.
|
|
1106
1102
|
if (urlPath.startsWith('/storage/')) {
|
|
1107
1103
|
const pub = path.join(backendDir, 'storage', 'app', 'public');
|
|
@@ -1189,7 +1185,7 @@ async function devServer(args, { production = false } = {}) {
|
|
|
1189
1185
|
|
|
1190
1186
|
/* ------------------------------------------------------------------ settings: kreftjs.config.json
|
|
1191
1187
|
* { "db": "sqlite:database/app.db", "tables": { "posts": true, "users": { "write": false, "hidden": ["password"] } } }
|
|
1192
|
-
* Looked for in the folder being served, then its parents (so `
|
|
1188
|
+
* Looked for in the folder being served, then its parents (so `kreft serve dist` finds the project's file).
|
|
1193
1189
|
* DATABASE_URL in the environment wins over "db" — put real passwords there, not in the file.
|
|
1194
1190
|
*/
|
|
1195
1191
|
function readConfig(start) { return require('./kreftjs-config.js').readConfig(start); }
|
|
@@ -1199,7 +1195,7 @@ function migrationsDir(...dirs) {
|
|
|
1199
1195
|
}
|
|
1200
1196
|
const describeDb = (url) => url.replace(/\/\/([^:@/]+):[^@/]*@/, '//$1:•••@');
|
|
1201
1197
|
|
|
1202
|
-
/* ------------------------------------------------------------------
|
|
1198
|
+
/* ------------------------------------------------------------------ kreft db */
|
|
1203
1199
|
async function dbCommand(args) {
|
|
1204
1200
|
const [sub = 'help', ...rest] = args;
|
|
1205
1201
|
let dbUrl = null, folder = '.', migrations = null;
|
|
@@ -1215,10 +1211,10 @@ async function dbCommand(args) {
|
|
|
1215
1211
|
dbUrl = dbUrl || process.env.DATABASE_URL || config.db;
|
|
1216
1212
|
if (sub === 'help' || !['migrate', 'seed', 'tables', 'sql'].includes(sub)) {
|
|
1217
1213
|
console.log(`
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1214
|
+
kreft db migrate The same as kreft migrate
|
|
1215
|
+
kreft db seed The same as kreft db:seed
|
|
1216
|
+
kreft db tables List tables and columns
|
|
1217
|
+
kreft db sql "<SQL>" Run one statement and print the result
|
|
1222
1218
|
|
|
1223
1219
|
The database comes from --db, DATABASE_URL or "db" in kreftjs.config.json.
|
|
1224
1220
|
`);
|
|
@@ -1229,7 +1225,7 @@ async function dbCommand(args) {
|
|
|
1229
1225
|
let db;
|
|
1230
1226
|
try {
|
|
1231
1227
|
db = await connect(dbUrl, { root: config.dir });
|
|
1232
|
-
if (sub === 'migrate' || sub === 'seed') { // the same as
|
|
1228
|
+
if (sub === 'migrate' || sub === 'seed') { // the same as kreft migrate and kreft db:seed
|
|
1233
1229
|
await db.close(); db = null;
|
|
1234
1230
|
return require('./artisan.js').commands[sub === 'migrate' ? 'migrate' : 'db:seed'](rest);
|
|
1235
1231
|
} else if (sub === 'tables') {
|
|
@@ -1240,7 +1236,7 @@ async function dbCommand(args) {
|
|
|
1240
1236
|
console.log('');
|
|
1241
1237
|
} else if (sub === 'sql') {
|
|
1242
1238
|
const sql = extra.join(' ');
|
|
1243
|
-
if (!sql.trim()) { console.error('
|
|
1239
|
+
if (!sql.trim()) { console.error(' kreft db sql "SELECT * FROM posts"'); process.exit(1); }
|
|
1244
1240
|
if (/^\s*(select|with|pragma|show|describe|explain)\b/i.test(sql)) console.table(await db.query(sql));
|
|
1245
1241
|
else { const r = await db.run(sql); console.log(` Done: ${r.changes} row${r.changes === 1 ? '' : 's'} changed.`); }
|
|
1246
1242
|
}
|
|
@@ -1252,7 +1248,7 @@ async function dbCommand(args) {
|
|
|
1252
1248
|
}
|
|
1253
1249
|
}
|
|
1254
1250
|
|
|
1255
|
-
/* ------------------------------------------------------------------
|
|
1251
|
+
/* ------------------------------------------------------------------ kreft dev --api db.json
|
|
1256
1252
|
* A small REST API for trying things out, made from a JSON file:
|
|
1257
1253
|
* { "posts": [ { "id": 1, "title": "Hello" } ], "$required": { "posts": ["title"] } }
|
|
1258
1254
|
*
|
package/bin/layout.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Where a project's parts are.
|
|
3
3
|
*
|
|
4
|
-
* New projects (
|
|
4
|
+
* New projects (kreft new) keep frontend and backend apart:
|
|
5
5
|
* frontend/ the only folder a browser can reach: index.html, pages, components, routes/web.kreftjs …
|
|
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
|
package/bin/no-auth.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
2
|
+
* kreft new my-app --no-auth
|
|
3
3
|
*
|
|
4
4
|
* A new app comes with login, registration, password reset, email verification, a profile and an admin area. This takes
|
|
5
5
|
* all of that out again, so the app starts as a plain site: the welcome page, the docs, the error monitor and the tests
|
|
@@ -24,7 +24,7 @@ const TO_REMOVE = [
|
|
|
24
24
|
|
|
25
25
|
const API = (todos) => `// Your API: every address here starts with /api.
|
|
26
26
|
// All API routes live directly in this file. Add your new routes here!
|
|
27
|
-
// See them all anytime with:
|
|
27
|
+
// See them all anytime with: kreft route:list
|
|
28
28
|
const { Route } = require('kreftjs/server')
|
|
29
29
|
${todos ? `const TodoController = require('../app/Http/Controllers/TodoController')
|
|
30
30
|
|
|
@@ -50,7 +50,7 @@ module.exports = AppServiceProvider
|
|
|
50
50
|
|
|
51
51
|
const SEEDER = (todos) => `const { Seeder } = require('kreftjs/server')
|
|
52
52
|
|
|
53
|
-
//
|
|
53
|
+
// kreft db:seed (kreft dev --seed fills a new database)
|
|
54
54
|
class DatabaseSeeder extends Seeder {
|
|
55
55
|
async run() {
|
|
56
56
|
${todos ? " await this.call(require('./TodoSeeder'))\n" : ''} }
|
|
@@ -134,7 +134,7 @@ function removeAuth(target) {
|
|
|
134
134
|
const to = html.indexOf(" Kreftjs.app('App.kreftjs')");
|
|
135
135
|
if (from >= 0 && to > from) {
|
|
136
136
|
html = html.slice(0, from) + ` const router = Kreftjs.router({
|
|
137
|
-
routes: ['routes/web.kreftjs'], // the pages are in routes/web.kreftjs; add more files:
|
|
137
|
+
routes: ['routes/web.kreftjs'], // the pages are in routes/web.kreftjs; add more files: kreft make:routes admin
|
|
138
138
|
layout: 'app', // every page goes inside layouts/app.kreftjs…
|
|
139
139
|
errors: 'errors', // error pages: errors/404.kreftjs for unknown addresses, abort(403) → errors/403.kreftjs
|
|
140
140
|
})
|
package/bin/prerender.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
|
-
*
|
|
2
|
+
* kreft build --prerender — saves every page of the router as ready HTML (static site generation).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* kreft build --prerender every route without :params
|
|
5
|
+
* kreft build --prerender /users/1,/users/2 also these addresses
|
|
6
6
|
*
|
|
7
7
|
* Each page opens in a simulated browser (jsdom), waits until its data has loaded, and the result
|
|
8
8
|
* is written to dist/<path>/index.html. Visitors and search engines get the content at once;
|
|
@@ -176,7 +176,7 @@ module.exports = async function prerender(dist, root, extra) {
|
|
|
176
176
|
try {
|
|
177
177
|
jsdom = loadJsdom(root);
|
|
178
178
|
} catch (_) {
|
|
179
|
-
throw new Error('it needs jsdom. Install it once in your project:\n\n
|
|
179
|
+
throw new Error('it needs jsdom. Install it once in your project:\n\n kreft add -D jsdom\n');
|
|
180
180
|
}
|
|
181
181
|
const { JSDOM } = jsdom;
|
|
182
182
|
if (typeof fetch !== 'function') throw new Error('it needs Node.js 18 or newer.');
|
package/bin/server-routes.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* Export get, post, put, patch and del (delete is a reserved word), or one `handle` for every method.
|
|
18
18
|
* What you return goes back as JSON (nothing → 204). ctx.fail(status, message or { field: [...] })
|
|
19
19
|
* stops with an error. ctx.res is Node's response, if you need it (stream, a file, a redirect).
|
|
20
|
-
*
|
|
20
|
+
* kreft dev picks up changes to these files by itself.
|
|
21
21
|
*/
|
|
22
22
|
const fs = require('fs');
|
|
23
23
|
const path = require('path');
|
|
@@ -62,7 +62,7 @@ function createServerRoutes(dir, { db = null, production = false, prefix = '/api
|
|
|
62
62
|
return out.sort((a, b) => a.dynamic - b.dynamic); // /users/me before /users/[id]
|
|
63
63
|
};
|
|
64
64
|
const list = () => {
|
|
65
|
-
//
|
|
65
|
+
// kreft dev looks for new files twice a second at most; kreft serve reads the folder once
|
|
66
66
|
if (!scannedAt || (!production && Date.now() - scannedAt > 500)) { routes = scan(); scannedAt = Date.now(); }
|
|
67
67
|
return routes;
|
|
68
68
|
};
|
package/bin/ssr.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Whole pages for crawlers and link previews: the server answers them with the page already drawn.
|
|
3
3
|
*
|
|
4
4
|
* A search engine or a chat app that does not run JavaScript would see an empty <div id="app">. For those
|
|
5
|
-
* visitors the server opens the page in a simulated browser (the same one `
|
|
5
|
+
* visitors the server opens the page in a simulated browser (the same one `kreft build --prerender` uses),
|
|
6
6
|
* waits until its data has loaded, and answers with the result. Everyone else gets the normal page.
|
|
7
7
|
*
|
|
8
8
|
* KREFT_SSR=bots (default) crawlers and link-preview bots only
|
|
@@ -45,7 +45,7 @@ function create({ root, origin, log = () => { }, cached = true }) {
|
|
|
45
45
|
if (jsdom || unavailable) return jsdom;
|
|
46
46
|
try { jsdom = require('./prerender.js').loadJsdom(root); } catch (_) {
|
|
47
47
|
unavailable = true;
|
|
48
|
-
if (mode !== 'off') log(' SSR for crawlers needs jsdom:
|
|
48
|
+
if (mode !== 'off') log(' SSR for crawlers needs jsdom: kreft add -D jsdom (crawlers get the normal page until then)');
|
|
49
49
|
}
|
|
50
50
|
return jsdom;
|
|
51
51
|
}
|
package/bin/terminal.js
CHANGED
|
@@ -167,7 +167,7 @@ function renderDevBanner({
|
|
|
167
167
|
lines.push(` ${c.dim('•')} ${c.bold('Database:')} ${c.green(database)}`);
|
|
168
168
|
}
|
|
169
169
|
if (routesCount > 0) {
|
|
170
|
-
lines.push(` ${c.dim('•')} ${c.bold('API:')} ${c.cyan(routesCount + ' routes')} ${c.dim('(
|
|
170
|
+
lines.push(` ${c.dim('•')} ${c.bold('API:')} ${c.cyan(routesCount + ' routes')} ${c.dim('(kreft route:list)')}`);
|
|
171
171
|
}
|
|
172
172
|
if (serverRoutesCount > 0) {
|
|
173
173
|
lines.push(` ${c.dim('•')} ${c.bold('Server:')} ${c.cyan(serverRoutesCount + ' custom endpoints')}`);
|
package/bin/to-ts.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// JavaScript backend files → TypeScript (
|
|
1
|
+
// JavaScript backend files → TypeScript (kreft new --ts, and kreftjs make:* in a TypeScript project):
|
|
2
2
|
// require → import, module.exports → export default. Inline require('./X') stays (it works at run time).
|
|
3
3
|
function toTs(code) {
|
|
4
4
|
return code
|