miqro 7.2.1 → 7.2.3

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 (38) hide show
  1. package/README.md +871 -492
  2. package/build/editor.bundle.js +44 -12
  3. package/build/esm/editor/http/admin/editor/api/fs/delete.api.d.ts +3 -2
  4. package/build/esm/editor/http/admin/editor/api/fs/delete.api.js +3 -3
  5. package/build/esm/editor/http/admin/editor/api/fs/delete.api.js.map +1 -1
  6. package/build/esm/editor/http/admin/editor/api/fs/read.api.d.ts +3 -1
  7. package/build/esm/editor/http/admin/editor/api/fs/read.api.js +3 -3
  8. package/build/esm/editor/http/admin/editor/api/fs/read.api.js.map +1 -1
  9. package/build/esm/editor/http/admin/editor/api/fs/rename.api.d.ts +4 -1
  10. package/build/esm/editor/http/admin/editor/api/fs/rename.api.js +3 -3
  11. package/build/esm/editor/http/admin/editor/api/fs/rename.api.js.map +1 -1
  12. package/build/esm/src/cluster.js +0 -0
  13. package/build/esm/src/common/jsx.d.ts +3 -3
  14. package/build/esm/src/common/jsx.js.map +1 -1
  15. package/build/esm/src/inflate/inflate-sea.js +2 -2
  16. package/build/esm/src/inflate/inflate-sea.js.map +1 -1
  17. package/build/esm/src/inflate/setup-http.js.map +1 -1
  18. package/build/esm/src/main.js +0 -0
  19. package/build/esm/src/services/editor.js.map +1 -1
  20. package/build/esm/src/services/utils/cluster-ws.js +2 -2
  21. package/build/esm/src/services/utils/cluster-ws.js.map +1 -1
  22. package/build/esm/src/types.d.ts +5 -4
  23. package/build/esm/src/types.js +4 -1
  24. package/build/esm/src/types.js.map +1 -1
  25. package/build/lib.cjs +444 -174
  26. package/editor/http/admin/editor/api/fs/delete.api.tsx +3 -3
  27. package/editor/http/admin/editor/api/fs/read.api.tsx +3 -3
  28. package/editor/http/admin/editor/api/fs/rename.api.tsx +3 -3
  29. package/package.json +12 -12
  30. package/sea/install-esbuild.sh +1 -1
  31. package/sea/install-nodejs.sh +1 -1
  32. package/sea/node.version.tag +1 -1
  33. package/src/common/jsx.ts +3 -3
  34. package/src/inflate/inflate-sea.ts +2 -2
  35. package/src/inflate/setup-http.ts +4 -4
  36. package/src/services/editor.tsx +1 -1
  37. package/src/services/utils/cluster-ws.ts +2 -2
  38. package/src/types.ts +21 -41
package/README.md CHANGED
@@ -1,66 +1,133 @@
1
1
  # miqro
2
2
 
3
- **experimental** development cli for **static web site generation** using JSX.
3
+ **experimental** Node.js web framework built from scratch with minimal runtime dependencies.
4
4
 
5
- it uses ```esbuild``` for faster transpilation.
5
+ fully typed TypeScript · REST · WebSocket · SQL · JWT · HTTP
6
6
 
7
- but also can
7
+ runtime dependencies: `jose`, `esbuild`, `cookie`, `showdown`
8
8
 
9
- - can create **javascript native** ```WebComponents``` using ```JSX``` with ```@miqro/jsx```.
9
+ - **Web Components** using JSX server-rendered and client-side
10
+ - **static site generation** — `.html.tsx` handlers run against a live DB at build time
11
+ - **REST API** endpoints with request/response validation
12
+ - **database** — `sqlite3`, `node:sqlite`, `postgres` with migrations
13
+ - **cluster** — multi-worker with shared cache and hot reload
14
+ - **NODE:SEA** — single binary, no Node.js required on target machine
15
+ - **built-in editor**, **test runner**, **API doc generation**
10
16
 
11
- - can transform ```markdown``` to **html** using ```showdown```.
17
+ ## packages
12
18
 
13
- - can also host custom **API** endpoints with a complete web framework if more than a static web site generator is needed.
14
-
15
- - can provide a database connection to ```sqlite3```, ```postgres``` and ```sql server``` using ```@miqro/query```. by default it uses the native ```node:sqlite3``` **experimental** module for ```Node.js >=20.x``` but can also use ```sqlite3```, ```pg``` and others.
19
+ ```
20
+ miqro
21
+ ├── @miqro/core router, middleware, session, CORS, logger
22
+ ├── @miqro/jsx vDOM, hooks, SSR runtime
23
+ ├── @miqro/jsx-dom Web Component define, browser runtime
24
+ ├── @miqro/jsx-node node SSR runtime
25
+ ├── @miqro/query query builder, ORM, migrations
26
+ ├── @miqro/parser schema validation
27
+ ├── @miqro/request http client
28
+ ├── @miqro/runner cluster manager
29
+ ├── @miqro/test test runner
30
+ └── @miqro/test-http http test helper
31
+ ```
16
32
 
17
- - can manage **database migrations** for your **app** or **static site** build using a database as source.
33
+ `@miqro/test` and `@miqro/request` are being phased out in favor of `node:test` and built-in `fetch`.
18
34
 
19
- - provide built-in ```editor``` for **development** using ```highlight.js``` for **code highlight**.
35
+ package docs: [@miqro/core](core-README.md) · [@miqro/query](query-README.md) · [@miqro/jsx](jsx-README.md) · [@miqro/jsx-dom](jsx-dom-README.md) · [@miqro/jsx-node](jsx-node-README.md) · [@miqro/request](request-README.md) · [@miqro/runner](runner-README.md) · [@miqro/test](test-README.md) · [@miqro/test-http](test-http-README.md) · [@miqro/parser](parser-README.md)
20
36
 
21
- - can run generate **API documentation** using **markdown** or **json**.
37
+ ## composition
22
38
 
23
- - can run **tests** on your **app** or **static site**.
39
+ services run sequentially. each service runs on every request until a route sends a response.
24
40
 
25
- - can be installed and run **without Node.js** installed as a standalone ```NODE:SEA``` binary for ```linux-x64```, ```linux-arm64```, ```darwin-x64``` and ```darwin-arm64```.
41
+ ```json
42
+ {
43
+ "services": ["a/", "b/", "c/"]
44
+ }
45
+ ```
26
46
 
27
- - can create a standalone ```NODE:SEA``` ```binary``` of your webapp for ```linux-x64```, ```linux-arm64```, ```darwin-x64``` and ```darwin-arm64```.
47
+ ```
48
+ request →
49
+ a/ runs (auth.ts, middleware.ts, then http/ routes)
50
+ if no route in a/ matched, b/ runs
51
+ if no route in b/ matched, c/ runs
52
+ ```
28
53
 
29
- ## installation
54
+ earlier services establish state. later services consume it.
30
55
 
