create-mantiq 0.7.0 → 0.7.1
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/package.json +2 -1
- package/skeleton/.env.example +64 -0
- package/skeleton/README.md +46 -0
- package/skeleton/app/Console/Commands/.gitkeep +0 -0
- package/skeleton/app/Enums/UserStatus.ts +7 -0
- package/skeleton/app/Http/Controllers/HomeController.ts +78 -0
- package/skeleton/app/Http/Middleware/.gitkeep +0 -0
- package/skeleton/app/Models/User.ts +7 -0
- package/skeleton/app/Providers/AppServiceProvider.ts +25 -0
- package/skeleton/app/Providers/DatabaseServiceProvider.ts +17 -0
- package/skeleton/bootstrap/.gitkeep +0 -0
- package/skeleton/config/ai.ts +51 -0
- package/skeleton/config/app.ts +108 -0
- package/skeleton/config/auth.ts +51 -0
- package/skeleton/config/broadcasting.ts +93 -0
- package/skeleton/config/cache.ts +61 -0
- package/skeleton/config/cors.ts +77 -0
- package/skeleton/config/database.ts +120 -0
- package/skeleton/config/filesystem.ts +58 -0
- package/skeleton/config/hashing.ts +47 -0
- package/skeleton/config/heartbeat.ts +112 -0
- package/skeleton/config/logging.ts +58 -0
- package/skeleton/config/mail.ts +93 -0
- package/skeleton/config/notify.ts +141 -0
- package/skeleton/config/queue.ts +59 -0
- package/skeleton/config/search.ts +96 -0
- package/skeleton/config/services.ts +110 -0
- package/skeleton/config/session.ts +84 -0
- package/skeleton/config/vite.ts +33 -0
- package/skeleton/database/factories/.gitkeep +0 -0
- package/skeleton/database/migrations/001_create_users_table.ts +19 -0
- package/skeleton/database/migrations/002_create_personal_access_tokens_table.ts +22 -0
- package/skeleton/database/seeders/DatabaseSeeder.ts +7 -0
- package/skeleton/index.ts +20 -0
- package/skeleton/mantiq.ts +8 -0
- package/skeleton/package.json +34 -0
- package/skeleton/public/.gitkeep +0 -0
- package/skeleton/routes/api.ts +8 -0
- package/skeleton/routes/channels.ts +23 -0
- package/skeleton/routes/console.ts +24 -0
- package/skeleton/routes/web.ts +6 -0
- package/skeleton/storage/cache/.gitkeep +0 -0
- package/skeleton/storage/framework/.gitkeep +0 -0
- package/skeleton/tests/feature/api.test.ts +14 -0
- package/skeleton/tests/feature/home.test.ts +17 -0
- package/skeleton/tests/unit/example.test.ts +11 -0
- package/skeleton/tsconfig.json +27 -0
- package/src/index.ts +271 -25
- package/src/templates.ts +141 -945
- package/src/terminal.ts +64 -0
- package/stubs/api-only/routes/api.ts.stub +24 -0
- package/stubs/api-only/tests/feature/token-auth.test.ts.stub +69 -0
- package/stubs/auth/api/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
- package/stubs/auth/api/routes/api.ts.stub +24 -0
- package/stubs/auth/api/tests/feature/token-auth.test.ts.stub +69 -0
- package/stubs/auth/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
- package/stubs/auth/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
- package/stubs/auth/web/app/Http/Controllers/AuthController.ts.stub +43 -0
- package/stubs/auth/web/app/Http/Controllers/PageController.ts.stub +66 -0
- package/stubs/auth/web/routes/web.ts.stub +25 -0
- package/stubs/auth/web/svelte/src/App.svelte.stub +77 -0
- package/stubs/auth/web/svelte/src/pages.ts.stub +17 -0
- package/stubs/auth/web/tests/feature/auth.test.ts.stub +69 -0
- package/stubs/auth/web/vue/src/App.vue.stub +74 -0
- package/stubs/auth/web/vue/src/pages.ts.stub +17 -0
- package/stubs/manifest.json +630 -2
- package/stubs/noauth/app/Http/Controllers/PageController.ts.stub +41 -0
- package/stubs/noauth/app/Models/User.ts.stub +5 -0
- package/stubs/noauth/database/migrations/001_create_users_table.ts.stub +17 -0
- package/stubs/noauth/routes/api.ts.stub +16 -0
- package/stubs/noauth/routes/web.ts.stub +15 -0
- package/stubs/noauth/svelte/src/App.svelte.stub +68 -0
- package/stubs/noauth/svelte/src/pages.ts.stub +7 -0
- package/stubs/noauth/vue/src/App.vue.stub +62 -0
- package/stubs/noauth/vue/src/pages.ts.stub +7 -0
- package/stubs/react/src/App.tsx.stub +4 -2
- package/stubs/react/src/components/layout/search-dialog.tsx.stub +2 -2
- package/stubs/react/src/components/layout/sidebar-data.ts.stub +2 -2
- package/stubs/react/src/lib/api.ts.stub +30 -6
- package/stubs/react/src/pages/Login.tsx.stub +3 -3
- package/stubs/react/src/pages/users/dialogs.tsx.stub +7 -26
- package/stubs/react/vite.config.ts.stub +26 -3
- package/stubs/shared/app/Http/Controllers/ApiAuthController.ts.stub +57 -0
- package/stubs/shared/app/Http/Controllers/AuthController.ts.stub +14 -38
- package/stubs/shared/app/Http/Controllers/PageController.ts.stub +3 -3
- package/stubs/shared/app/Http/Controllers/UserController.ts.stub +61 -0
- package/stubs/shared/app/Http/Requests/LoginRequest.ts.stub +10 -0
- package/stubs/shared/app/Http/Requests/RegisterRequest.ts.stub +11 -0
- package/stubs/shared/app/Http/Requests/StoreUserRequest.ts.stub +11 -0
- package/stubs/shared/app/Http/Requests/UpdateUserRequest.ts.stub +11 -0
- package/stubs/shared/config/app.ts.stub +36 -0
- package/stubs/shared/config/vite.ts.stub +8 -0
- package/stubs/shared/database/factories/UserFactory.ts.stub +4 -6
- package/stubs/shared/routes/api.ts.stub +12 -102
- package/stubs/shared/routes/web.ts.stub +5 -3
- package/stubs/shared/tests/feature/auth.test.ts.stub +69 -0
- package/stubs/shared/tests/feature/users.test.ts.stub +90 -0
- package/stubs/svelte/src/App.svelte.stub +1 -1
- package/stubs/svelte/src/lib/api.ts.stub +30 -6
- package/stubs/svelte/src/main.ts.stub +3 -1
- package/stubs/svelte/src/pages/Login.svelte.stub +3 -3
- package/stubs/svelte/vite.config.ts.stub +20 -1
- package/stubs/tailwind-only/react/src/components/layout/app-sidebar.tsx.stub +68 -0
- package/stubs/tailwind-only/react/src/components/layout/authenticated-layout.tsx.stub +57 -0
- package/stubs/tailwind-only/react/src/components/layout/header.tsx.stub +52 -0
- package/stubs/tailwind-only/react/src/components/layout/main.tsx.stub +21 -0
- package/stubs/tailwind-only/react/src/components/layout/nav-group.tsx.stub +185 -0
- package/stubs/tailwind-only/react/src/components/layout/nav-user.tsx.stub +106 -0
- package/stubs/tailwind-only/react/src/components/layout/sidebar-data.ts.stub +58 -0
- package/stubs/tailwind-only/react/src/components/layout/theme-toggle.tsx.stub +36 -0
- package/stubs/tailwind-only/react/src/components/layout/top-nav.tsx.stub +72 -0
- package/stubs/tailwind-only/react/src/lib/utils.ts.stub +6 -0
- package/stubs/tailwind-only/react/src/pages/Dashboard.tsx.stub +205 -0
- package/stubs/tailwind-only/react/src/pages/Login.tsx.stub +122 -0
- package/stubs/tailwind-only/react/src/pages/Register.tsx.stub +137 -0
- package/stubs/tailwind-only/react/src/pages/Users.tsx.stub +426 -0
- package/stubs/tailwind-only/react/src/pages/account/layout.tsx.stub +64 -0
- package/stubs/tailwind-only/react/src/pages/account/preferences.tsx.stub +80 -0
- package/stubs/tailwind-only/react/src/pages/account/profile.tsx.stub +67 -0
- package/stubs/tailwind-only/react/src/pages/account/security.tsx.stub +91 -0
- package/stubs/tailwind-only/react/src/style.css.stub +14 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/app-sidebar.svelte.stub +104 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/authenticated-layout.svelte.stub +51 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/header.svelte.stub +66 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/main.svelte.stub +26 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-group.svelte.stub +131 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/nav-user.svelte.stub +104 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/sidebar-data.ts.stub +57 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/theme-toggle.svelte.stub +28 -0
- package/stubs/tailwind-only/svelte/src/lib/components/layout/top-nav.svelte.stub +99 -0
- package/stubs/tailwind-only/svelte/src/lib/utils.ts.stub +6 -0
- package/stubs/tailwind-only/svelte/src/pages/Dashboard.svelte.stub +192 -0
- package/stubs/tailwind-only/svelte/src/pages/Login.svelte.stub +120 -0
- package/stubs/tailwind-only/svelte/src/pages/Register.svelte.stub +134 -0
- package/stubs/tailwind-only/svelte/src/pages/Users.svelte.stub +293 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Layout.svelte.stub +61 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Preferences.svelte.stub +81 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Profile.svelte.stub +76 -0
- package/stubs/tailwind-only/svelte/src/pages/account/Security.svelte.stub +140 -0
- package/stubs/tailwind-only/svelte/src/style.css.stub +127 -0
- package/stubs/tailwind-only/vue/src/components/layout/AppSidebar.vue.stub +60 -0
- package/stubs/tailwind-only/vue/src/components/layout/AuthenticatedLayout.vue.stub +73 -0
- package/stubs/tailwind-only/vue/src/components/layout/Header.vue.stub +54 -0
- package/stubs/tailwind-only/vue/src/components/layout/Main.vue.stub +22 -0
- package/stubs/tailwind-only/vue/src/components/layout/NavGroup.vue.stub +107 -0
- package/stubs/tailwind-only/vue/src/components/layout/NavUser.vue.stub +104 -0
- package/stubs/tailwind-only/vue/src/components/layout/ThemeToggle.vue.stub +28 -0
- package/stubs/tailwind-only/vue/src/components/layout/TopNav.vue.stub +86 -0
- package/stubs/tailwind-only/vue/src/components/layout/sidebar-data.ts.stub +57 -0
- package/stubs/tailwind-only/vue/src/lib/utils.ts.stub +7 -0
- package/stubs/tailwind-only/vue/src/pages/Dashboard.vue.stub +195 -0
- package/stubs/tailwind-only/vue/src/pages/Login.vue.stub +121 -0
- package/stubs/tailwind-only/vue/src/pages/Register.vue.stub +137 -0
- package/stubs/tailwind-only/vue/src/pages/Users.vue.stub +401 -0
- package/stubs/tailwind-only/vue/src/pages/account/Layout.vue.stub +56 -0
- package/stubs/tailwind-only/vue/src/pages/account/Preferences.vue.stub +81 -0
- package/stubs/tailwind-only/vue/src/pages/account/Profile.vue.stub +69 -0
- package/stubs/tailwind-only/vue/src/pages/account/Security.vue.stub +85 -0
- package/stubs/tailwind-only/vue/src/style.css.stub +26 -0
- package/stubs/themes/corporate/react/src/components/layout/app-sidebar.tsx.stub +74 -0
- package/stubs/themes/corporate/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/corporate/react/src/pages/Dashboard.tsx.stub +310 -0
- package/stubs/themes/corporate/react/src/pages/Login.tsx.stub +122 -0
- package/stubs/themes/corporate/react/src/pages/Register.tsx.stub +144 -0
- package/stubs/themes/corporate/react/src/style.css.stub +135 -0
- package/stubs/themes/corporate/svelte/src/pages/Dashboard.svelte.stub +271 -0
- package/stubs/themes/corporate/svelte/src/pages/Login.svelte.stub +117 -0
- package/stubs/themes/corporate/svelte/src/pages/Register.svelte.stub +138 -0
- package/stubs/themes/corporate/svelte/src/style.css.stub +134 -0
- package/stubs/themes/corporate/vue/src/pages/Dashboard.vue.stub +325 -0
- package/stubs/themes/corporate/vue/src/pages/Login.vue.stub +118 -0
- package/stubs/themes/corporate/vue/src/pages/Register.vue.stub +139 -0
- package/stubs/themes/corporate/vue/src/style.css.stub +134 -0
- package/stubs/themes/minimal/react/src/components/layout/app-sidebar.tsx.stub +68 -0
- package/stubs/themes/minimal/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/minimal/react/src/pages/Dashboard.tsx.stub +166 -0
- package/stubs/themes/minimal/react/src/pages/Login.tsx.stub +95 -0
- package/stubs/themes/minimal/react/src/pages/Register.tsx.stub +73 -0
- package/stubs/themes/minimal/react/src/style.css.stub +142 -0
- package/stubs/themes/minimal/svelte/src/pages/Dashboard.svelte.stub +149 -0
- package/stubs/themes/minimal/svelte/src/pages/Login.svelte.stub +90 -0
- package/stubs/themes/minimal/svelte/src/pages/Register.svelte.stub +70 -0
- package/stubs/themes/minimal/svelte/src/style.css.stub +142 -0
- package/stubs/themes/minimal/vue/src/pages/Dashboard.vue.stub +163 -0
- package/stubs/themes/minimal/vue/src/pages/Login.vue.stub +91 -0
- package/stubs/themes/minimal/vue/src/pages/Register.vue.stub +73 -0
- package/stubs/themes/minimal/vue/src/style.css.stub +142 -0
- package/stubs/themes/starter/react/src/components/layout/app-sidebar.tsx.stub +74 -0
- package/stubs/themes/starter/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/starter/react/src/pages/Dashboard.tsx.stub +236 -0
- package/stubs/themes/starter/react/src/pages/Login.tsx.stub +131 -0
- package/stubs/themes/starter/react/src/pages/Register.tsx.stub +145 -0
- package/stubs/themes/starter/react/src/style.css.stub +141 -0
- package/stubs/themes/starter/svelte/src/pages/Dashboard.svelte.stub +212 -0
- package/stubs/themes/starter/svelte/src/pages/Login.svelte.stub +126 -0
- package/stubs/themes/starter/svelte/src/pages/Register.svelte.stub +139 -0
- package/stubs/themes/starter/svelte/src/style.css.stub +141 -0
- package/stubs/themes/starter/vue/src/pages/Dashboard.vue.stub +228 -0
- package/stubs/themes/starter/vue/src/pages/Login.vue.stub +127 -0
- package/stubs/themes/starter/vue/src/pages/Register.vue.stub +140 -0
- package/stubs/themes/starter/vue/src/style.css.stub +141 -0
- package/stubs/themes/workspace/react/src/components/layout/app-sidebar.tsx.stub +97 -0
- package/stubs/themes/workspace/react/src/components/layout/authenticated-layout.tsx.stub +42 -0
- package/stubs/themes/workspace/react/src/pages/Dashboard.tsx.stub +304 -0
- package/stubs/themes/workspace/react/src/pages/Login.tsx.stub +131 -0
- package/stubs/themes/workspace/react/src/pages/Register.tsx.stub +82 -0
- package/stubs/themes/workspace/react/src/style.css.stub +138 -0
- package/stubs/themes/workspace/svelte/src/pages/Dashboard.svelte.stub +215 -0
- package/stubs/themes/workspace/svelte/src/pages/Login.svelte.stub +124 -0
- package/stubs/themes/workspace/svelte/src/pages/Register.svelte.stub +76 -0
- package/stubs/themes/workspace/svelte/src/style.css.stub +134 -0
- package/stubs/themes/workspace/vue/src/pages/Dashboard.vue.stub +220 -0
- package/stubs/themes/workspace/vue/src/pages/Login.vue.stub +128 -0
- package/stubs/themes/workspace/vue/src/pages/Register.vue.stub +80 -0
- package/stubs/themes/workspace/vue/src/style.css.stub +134 -0
- package/stubs/vue/src/App.vue.stub +2 -1
- package/stubs/vue/src/lib/api.ts.stub +30 -6
- package/stubs/vue/src/main.ts.stub +3 -1
- package/stubs/vue/src/pages/Login.vue.stub +3 -3
- package/stubs/vue/vite.config.ts.stub +20 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-mantiq",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"description": "Scaffold a new MantiqJS application",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"files": [
|
|
36
36
|
"src/",
|
|
37
37
|
"stubs/",
|
|
38
|
+
"skeleton/",
|
|
38
39
|
"package.json",
|
|
39
40
|
"README.md"
|
|
40
41
|
],
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Application
|
|
2
|
+
APP_NAME=MantiqJS
|
|
3
|
+
APP_ENV=local
|
|
4
|
+
APP_DEBUG=true
|
|
5
|
+
APP_KEY=
|
|
6
|
+
APP_URL=http://localhost:3000
|
|
7
|
+
APP_PORT=3000
|
|
8
|
+
|
|
9
|
+
# Database
|
|
10
|
+
DB_CONNECTION=sqlite
|
|
11
|
+
DB_DATABASE=database/database.sqlite
|
|
12
|
+
# DB_HOST=127.0.0.1
|
|
13
|
+
# DB_PORT=5432
|
|
14
|
+
# DB_USERNAME=postgres
|
|
15
|
+
# DB_PASSWORD=
|
|
16
|
+
|
|
17
|
+
# Session
|
|
18
|
+
SESSION_DRIVER=memory
|
|
19
|
+
SESSION_LIFETIME=120
|
|
20
|
+
SESSION_COOKIE=mantiq_session
|
|
21
|
+
|
|
22
|
+
# Cache
|
|
23
|
+
CACHE_STORE=memory
|
|
24
|
+
# REDIS_HOST=127.0.0.1
|
|
25
|
+
# REDIS_PORT=6379
|
|
26
|
+
# REDIS_PASSWORD=
|
|
27
|
+
|
|
28
|
+
# Queue
|
|
29
|
+
QUEUE_CONNECTION=sync
|
|
30
|
+
|
|
31
|
+
# Mail
|
|
32
|
+
MAIL_MAILER=log
|
|
33
|
+
MAIL_FROM_ADDRESS=hello@example.com
|
|
34
|
+
MAIL_FROM_NAME=${APP_NAME}
|
|
35
|
+
# MAIL_HOST=localhost
|
|
36
|
+
# MAIL_PORT=587
|
|
37
|
+
# MAIL_USERNAME=
|
|
38
|
+
# MAIL_PASSWORD=
|
|
39
|
+
|
|
40
|
+
# Logging
|
|
41
|
+
LOG_CHANNEL=stack
|
|
42
|
+
|
|
43
|
+
# Hashing
|
|
44
|
+
HASH_DRIVER=bcrypt
|
|
45
|
+
BCRYPT_ROUNDS=10
|
|
46
|
+
|
|
47
|
+
# Broadcasting
|
|
48
|
+
BROADCAST_DRIVER=bun
|
|
49
|
+
|
|
50
|
+
# Filesystem
|
|
51
|
+
FILESYSTEM_DISK=local
|
|
52
|
+
|
|
53
|
+
# Search
|
|
54
|
+
# ALGOLIA_APP_ID=
|
|
55
|
+
# ALGOLIA_SECRET=
|
|
56
|
+
# MEILISEARCH_HOST=http://127.0.0.1:7700
|
|
57
|
+
# MEILISEARCH_KEY=
|
|
58
|
+
|
|
59
|
+
# AI
|
|
60
|
+
AI_PROVIDER=openai
|
|
61
|
+
AI_MODEL=gpt-4o
|
|
62
|
+
OPENAI_API_KEY=
|
|
63
|
+
ANTHROPIC_API_KEY=
|
|
64
|
+
GEMINI_API_KEY=
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# MantiqJS Skeleton
|
|
2
|
+
|
|
3
|
+
The official MantiqJS application skeleton — API-only, no frontend framework.
|
|
4
|
+
|
|
5
|
+
This is the reference implementation used by `create-mantiq` to scaffold new projects.
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun install
|
|
11
|
+
bun mantiq migrate
|
|
12
|
+
bun run dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Structure
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
├── app/
|
|
19
|
+
│ ├── Http/Controllers/ # Request handlers
|
|
20
|
+
│ ├── Models/ # Database models
|
|
21
|
+
│ └── Providers/ # Service providers
|
|
22
|
+
├── config/ # Configuration files
|
|
23
|
+
├── database/
|
|
24
|
+
│ ├── migrations/ # Database migrations
|
|
25
|
+
│ ├── seeders/ # Data seeders
|
|
26
|
+
│ └── factories/ # Model factories
|
|
27
|
+
├── routes/
|
|
28
|
+
│ ├── web.ts # Web routes
|
|
29
|
+
│ └── api.ts # API routes
|
|
30
|
+
├── storage/ # Logs, cache, uploads
|
|
31
|
+
├── index.ts # Application bootstrap
|
|
32
|
+
├── mantiq.ts # CLI entry point
|
|
33
|
+
└── package.json
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Available Commands
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
bun run dev # Start dev server (with watch)
|
|
40
|
+
bun run start # Start production server
|
|
41
|
+
bun mantiq migrate # Run migrations
|
|
42
|
+
bun mantiq seed # Run seeders
|
|
43
|
+
bun mantiq make:model # Generate a model
|
|
44
|
+
bun mantiq make:migration # Generate a migration
|
|
45
|
+
bun mantiq route:list # List all routes
|
|
46
|
+
```
|
|
File without changes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { MantiqRequest } from '@mantiq/core'
|
|
2
|
+
import { config } from '@mantiq/core'
|
|
3
|
+
|
|
4
|
+
export class HomeController {
|
|
5
|
+
async index(_request: MantiqRequest): Promise<Response> {
|
|
6
|
+
const appName = config('app.name') ?? 'MantiqJS'
|
|
7
|
+
const appEnv = config('app.env') ?? 'production'
|
|
8
|
+
const debug = config('app.debug') ? 'Enabled' : 'Disabled'
|
|
9
|
+
const bunVersion = typeof Bun !== 'undefined' ? Bun.version : 'unknown'
|
|
10
|
+
|
|
11
|
+
let mantiqVersion = '0.0.0'
|
|
12
|
+
try {
|
|
13
|
+
const pkg = await Bun.file(require.resolve('@mantiq/core/package.json')).json()
|
|
14
|
+
mantiqVersion = pkg.version
|
|
15
|
+
} catch { /* fallback */ }
|
|
16
|
+
|
|
17
|
+
const html = `<!DOCTYPE html>
|
|
18
|
+
<html lang="en">
|
|
19
|
+
<head>
|
|
20
|
+
<meta charset="UTF-8">
|
|
21
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
22
|
+
<title>${appName}</title>
|
|
23
|
+
<style>
|
|
24
|
+
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
25
|
+
body{
|
|
26
|
+
font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
|
|
27
|
+
background:#0a0a0b;color:#fafafa;min-height:100vh;
|
|
28
|
+
display:flex;align-items:center;justify-content:center;
|
|
29
|
+
-webkit-font-smoothing:antialiased;
|
|
30
|
+
}
|
|
31
|
+
.c{width:100%;max-width:460px;padding:32px;animation:up .5s ease}
|
|
32
|
+
@keyframes up{from{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}
|
|
33
|
+
.w{font-size:28px;font-weight:600;letter-spacing:-0.04em;color:#fafafa}
|
|
34
|
+
.w .d{color:#10b981}
|
|
35
|
+
.v{font-family:'SF Mono',ui-monospace,monospace;font-size:12px;color:#52525b;margin-top:6px}
|
|
36
|
+
hr{border:none;border-top:1px solid #1e1e1e;margin:24px 0}
|
|
37
|
+
.g{display:grid;grid-template-columns:1fr 1fr;gap:8px}
|
|
38
|
+
.l{
|
|
39
|
+
background:#111113;border:1px solid #1e1e1e;border-radius:8px;
|
|
40
|
+
padding:14px 16px;text-decoration:none;color:#a1a1aa;font-size:13px;
|
|
41
|
+
display:flex;align-items:center;justify-content:space-between;
|
|
42
|
+
transition:border-color .15s,color .15s;
|
|
43
|
+
}
|
|
44
|
+
.l:hover{border-color:#27272a;color:#34d399}
|
|
45
|
+
.l .a{color:#52525b;font-size:11px;transition:color .15s}
|
|
46
|
+
.l:hover .a{color:#34d399}
|
|
47
|
+
.e{
|
|
48
|
+
margin-top:24px;font-family:'SF Mono',ui-monospace,monospace;
|
|
49
|
+
font-size:11px;color:#3f3f46;line-height:2;
|
|
50
|
+
}
|
|
51
|
+
.e span{color:#52525b}
|
|
52
|
+
</style>
|
|
53
|
+
</head>
|
|
54
|
+
<body>
|
|
55
|
+
<div class="c">
|
|
56
|
+
<div class="w"><span class="d">.</span>mantiq</div>
|
|
57
|
+
<div class="v">v${mantiqVersion} — ${appName}</div>
|
|
58
|
+
<hr>
|
|
59
|
+
<div class="g">
|
|
60
|
+
<a class="l" href="/_heartbeat">Heartbeat<span class="a">→</span></a>
|
|
61
|
+
<a class="l" href="/api/ping">API Ping<span class="a">→</span></a>
|
|
62
|
+
<a class="l" href="https://github.com/mantiqjs/mantiq" target="_blank" rel="noopener">GitHub<span class="a">↗</span></a>
|
|
63
|
+
<a class="l" href="https://www.npmjs.com/org/mantiq" target="_blank" rel="noopener">npm<span class="a">↗</span></a>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="e">
|
|
66
|
+
<span>Runtime</span> Bun ${bunVersion}<br>
|
|
67
|
+
<span>Environment</span> ${appEnv}<br>
|
|
68
|
+
<span>Debug</span> ${debug}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</body>
|
|
72
|
+
</html>`
|
|
73
|
+
|
|
74
|
+
return new Response(html, {
|
|
75
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' },
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Model } from '@mantiq/database'
|
|
2
|
+
import { AuthenticatableModel } from '@mantiq/auth'
|
|
3
|
+
|
|
4
|
+
export class User extends AuthenticatableModel(Model) {
|
|
5
|
+
static override fillable = ['name', 'email', 'password']
|
|
6
|
+
static override hidden = ['password', 'remember_token']
|
|
7
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ServiceProvider } from '@mantiq/core'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Application Service Provider
|
|
5
|
+
*
|
|
6
|
+
* Register application-level bindings and run bootstrap logic here.
|
|
7
|
+
* This provider is auto-discovered from app/Providers/.
|
|
8
|
+
*/
|
|
9
|
+
export class AppServiceProvider extends ServiceProvider {
|
|
10
|
+
/**
|
|
11
|
+
* Register bindings into the container.
|
|
12
|
+
* Called before any provider's boot() method.
|
|
13
|
+
*/
|
|
14
|
+
override register(): void {
|
|
15
|
+
//
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Bootstrap application services.
|
|
20
|
+
* Called after all providers have been registered.
|
|
21
|
+
*/
|
|
22
|
+
override async boot(): Promise<void> {
|
|
23
|
+
//
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ServiceProvider, config } from '@mantiq/core'
|
|
2
|
+
import { DatabaseManager, setupModels, setManager } from '@mantiq/database'
|
|
3
|
+
|
|
4
|
+
export class DatabaseServiceProvider extends ServiceProvider {
|
|
5
|
+
override register(): void {
|
|
6
|
+
this.app.singleton(DatabaseManager, () => {
|
|
7
|
+
const manager = new DatabaseManager(config('database'))
|
|
8
|
+
setManager(manager)
|
|
9
|
+
setupModels(manager)
|
|
10
|
+
return manager
|
|
11
|
+
})
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
override async boot(): Promise<void> {
|
|
15
|
+
this.app.make(DatabaseManager)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { env } from '@mantiq/core'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
default: env('AI_PROVIDER', 'openai'),
|
|
5
|
+
|
|
6
|
+
providers: {
|
|
7
|
+
openai: {
|
|
8
|
+
driver: 'openai' as const,
|
|
9
|
+
apiKey: env('OPENAI_API_KEY', ''),
|
|
10
|
+
},
|
|
11
|
+
anthropic: {
|
|
12
|
+
driver: 'anthropic' as const,
|
|
13
|
+
apiKey: env('ANTHROPIC_API_KEY', ''),
|
|
14
|
+
},
|
|
15
|
+
gemini: {
|
|
16
|
+
driver: 'gemini' as const,
|
|
17
|
+
apiKey: env('GEMINI_API_KEY', ''),
|
|
18
|
+
},
|
|
19
|
+
ollama: {
|
|
20
|
+
driver: 'ollama' as const,
|
|
21
|
+
host: env('OLLAMA_HOST', 'http://localhost'),
|
|
22
|
+
port: 11434,
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
defaultModel: env('AI_MODEL', 'gpt-4o'),
|
|
27
|
+
|
|
28
|
+
embeddings: {
|
|
29
|
+
default: 'openai',
|
|
30
|
+
providers: {},
|
|
31
|
+
defaultModel: 'text-embedding-3-small',
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
vectorStores: {
|
|
35
|
+
default: 'memory',
|
|
36
|
+
stores: {
|
|
37
|
+
memory: { driver: 'memory' as const },
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
observability: {
|
|
42
|
+
enabled: true,
|
|
43
|
+
logRequests: env('AI_LOG_REQUESTS', 'false') === 'true',
|
|
44
|
+
trackCosts: true,
|
|
45
|
+
},
|
|
46
|
+
|
|
47
|
+
limits: {
|
|
48
|
+
maxTokensPerRequest: 4096,
|
|
49
|
+
maxCostPerDay: 100.00,
|
|
50
|
+
},
|
|
51
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { env } from '@mantiq/core'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
|--------------------------------------------------------------------------
|
|
7
|
+
| Application Name
|
|
8
|
+
|--------------------------------------------------------------------------
|
|
9
|
+
|
|
|
10
|
+
| This value is the name of your application. It is used when the
|
|
11
|
+
| framework needs to place the application's name in a notification,
|
|
12
|
+
| log entry, or any other location as required by the application.
|
|
13
|
+
|
|
|
14
|
+
*/
|
|
15
|
+
name: env('APP_NAME', 'MantiqJS'),
|
|
16
|
+
|
|
17
|
+
/*
|
|
18
|
+
|--------------------------------------------------------------------------
|
|
19
|
+
| Application Environment
|
|
20
|
+
|--------------------------------------------------------------------------
|
|
21
|
+
|
|
|
22
|
+
| This value determines the "environment" your application is running in.
|
|
23
|
+
| This may influence how you configure various services the application
|
|
24
|
+
| uses. Set this in your ".env" file.
|
|
25
|
+
|
|
|
26
|
+
| Supported: 'production', 'local', 'staging', 'testing'
|
|
27
|
+
|
|
|
28
|
+
*/
|
|
29
|
+
env: env('APP_ENV', 'production'),
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
|--------------------------------------------------------------------------
|
|
33
|
+
| Application Debug Mode
|
|
34
|
+
|--------------------------------------------------------------------------
|
|
35
|
+
|
|
|
36
|
+
| When your application is in debug mode, detailed error messages with
|
|
37
|
+
| stack traces will be shown on every error. If disabled, a simple
|
|
38
|
+
| generic error page is shown. Also controls the heartbeat debug widget.
|
|
39
|
+
|
|
|
40
|
+
| WARNING: Never enable debug mode in production.
|
|
41
|
+
|
|
|
42
|
+
*/
|
|
43
|
+
debug: env('APP_DEBUG', false),
|
|
44
|
+
|
|
45
|
+
/*
|
|
46
|
+
|--------------------------------------------------------------------------
|
|
47
|
+
| Encryption Key
|
|
48
|
+
|--------------------------------------------------------------------------
|
|
49
|
+
|
|
|
50
|
+
| This key is used by the encryption service and should be set to a
|
|
51
|
+
| random, 32-character string. You should do this before deploying.
|
|
52
|
+
|
|
|
53
|
+
| Generate with: bun mantiq key:generate
|
|
54
|
+
|
|
|
55
|
+
*/
|
|
56
|
+
key: env('APP_KEY', ''),
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
|--------------------------------------------------------------------------
|
|
60
|
+
| Application URL
|
|
61
|
+
|--------------------------------------------------------------------------
|
|
62
|
+
|
|
|
63
|
+
| This URL is used by the framework to generate URLs, configure CORS
|
|
64
|
+
| origin, and properly redirect. You should set this to the root of
|
|
65
|
+
| your application so that it is used when running CLI commands.
|
|
66
|
+
|
|
|
67
|
+
*/
|
|
68
|
+
url: env('APP_URL', 'http://localhost:3000'),
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
|--------------------------------------------------------------------------
|
|
72
|
+
| Application Port
|
|
73
|
+
|--------------------------------------------------------------------------
|
|
74
|
+
|
|
|
75
|
+
| The port the HTTP server will listen on.
|
|
76
|
+
|
|
|
77
|
+
*/
|
|
78
|
+
port: Number(env('APP_PORT', '3000')),
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
|--------------------------------------------------------------------------
|
|
82
|
+
| Base Path
|
|
83
|
+
|--------------------------------------------------------------------------
|
|
84
|
+
|
|
|
85
|
+
| The absolute path to the project root directory. Used for resolving
|
|
86
|
+
| config files, routes, migrations, and other project resources.
|
|
87
|
+
|
|
|
88
|
+
*/
|
|
89
|
+
basePath: import.meta.dir + '/..',
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
|--------------------------------------------------------------------------
|
|
93
|
+
| Middleware Groups
|
|
94
|
+
|--------------------------------------------------------------------------
|
|
95
|
+
|
|
|
96
|
+
| Middleware groups are applied automatically based on the route file:
|
|
97
|
+
| routes/web.ts → 'web' group (stateful: sessions, CSRF, cookies)
|
|
98
|
+
| routes/api.ts → 'api' group (stateless: rate-limited, no sessions)
|
|
99
|
+
|
|
|
100
|
+
| Available aliases: cors, encrypt.cookies, session, csrf, throttle,
|
|
101
|
+
| auth, guest, trim, static, heartbeat
|
|
102
|
+
|
|
|
103
|
+
*/
|
|
104
|
+
middlewareGroups: {
|
|
105
|
+
web: ['cors', 'encrypt.cookies', 'session', 'csrf'],
|
|
106
|
+
api: ['cors', 'throttle'],
|
|
107
|
+
},
|
|
108
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { User } from '../app/Models/User.ts'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
|--------------------------------------------------------------------------
|
|
7
|
+
| Authentication Defaults
|
|
8
|
+
|--------------------------------------------------------------------------
|
|
9
|
+
|
|
|
10
|
+
| This option controls the default authentication "guard" for your
|
|
11
|
+
| application. You may change this to any of the guards defined below.
|
|
12
|
+
|
|
|
13
|
+
*/
|
|
14
|
+
defaults: {
|
|
15
|
+
guard: 'web',
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
/*
|
|
19
|
+
|--------------------------------------------------------------------------
|
|
20
|
+
| Authentication Guards
|
|
21
|
+
|--------------------------------------------------------------------------
|
|
22
|
+
|
|
|
23
|
+
| Guards define how users are authenticated for each request. The "web"
|
|
24
|
+
| guard uses session cookies (for browsers and SPAs). The "api" guard
|
|
25
|
+
| uses Sanctum-style bearer tokens (for mobile apps and third-party).
|
|
26
|
+
|
|
|
27
|
+
| Supported drivers: 'session', 'token'
|
|
28
|
+
|
|
|
29
|
+
| Token format: Authorization: Bearer {id}|{plaintext}
|
|
30
|
+
|
|
|
31
|
+
*/
|
|
32
|
+
guards: {
|
|
33
|
+
web: { driver: 'session', provider: 'users' },
|
|
34
|
+
api: { driver: 'token', provider: 'users' },
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
/*
|
|
38
|
+
|--------------------------------------------------------------------------
|
|
39
|
+
| User Providers
|
|
40
|
+
|--------------------------------------------------------------------------
|
|
41
|
+
|
|
|
42
|
+
| Providers define how users are retrieved from your database. The
|
|
43
|
+
| "database" driver queries the model specified below.
|
|
44
|
+
|
|
|
45
|
+
| Supported drivers: 'database'
|
|
46
|
+
|
|
|
47
|
+
*/
|
|
48
|
+
providers: {
|
|
49
|
+
users: { driver: 'database', model: User },
|
|
50
|
+
},
|
|
51
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { env } from '@mantiq/core'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
|--------------------------------------------------------------------------
|
|
7
|
+
| Realtime Enabled
|
|
8
|
+
|--------------------------------------------------------------------------
|
|
9
|
+
|
|
|
10
|
+
| Master switch for the realtime server. When disabled, WebSocket and
|
|
11
|
+
| SSE endpoints are not registered and broadcast events are no-ops.
|
|
12
|
+
|
|
|
13
|
+
*/
|
|
14
|
+
enabled: true,
|
|
15
|
+
|
|
16
|
+
/*
|
|
17
|
+
|--------------------------------------------------------------------------
|
|
18
|
+
| Broadcast Driver
|
|
19
|
+
|--------------------------------------------------------------------------
|
|
20
|
+
|
|
|
21
|
+
| The default broadcast driver for sending real-time events to clients.
|
|
22
|
+
| The 'bun' driver works in-process with zero dependencies. Use 'redis'
|
|
23
|
+
| for multi-server deployments.
|
|
24
|
+
|
|
|
25
|
+
| Supported: 'bun', 'redis', 'log', 'null'
|
|
26
|
+
|
|
|
27
|
+
*/
|
|
28
|
+
driver: env('BROADCAST_DRIVER', 'bun'),
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
|--------------------------------------------------------------------------
|
|
32
|
+
| WebSocket Server
|
|
33
|
+
|--------------------------------------------------------------------------
|
|
34
|
+
|
|
|
35
|
+
| Bun's native WebSocket server handles real-time connections. Clients
|
|
36
|
+
| connect to ws://host:port/<path>. The server sends heartbeat pings
|
|
37
|
+
| and closes idle connections after the timeout.
|
|
38
|
+
|
|
|
39
|
+
*/
|
|
40
|
+
websocket: {
|
|
41
|
+
path: '/ws',
|
|
42
|
+
maxConnectionsPerUser: 10, // Per-user limit (0 = unlimited)
|
|
43
|
+
maxConnections: 0, // Total limit (0 = unlimited)
|
|
44
|
+
heartbeatInterval: 25_000, // Ping interval (ms)
|
|
45
|
+
heartbeatTimeout: 10_000, // Close if no pong after (ms)
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
|--------------------------------------------------------------------------
|
|
50
|
+
| Server-Sent Events (SSE) Fallback
|
|
51
|
+
|--------------------------------------------------------------------------
|
|
52
|
+
|
|
|
53
|
+
| SSE provides a fallback for clients that can't use WebSockets
|
|
54
|
+
| (corporate proxies, older browsers). One-directional: server → client.
|
|
55
|
+
|
|
|
56
|
+
*/
|
|
57
|
+
sse: {
|
|
58
|
+
enabled: true,
|
|
59
|
+
path: '/_sse',
|
|
60
|
+
keepAliveInterval: 15_000, // Keep-alive ping interval (ms)
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
|--------------------------------------------------------------------------
|
|
65
|
+
| Presence Channels
|
|
66
|
+
|--------------------------------------------------------------------------
|
|
67
|
+
|
|
|
68
|
+
| Presence channels track which users are currently subscribed.
|
|
69
|
+
| memberTtl controls how long a disconnected user stays in the member
|
|
70
|
+
| list before being removed (handles brief network interruptions).
|
|
71
|
+
|
|
|
72
|
+
*/
|
|
73
|
+
presence: {
|
|
74
|
+
memberTtl: 30_000, // Remove member after disconnect (ms)
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
/*
|
|
78
|
+
|--------------------------------------------------------------------------
|
|
79
|
+
| Redis Driver
|
|
80
|
+
|--------------------------------------------------------------------------
|
|
81
|
+
|
|
|
82
|
+
| When using the 'redis' broadcast driver, events are published to
|
|
83
|
+
| Redis pub/sub. This allows multiple server instances to broadcast
|
|
84
|
+
| to each other's connected clients.
|
|
85
|
+
|
|
|
86
|
+
*/
|
|
87
|
+
redis: {
|
|
88
|
+
host: env('REDIS_HOST', '127.0.0.1'),
|
|
89
|
+
port: Number(env('REDIS_PORT', '6379')),
|
|
90
|
+
password: env('REDIS_PASSWORD', ''),
|
|
91
|
+
prefix: 'mantiq_realtime:',
|
|
92
|
+
},
|
|
93
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { env } from '@mantiq/core'
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
|
|
5
|
+
/*
|
|
6
|
+
|--------------------------------------------------------------------------
|
|
7
|
+
| Default Cache Store
|
|
8
|
+
|--------------------------------------------------------------------------
|
|
9
|
+
|
|
|
10
|
+
| This option controls the default cache connection that gets used
|
|
11
|
+
| while using this caching library. You may use any of the stores
|
|
12
|
+
| defined in the "stores" object below.
|
|
13
|
+
|
|
|
14
|
+
| Supported: 'memory', 'file', 'redis', 'memcached', 'null'
|
|
15
|
+
|
|
|
16
|
+
*/
|
|
17
|
+
default: env('CACHE_STORE', 'memory'),
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
|--------------------------------------------------------------------------
|
|
21
|
+
| Cache Key Prefix
|
|
22
|
+
|--------------------------------------------------------------------------
|
|
23
|
+
|
|
|
24
|
+
| When utilizing a RAM-based store such as Redis or Memcached, there
|
|
25
|
+
| might be other applications using the same cache. To avoid collisions,
|
|
26
|
+
| you may prefix every cache key.
|
|
27
|
+
|
|
|
28
|
+
*/
|
|
29
|
+
prefix: env('CACHE_PREFIX', 'mantiq_cache_'),
|
|
30
|
+
|
|
31
|
+
/*
|
|
32
|
+
|--------------------------------------------------------------------------
|
|
33
|
+
| Cache Stores
|
|
34
|
+
|--------------------------------------------------------------------------
|
|
35
|
+
|
|
|
36
|
+
| Here you may define all of the cache "stores" for your application
|
|
37
|
+
| as well as their drivers. You may even define multiple stores for
|
|
38
|
+
| the same driver to group types of items stored in your caches.
|
|
39
|
+
|
|
|
40
|
+
*/
|
|
41
|
+
stores: {
|
|
42
|
+
memory: {},
|
|
43
|
+
|
|
44
|
+
file: {
|
|
45
|
+
path: 'storage/cache',
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
redis: {
|
|
49
|
+
url: env('REDIS_URL', ''),
|
|
50
|
+
host: env('REDIS_HOST', '127.0.0.1'),
|
|
51
|
+
port: Number(env('REDIS_PORT', '6379')),
|
|
52
|
+
password: env('REDIS_PASSWORD', ''),
|
|
53
|
+
db: Number(env('REDIS_CACHE_DB', '1')),
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
memcached: {
|
|
57
|
+
host: env('MEMCACHED_HOST', '127.0.0.1'),
|
|
58
|
+
port: Number(env('MEMCACHED_PORT', '11211')),
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
}
|