lakutata 3.0.0 → 3.1.0

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 (117) hide show
  1. package/README.md +50 -30
  2. package/README.zh-CN.md +130 -0
  3. package/dist/cjs/exports/QueueComponent.d.ts +1 -0
  4. package/dist/cjs/exports/QueueComponent.js +20 -0
  5. package/dist/esm/exports/QueueComponent.js +1 -0
  6. package/dist/types/exports/QueueComponent.d.ts +1 -0
  7. package/doc/en/Application.md +107 -0
  8. package/doc/en/CLI.md +274 -0
  9. package/doc/en/Cache.md +379 -0
  10. package/doc/en/Command.md +110 -0
  11. package/doc/en/ContainerdIntegration.md +17 -16
  12. package/doc/en/Controllers.md +256 -0
  13. package/doc/en/DBus.md +291 -0
  14. package/doc/en/DTOValidation.md +72 -43
  15. package/doc/en/Database.md +188 -0
  16. package/doc/en/DatabaseDrivers.md +287 -0
  17. package/doc/en/Decorator.md +52 -40
  18. package/doc/en/DockerIntegration.md +7 -6
  19. package/doc/en/Entities.md +240 -0
  20. package/doc/en/Entrypoint.md +216 -0
  21. package/doc/en/Exceptions.md +174 -0
  22. package/doc/en/GRPC.md +251 -0
  23. package/doc/en/GettingStarted.md +165 -0
  24. package/doc/en/HTTP.md +507 -0
  25. package/doc/en/HelperFunctions.md +11 -11
  26. package/doc/en/I18n.md +119 -115
  27. package/doc/en/Injection.md +144 -0
  28. package/doc/en/Installers.md +280 -0
  29. package/doc/en/Logger.md +206 -0
  30. package/doc/en/MCP.md +293 -0
  31. package/doc/en/Middlewares.md +213 -0
  32. package/doc/en/Migrations.md +202 -0
  33. package/doc/en/MongoEmbedded.md +149 -0
  34. package/doc/en/Monitor.md +164 -0
  35. package/doc/en/Mutex.md +27 -25
  36. package/doc/en/NATS.md +246 -0
  37. package/doc/en/NativeAddons.md +212 -0
  38. package/doc/en/Objects.md +143 -0
  39. package/doc/en/Overview.md +62 -85
  40. package/doc/en/Packaging.md +193 -0
  41. package/doc/en/ProjectStructure.md +124 -0
  42. package/doc/en/Queue.md +269 -0
  43. package/doc/en/Schedules.md +217 -0
  44. package/doc/en/Security.md +10 -9
  45. package/doc/en/ServiceCalls.md +504 -0
  46. package/doc/en/Time.md +19 -20
  47. package/doc/en/UpgradingFrom1.md +435 -0
  48. package/doc/en/UpgradingFrom2.md +315 -0
  49. package/doc/en/Workspaces.md +189 -0
  50. package/doc/en/examples/BackgroundJobs.md +677 -0
  51. package/doc/en/examples/CommandLineTool.md +664 -0
  52. package/doc/en/examples/DesktopApp.md +809 -0
  53. package/doc/en/examples/DeviceService.md +607 -0
  54. package/doc/en/examples/MCPServer.md +653 -0
  55. package/doc/en/examples/README.md +16 -0
  56. package/doc/en/examples/RestAPI.md +490 -0
  57. package/doc/en/examples/ServiceCalls.md +829 -0
  58. package/doc/en/examples/WebApp.md +568 -0
  59. package/doc/zh/Application.md +75 -0
  60. package/doc/zh/CLI.md +250 -0
  61. package/doc/zh/Cache.md +328 -0
  62. package/doc/zh/Command.md +78 -0
  63. package/doc/zh/ContainerdIntegration.md +9 -9
  64. package/doc/zh/Controllers.md +228 -0
  65. package/doc/zh/DBus.md +257 -0
  66. package/doc/zh/DTOValidation.md +49 -19
  67. package/doc/zh/Database.md +175 -0
  68. package/doc/zh/DatabaseDrivers.md +261 -0
  69. package/doc/zh/Decorator.md +25 -18
  70. package/doc/zh/DockerIntegration.md +6 -6
  71. package/doc/zh/Entities.md +224 -0
  72. package/doc/zh/Entrypoint.md +193 -0
  73. package/doc/zh/Exceptions.md +158 -0
  74. package/doc/zh/GRPC.md +226 -0
  75. package/doc/zh/GettingStarted.md +148 -0
  76. package/doc/zh/HTTP.md +445 -0
  77. package/doc/zh/HelperFunctions.md +2 -2
  78. package/doc/zh/I18n.md +26 -26
  79. package/doc/zh/Injection.md +129 -0
  80. package/doc/zh/Installers.md +232 -0
  81. package/doc/zh/Logger.md +188 -0
  82. package/doc/zh/MCP.md +265 -0
  83. package/doc/zh/Middlewares.md +198 -0
  84. package/doc/zh/Migrations.md +178 -0
  85. package/doc/zh/MongoEmbedded.md +118 -0
  86. package/doc/zh/Monitor.md +145 -0
  87. package/doc/zh/Mutex.md +10 -10
  88. package/doc/zh/NATS.md +207 -0
  89. package/doc/zh/NativeAddons.md +180 -0
  90. package/doc/zh/Objects.md +119 -0
  91. package/doc/zh/Overview.md +46 -71
  92. package/doc/zh/Packaging.md +154 -0
  93. package/doc/zh/ProjectStructure.md +102 -0
  94. package/doc/zh/Queue.md +214 -0
  95. package/doc/zh/Schedules.md +193 -0
  96. package/doc/zh/Security.md +6 -6
  97. package/doc/zh/ServiceCalls.md +459 -0
  98. package/doc/zh/Time.md +2 -2
  99. package/doc/zh/UpgradingFrom1.md +347 -0
  100. package/doc/zh/UpgradingFrom2.md +230 -0
  101. package/doc/zh/Workspaces.md +150 -0
  102. package/doc/zh/examples/BackgroundJobs.md +618 -0
  103. package/doc/zh/examples/CommandLineTool.md +618 -0
  104. package/doc/zh/examples/DesktopApp.md +748 -0
  105. package/doc/zh/examples/DeviceService.md +546 -0
  106. package/doc/zh/examples/MCPServer.md +604 -0
  107. package/doc/zh/examples/README.md +14 -0
  108. package/doc/zh/examples/RestAPI.md +458 -0
  109. package/doc/zh/examples/ServiceCalls.md +765 -0
  110. package/doc/zh/examples/WebApp.md +520 -0
  111. package/package.json +46 -17
  112. package/doc/en/ActionPattern.md +0 -408
  113. package/doc/en/Core.md +0 -312
  114. package/doc/en/ORMIntegration.md +0 -341
  115. package/doc/zh/ActionPattern.md +0 -334
  116. package/doc/zh/Core.md +0 -256
  117. package/doc/zh/ORMIntegration.md +0 -319