31
- ### without Node.js installed as a NODE:SEA binary.
56
+ ```
57
+ a/auth.ts → sets req.session
58
+ b/db.ts → req.server.db.get("b") available
59
+ c/http/ → has req.session and req.server.db, handles routes
60
+ ```
32
61
 
33
- download the standalone binary from the [releases](https://github.com/claukers/miqro/releases) page.
62
+ `req.session.account` is the tenant identifier. use it to isolate data:
34
63
 
35
- ### npm dependency for Node.js project
64
+ ```ts
65
+ // any handler in c/
66
+ const posts = await req.server.db.get("b")
67
+ .select().from("posts")
68
+ .eq("account", req.session.account)
69
+ .yield();
70
+ ```
36
71
 
37
- or use it as a dependecy on your Node.js project.
72
+ seed shared state in `server.ts` using `isPrimaryWorker()`:
38
73
 
39
- ```npm install miqro```
74
+ ```ts
75
+ // a/server.ts
76
+ export default {
77
+ load: async (server) => {
78
+ if (server.isPrimaryWorker()) {
79
+ const config = await server.db.get("b").select().from("config").yield();
80
+ server.cache.set("config", config);
81
+ }
82
+ }
83
+ }
84
+ ```
40
85
 
41
- ## getting started basic example static site generated with jsx
86
+ swap `a/` for a different implementation `b/` and `c/` don't change. they read from `req.session`, not from `a/` directly.
42
87
 
43
- project structure
88
+ same service folders, different `miqro.json`:
44
89
 
90
+ ```json
91
+ { "services": ["a1/", "b/", "c/"] } // production auth
92
+ { "services": ["a2/", "b/", "c/"] } // test auth
93
+ { "services": ["b/", "c/"] } // no auth
45
94
  ```
46
- example/
47
- http/
48
- about/
49
- ...
50
- index.html.tsx
51
- static/
52
- ...
95
+
96
+ service folders can be npm packages:
97
+
98
+ ```json
99
+ {
100
+ "services": [
101
+ "node_modules/@myorg/auth/service/",
102
+ "node_modules/@myorg/db/service/",
103
+ "services/app/"
104
+ ]
105
+ }
53
106
  ```
54
107
 
55
- ### 1. create an empty folder to contain the example service and files
108
+ ## installation
109
+
110
+ ### standalone binary (no Node.js required) ( Not Up-To-Date versions )
111
+
112
+ download from [releases](https://github.com/claukers/miqro/releases). (diff release cycle so expect OLD versions published)
113
+
114
+ for newer releases use the npm install and the npx miqro --compile to produce a standalone binary of the app
115
+
116
+ ### npm
56
117
 
57
- ```mkdir -p example/http```
118
+ ```
119
+ npm install miqro
120
+ ```
121
+
122
+ ## getting started
58
123
 
59
- ### 2. create a basic ```.html.tsx``` file.
124
+ ```
125
+ mkdir -p example/http
126
+ ```
60
127
 
61
- ```example/http/index.html.tsx```
128
+ `example/http/index.html.tsx`
62
129
 
63
- ```typescript
130
+ ```tsx
64
131
  import JSX from "@miqro/jsx";
65
132
 
66
133
  export default (req, res) => {
@@ -72,631 +139,943 @@ export default (req, res) => {
72
139
  }
73
140
  ```
74
141
 
75
- to host a watch server with the example run the following command.
142
+ ```
143
+ miqro --watch --service example/
144
+ ```
76
145
 
77
- ```miqro --watch --service example/```
146
+ open `http://localhost:8080/index.html`.
78
147
 
79
- then open a browser and go to ```http://localhost:8080/index.html``` to watch the changes you make into the file.
148
+ ### generate static files
80
149
 
81
- ### 3. generate static files to host with a web server
150
+ ```
151
+ miqro --inflate --inflate-dir build/ --service example/
152
+ ```
82
153
 
83
- to generate the static files just run the command.
154
+ output in `build/example/static/`. serve with any http server.
84
155
 
85
- ```miqro --inflate --inflate-dir build/ --service example/```
156
+ ## service folder
86
157
 
87
- the generated static files will be written in ```build/example/http/static````
158
+ ```
159
+ app/
160
+ http/ endpoints
161
+ static/ files served as-is
162
+ migration/ db migrations
163
+ test/ tests
164
+ db.ts database config
165
+ ws.ts websocket config
166
+ auth.ts session/auth config
167
+ server.ts lifecycle hooks
168
+ log.ts log transport config
169
+ middleware.ts pre/post route middleware
170
+ catch.ts error handlers
171
+ miqro.json multi-service composition
172
+ ```
88
173
 
89
- and can be served like this.
174
+ all files and folders are optional.
90
175
 
91
- ```python3 -m http.server 8080 build/example/http/static```
176
+ ```
177
+ miqro --service app/
178
+ miqro --service app/ --editor
179
+ ```
92
180
 
181
+ ## http folder
93
182
 
94
- ## Documentation
183
+ files are served by their path in the directory.
95
184
 
96
- ### usage as a module
185
+ ```
186
+ http/
187
+ index.html.tsx → GET /index.html
188
+ posts/
189
+ index.html.tsx → GET /posts/index.html
190
+ list.api.ts → GET /posts/list
191
+ js/
192
+ app.min.tsx → GET /js/app.js (minified bundle)
193
+ ```
97
194
 
98
- first install as a dependency
195
+ ### .html.tsx
99
196
 
100
- ```npm install miqro --save```
197
+ server-rendered JSX. runs at request time or at build time with `--inflate`.
101
198
 
102
- example loading the service created in the getting started above.
199
+ ```tsx
200
+ import JSX from "@miqro/jsx";
103
201
 
104
- ```typescript
105
- import { Miqro } from "miqro";
202
+ export default (req, res) => {
203
+ return <html>
204
+ <body>
205
+ <h1>Hello</h1>
206
+ </body>
207
+ </html>
208
+ }
209
+ ```
106
210
 
107
- const app = new Miqro({
108
- services: ["example/"],
109
- //name: "SOME NAME", // if running inside node:cluster worker you MUST set this value to allow worker syncronization
110
- //port: "3000",
111
- //hotreload: false,
112
- //editor: false,
113
- //editor: false,
114
- });
115
- // to inflate to a dir
116
- await app.inflate({
117
- inflateDir: "build/";
118
- inflateSea: false;
119
- });
120
- // or to inflate to memory
121
- // await app.inflate();
122
- // to start the server
123
- // await app.start();
124
- // to stop the server
125
- // await app.stop();
126
- // to dispose the server and disconnect all node:cluster worker syncronization for safe exiting
127
- // await app.dispose();
211
+ with database access:
212
+
213
+ ```tsx
214
+ import JSX from "@miqro/jsx";
215
+
216
+ export default async (req, res) => {
217
+ const posts = await req.server.db.get("mydb")
218
+ .select().from("posts").yield();
219
+
220
+ return <html>
221
+ <body>
222
+ {posts.map(p => <h2>{p.title}</h2>)}
223
+ </body>
224
+ </html>
225
+ }
128
226
  ```
129
227
 
130
- ### usage as cli
228
+ customize path/method with `apiOptions`:
131
229
 
132
- #### inflate static files with the cli
230
+ ```tsx
231
+ import JSX from "@miqro/jsx";
232
+ import { APIOptions } from "miqro";
133
233
 
134
- ```miqro --service example/ --inflate --inflate-dir build/```
234
+ export const apiOptions: APIOptions = {
235
+ path: ["/", "/index.html"],
236
+ method: ["GET"]
237
+ };
135
238
 
136
- #### watch and reload server to see the changes to the files in real-time
239
+ export default (req, res) => { ... }
240
+ ```
137
241
 
138
- ```miqro --watch --service example/```
242
+ ### .min.tsx
139
243
 
140
- #### start multiple services
244
+ bundled and minified client-side JavaScript. use to define Web Components.
141
245
 
142
- ```miqro --service example/ --service api/```
246
+ ```tsx
247
+ import JSX, { useState } from "@miqro/jsx";
248
+ import { define } from "@miqro/jsx-dom";
143
249
 
144
- #### start multiple services in a node:cluster
250
+ function Counter() {
251
+ const [n, setN] = useState(0);
252
+ return <button onClick={() => setN(n + 1)}>count: {n}</button>;
253
+ }
145
254
 
146
- ```npx miqro-cluster --service example/ --service api/```
255
+ define("my-counter", Counter, {
256
+ observedAttributes: ["initial"],
257
+ shadowInit: false
258
+ });
259
+ ```
147
260
 
148
- ## basic service folder structure
261
+ included in HTML:
149
262
 
263
+ ```tsx
264
+ export default (req, res) => (
265
+ <html>
266
+ <body>
267
+ <my-counter initial="0" />
268
+ <script src="/js/app.js" />
269
+ </body>
270
+ </html>
271
+ );
150
272
  ```
151
- app/
152
- http/
153
- ...
154
- static/
155
- ...
156
- migration/
157
- ...
158
- test/
159
- ....
160
- db.ts
161
- ws.ts
162
- auth.ts
163
- server.ts
273
+
274
+ ### .api.ts
275
+
276
+ REST endpoint. file path is the route path.
277
+
278
+ ```ts
279
+ export default (req, res) => {
280
+ return res.json({ ok: true });
281
+ }
164
282
  ```
165
283
 
166
- all files and folders are ***optional***.
284
+ full declaration with validation:
285
+
286
+ ```ts
287
+ import { APIRoute, JSONParser } from "@miqro/core";
167
288
 
168
- to start the development server run
289
+ export default {
290
+ name: "create post",
291
+ method: "POST",
292
+ middleware: [JSONParser()],
293
+ request: {
294
+ body: {
295
+ title: "string",
296
+ content: "string"
297
+ }
298
+ },
299
+ response: {
300
+ status: [200],
301
+ body: {
302
+ id: "number"
303
+ }
304
+ },
305
+ handler: async (req, res) => {
306
+ const post = await req.server.db.get("mydb")
307
+ .insert("posts")
308
+ .values({ title: req.body.title, content: req.body.content })
309
+ .returning("id")
310
+ .yield();
311
+ return res.json({ id: post[0].id });
312
+ }
313
+ } as APIRoute;
314
+ ```
169
315
 
170
- ```miqro --service app/```
316
+ `method: "use"` registers the handler for all methods (middleware pattern):
171
317
 
172
- and with the included editor
318
+ ```ts
319
+ import { Router } from "@miqro/core";
173
320
 
174
- ```miqro --service app/ --editor```
321
+ const router = new Router();
322
+ router.use(myMiddleware);
175
323
 
176
- ### http folder
324
+ export default {
325
+ path: "/admin",
326
+ method: "use",
327
+ handler: router
328
+ }
329
+ ```
177
330
 
178
- the http folder will be recursivly scan for files to serve.
179
- the files will be server acording to the location in the directory.
331
+ ### .html.md
180
332
 
181
- for example.
333
+ markdown file converted to HTML. served as `text/html`.
182
334
 
183
335
  ```
184
336
  http/
185
- index.html.tsx
186
- css/
187
- style.css
188
- js/
189
- script.min.js
337
+ docs/
338
+ guide.html.md → GET /docs/guide
190
339
  ```
191
340
 
192
- this will create the routes
341
+ `guide.html.md`:
193
342
 
194
- 1. /index.html
195
- 2. /css/style.css
196
- 3. /js/script.min.js
343
+ ```markdown
344
+ # Guide
197
345
 
198
- #### .html.tsx
346
+ some **markdown** content.
347
+ ```
199
348
 
200
- a file with the extension ```.html.tsx``` will be rendered as an html created by a JSX expression. for example.
349
+ converted using `showdown`. also works with `--inflate` outputs static HTML.
201
350
 
202
- ```ìndex.html.tsx```
203
- ```tsx
204
- import { MyComponent } from "./component.js";
351
+ available as `req.server.inflateMDtoHTML(str)` from any handler.
352
+
353
+
354
+ ## static folder
355
+
356
+ files served as-is, by path.
205
357
 
206
- export default <html>
207
- <body>
208
- <MyComponent />
209
- </body>
210
- </html>
358
+ ```
359
+ static/
360
+ logo.png → GET /logo.png
361
+ style.css → GET /style.css
211
362
  ```
212
363
 
213
- you can also export a request function and customize the route by exporting a ```apiOptions``` object.
364
+ ## db.ts
214
365
 
215
- ```ìndex.html.tsx```
216
- ```tsx
217
- import JSX from "@miqro/jsx";
218
- import { ServerRequest, ServerResponse, APIOptions } from "miqro";
219
- import { MyComponent } from "./component.js";
366
+ ```ts
367
+ import { DBConfig } from "miqro";
220
368
 
221
- // export the object apiOptions to customize the paths and methods
222
- export const apiOptions: APIOptions = {
223
- path: ["/", "/index.html"],
224
- method: ["GET", "POST"]
225
- };
369
+ export default {
370
+ dialect: "node:sqlite", // node:sqlite | sqlite3 | pg
371
+ name: "mydb", // req.server.db.get("mydb")
372
+ storage: "./data.sqlite3", // sqlite only
373
+ // connectionString: "..." // postgres
374
+ } as DBConfig;
375
+ ```
226
376
 
227
- export default (req: ServerRequest, res: ServerResponse) => {
228
- return <html>
229
- <body>
230
- <MyComponent />
231
- </body>
232
- </html>
233
- }
377
+ migrations run automatically on startup (primary worker only).
378
+
379
+ ## migration folder
380
+
381
+ files named `NNN_name.ts` run in order.
382
+
383
+ ```ts
384
+ // migration/001_create_posts.ts
385
+ import { MigrationModule } from "miqro";
386
+
387
+ export default {
388
+ name: "001_create_posts",
389
+ dbName: "mydb",
390
+ up: async (db) => {
391
+ await db.createTable("posts", {
392
+ id: { type: "integer", primaryKey: true, autoIncrement: true },
393
+ title: { type: "string" },
394
+ content: { type: "string" }
395
+ }).yield();
396
+ }
397
+ } as MigrationModule;
234
398
  ```
235
399
 
236
- #### .min.tsx
400
+ run manually:
237
401
 
238
- a file with the extension ```.min.tsx``` will be rendered as a **minified** javascript script that bundles the ```@miqro/jsx``` module.
402
+ ```
403
+ miqro --migrate-up --service app/
404
+ miqro --migrate-down --service app/
405
+ ```
239
406
 
240
- to avoid minification just use the ```.tsx``` extension inside the ```http``` folder.
407
+ ## cors.ts
241
408
 
242
- example defining a ```WebComponent``` with ```JSX``` using ```@miqro/jsx```.
409
+ ```ts
410
+ import { CORSOptions } from "miqro";
243
411
 
244
- ```script.min.tsx```
245
- ```typescript
412
+ export default {
413
+ origins: ["https://myapp.com", "https://staging.myapp.com"],
414
+ methods: "GET,POST,PUT,DELETE"
415
+ } as CORSOptions;
416
+ ```
417
+
418
+ without `cors.ts` all origins are allowed. with it only listed origins are accepted — requests from other origins get `400 Bad Request`.
419
+
420
+
421
+ ## ORM
422
+
423
+ quick reference. full docs in [@miqro/query](query-README.md).
424
+
425
+ ```ts
426
+ import { defineModel } from "@miqro/query";
427
+
428
+ const Post = defineModel(db, "posts", {
429
+ id: { type: "integer", primaryKey: true, autoIncrement: true },
430
+ title: { type: "string" },
431
+ published: { type: "boolean" },
432
+ createdAt: { type: "datetime" }
433
+ });
434
+
435
+ // create
436
+ await Post.create({ title: "hello", published: false });
437
+
438
+ // findAll
439
+ const posts = await Post.findAll(
440
+ Post.where().eq("published", true).order("createdAt", "DESC"),
441
+ { limit: 10 }
442
+ );
443
+
444
+ // updateAll
445
+ await Post.updateAll({ published: true }, Post.where().eq("id", 1));
446
+
447
+ // deleteAll
448
+ await Post.deleteAll(Post.where().eq("id", 1));
449
+
450
+ // count
451
+ const n = await Post.count(Post.where().eq("published", true));
452
+
453
+ // sync (create table if not exists)
454
+ await Post.sync();
455
+ ```
456
+
457
+ access the db directly:
458
+
459
+ ```ts
460
+ const db = req.server.db.get("mydb");
461
+ const rows = await db.select().from("posts").eq("published", true).yield();
462
+ const raw = await db.query("SELECT * FROM posts WHERE id = ?", [1]);
463
+ ```
464
+
465
+
466
+ ## ws.ts
467
+
468
+ ```ts
469
+ import { WSConfig } from "miqro";
470
+
471
+ export default {
472
+ path: "/updates", // req.server.ws.get("/updates")
473
+ disabled: false
474
+ } as WSConfig;
475
+ ```
476
+
477
+ broadcast from a handler:
478
+
479
+ ```ts
480
+ export default async (req, res) => {
481
+ const ws = req.server.ws.get("/updates");
482
+ await ws.broadcast(JSON.stringify({ type: "update", data: "..." }));
483
+ return res.json({ ok: true });
484
+ }
485
+ ```
486
+
487
+ ### WebSocket client (.min.tsx)
488
+
489
+ ```tsx
246
490
  import JSX, { useState, useEffect } from "@miqro/jsx";
247
491
  import { define } from "@miqro/jsx-dom";
248
- /*
249
- basic dynamic component example
250
- */
251
- export function TickerComponent() {
252
- // create a state variable count
253
- const [count, setCount] = useState(0);
254
- // create a effect with a setTimeout that updates count after 1000ms
492
+
493
+ function LiveFeed(props) {
494
+ const [messages, setMessages] = useState([]);
495
+
255
496
  useEffect(() => {
256
- // create the timeout
257
- const timeout = setTimeout(() => {
258
- setCount(count + 1);
259
- }, 1000);
260
- // return a clean up function to clear the timeout if it's running when the component is removed from the DOM.
261
- return () => {
262
- // clear the timeout if the effect is canceled.
263
- clearTimeout(timeout);
264
- }
265
- }, [count]);
266
- // return the jsx to be rendered
267
- return <p>Count: {count}</p>;
497
+ const ws = new WebSocket(`ws://${location.host}/updates`);
498
+ ws.onmessage = (e) => {
499
+ const msg = JSON.parse(e.data);
500
+ setMessages(prev => [...prev, msg]);
501
+ };
502
+ return () => ws.close();
503
+ }, []);
504
+
505
+ return <ul>{messages.map((m, i) => <li>{m.text}</li>)}</ul>;
268
506
  }
269
507
 
270
- window.addEventListener("load", async (event) => {
271
- /* this will define a custom element called ticker-tag with the tag
272
-
273
- <ticker-tag></ticker-tag>
508
+ define("live-feed", LiveFeed, { shadowInit: false });
509
+ ```
274
510
 
275
- as a standard web component.
511
+ broadcast from a handler:
276
512
 
277
- just include this script in the page with a script tag like
278
- <script src="..."></script>
279
-
280
- */
281
- define("ticker-tag", TickerComponent, {
282
- shadowInit: false, // or { mode: "closed" | "closed" }
283
- //extends: "p";
284
- //observedAttributes: ["width", "height", "some-attr"]; // attribues that are observed for changes to re-render the JSX component
285
- });
286
- });
513
+ ```ts
514
+ // http/publish.api.ts
515
+ export default async (req, res) => {
516
+ const ws = req.server.ws.get("/updates");
517
+ await ws.broadcast(JSON.stringify({ text: req.body.text }));
518
+ return res.json({ ok: true });
519
+ }
287
520
  ```
288
521
 
289
- #### .api.ts
290
522
 
291
- a file with the extension ```.api.ts``` will be use as a custom REST API endpoint.
523
+ ## auth.ts
292
524
 
293
- for example
525
+ ```ts
526
+ import { AuthConfig, jwt } from "miqro";
527
+ import { createSecretKey } from "node:crypto";
294
528
 
295
- ```/posts/post.api.tsx```
296
- ```typescript
297
- export default (req, res) => {
298
- return res.json({
299
- someValue: 1
300
- });
529
+ const secret = createSecretKey(Buffer.from(process.env.JWT_SECRET, "hex"));
530
+
531
+ export default {
532
+ verify: async ({ token }) => {
533
+ try {
534
+ const payload = await jwt.verify(token, secret);
535
+ return {
536
+ account: payload.account as string,
537
+ username: payload.username as string,
538
+ groups: payload.groups as string[],
539
+ token
540
+ };
541
+ } catch {
542
+ return null;
543
+ }
544
+ }
545
+ } as AuthConfig;
546
+ ```
547
+
548
+ session available on `req.session`:
549
+
550
+ ```ts
551
+ req.session.account // tenant identifier
552
+ req.session.username
553
+ req.session.groups
554
+ req.session.token
555
+ ```
556
+
557
+ restrict by group using `policy` on any endpoint:
558
+
559
+ ```ts
560
+ export default {
561
+ policy: {
562
+ groups: ["admin"],
563
+ groupPolicy: "at_least_one"
564
+ },
565
+ handler: ...
301
566
  }
302
567
  ```
303
568
 
304
- to costumize the route and middleware used and parse the request input before your function use export an ```APIRoute```object.
305
- this example uses the ```server.middleware.json()``` to parse the request body as a json.
569
+ ## server.ts
306
570
 
307
- ```/posts/post.api.tsx```
308
- ```typescript
309
- import { ServerRequest, ServerResponse } from "miqro";
310
- import { APIRoute } from "@miqro/core";
571
+ lifecycle hooks.
572
+
573
+ ```ts
574
+ import { ServerConfig } from "miqro";
311
575
 
312
576
  export default {
313
- name: "post api",
314
- description: "to do posts",
315
- path: ["/", "/do"],
316
- method: ["POST"],
317
- middleware: [server.middleware.json()],
318
- request: {
319
- headers: {
320
- auth: "string"
321
- },
322
- query: {
323
- pagination: "number"
324
- },
325
- body: {
326
- inputValue: "string"
327
- otherInputValues: "number[]?"
328
- }
577
+ preload: async (server) => {
578
+ // runs before db connections
329
579
  },
330
- response: {
331
- status: [200, 400],
332
- body: {
333
- someValue: "number"
334
- }
335
- }
336
- handler: (req: ServerRequest, res: ServerResponse) => {
337
- // with req?.server?.db.get(..)? you can query the database MyDB if it's configured with a db.ts file
338
- // const rows = await req?.server?.db.get("MyDB")?.select().from("....
339
- return res.json({
340
- someValue: 1
341
- });
580
+ load: async (server) => {
581
+ // runs after db connections, before listening
582
+ // seed cache here
583
+ const rows = await server.db.get("mydb").select().from("config").yield();
584
+ server.cache.set("config", rows);
585
+ },
586
+ start: async (server) => {
587
+ // runs after listening
588
+ },
589
+ stop: async (server) => {
590
+ // runs on shutdown
342
591
  }
343
- } as APIRoute;
592
+ } as ServerConfig;
344
593
  ```
345
594
 
346
- ```req.server```
347
-
348
- all request's have a property called ```server``` that it can be used to access server shared content.
595
+ `load` runs on all workers. use `server.isPrimaryWorker()` to gate one-time operations.
349
596
 
350
- this is necesary because every ```service``` file is imported ```isolated``` from the others using an ```esbuild``` ```bundle``` to **force state-less coding**.
597
+ ## middleware.ts
351
598
 
352
- ```ServerRequest```
599
+ pre and post route middleware for the service.
353
600
 
354
- ```typescript
355
- import { Request } from "@miqro/core";
601
+ ```ts
602
+ import { MiddlewareConfig } from "miqro";
356
603
 
357
- interface ServerRequest extends Request {
358
- server?: {
359
- // null values are if the feature has been disabled
360
- // database connections interface
361
- db: {
362
- get(name: string): Database | null;
363
- getMigrations(): NamedMigration[];
364
- migrate(options: MigrateOptions): Promise<void>;
365
- },
366
- // websocket server interface
367
- ws: {
368
- get(path: string): WebSocketServer | undefined;
369
- disconnectAll(path: string): void;
370
- };
371
- cache: CacheInterface; // this cache will be syncronized between all node:cluster workers
372
- localCache: CacheInterface; // this cache will local to the node:cluster worker
373
- logger?: Logger;
374
- isPrimaryWorker: () => boolean;
375
- openBrowser: (path: string) => void;
376
- getLogger: (identifier: string, options?: { level?: any; transports?: any[]; formatter?: any; }) => Logger;
377
- };
378
- }
604
+ export default {
605
+ middleware: [
606
+ // runs before all routes
607
+ async (req, res) => {
608
+ req.startTime = Date.now();
609
+ }
610
+ ],
611
+ post: [
612
+ // runs after all routes
613
+ async (req, res) => {
614
+ req.logger.debug("took %dms", Date.now() - req.startTime);
615
+ }
616
+ ]
617
+ } as MiddlewareConfig;
379
618
  ```
380
619
 
381
- example using ```req.server``` to access a key in the node:cluster synced cache.
620
+ ## catch.ts
382
621
 
383
- ```typescript
384
- import { ServerRequest, ServerResponse } from "miqro";
622
+ error handlers.
385
623
 
386
- export default (req: ServerRequest, res: ServerResponse) => {
387
- const value = req?.cache?.get("some_key");
388
- // req?.cache?.set("some_key", "value");
389
- return {
390
- status: 200,
391
- body: {
392
- some_key: value
624
+ ```ts
625
+ import { ErrorConfig } from "miqro";
626
+
627
+ export default {
628
+ catch: [
629
+ async (err, req, res) => {
630
+ req.logger.error(err);
631
+ return res.json({ error: err.message }, {}, 500);
393
632
  }
633
+ ]
634
+ } as ErrorConfig;
635
+ ```
636
+
637
+ ## log.ts
638
+
639
+ custom log transport. called for every log message.
640
+
641
+ ```ts
642
+ import { LogConfig } from "miqro";
643
+
644
+ export default {
645
+ level: "error", // only receive messages at this level
646
+ replaceConsoleTransport: false, // keep default console output
647
+ replaceFileTransport: false, // keep default file output
648
+ write: async ({ out, level, identifier }) => {
649
+ // out — formatted log string
650
+ // level — "error" | "warn" | "info" | "debug" | "trace"
651
+ // identifier — route/worker identifier
652
+ await fetch("https://logs.example.com/ingest", {
653
+ method: "POST",
654
+ body: JSON.stringify({ out, level, identifier })
655
+ });
394
656
  }
395
- }
657
+ } as LogConfig;
396
658
  ```
397
659
 
398
- #### .html.md
660
+ log levels: `error` → `warn` → `info` → `debug` → `trace` → `none`
399
661
 
400
- TODO
662
+ default output: console + `./server.log` (or `LOG_FILE` env var).
401
663
 
402
- #### .min.js
664
+ per-identifier level override via env:
403
665
 
404
- TODO
666
+ ```
667
+ LOG_LEVEL=info
668
+ LOG_LEVEL_POSTS_GET=debug // debug only for GET /posts
669
+ LOG_LEVEL_WORKER_0=trace // trace only for worker 0
670
+ ```
405
671
 
406
- #### .bundle.js
672
+ **cluster mode:** each worker writes to the same log file independently. at high throughput use pipes instead of `FileTransport`:
407
673
 
408
- TODO
674
+ ```
675
+ miqro --service app/ 2>&1 | tee app.log
676
+ ```
409
677
 
410
- #### .css.bundle
678
+ or send to an external aggregator via `log.ts` `write`.
411
679
 
412
- TODO
680
+ ## doc.ts
413
681
 
414
- ### static folder
682
+ publish API documentation as a static file or live endpoint.
415
683
 
416
- the static folder will act the same as the http folder but will treath every file **as is**.
684
+ ```ts
685
+ import { DocConfig } from "miqro";
686
+
687
+ export default {
688
+ publish: {
689
+ "/api/docs": { type: "MD" }, // markdown
690
+ "/api/schema": { type: "JSON" }, // json
691
+ "/api/docs.html": { type: "HTML" } // html
692
+ }
693
+ } as DocConfig;
694
+ ```
417
695
 
418
- the files will be server acording to the location in the directory.
696
+ with `--inflate` the docs are written to `build/` as static files.
419
697
 
420
- for example.
698
+ at runtime the docs are served as live endpoints — useful for development.
699
+
700
+ generate docs via CLI:
421
701
 
422
702
  ```
423
- static/
424
- index.html
425
- css/
426
- style.css
427
- js/
428
- script.min.js
703
+ miqro --generate-doc --generate-doc-out API.md --service app/
704
+ miqro --generate-doc --generate-doc-type JSON --generate-doc-out api.json --service app/
429
705
  ```
430
706
 
431
- this will create the routes
707
+ doc output is derived from `APIRoute` declarations — `name`, `description`, `request`, `response`, `policy` fields.
432
708
 
433
- 1. /index.html
434
- 2. /css/style.css
435
- 3. /js/script.min.js
436
709
 
437
- ### migration folder
710
+ ## miqro.json
438
711
 
439
- TODO
712
+ compose multiple services.
440
713
 
441
- ### test folder
442
-
443
- TODO
714
+ ```json
715
+ {
716
+ "name": "myapp",
717
+ "port": "3000",
718
+ "services": [
719
+ "a/",
720
+ "b/",
721
+ "c/"
722
+ ],
723
+ "inflateDir": "build/",
724
+ "logFile": false,
725
+ "browser": true
726
+ }
727
+ ```
444
728
 
445
- ### db.ts
729
+ all fields optional except `services`.
446
730
 
447
- TODO
731
+ ```
732
+ name server name — required in cluster mode
733
+ port default: 8080
734
+ services ordered list of service folders
735
+ inflateDir default inflate output directory
736
+ logFile false | true | "./path/server.log"
737
+ browser open browser on start (true | false | "browser-name")
738
+ ```
448
739
 
449
- ### ws.ts
740
+ generate default `miqro.json`:
450
741
 
451
- TODO
742
+ ```
743
+ miqro --install-miqrojson
744
+ ```
452
745
 
453
- ### auth.ts
746
+ run with miqro.json:
454
747
 
455
- TODO
748
+ ```
749
+ miqro
750
+ ```
456
751
 
457
- ### server.ts
752
+ or override:
458
753
 
459
- TODO
754
+ ```
755
+ miqro --service a/ --service b/
756
+ ```
460
757
 
461
- ### log.ts
758
+ swap implementations by changing the services array. same service folders work across different compositions.
759
+
760
+ ## req.server
761
+
762
+ available on every handler.
763
+
764
+ ```ts
765
+ req.server.db.get("name") // Database | null
766
+ req.server.ws.get("/path") // WebSocketServer | undefined
767
+ req.server.cache // ClusterCache — synced across all cluster workers via IPC
768
+ req.server.localCache // LocalCache — in-memory, per worker only
769
+ req.server.cache.set("key", value)
770
+ req.server.cache.get("key")
771
+ req.server.cache.has("key")
772
+ req.server.cache.unset("key")
773
+ req.server.cache.set_add("key", value) // set operations
774
+ req.server.cache.set_has("key", value)
775
+ req.server.cache.set_delete("key", value)
776
+
777
+ req.server.middleware.json() // body parser → req.body
778
+ req.server.middleware.url() // url-encoded body parser → req.body
779
+ req.server.middleware.text() // text body parser → req.body
780
+ req.server.middleware.buffer() // raw buffer → req.buffer
781
+ req.server.middleware.cors(opts) // CORS middleware
782
+ req.server.middleware.session(opts)// auth middleware
783
+
784
+ req.server.jwt.sign(payload, secret, opts)
785
+ req.server.jwt.verify(token, secret, opts)
786
+ req.server.jwt.decode(token)
787
+
788
+ req.server.isPrimaryWorker() // true on worker 0
789
+ req.server.getWorkerNumber() // 0..n
790
+ req.server.getWorkerCount() // total workers
791
+
792
+ req.server.reload() // hot reload
793
+ req.server.restart() // full restart
794
+ req.server.stop() // shutdown
795
+
796
+ req.server.encodeHTML(str)
797
+ req.server.inflateMDtoHTML(str)
798
+ req.server.newParser()
799
+ req.server.newClusterCache(name)
800
+ req.server.newLocalCache(name)
801
+ req.server.getLogger(identifier)
802
+ ```
462
803
 
463
- TODO
804
+ ## req
805
+
806
+ ```ts
807
+ req.path // normalized pathname
808
+ req.hash // url hash fragment
809
+ req.searchParams // URLSearchParams
810
+ req.query // parsed query string { [key]: string | string[] }
811
+ req.params // path parameters { [key]: string }
812
+ req.cookies // parsed cookies { [name]: string }
813
+ req.body // parsed body (requires body parser middleware)
814
+ req.buffer // raw body buffer (requires ReadBuffer middleware)
815
+ req.session // set by auth.ts
816
+ req.session.account // tenant identifier
817
+ req.session.username
818
+ req.session.groups // string[]
819
+ req.session.token
820
+ req.uuid // unique request id
821
+ req.startMS // request start timestamp ms
822
+ req.logger // per-request logger — includes path/method/uuid/remoteAddress
823
+ req.results // pipeline accumulator
824
+ ```
464
825
 
465
- ### middleware.ts
826
+ ## test folder
466
827
 
467
- TODO
828
+ test files named `*.test.ts`.
468
829
 
469
- ### catch.ts
830
+ ```ts
831
+ import { describe, it } from "node:test";
832
+ import { strictEqual } from "assert";
470
833
 
471
- TODO
834
+ describe("posts", () => {
835
+ it("GET /posts returns 200", async () => {
836
+ const res = await test.request({
837
+ url: "/posts",
838
+ method: "GET",
839
+ disableThrow: true
840
+ });
841
+ strictEqual(res.status, 200);
842
+ });
843
+ });
844
+ ```
472
845
 
473
- ### miqro.json
846
+ `test.request` hits the running miqro server via Unix socket. no port needed.
474
847
 
475
- TODO
848
+ test JSX components:
476
849
 
477
- ### Globals
850
+ ```ts
851
+ import JSX from "@miqro/jsx";
852
+ import { Counter } from "./counter.js";
478
853
 
479
- TODO
854
+ it("renders counter", test.jsx.test(async (container, root, runtime) => {
855
+ container.render(JSX.createElement(Counter, { initial: 0 }));
856
+ strictEqual(root.innerHTML.includes("0"), true);
857
+ }));
858
+ ```
480
859
 
481
- #### test global
860
+ run tests:
482
861
 
483
- TODO
862
+ ```
863
+ miqro --test --service app/
864
+ ```
484
865
 
485
- ## static web site generator
866
+ ## Miqro object
486
867
 
487
- you can also inflate your project to avoid rendering ```http/**/*.html.tsx``` and other files per request. this can be done pre-rendereding with the ```--inflate``` flag.
868
+ ```ts
869
+ import { Miqro } from "miqro";
488
870
 
489
- ```miqro --service app/ --inflate --inflate-dir build/```
871
+ const app = new Miqro({
872
+ services: ["app/"],
873
+ port: "3000",
874
+ name: "myapp", // required in cluster mode
875
+ hotreload: false,
876
+ editor: false
877
+ });
490
878
 
491
- this will create the ```build/``` folder with the inflated app static files.
879
+ await app.inflate({ inflateDir: "build/" }); // generate static files
880
+ await app.inflate(); // inflate to memory
881
+ await app.start(); // start server
882
+ await app.stop(); // stop server
883
+ await app.reload(); // hot reload
884
+ await app.restart(); // full restart
885
+ await app.dispose(); // cleanup cluster connections
886
+ ```
492
887
 
493
- you can host only the generated static ```*.html.tsx``` files with other http servers.
888
+ trigger static generation from a running server:
494
889
 
495
- ```python3 -m http.server 8080 build/app/static/```
890
+ ```ts
891
+ export default {
892
+ path: "/publish",
893
+ method: "POST",
894
+ handler: async (req, res) => {
895
+ const generator = new Miqro({ services: ["app/"] });
896
+ await generator.inflate({ inflateDir: "build/" });
897
+ return res.json({ ok: true });
898
+ }
899
+ }
900
+ ```
496
901
 
497
902
  ## cluster
498
903
 
499
- for this you will need to install miqro as a dependency of your project.
904
+ ```
905
+ npx miqro-cluster --service app/
906
+ CLUSTER_COUNT=4 npx miqro-cluster --service app/
907
+ npx miqro-cluster
908
+ ```
909
+
910
+ to run arbitrary scripts in cluster mode:
911
+
912
+ ```
913
+ npx miqro-runner server.js
914
+ CLUSTER_COUNT=4 npx miqro-runner server.js
915
+ ```
916
+
917
+ ## --no-build
500
918
 
501
- ```npm install miqro --save```
919
+ use tsc instead of esbuild. run tsc first, then miqro.
502
920
 
503
- ```npx miqro-cluster --service app/```
921
+ generate a tsconfig:
504
922
 
505
- this will launch your app in a cluster mode.
923
+ ```
924
+ miqro --install-tsconfig
925
+ ```
506
926
 
507
- to change the number of nodes use ```CLUSTER_COUNT=10```for example to set the count to 10 nodes.
927
+ `tsconfig.json`:
928
+
929
+ ```json
930
+ {
931
+ "compilerOptions": {
932
+ "target": "es2022",
933
+ "noEmit": true,
934
+ "module": "NodeNext",
935
+ "moduleResolution": "nodenext",
936
+ "lib": ["es2021", "dom"],
937
+ "jsx": "react",
938
+ "jsxFactory": "JSX.createElement",
939
+ "jsxFragmentFactory": "JSX.Fragment"
940
+ }
941
+ }
942
+ ```
508
943
 
509
- ```CLUSTER_COUNT=10 npx miqro-cluster --service app/```
944
+ `noEmit: true` — tsc type-checks only, esbuild handles transpilation at runtime. remove `noEmit` and set `outDir` to use tsc output with `--no-build`.
510
945
 
511
- ## Using TSC or another transpiler insted of esbuild on runtime
946
+ development with tsc + miqro:
512
947
 
513
- ```miqro --no-build ...```
948
+ ```
949
+ tsc --watch &
950
+ miqro --no-build --watch --service app/
951
+ ```
514
952
 
515
- for this to work you will need to run ```tsc``` or another transpiler to transform your JSX files.
953
+ **note:** in `--no-build` mode module-level state is shared across routes within a process. the stateless coding guarantee that esbuild provides does not apply. avoid module-level mutable state.
516
954
 
517
- ## cli usage
955
+ ## static site generator
518
956
 
519
- ### start a project
957
+ ```
958
+ miqro --inflate --inflate-dir build/ --service app/
959
+ ```
520
960
 
521
- ```miqro --service app/```
961
+ `.html.tsx` handlers run with a live db connection. output is static HTML written to `build/`.
522
962
 
523
- by default the project will be hosted on ```http://localhost:8080```.
963
+ ```
964
+ miqro --inflate --inflate-dir build/ --service app/
965
+ python3 -m http.server 8080 build/app/static/
966
+ ```
524
967
 
525
- start with hot-reload disabled
968
+ ## https
526
969
 
527
- ```miqro --watch --service app/```
970
+ ```
971
+ miqro --https --https-key server.key --https-cert server.cert --service app/
972
+ ```
528
973
 
529
- start on custom port
974
+ with http redirect:
530
975
 
531
- ```PORT=8181 miqro app/```
976
+ ```
977
+ miqro --https --https-key server.key --https-cert server.cert --https-redirect 8080 --service app/
978
+ ```
532
979
 
533
- ### run migrations on the project
980
+ starts an additional http server on port 8080 that redirects all requests to https.
534
981
 
535
- TODO
982
+ via env or `miqro.json`:
536
983
 
537
- ### run the project tests
984
+ ```json
985
+ {
986
+ "https": true,
987
+ "httpsKey": "./server.key",
988
+ "httpsCert": "./server.cert",
989
+ "httpsRedirect": "8080"
990
+ }
991
+ ```
992
+
993
+
994
+ ## cli
995
+
996
+ ```
997
+ miqro --service app/
998
+ miqro --watch --service app/
999
+ miqro --editor --service app/
1000
+ miqro --test --service app/
1001
+ miqro --migrate-up --service app/
1002
+ miqro --migrate-down --service app/
1003
+ miqro --inflate --inflate-dir build/ --service app/
1004
+ miqro --generate-doc --generate-doc-out API.md --service app/
1005
+ miqro --compile --service app/
1006
+ ```
1007
+
1008
+ flags:
538
1009
 
539
- TODO
1010
+ ```
1011
+ --watch auto reload on file changes
1012
+ --hot-reload enable hot-reload with --watch
1013
+ --test run tests
1014
+ --migrate-up run migrations up
1015
+ --migrate-down run migrations down
1016
+ --inflate generate static files
1017
+ --inflate-dir output directory (default: inflated/)
1018
+ --editor run with built-in editor
1019
+ --generate-doc generate API documentation
1020
+ --generate-doc-out output file (default: API.md)
1021
+ --generate-doc-type MD | JSON | HTML (default: MD)
1022
+ --generate-doc-all include all routes
1023
+ --compile build NODE:SEA binary
1024
+ --no-build skip esbuild, use pre-compiled files
1025
+ --no-minify skip minification
1026
+ --inflate-only-assets inflate assets only
1027
+ --inflate-flat inflate into dir directly
1028
+ --inflate-sea inflate with SEA compilation scripts
1029
+ --install-tsconfig create tsconfig.json
1030
+ --install-miqrojson create miqro.json
1031
+ --install install from binary cache (SEA only)
1032
+ --disable-miqrojson ignore miqro.json
1033
+ --log-file override LOG_FILE
1034
+ --browser override BROWSER
1035
+ --config override miqro.json path
1036
+ --port override PORT
1037
+ --name override server name
1038
+ --https serve with https
1039
+ --https-key path to server.key
1040
+ --https-cert path to server.cert
1041
+ --https-redirect http redirect port
1042
+ --inflate-parallel max parallel esbuild instances (default: 1)
1043
+ ```
540
1044
 
541
- ### generate API documentation
1045
+ environment variables:
542
1046
 
543
- TODO
1047
+ ```
1048
+ PORT default: 8080
1049
+ BROWSER default browser, none to disable
1050
+ LOG_FILE default: ./server.log
1051
+ LOG_LEVEL error | warn | info | debug | trace | none
1052
+ LOG_LEVEL_<IDENTIFIER> per-route log level
1053
+ DB enable db features
1054
+ DB_STORAGE sqlite storage path (default: ./db.sqlite3)
1055
+ DB_DIALECT node:sqlite | sqlite3 | pg
1056
+ DB_CONNECTION connection url (postgres)
1057
+ CLEAR_JSX_CACHE clear esbuild cache (default: 1)
1058
+ JSX_TMP esbuild tmp dir (default: /tmp/jsx_tmp)
1059
+ CLUSTER_COUNT number of cluster workers
1060
+ ```
544
1061
 
545
- ### inflate project or eject from miqro
1062
+ ## build
546
1063
 
547
- to inflate all http files into static files use the ```--inflate``` with the ```--inflate-dir``` arguments.
1064
+ ```
1065
+ npm install
1066
+ npm run build
1067
+ ```
548
1068
 
549
- ```miqro --inflate --inflate-dir build/ --service app/```
1069
+ ### SEA binary
550
1070
 
551
- this will render the ```.html.tsx``` and other files in the ```http/``` folder and the ```static/``` folder into the ```build``` folder for static serving.
1071
+ ```
1072
+ npm install
1073
+ npm run precompile
1074
+ npm run compile
1075
+ ```
552
1076
 
553
- for example.
1077
+ binaries in `bin/`.
554
1078
 
555
1079
  ```
556
- miqro --inflate --inflate-dir build/ --service app/
557
- cd build/
558
- python3 -m http.server 8080
559
- ```
560
-
561
- ### more cli usages
562
-
563
- ```miqro --help```
564
-
565
- ```
566
- usage: miqro [...FLAGS] --service app/
567
-
568
- ==examples==
569
-
570
- miqro --watch --service front/
571
- PORT=8181 miqro --service api/ --service front/
572
- miqro --test --service front/
573
- miqro --inflate --service front/
574
- miqro --generate-doc --generate-doc-out API.md --service front/
575
- CLUSTER_COUNT=10 miqro-cluster --service api/
576
-
577
- ==flags==
578
-
579
- -v, --version
580
- outputs the version number
581
- -h, --help
582
- outputs this page.
583
- --watch
584
- use to auto reload the server when files change.
585
- --hot-reload
586
- enables the hot-reload functionality use with --watch.
587
- --test
588
- run the tests for a service.
589
- --migrate-up
590
- migrations up.
591
- --migrate-down
592
- migrations down.
593
- --inflate
594
- inflates the application into a directory using esbuild.
595
- --inflate-dir
596
- to set the output directory of the --inflate command. default value is inflated/.
597
- --editor
598
- runs the application with a built-in editor.
599
- --generate-doc
600
- generates a documentation for the api endpoints of the service.
601
- --generate-doc-out
602
- the output file for the generated documentation. default value is API.md.
603
- --generate-doc-type
604
- the format of the generated documentation. it can be JSON or MD. default value is MD.
605
- --generate-doc-all
606
- outputs all the server routes in the documentation output.
607
- --compile
608
- inflates the application and tries to create a NODE SEA binary.
609
- --no-build
610
- disables calling esbuild during imports in runtime. Notice that to use jsx you will need to run tsc or esbuild on your jsx files to transpile them to js.
611
- --no-minify
612
- disables calling minifing min.js files.
613
- --inflate-only-assets
614
- inflates ONLY the application assets. must be used with --inflate.
615
- --inflate-flat
616
- inflates files into the inflate-dir directly.
617
- --inflate-sea
618
- inflates the application with sea compilation scripts.
619
- --install-tsconfig
620
- creates a tsconfig.json configured to use with --install-types.
621
- --install-miqrojson
622
- creates a default miqro.json file.
623
- --install
624
- creates a node_modules folder from binary cache (only available in sea binary).
625
- --disable-miqrojson
626
- disables the load of miqro.json file.
627
- --log-file
628
- overrides the default log file from LOG_FILE.
629
- --browser
630
- overrides the default browser from BROWSER.
631
- --config
632
- overrides the default miqro.json path.
633
- --port
634
- overrides the default port from PORT.
635
- --name
636
- overrides the default name of the server.
637
- --https
638
- serves the server in https instead of http
639
- --https-key
640
- point to a server.key file for https.
641
- --https-cert
642
- point to a server.cert file for https.
643
- --https-redirect
644
- serves an aditional http server that redirects to https. it needs a port number.
645
- --inflate-parallel
646
- sets the max parallel esbuild instances. defaults to 1.
647
-
648
- ==environment variables==
649
-
650
- PORT
651
- override the default 8080 port.
652
- BROWSER
653
- override the default browser. change to none to disable.".
654
- LOG_FILE
655
- override the default ./server.log file
656
- DB
657
- enable the server.db features
658
- DB_STORAGE
659
- override the default local db location ./db.sqlite3
660
- DB_DIALECT
661
- override the default node:sqlite
662
- DB_CONNECTION
663
- override the default connection url
664
- CLEAR_JSX_CACHE
665
- set to 1 or 0 to enable or disable the clearing of the esbuild cache defaults to 1.
666
- JSX_TMP
667
- set custom location of esbuild builds defaults to /tmp/jsx_tmp.
668
- ```
669
-
670
- ## development
671
-
672
- ### build node package
673
-
674
- 1. install dependencies
675
-
676
- ```npm install```
677
-
678
- 2. build
679
-
680
- ```npm build```
681
-
682
- ### build binary for running as standalone binary
683
-
684
- 1. install dependencies
685
-
686
- ```npm install```
687
-
688
- 2. install sea deps (esbuild and nodejs binaries)
689
-
690
- ```npm run precompile``` or ```sh ./sea/precompile.sh```
691
-
692
- 3. compile
693
-
694
- ```npm run compile``` or ```sh ./compile.sh```
695
-
696
- to binaries will be produced in the ```bin/``` folder.
697
-
698
- example
699
-
700
- ```./bin/linux-x64/miqro --help```
701
-
702
- you can copy this binary to a computer without Node.js installed and run it to try.
1080
+ ./bin/linux-x64/miqro --help
1081
+ ```