@lakutata/template-default 3.0.0-beta.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.
package/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-present Lakutata
4
+
5
+ All rights reserved
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ of this software and associated documentation files (the "Software"), to deal
9
+ in the Software without restriction, including without limitation the rights
10
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ copies of the Software, and to permit persons to whom the Software is
12
+ furnished to do so, subject to the following conditions:
13
+
14
+ The above copyright notice and this permission notice shall be included in all
15
+ copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @lakutata/template-default
2
+
3
+ The default template of the [lakutata](https://github.com/lakutata/lakutata) projects: a minimal application whose
4
+ controller serves HTTP actions with the express adapter.
5
+
6
+ ```bash
7
+ npx @lakutata/cli create --name my-app
8
+ ```
9
+
10
+ The files of the project are in `template/`; `lakutata create` fills `{$APP_NAME}`, `{$APP_ID}`, `{$APP_DESC}`,
11
+ `{$APP_AUTHOR}` and `{$APP_LICENSE}`, and renames `_gitignore` to `.gitignore`.
@@ -0,0 +1,6 @@
1
+ {
2
+ "scripts": {
3
+ "i18n:check": "lakutata i18n check --dir src/locales",
4
+ "i18n:types": "lakutata i18n types --dir src/locales"
5
+ }
6
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "greeting": {
3
+ "hello": "Hello, {name}!"
4
+ }
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "greeting": {
3
+ "hello": "你好,{name}!"
4
+ }
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "compilerOptions": {
3
+ "resolveJsonModule": true
4
+ }
5
+ }
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "@lakutata/template-default",
3
+ "version": "3.0.0-beta.0",
4
+ "description": "The default template of the lakutata projects: a minimal application serving HTTP actions.",
5
+ "keywords": [
6
+ "lakutata",
7
+ "lakutata-template"
8
+ ],
9
+ "license": "MIT",
10
+ "files": [
11
+ "template",
12
+ "features",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "lakutata": {
17
+ "template": "default",
18
+ "features": {
19
+ "i18n": "The messages in several languages (lakutata/com/i18n): src/locales, the language of each request"
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,48 @@
1
+ # {$APP_NAME}
2
+
3
+ {$APP_DESC}
4
+
5
+ A [lakutata](https://github.com/lakutata/lakutata) application.
6
+
7
+ ```bash
8
+ npm run dev # build and start, http://localhost:8080/example
9
+ npm test # build and run the tests
10
+ npm run build # compile into build/
11
+ npm start # start the compiled application
12
+ ```
13
+
14
+ - `src/App.ts` starts the application;
15
+ - `src/config/Config.ts` declares its components, the entrypoint and its adapters;
16
+ - `src/controllers/` holds the controllers: their actions are served by the adapters of the entrypoint.
17
+
18
+ ## Database migrations
19
+
20
+ ```bash
21
+ npm run migration:generate # the migrations of the changes of the entities of the databases
22
+ npm run migration:create -- seed-users # an empty migration, written by hand
23
+ npm run migration:show # the migrations run [X] and pending [ ]
24
+ npm run migration:run # run the pending migrations
25
+ npm run migration:revert # revert the last migration run
26
+ ```
27
+
28
+ The commands (`lakutata migration <action>`) build and start the application, which connects its databases with their
29
+ options (without synchronizing their schemas), does the command and exits; `-- --database <name>` selects a database
30
+ (required to revert when there are several), `-- --fake` marks the migrations as run or reverted without executing
31
+ them. The migrations are written into `src/migrations`, compiled with the application and given to the options of the
32
+ databases, run when they connect:
33
+
34
+ ```typescript
35
+ import {buildDatabaseOptions} from 'lakutata/com/database'
36
+ import {Migrations1788773616343} from '../migrations/1788773616343-db.js'
37
+
38
+ components: {
39
+ db: buildDatabaseOptions({
40
+ type: 'postgres',
41
+ url: process.env.DATABASE_URL,
42
+ entities: [/* the entities */],
43
+ synchronize: false,
44
+ migrationsRun: true,
45
+ migrations: [Migrations1788773616343]
46
+ })
47
+ }
48
+ ```
@@ -0,0 +1,8 @@
1
+ node_modules
2
+ /build
3
+ *.log
4
+ .env.local
5
+ .env.*.local
6
+ .DS_Store
7
+ .idea
8
+ .vscode
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "{$APP_ID}",
3
+ "version": "0.0.1",
4
+ "description": "{$APP_DESC}",
5
+ "author": "{$APP_AUTHOR}",
6
+ "license": "{$APP_LICENSE}",
7
+ "private": true,
8
+ "type": "module",
9
+ "main": "build/App.js",
10
+ "scripts": {
11
+ "clean": "lakutata clean",
12
+ "build": "npm run clean && tsc",
13
+ "start": "node build/App.js",
14
+ "dev": "npm run build && node build/App.js",
15
+ "migration:generate": "lakutata migration generate",
16
+ "migration:create": "lakutata migration create",
17
+ "migration:run": "lakutata migration run",
18
+ "migration:revert": "lakutata migration revert",
19
+ "migration:show": "lakutata migration show",
20
+ "test": "npm run build && node --test \"build/tests/**/*.spec.js\""
21
+ },
22
+ "dependencies": {
23
+ "express": "^5.2.1",
24
+ "lakutata": "^{$LAKUTATA_VERSION}"
25
+ },
26
+ "devDependencies": {
27
+ "@lakutata/cli": "^{$LAKUTATA_VERSION}",
28
+ "@types/express": "^5.0.6",
29
+ "@types/node": "^22.0.0",
30
+ "typescript": "^6.0.3"
31
+ },
32
+ "engines": {
33
+ "node": ">=22"
34
+ }
35
+ }
@@ -0,0 +1,7 @@
1
+ import {Application, type ILogger} from 'lakutata'
2
+ import {installerConfig} from './config/Config.js'
3
+
4
+ Application
5
+ .run(installerConfig)
6
+ .onLaunched((app: Application, log: ILogger): void => log.info('%s started in %s mode', app.appName, app.mode()))
7
+ .onFatalException((error: Error, log: ILogger): void => log.error('The application cannot start: %s', error.message))
@@ -0,0 +1,36 @@
1
+ import type {ApplicationOptions} from 'lakutata'
2
+ import {buildEntrypoints} from 'lakutata/com/entrypoint'
3
+ import {expressHTTPEntrypoint} from 'lakutata/adapter/express'
4
+ import {ExampleController} from '../controllers/ExampleController.js'
5
+ //@if i18n
6
+ import {buildI18nOptions, I18nMiddleware} from 'lakutata/com/i18n'
7
+ import en from '../locales/en.json' with {type: 'json'}
8
+ import zhCN from '../locales/zh-CN.json' with {type: 'json'}
9
+ //@end
10
+
11
+ /**
12
+ * The options of the application
13
+ * @param port the port of the HTTP server, the PORT environment variable or 8080 by default
14
+ */
15
+ export function installerConfig(port: number = Number(process.env.PORT ?? 8080)): ApplicationOptions {
16
+ return {
17
+ id: '{$APP_ID}',
18
+ name: '{$APP_NAME}',
19
+ mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
20
+ components: {
21
+ //@if i18n
22
+ //The messages of the languages (src/locales), bundled with the code; created by the first request
23
+ i18n: buildI18nOptions({messages: {'en': en, 'zh-CN': zhCN}}),
24
+ //@end
25
+ entrypoint: buildEntrypoints({
26
+ controllers: [ExampleController],
27
+ //@if i18n
28
+ //The messages in the language of each request: ?lang=, the cookie lang, Accept-Language
29
+ middlewares: [I18nMiddleware],
30
+ //@end
31
+ http: expressHTTPEntrypoint({port: port})
32
+ })
33
+ },
34
+ bootstrap: ['entrypoint']
35
+ }
36
+ }
@@ -0,0 +1,32 @@
1
+ import {Controller} from 'lakutata/com/entrypoint'
2
+ import {CLIAction, GET} from 'lakutata/decorator/ctrl'
3
+ import {GreetDTO} from '../dtos/GreetDTO.js'
4
+ //@if i18n
5
+ import {Inject} from 'lakutata/decorator/di'
6
+ import {Translator} from 'lakutata/com/i18n'
7
+ //@end
8
+
9
+ export class ExampleController extends Controller {
10
+ //@if i18n
11
+
12
+ /**
13
+ * The messages of the language of the request
14
+ */
15
+ @Inject(Translator)
16
+ protected readonly i18n: Translator
17
+ //@end
18
+
19
+ /**
20
+ * GET /example?name=you, or the command "greet --name you" with a CLI adapter
21
+ * @param input
22
+ */
23
+ @GET('/example', GreetDTO)
24
+ @CLIAction('greet', GreetDTO)
25
+ public async greet(input: GreetDTO): Promise<{ message: string }> {
26
+ //@if i18n
27
+ return {message: this.i18n.t('greeting.hello', {name: input.name})}
28
+ //@else
29
+ return {message: `Hello, ${input.name}!`}
30
+ //@end
31
+ }
32
+ }
@@ -0,0 +1,7 @@
1
+ import {DTO} from 'lakutata'
2
+ import {Expect} from 'lakutata/decorator/dto'
3
+
4
+ export class GreetDTO extends DTO {
5
+ @Expect(DTO.String().optional().default('world').description('Who is greeted'))
6
+ public name: string
7
+ }
@@ -0,0 +1,33 @@
1
+ import {after, before, describe, it} from 'node:test'
2
+ import assert from 'node:assert'
3
+ import {Application} from 'lakutata'
4
+ import {installerConfig} from '../config/Config.js'
5
+
6
+ const PORT: number = 18080
7
+
8
+ describe('{$APP_NAME}', (): void => {
9
+
10
+ let app: Application
11
+
12
+ before(async (): Promise<void> => {
13
+ app = await new Promise<Application>((resolve: (app: Application) => void): void => {
14
+ Application.run(installerConfig(PORT)).onLaunched((launched: Application): void => resolve(launched))
15
+ })
16
+ })
17
+
18
+ after(async (): Promise<void> => {
19
+ await app?.dispose()
20
+ })
21
+
22
+ it('greets', async (): Promise<void> => {
23
+ const response: Response = await fetch(`http://127.0.0.1:${PORT}/example?name=you`)
24
+ assert.deepStrictEqual(await response.json(), {message: 'Hello, you!'})
25
+ })
26
+ //@if i18n
27
+
28
+ it('greets in the language of the request', async (): Promise<void> => {
29
+ const response: Response = await fetch(`http://127.0.0.1:${PORT}/example?name=you`, {headers: {'Accept-Language': 'zh-CN,zh;q=0.9'}})
30
+ assert.deepStrictEqual(await response.json(), {message: '你好,you!'})
31
+ })
32
+ //@end
33
+ })
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "ESNext.Disposable"],
5
+ "module": "NodeNext",
6
+ "moduleResolution": "NodeNext",
7
+ "rootDir": "src",
8
+ "outDir": "build",
9
+ "types": ["node"],
10
+ "experimentalDecorators": true,
11
+ "emitDecoratorMetadata": true,
12
+ "useDefineForClassFields": false,
13
+ "strict": true,
14
+ "strictPropertyInitialization": false,
15
+ "esModuleInterop": true,
16
+ "skipLibCheck": true,
17
+ "sourceMap": true
18
+ },
19
+ "include": ["src"]
20
+ }