@@ -1,82 +1,27 @@
1
1
  # Lakutata Overview
2
2
 
3
- **Lakutata** is an IoC-based application framework for Node.js and TypeScript: one programming model for web
4
- services, CLI tools, desktop (Electron) applications and embedded devices. An application is a tree of objects created
5
- by a container (components, providers, modules, controllers), whose options and inputs are validated by DTOs, and whose
6
- controllers are served by transports: HTTP (Express, Fastify), CLI (Commander), service RPC (HTTP, Socket.IO,
7
- JSON-RPC 2.0, gRPC, NATS, Electron IPC) and schedules. One controller method can be all of them at once.
3
+ **Lakutata** is an IoC application framework for Node.js and TypeScript. It gives web services, CLI tools, desktop
4
+ (Electron) applications and embedded devices one programming model: an application is a tree of objects (components,
5
+ providers, controllers) that a container creates. DTOs validate their options and inputs, and transports expose
6
+ the controllers: HTTP (Express, Fastify), CLI (Commander), service RPC (HTTP, Socket.IO, JSON-RPC 2.0, gRPC, NATS,
7
+ Electron IPC), schedules and message queues. One controller method can serve all of them at once.
8
8
 
9
9
  The package `lakutata` re-exports the `@lakutata/*` packages under its subpaths (see the table below) and presets two
10
- components in every application: `log` (the pino `Logger`) and `entrypoint` (the `Entrypoint` that serves the
11
- controllers).
10
+ components in every application: `log` (the `Logger`, which writes pino-compatible JSON lines) and `entrypoint` (the
11
+ `Entrypoint` that serves the controllers).
12
12
 
13
- ## Requirements
13
+ ## Where to start
14
14
 
