@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 +23 -0
- package/README.md +11 -0
- package/features/i18n/package.json +6 -0
- package/features/i18n/src/locales/en.json +5 -0
- package/features/i18n/src/locales/zh-CN.json +5 -0
- package/features/i18n/tsconfig.json +5 -0
- package/package.json +22 -0
- package/template/README.md +48 -0
- package/template/_gitignore +8 -0
- package/template/package.json +35 -0
- package/template/src/App.ts +7 -0
- package/template/src/config/Config.ts +36 -0
- package/template/src/controllers/ExampleController.ts +32 -0
- package/template/src/dtos/GreetDTO.ts +7 -0
- package/template/src/tests/App.spec.ts +33 -0
- package/template/tsconfig.json +20 -0
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`.
|
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,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,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
|
+
}
|