15
- - Node.js 22 or later.
16
- - ESM (`"type": "module"`); the package also ships CommonJS builds.
17
- - TypeScript with `experimentalDecorators` and `emitDecoratorMetadata`. The package publishes the compiler options the
18
- framework needs as `lakutata/tsconfig.json`.
19
-
20
- ## Installation
21
-
22
- ```bash
23
- npx @lakutata/cli create --name my-app # a new project from a template (web, service, CLI, Electron…)
24
- npm install lakutata # or the framework in an existing project
25
- ```
26
-
27
- ```json
28
- {
29
- "extends": "lakutata/tsconfig.json",
30
- "compilerOptions": {"rootDir": "src", "outDir": "dist"}
31
- }
32
- ```
33
-
34
- The transports and the integrations use optional peer dependencies, installed when used: `express` or `fastify`,
35
- `commander`, `socket.io`, `ws`, the database drivers (`pg`, `mysql2`, `sqlite3`…), the cache stores (`redis`…).
36
-
37
- ## A first application
38
-
39
- ```typescript
40
- import {Application, DTO, type ILogger} from 'lakutata'
41
- import {buildEntrypoints, Controller} from 'lakutata/com/entrypoint'
42
- import {GET, ServiceAction} from 'lakutata/decorator/ctrl'
43
- import {Expect} from 'lakutata/decorator/dto'
44
- import {expressHTTPEntrypoint} from 'lakutata/adapter/express'
45
-
46
- class GreetDTO extends DTO {
47
- @Expect(DTO.String().optional().default('world'))
48
- public name: string
49
- }
50
-
51
- class GreetController extends Controller {
52
- //GET /greet?name=you, and the service action {cmd: 'greet', name: 'you'}
53
- @GET('/greet', GreetDTO)
54
- @ServiceAction({cmd: 'greet'}, GreetDTO)
55
- public async greet(input: GreetDTO): Promise<{ message: string }> {
56
- return {message: `Hello, ${input.name}!`}
57
- }
58
- }
59
-
60
- Application
61
- .run(() => ({
62
- id: 'com.example.greeter',
63
- name: 'Greeter',
64
- components: {
65
- entrypoint: buildEntrypoints({
66
- controllers: [GreetController],
67
- http: expressHTTPEntrypoint({port: 8080})
68
- })
69
- },
70
- bootstrap: ['entrypoint']
71
- }))
72
- .onLaunched((app: Application, log: ILogger): void => log.info('%s started', app.appName))
73
- ```
15
+ [GettingStarted](GettingStarted.md) creates a first project from a template and shows a first application;
16
+ [ProjectStructure](ProjectStructure.md) describes the files of a project; the guides below cover each part of the
17
+ framework. The [examples](examples/README.md) build whole applications from the templates: a REST API, a command line
18
+ tool, a web and a desktop application, calls between services, background jobs, an MCP server and a service on a device.
74
19
 
75
20
  ## The subpaths
76
21
 
77
22
  | Subpath | What it provides |
78
23
  |---|---|
79
- | `lakutata` | `Application`, `Module`, `Component`, `Provider`, `BaseObject`, `Container`, `DTO`, `Exception`, `Time`, `isPackaged`, `resourcesPath`, the validation messages |
24
+ | `lakutata` | `Application`, `Component`, `Provider`, `BaseObject`, `Container`, `DTO`, `Exception`, `Time`, `isPackaged`, `resourcesPath`, the validation messages |
80
25
  | `lakutata/decorator/di` | `@Inject`, `@Configurable`, `@Autoload`, `@Singleton`, `@Scoped`, `@Transient`, `@Lifetime` |
81
26
  | `lakutata/decorator/dto` | `@Expect`, `@Accept`, `@Return`, `@IndexSignature` |
82
27
  | `lakutata/decorator/asst` | `@Before`, `@After` |
@@ -86,38 +31,70 @@ Application
86
31
  | `lakutata/adapter/express`, `lakutata/adapter/fastify` | The HTTP transports |
87
32
  | `lakutata/adapter/commander` | The CLI transport |
88
33
  | `lakutata/adapter/socket.io`, `lakutata/adapter/jsonrpc`, `lakutata/adapter/electron` | The service transports |
89
- | `lakutata/com/logger` | The `Logger` component (pino), preset as `log` |
34
+ | `lakutata/com/logger` | The `Logger` component, preset as `log` (pino-compatible JSON lines) |
90
35
  | `lakutata/orm`, `lakutata/decorator/orm` | TypeORM and its decorators |
91
36
  | `lakutata/com/database`, `lakutata/provider/database` | The `Database` component and provider |
92
37
  | `lakutata/com/cacher` | The `Cacher` component |
93
38
  | `lakutata/com/mutex` | The `Mutex` component, `@Synchronized` |
39
+ | `lakutata/com/queue` | The `Queue` component, `@QueueAction`, `queueEntrypoint` |
94
40
  | `lakutata/com/i18n` | The `I18n` component, the `Translator`, the language middleware |
95
41
  | `lakutata/com/docker` | The `Docker` component |
96
42
  | `lakutata/com/containerd` | The `Containerd` component |
97
- | `lakutata/com/monitor` | The CPU, memory, event loop and HTTP monitors |
43
+ | `lakutata/com/monitor` | CPU, memory, event loop and HTTP monitors |
98
44
  | `lakutata/security`, `lakutata/provider/passwordHash` | Hashing, ciphers, signatures, the `PasswordHash` provider |
99
45
  | `lakutata/utils` | The helper functions |
100
46
 
101
- Outside this package: `@lakutata/cli` (the `lakutata` command: projects, bundles, executables, migrations),
102
- `@lakutata/grpc` (gRPC client, server and service transport), `@lakutata/nats` (NATS component and service transport),
103
- `@lakutata/dbus` (D-Bus) and `@lakutata/mcp` (the Model Context Protocol).
47
+ Not part of this package: `@lakutata/cli` (the `lakutata` command for creating projects, running migrations and packing
48
+ applications, see [Command](Command.md)), `@lakutata/grpc` (a gRPC client, server and service transport),
49
+ `@lakutata/nats` (a NATS component and service transport), `@lakutata/dbus` (D-Bus) and `@lakutata/mcp` (the Model
50
+ Context Protocol).
104
51
 
105
52
  ## The guides
106
53
 
107
54
  | Guide | Topic |
108
55
  |---|---|
109
- | [Core](Core.md) | The application, the container, the lifetimes, dependency injection, modules, the lifecycle |
110
- | [DTOValidation](DTOValidation.md) | DTOs, the schemas, the validation of the options, inputs and results |
111
- | [Decorator](Decorator.md) | The decorators of each subpath |
112
- | [ActionPattern](ActionPattern.md) | The controllers, their actions and their transports (HTTP, CLI, services, schedules) |
113
- | [ORMIntegration](ORMIntegration.md) | The `Database` component and TypeORM |
114
- | [I18n](I18n.md) | The messages of each language |
115
- | [Mutex](Mutex.md) | The locks between the instances and the processes |
56
+ | [GettingStarted](GettingStarted.md) | Requirements, creating a project, adding Lakutata to an existing project, a first application |
57
+ | [ProjectStructure](ProjectStructure.md) | The files, scripts and features of the projects made from the templates, and templates of your own |
58
+ | [UpgradingFrom2](UpgradingFrom2.md) | Upgrading a project from Lakutata 2.x (the package `lakutata` 2.x) |
59
+ | [UpgradingFrom1](UpgradingFrom1.md) | Porting a project from Lakutata 1.x (`@lakutata/core` 1.x and the `@lakutata-module/*`, `@lakutata-component/*` packages) |
60
+ | [Application](Application.md) | The application: its options, the fluent API, the lifecycle, the mode, packed applications |
61
+ | [Objects](Objects.md) | Components, providers and their container: lifetimes, scopes, creation and teardown, a container without an application |
62
+ | [Injection](Injection.md) | Dependency injection, the options of objects, sharing features between applications |
63
+ | [DTOValidation](DTOValidation.md) | DTOs and schemas: validating options, inputs and results |
64
+ | [Exceptions](Exceptions.md) | Declaring exceptions, their messages, what the clients receive, the exceptions of the framework |
65
+ | [Logger](Logger.md) | The `log` component: writing lines, readable lines or JSON, destinations, another logger |
66
+ | [Decorator](Decorator.md) | The decorators, by subpath |
67
+ | [Time](Time.md) | The `Time` class |
68
+ | [HelperFunctions](HelperFunctions.md) | The helper functions of `lakutata/utils` |
69
+ | [Controllers](Controllers.md) | Controllers and actions: their addresses, input and results, prefixes, inheritance |
70
+ | [Entrypoint](Entrypoint.md) | The entrypoint component: its options and adapters, starting and stopping, the list of the actions |
71
+ | [Middlewares](Middlewares.md) | The middlewares and the access control of the actions |
72
+ | [HTTP](HTTP.md) | The HTTP adapters: routes, input, responses, errors, the features of Express and Fastify |
73
+ | [CLI](CLI.md) | Command line tools: commands, options, prompts, output and exit codes |
74
+ | [ServiceCalls](ServiceCalls.md) | The service actions over HTTP, Socket.IO, JSON-RPC 2.0 and Electron: patterns, responses, clients and their events |
75
+ | [GRPC](GRPC.md) | The service actions over gRPC (`@lakutata/grpc`), and calling them from other applications and languages |
76
+ | [NATS](NATS.md) | The NATS component, the service actions over NATS (`@lakutata/nats`), the service proxies and their events |
77
+ | [Schedules](Schedules.md) | Scheduled jobs: intervals, cron expressions, jobs run by one instance |
78
+ | [Queue](Queue.md) | The message queues: producers, `@QueueAction` consumers, retries, dead letters, results |
79
+ | [Database](Database.md) | The `Database` component and provider, the connection options, several databases |
80
+ | [DatabaseDrivers](DatabaseDrivers.md) | The database drivers, one by one: what to install, their options, their limits |
81
+ | [MongoEmbedded](MongoEmbedded.md) | A MongoDB inside the application, its documents in files |
82
+ | [Entities](Entities.md) | The entities, the queries, the transactions and the errors |
83
+ | [Migrations](Migrations.md) | Writing, generating and running the migrations |
84
+ | [Cache](Cache.md) | The `Cacher` component: `wrap()`, the stores and their tiers, what they keep |
85
+ | [Mutex](Mutex.md) | Locks shared between processes and instances |
86
+ | [I18n](I18n.md) | Messages in several languages |
116
87
  | [DockerIntegration](DockerIntegration.md) | The `Docker` component |
117
88
  | [ContainerdIntegration](ContainerdIntegration.md) | The `Containerd` component |
89
+ | [Monitor](Monitor.md) | The CPU, memory, event loop and HTTP request monitors |
118
90
  | [Security](Security.md) | Hashing, ciphers, signatures, passwords |
119
- | [Time](Time.md) | The `Time` class |
120
- | [HelperFunctions](HelperFunctions.md) | The helper functions of `lakutata/utils` |
121
-
122
- Each `@lakutata/*` package has its own README, and the typings of each subpath document every declaration with
123
- examples.
91
+ | [DBus](DBus.md) | A D-Bus service and client (`@lakutata/dbus`): methods, objects, properties, signals |
92
+ | [MCP](MCP.md) | The tools, resources and prompts of the Model Context Protocol (`@lakutata/mcp`), over stdio and HTTP |
93
+ | [Command](Command.md) | The `lakutata` command: creating projects, migrations, translations, environment variables |
94
+ | [Workspaces](Workspaces.md) | Projects of several packages: running their scripts, giving them a version, adding packages |
95
+ | [NativeAddons](NativeAddons.md) | Native addons in C++ or Rust: creating them, linking libraries, shipping them |
96
+ | [Packaging](Packaging.md) | Bundles and executables, and what a packed application reads at run time |
97
+ | [Installers](Installers.md) | The installers of each platform, services, installer scripts, signing |
98
+
99
+ Each `@lakutata/*` package has its own README, and the type declarations of every subpath document each export with an
100
+ example.
@@ -0,0 +1,193 @@
1
+ # Lakutata Packaging
2
+
3
+ A compiled application can be shipped without its `node_modules`, in three forms:
4
+
5
+ - a **bundle**: one JavaScript file that Node.js runs;
6
+ - an **executable**: one program that runs without Node.js installed;
7
+ - **installers**: the packages of the system (deb, rpm, pkg, msi…) that install the executable, put its program in the
8
+ PATH and can register it as a service ([Installers](Installers.md)).
9
+
10
+ `lakutata package bundle`, `package exe` and `package installer` make them with `@lakutata/builder`, which the project
11
+ installs (`npm install --save-dev @lakutata/builder`; the templates that pack their application already have it).
12
+
13
+ ## 1. What is packed
14
+
15
+ - **The compiled application**: the output of `tsc` (which emits the metadata of the decorators), not the TypeScript
16
+ sources, so build it first. The entry is `--entry`, else the `main` of the `package.json`, else `build/App.js`.
17
+ - **Its dependencies**, bundled by esbuild into one file, except the native addons and the files read by path
18
+ (sections 3 and 4). The packages of the framework, and those built on it, are always bundled, so that there is one
19
+ copy of the framework, of its classes and of its container.
20
+ - **CommonJS**: the bundle is a CommonJS file, so the application cannot use top-level `await`; await inside an async
21
+ function instead.
22
+ - **Optional dependencies** that are not installed (the drivers of the stores the application does not use) are left
23
+ out: loading one throws at run time, as it would without the bundle.
24
+ - **Resources**: the other files the application reads at run time (the built pages of a web interface, templates,
25
+ data) are declared in its `package.json` (section 6).
26
+
27
+ ## 2. Bundles
28
+
29
+ ```bash
30
+ npm run build
31
+ npx lakutata package bundle # dist/<name>.cjs
32
+ node dist/greet.cjs
33
+ ```
34
+
35
+ ```
36
+ ✔ dist/greet.cjs (1.1 MB): node dist/greet.cjs
37
+ ✔ dist/greet.native: the native addons (better-sqlite3) and the scripts run on their own (build/child.js), distributed with the bundle
38
+ ✔ dist/greet.resources: the resources (texts), distributed with the bundle
39
+ ```
40
+
41
+ The name is the first `bin` of the `package.json`, else the name of the package without its scope. When needed, two
42
+ directories are written next to the bundle and must be shipped with it: `dist/<name>.native/` (native addons, scripts
43
+ run on their own, files read by path) and `dist/<name>.resources/` (the resources). The bundle runs from any
44
+ directory, once moved with them.
45
+
46
+ | Option | Meaning |
47
+ |---|---|
48
+ | `--entry <file>` | The compiled entry |
49
+ | `--outfile <file>` | The bundle, `dist/<name>.cjs` by default |
50
+ | `--no-minify` | Do not minify the bundle (the names of the classes are kept either way) |
51
+ | `--external <modules...>` | Modules left out of the bundle, loaded at run time from a `node_modules` next to it |
52
+
53
+ ## 3. Native addons
54
+
55
+ The packages holding `.node` files (better-sqlite3, the addons of the workspace made by
56
+ [`lakutata add --native`](NativeAddons.md)), and the packages that load them through computed paths (sharp), cannot be
57
+ bundled. They are left out, and laid out as in `node_modules` in `dist/<name>.native/`, with what they load at run time:
58
+
59
+ - all their files, and those of the packages of the shared libraries their addons link (such as the libvips of sharp),
60
+ but not their C and C++ sources and objects (better-sqlite3 holds the sources of SQLite), nor what built them (the
61
+ files of node-gyp and of CMake in `build/`, the `target` directory of cargo, the static and import libraries);
62
+ - the JavaScript they load;
63
+ - the addons of the application itself (`createRequire(import.meta.url)('./x.node')`).
64
+
65
+ The type declarations, source maps, TypeScript sources and documentation of the packages are left out. An addon is
66
+ built for the platform and the architecture of the machine, and needs the system libraries it was built for, so pack
67
+ the application of each platform on that platform.
68
+
69
+ ## 4. Files read by path
70
+
71
+ The bundle is not where the modules were: a script started on its own (a worker, a child process of `fork()`) or a
72
+ file the application reads (`defaults.json`, a directory of schemas) would not be found next to it. The tool finds the
73
+ paths built from the location of a module, in the modules of the application and in those of its packages, and
74
+ rewrites them to point into `dist/<name>.native/`:
75
+
76
+ | Path | |
77
+ |---|---|
78
+ | `new URL('./worker.js', import.meta.url)` | Also `pathToFileURL(__filename)` |
79
+ | `path.join(import.meta.dirname, 'child.js')`, `path.resolve(__dirname, '../schema')` | Also with `path.dirname(fileURLToPath(import.meta.url))` |
80
+ | `__dirname + '/worker.js'`, `` `${__dirname}/worker.js` `` | |
81
+ | `require.resolve('./worker')` | The extension is found as Node.js finds it |
82
+ | `` path.join(__dirname, 'locales', `${lang}.json`) `` | Partly known: every file its pattern matches is shipped |
83
+
84
+ | The path names | |
85
+ |---|---|
86
+ | A script (`.js`, `.cjs`) | Bundled on its own, with what it loads |
87
+ | Another file, a directory of data | Copied |
88
+ | A directory that holds the module (`path.join(__dirname, '..')`: the application, its package) | Not shipped, with a warning: declare its files as resources |
89
+ | A directory that holds scripts or packages (`package.json`, `node_modules`) | Not shipped, with a warning: its scripts would need their packages at run time |
90
+ | Nothing yet (a directory the application creates) | Left as it is |
91
+
92
+ ```typescript
93
+ import {fork} from 'node:child_process'
94
+ import {readFileSync} from 'node:fs'
95
+ import path from 'node:path'
96
+
97
+ //Both are shipped: the script bundled on its own, the file copied
98
+ fork(path.join(import.meta.dirname, 'child.js'), ['one', 'two'])
99
+ const defaults: Record<string, unknown> = JSON.parse(readFileSync(new URL('./defaults.json', import.meta.url), 'utf8'))
100
+ ```
101
+
102
+ The tool warns, with the file and the line, of what it cannot follow in the modules of the application: a worker whose
103
+ path is known only at run time (`new Worker(file)`) or relative to the current directory (`new Worker('./worker.js')`),
104
+ and a script that the application also imports (it would be bundled twice, with two copies of its module). Build these
105
+ paths from the directory of their module, or ship the files as resources.
106
+
107
+ ## 5. Executables
108
+
109
+ ```bash
110
+ npx lakutata package exe # dist/<name> (dist/<name>.exe on Windows), with Node.js
111
+ npx lakutata package exe --runtime bun # with Bun
112
+ ```
113
+
114
+ ```
115
+ › Node.js v24.11.1 embedded
116
+ › Resources embedded, extracted at the first run: texts
117
+ › Scripts run on their own embedded, extracted at the first run: build/child.js
118
+ ✔ dist/greet (darwin-arm64, 112.9 MB)
119
+ ```
120
+
121
+ An executable is made for the platform it is made on. Make the executables of the other platforms on those platforms,
122
+ as their native addons are built there: a CI matrix of Linux, macOS and Windows machines, or a container of the
123
+ architecture for Linux (`docker run --platform linux/arm64`); the README of the `cli` template shows both.
124
+
125
+ | Option | Meaning |
126
+ |---|---|
127
+ | `--runtime node` (default) | The bundle is embedded in a copy of the Node.js running the tool (a single executable application of Node.js): about 110 MB on macOS arm64 |
128
+ | `--runtime bun` | The bundle is compiled by Bun (the `bun` package of the project, else the `bun` of the system): about 70 MB on macOS arm64, and it starts faster; the runtime is then Bun |
129
+ | `--layout file` (default) | One file: the native addons, the files read by path and the resources are embedded, and extracted when it starts |
130
+ | `--layout directory` | `dist/<name>/` holds the executable, `native/` and `resources/`, loaded from there without extraction (the installers use it) |
131
+ | `--outdir <directory>` | Where the executable is written, `dist` by default |
132
+ | `--entry`, `--no-minify`, `--external` | As for a bundle |
133
+
134
+ - **Extraction**: an executable of the file layout extracts what it embeds at its first run, into its cache directory,
135
+ in a directory named after the content, so each version extracts once: `~/Library/Caches/<name>` on macOS,
136
+ `%LOCALAPPDATA%\<name>\Cache` on Windows, `$XDG_CACHE_HOME/<name>` or `~/.cache/<name>` on Linux, or the directory
137
+ given by `LAKUTATA_NATIVE_DIR`. When the cache directory cannot be written, it uses `<name>` in the temporary
138
+ directory (not when `LAKUTATA_NATIVE_DIR` is given).
139
+ - **Native addons**: Bun loads the addons of Node-API, but may not load those built on the V8 API of Node.js: an
140
+ executable of Bun warns of them, and fails when it loads such a package (better-sqlite3, for example). On Alpine
141
+ (musl), the executables of Node.js do not load native addons: make them with Bun.
142
+ - **External modules**: the `--external` modules are loaded from a `node_modules` next to the executable.
143
+ - **Child processes**: an executable started for one of its scripts (`fork(path.join(import.meta.dirname, 'child.js'))`)
144
+ runs that script, in both layouts, with its arguments. With Node.js, `require.main` is that script, as in Node.js;
145
+ with Bun, it is not.
146
+ - **No `.env`**: the executables do not load the `.env` of the directory they run in; use `LAKUTATA_ENV_FILE`
147
+ (section 6).
148
+ - **Icon and signature**: `lakutata.icon` in the `package.json` (a square PNG of 256 px or more) becomes the icon of the
149
+ Windows executables. The executables of macOS are signed ad hoc. The ones of Windows made with Node.js keep the
150
+ signature of `node.exe`, which no longer matches: sign them (signtool) before distributing them.
151
+
152
+ ## 6. At run time
153
+
154
+ The resources are declared as a list of `{from, to}` objects in `lakutata.resources`: `from` is a file or a directory
155
+ of the project (it may be outside the package, such as `../ui/dist`), `to` its path among the resources.
156
+
157
+ ```json
158
+ {
159
+ "lakutata": {
160
+ "resources": [{"from": "../ui/dist", "to": "ui"}]
161
+ }
162
+ }
163
+ ```
164
+
165
+ `isPackaged()` and `resourcesPath()` (from `lakutata`) tell the application how it runs:
166
+
167
+ | How it runs | `isPackaged()` | `resourcesPath()` |
168
+ |---|---|---|
169
+ | Not packed (`node build/App.js`, `electron .`) | `false` | `undefined` |
170
+ | A bundle | `true` | `dist/<name>.resources` next to the bundle |
171
+ | An executable, file layout | `true` | The directory the resources were extracted to |
172
+ | An executable, directory layout, or an installed application | `true` | `resources` next to the executable |
173
+ | A packaged Electron application | `true` | `main.resources` in the resources of Electron |
174
+
175
+ `resourcesPath()` returns the path even when the application declares no resources, so the directory may not exist.
176
+ The application chooses where to read its files from:
177
+
178
+ ```typescript
179
+ import {createRequire} from 'node:module'
180
+ import path from 'node:path'
181
+ import {resourcesPath} from 'lakutata'
182
+
183
+ const resources: string | undefined = resourcesPath()
184
+ //The built pages of the "ui" package of the workspace: among the resources when packed, in its dist directory otherwise
185
+ const ui: string = resources ? path.join(resources, 'ui') : path.join(path.dirname(createRequire(import.meta.url).resolve('ui/package.json')), 'dist')
186
+ ```
187
+
188
+ Every packed form loads the environment file named by `LAKUTATA_ENV_FILE` before the application starts: its lines
189
+ `NAME=value` or `NAME="value"`, and comments (`#`). Its values replace the variables already set.
190
+
191
+ ```bash
192
+ LAKUTATA_ENV_FILE=/etc/greet.env ./greet
193
+ ```
@@ -0,0 +1,124 @@
1
+ # Lakutata Project Structure
2
+
3
+ This page describes the projects that `lakutata create` makes: the files of the `default` template, the workspaces of
4
+ the other templates, their scripts and their optional features, and how to make a template of your own.
5
+
6
+ ## 1. The default template
7
+
8
+ ```
9
+ my-app/
10
+ package.json
11
+ tsconfig.json
12
+ README.md
13
+ .gitignore
14
+ src/
15
+ App.ts starts the application
16
+ config/Config.ts its options: components, entrypoint, adapters
17
+ controllers/ExampleController.ts the actions
18
+ dtos/GreetDTO.ts the input of the actions
19
+ tests/App.spec.ts the tests (node --test)
20
+ build/ the compiled application (npm run build)
21
+ ```
22
+
23
+ `src/App.ts` starts the application with the options of `src/config/Config.ts` and logs its launch:
24
+
25
+ ```typescript
26
+ import {Application, type ILogger} from 'lakutata'
27
+ import {config} from './config/Config.js'
28
+
29
+ Application
30
+ .run(config)
31
+ .onLaunched((app: Application, log: ILogger): void => log.info('%s started in %s mode', app.appName, app.mode()))
32
+ .onFatalException((error: Error, log: ILogger): void => log.error('The application cannot start: %s', error.message))
33
+ ```
34
+
35
+ `config()` returns the options of the application: its ID and name, its mode (`production` when
36
+ `NODE_ENV=production`), and the `entrypoint` component, which serves `ExampleController` over HTTP on the `PORT`
37
+ environment variable (8080 by default). It is a function so that the tests can start the application on a port of
38
+ their own: `src/tests/App.spec.ts` runs `Application.run(config(18080))`, requests `/example?name=you`, then disposes
39
+ of the application.
40
+
41
+ | Script | What it does |
42
+ |---|---|
43
+ | `dev` | `build`, then starts the application |
44
+ | `build` | Removes `build/` (`lakutata clean`), then compiles `src/` into it (`tsc`) |
45
+ | `start` | Starts the compiled application (`node build/App.js`) |
46
+ | `test` | `build`, then runs the tests (`node --test "build/tests/**/*.spec.js"`) |
47
+ | `migration:generate`, `migration:create`, `migration:run`, `migration:revert`, `migration:show` | The migrations of the databases (`lakutata migration`, see [Migrations](Migrations.md)) |
48
+
49
+ The template writes its own compiler options in `tsconfig.json` (the ones of `lakutata/tsconfig.json` that it needs,
50
+ with `module: "NodeNext"` and source maps); a project may extend `lakutata/tsconfig.json` instead, as the workspace
51
+ templates other than `cli` do.
52
+
53
+ ## 2. The workspace templates
54
+
55
+ The other templates are npm workspaces: the application is the package `packages/app`, and the templates with an
56
+ interface or with installers add `packages/ui` (the web pages, or the renderer of Electron) and `packages/resources`
57
+ (the icon). The `service` template:
58
+
59
+ ```
60
+ shop/
61
+ package.json the workspace: workspaces ["packages/*"], the scripts
62
+ Dockerfile the image of the service
63
+ packages/
64
+ app/
65
+ package.json
66
+ tsconfig.json extends lakutata/tsconfig.json
67
+ src/
68
+ App.ts
69
+ config/Config.ts the express adapter, its middlewares, compression
70
+ controllers/ExampleController.ts
71
+ controllers/HealthController.ts GET /health
72
+ dtos/GreetDTO.ts
73
+ middlewares/Authenticate.ts a bearer token, when API_TOKEN is set
74
+ tests/App.spec.ts
75
+ ```
76
+
77
+ | Script (root) | What it does |
78
+ |---|---|
79
+ | `npm run build` | Builds every package, in the order of their dependencies (`lakutata run rebuild`) |
80
+ | `npm test` | Builds every package, then runs their tests (`npm run build && lakutata run test`) |
81
+ | `npm run dev` | Starts the `dev` script of every package at once (`lakutata run dev --parallel`): the application, and the dev server of the interface when there is one |
82
+ | `npm start` | Starts the compiled application (`npm start -w app`) |
83
+ | `npm run version:patch` | Gives every package the next patch version (`lakutata version patch --yes`) |
84
+
85
+ The other templates add to this layout:
86
+
87
+ - `web-react` and `web-vue`: `packages/ui`, a Vite application. In development, its dev server
88
+ (`http://localhost:5173`) forwards `/api` to the application; once built, the application serves the pages itself
89
+ (the actions are under `/api`). The `lakutata.resources` of the application ship the built pages in its packed forms.
90
+ - `web-next` and `web-nuxt`: `packages/ui`, a Next.js or Nuxt application that the application renders in the same
91
+ process.
92
+ - `cli`: a command line tool (`commanderCLIEntrypoint`), with the scripts `package:bundle` and `package:exe` that pack
93
+ it into `dist/` ([Packaging](Packaging.md)).
94
+ - `electron-react` and `electron-vue`: the main process of Electron in `packages/app` (its window and its service
95
+ actions over IPC), the renderer in `packages/ui`, and the scripts that make the installers.
96
+
97
+ The packed forms are written to `dist/` at the root of the workspace; `.gitignore` leaves out `build`, `dist` and the
98
+ outputs of the interfaces.
99
+
100
+ ## 3. The features
101
+
102
+ `lakutata create --with <features>` (or the list offered in a terminal) adds optional features to the template:
103
+
104
+ | Feature | Templates | What it adds |
105
+ |---|---|---|
106
+ | `i18n` | all | The messages of the languages in `src/locales` (`en`, `zh-CN`), the `i18n` component, the language middleware, and the scripts `i18n:check` and `i18n:types` ([I18n](I18n.md)) |
107
+ | `installer` | `cli`, `service`, `web-*` | The `lakutata.installer` of the application, the scripts that make the installers (on the machine, and for Linux in Docker), and for the services a system service ([Installers](Installers.md)) |
108
+
109
+ The Electron templates make installers without this feature.
110
+
111
+ ## 4. Templates of your own
112
+
113
+ `--template` also takes a template that is not in the catalog: `npm:<package>[@<version>]`,
114
+ `github:<owner>/<repo>[#<ref>]`, or a directory. A directory without a `template/` subdirectory is copied as it is; a
115
+ template package (as the official ones) holds:
116
+
117
+ - `template/`: the files of the project. npm does not publish some dotfiles, so they are named with `_` and renamed
118
+ (`_gitignore` becomes `.gitignore`). `{$APP_NAME}`, `{$APP_ID}`, `{$APP_DESC}`, `{$APP_AUTHOR}`, `{$APP_LICENSE}` and
119
+ `{$LAKUTATA_VERSION}` are replaced in the text files.
120
+ - `features/<name>/`: the files of each feature, declared with its description in the `lakutata.features` of the
121
+ `package.json` of the template. They are added to the project: a JSON file the project already has is merged into it
122
+ (arrays replaced), any other file replaces the one of the template.
123
+ - Blocks kept for a feature only: lines between `//@if i18n` and `//@end` (with `//@else`, and `@if !i18n` for the
124
+ opposite), written as comments of the file (`#@if`, `<!--@if-->`, `/*@if*/`).