@appweaver/cli 1.0.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 +1 -0
- package/README.md +7 -0
- package/build/build-command.d.ts +2 -0
- package/build/build-command.js +15 -0
- package/build/build-project.d.ts +8 -0
- package/build/build-project.js +19 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +18 -0
- package/generate/generate-command.d.ts +2 -0
- package/generate/generate-command.js +38 -0
- package/generate/generate-schema.d.ts +12 -0
- package/generate/generate-schema.js +475 -0
- package/generate/generate-types.d.ts +10 -0
- package/generate/generate-types.js +86 -0
- package/generate/index.d.ts +3 -0
- package/generate/index.js +19 -0
- package/migrate/index.d.ts +1 -0
- package/migrate/index.js +17 -0
- package/migrate/migrate-command.d.ts +2 -0
- package/migrate/migrate-command.js +13 -0
- package/migration/index.d.ts +1 -0
- package/migration/index.js +17 -0
- package/migration/migration-command.d.ts +2 -0
- package/migration/migration-command.js +34 -0
- package/openapi/index.d.ts +1 -0
- package/openapi/index.js +17 -0
- package/openapi/openapi-command.d.ts +2 -0
- package/openapi/openapi-command.js +46 -0
- package/package.json +56 -0
- package/seed/index.d.ts +1 -0
- package/seed/index.js +17 -0
- package/seed/seed-command.d.ts +2 -0
- package/seed/seed-command.js +33 -0
- package/skill/GUIDELINES.md +298 -0
- package/skill/SKILL.md +593 -0
- package/skill/references/cache.md +207 -0
- package/skill/references/cli.md +213 -0
- package/skill/references/client.md +507 -0
- package/skill/references/configuration.md +402 -0
- package/skill/references/database.md +134 -0
- package/skill/references/dependency-injection.md +214 -0
- package/skill/references/events.md +152 -0
- package/skill/references/mailer.md +235 -0
- package/skill/references/queue.md +196 -0
- package/skill/references/resources.md +961 -0
- package/skill/references/scheduler.md +184 -0
- package/skill/references/security.md +694 -0
- package/skill/references/storage.md +251 -0
- package/start/index.d.ts +2 -0
- package/start/index.js +18 -0
- package/start/start-command.d.ts +2 -0
- package/start/start-command.js +17 -0
- package/start/start-project.d.ts +8 -0
- package/start/start-project.js +147 -0
- package/testing/index.d.ts +1 -0
- package/testing/index.js +17 -0
- package/testing/testing-command.d.ts +2 -0
- package/testing/testing-command.js +96 -0
- package/update/index.d.ts +2 -0
- package/update/index.js +18 -0
- package/update/update-command.d.ts +2 -0
- package/update/update-command.js +84 -0
- package/update/update-packages.d.ts +10 -0
- package/update/update-packages.js +45 -0
- package/update/update-skill.d.ts +8 -0
- package/update/update-skill.js +93 -0
- package/utils/index.d.ts +3 -0
- package/utils/index.js +19 -0
- package/utils/loader-util.d.ts +29 -0
- package/utils/loader-util.js +132 -0
- package/utils/path-util.d.ts +41 -0
- package/utils/path-util.js +98 -0
- package/utils/process-util.d.ts +39 -0
- package/utils/process-util.js +92 -0
- package/weaver.d.ts +2 -0
- package/weaver.js +53 -0
package/skill/SKILL.md
ADDED
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: appweaver
|
|
3
|
+
description: >
|
|
4
|
+
Use this skill whenever the user is building, debugging, scaffolding, or
|
|
5
|
+
asking questions about Appweaver - a web development library. Triggers
|
|
6
|
+
include: any mention of 'Appweaver', requests to create backend server logic,
|
|
7
|
+
configurations, resources, models, routes, services and security policy,
|
|
8
|
+
questions about the file conventions or config system. Use this skill
|
|
9
|
+
if @appweaver npm package or Appweaver is detected anywhere in the project
|
|
10
|
+
structure of Node.js (TypeScript) project.
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Appweaver skill
|
|
14
|
+
|
|
15
|
+
## Purpose
|
|
16
|
+
|
|
17
|
+
Appweaver is a library for building web applications with TypeScript and Node.js (or Bun). It provides a set of tools
|
|
18
|
+
and conventions to simplify the development process, including file-based routing, reusable UI components, and
|
|
19
|
+
centralized configuration. It is based mainly on Fastify for web server and Prisma for database ORM. The library
|
|
20
|
+
provides a series of factory methods used for creating resource models, services, policies, and routes with predefined
|
|
21
|
+
defaults. It provides a CLI tool for building the application, starting a server, generating schema and types, executing
|
|
22
|
+
migrations, running seeders, testing, and more.
|
|
23
|
+
|
|
24
|
+
## Project structure
|
|
25
|
+
|
|
26
|
+
The basic file structure of the Appweaver project:
|
|
27
|
+
|
|
28
|
+
- `database/` - database migrations, seeders, generated prisma client, and client used by the application
|
|
29
|
+
- `dist/` - the output directory for transpiled JavaScript files
|
|
30
|
+
- `public/` - publicly exposed files if static file serving is enabled
|
|
31
|
+
- `src/features/` - main application logic structured using vertical slice architecture (VSA)
|
|
32
|
+
- `src/resources/` - application resources (models, services, policies, and routes)
|
|
33
|
+
- `src/types/` - application types (generated and manually created)
|
|
34
|
+
- `src/main.ts` - the main application entrypoint
|
|
35
|
+
- `test/e2e/` - the end-to-end tests root directory
|
|
36
|
+
- `test/unit/` - the unit tests root directory
|
|
37
|
+
- `.env` - override the central configuration (optional)
|
|
38
|
+
- `.env.{env}` - override the central configuration for specific envirnment (optional)
|
|
39
|
+
- `appweaver.json` - central library configuration file
|
|
40
|
+
- `appweaver.{env}.json` - environment specific configuration files that override the central configuration
|
|
41
|
+
- `Dockerfile` - the dockerfile used for building a docker image for deploying the application
|
|
42
|
+
|
|
43
|
+
**IMPORTANT:** `{env}` is controlled by `NODE_ENV` environment variable set before any command is executed (can also be
|
|
44
|
+
set in the `.env` file).
|
|
45
|
+
|
|
46
|
+
## Core patterns
|
|
47
|
+
|
|
48
|
+
### Scaffolding a new application
|
|
49
|
+
|
|
50
|
+
Use `create-weaver-app` to scaffold a new project. It copies a default template, installs dependencies, and generates
|
|
51
|
+
initial Prisma schema and models.
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
create-weaver-app <name> [description] [options]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
**Options:**
|
|
58
|
+
|
|
59
|
+
| Flag | Description | Default |
|
|
60
|
+
|-------------------|----------------------------------------------------------------|--------------|
|
|
61
|
+
| `-o, --outputDir` | Output directory (use ./ for current working directory) | project name |
|
|
62
|
+
| `--database` | Database type: `sqlite`, `postgresql`, `mysql`, `sqlserver` | `sqlite` |
|
|
63
|
+
| `--host` | Hostname or IP address where the application server will bind. | 0.0.0.0 |
|
|
64
|
+
| `--port` | Port number where the application server will listen. | 5000 |
|
|
65
|
+
| `--agent` | The AI agent for which to configure guidelines and skill files | `claude` |
|
|
66
|
+
| `--bun` | Use Bun as application runtime. (default is node and npm) | false |
|
|
67
|
+
| `--skipInstall` | Skip all dependencies installation. | false |
|
|
68
|
+
| `--noRedis` | Skip ioredis | false |
|
|
69
|
+
| `--noQueue` | Skip bullmq | false |
|
|
70
|
+
| `--noMailer` | Skip nodemailer | false |
|
|
71
|
+
| `--noCron` | Skip cron | false |
|
|
72
|
+
|
|
73
|
+
**Example — PostgreSQL project without queue:**
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
create-weaver-app MyBlogAPI "My own CMS for blogging" --database postgresql --noQueue
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This creates a `./my-blog-api` directory, installs all dependencies, and runs the initial schema and type generation.
|
|
80
|
+
Default test runner is `jest` with `swc` transpiler.
|
|
81
|
+
|
|
82
|
+
**Example — Bun project with Sqlite:**
|
|
83
|
+
|
|
84
|
+
```sh
|
|
85
|
+
create-weaver-app BunApp "Bun application with simple API" --bun --database sqlite
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This creates a `./bun-app` directory, installs all dependencies using bun package manager, and runs the initial
|
|
89
|
+
schema and type generation. Default test runner is `bun`.
|
|
90
|
+
|
|
91
|
+
After the application is scaffolded, the following commands need to be run to finish the application setup:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
npx weaver migration new init # use --no-install flag if npx tries to install package
|
|
95
|
+
npm run seed
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Or, for bun runtime:
|
|
99
|
+
|
|
100
|
+
```sh
|
|
101
|
+
bun weaver migration new init
|
|
102
|
+
bun run seed
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Creating and starting the application server
|
|
106
|
+
|
|
107
|
+
The main entrypoint to the application. This function creates an application object and initializes all resources and
|
|
108
|
+
services.
|
|
109
|
+
|
|
110
|
+
Default application bootstrap:
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
// src/main.ts
|
|
114
|
+
import { createApp } from '@appweaver/core';
|
|
115
|
+
import { logger } from '@appweaver/common';
|
|
116
|
+
|
|
117
|
+
createApp().catch((err) => logger.error(err));
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Manually starting an application:
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
// src/main.ts
|
|
124
|
+
import { createApp } from '@appweaver/core';
|
|
125
|
+
import { logger } from '@appweaver/common';
|
|
126
|
+
|
|
127
|
+
const app = createApp({ autoStart: false, scanPath: './dist/my/app/path' });
|
|
128
|
+
|
|
129
|
+
// custom init logic...
|
|
130
|
+
|
|
131
|
+
app.start().then(address => {
|
|
132
|
+
logger.info(address);
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Creating resources
|
|
137
|
+
|
|
138
|
+
Resources are the core building blocks for a web application. There are four resource types: **model**, **service**,
|
|
139
|
+
**routes**, and **policy**. Created and exported resources are loaded automatically on application start. Except for a
|
|
140
|
+
resource model, other resource types are optional and do not need to be created. If a service is created, then a model
|
|
141
|
+
must be also created. If routes are created, then service must be created. Only policy is not required for other
|
|
142
|
+
resources.
|
|
143
|
+
|
|
144
|
+
Dependency chain: **model** → **service** → **routes** → **policy**
|
|
145
|
+
|
|
146
|
+
**DOS:**
|
|
147
|
+
|
|
148
|
+
- Use default configuration values whenever possible
|
|
149
|
+
- Rely on library defaults for `omit`/`pick`, ad `input`/`output` settings
|
|
150
|
+
- Use default `mimeType` and `namePattern` patterns in file configurations unless specifically requested
|
|
151
|
+
- Prefer storing configuration in JSON file (`appweaver.json`) over environment (`.env`) file, but prefer it for secrets
|
|
152
|
+
- Always create all four resource configs (model, service, routes, and policy) unless specified otherwise
|
|
153
|
+
|
|
154
|
+
**DON'TS:**
|
|
155
|
+
|
|
156
|
+
- Don't explicitly set default values in configuration unless specifically requested
|
|
157
|
+
- Don't override `omit`/`pick` for `read`, `create` and `update` settings unnecessarily
|
|
158
|
+
- Don't specify `input`/`output` configurations if defaults suffice
|
|
159
|
+
- Don't modify file's `mimeType` and `namePattern` patterns unless specifically instructed
|
|
160
|
+
- Don't customize index arrays without an explicit requirement
|
|
161
|
+
|
|
162
|
+
#### Creating a resource model
|
|
163
|
+
|
|
164
|
+
Resource model defines all aspects of the domain model: database table fields, relations, files, virtual fields, CRUD
|
|
165
|
+
data transfer objects. The exported model is used to construct Prisma schema, generate TypeScript types for all model
|
|
166
|
+
variations, define schema for CRUD routes, and input/output arguments to resource service methods.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
// src/resources/product/model.ts
|
|
170
|
+
import { createModel } from '@appweaver/core';
|
|
171
|
+
|
|
172
|
+
export default createModel({
|
|
173
|
+
name: 'Product',
|
|
174
|
+
scalars: {
|
|
175
|
+
title: {
|
|
176
|
+
type: 'string',
|
|
177
|
+
minLength: 1,
|
|
178
|
+
maxLength: 200
|
|
179
|
+
},
|
|
180
|
+
price: {
|
|
181
|
+
type: 'float',
|
|
182
|
+
minimum: 0
|
|
183
|
+
},
|
|
184
|
+
status: {
|
|
185
|
+
type: 'enum',
|
|
186
|
+
default: 'Draft',
|
|
187
|
+
values: ['Draft', 'Active', 'Sold']
|
|
188
|
+
},
|
|
189
|
+
description: {
|
|
190
|
+
type: 'string',
|
|
191
|
+
required: false
|
|
192
|
+
},
|
|
193
|
+
lastViewedAt: {
|
|
194
|
+
type: 'dateTime',
|
|
195
|
+
defaultGenerator: 'now()'
|
|
196
|
+
},
|
|
197
|
+
enabled: {
|
|
198
|
+
type: 'boolean',
|
|
199
|
+
default: true
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
relations: {
|
|
203
|
+
category: {
|
|
204
|
+
model: 'Category',
|
|
205
|
+
mappedBy: 'products',
|
|
206
|
+
owner: true,
|
|
207
|
+
output: {
|
|
208
|
+
type: 'always'
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
files: {
|
|
213
|
+
photo: {
|
|
214
|
+
mimeType: 'image/*',
|
|
215
|
+
maxSize: '2 MB'
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
create: {
|
|
219
|
+
omit: ['status']
|
|
220
|
+
},
|
|
221
|
+
update: {
|
|
222
|
+
pick: ['title', 'price', 'status', 'description']
|
|
223
|
+
},
|
|
224
|
+
index: ['title']
|
|
225
|
+
});
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
#### Creating a resource service
|
|
229
|
+
|
|
230
|
+
Resource service defines the business logic layer for a resource: lifecycle hooks (before/after create, update, delete),
|
|
231
|
+
custom data access behavior, and text search configuration. The exported service is automatically invoked by the CRUD
|
|
232
|
+
route handlers to perform database operations for a bound model and trigger side effects.
|
|
233
|
+
|
|
234
|
+
```ts
|
|
235
|
+
// src/resources/product/service.ts
|
|
236
|
+
import { createService } from '@appweaver/core';
|
|
237
|
+
|
|
238
|
+
export default createService({
|
|
239
|
+
modelName: 'Product',
|
|
240
|
+
afterCreate: (resource) => {
|
|
241
|
+
console.log('Product created:', resource.id);
|
|
242
|
+
},
|
|
243
|
+
textSearch: {
|
|
244
|
+
title: {
|
|
245
|
+
contains: '{input}',
|
|
246
|
+
mode: 'insensitive'
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### Creating the resource routes
|
|
253
|
+
|
|
254
|
+
Resource routes define which CRUD endpoints are exposed for a resource and how they behave: the base URL path,
|
|
255
|
+
per-operation role and permission requirements, caching settings, rate-limiting, and which operations to include or
|
|
256
|
+
exclude. The exported routes are registered automatically on application start and derive their request/response schemas
|
|
257
|
+
from the resource model.
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
// src/resources/product/routes.ts
|
|
261
|
+
import { createRoutes } from '@appweaver/core';
|
|
262
|
+
|
|
263
|
+
export default createRoutes({
|
|
264
|
+
modelName: 'Product',
|
|
265
|
+
find: {
|
|
266
|
+
cache: true,
|
|
267
|
+
roles: ['Admin', 'User'],
|
|
268
|
+
rateLimit: {
|
|
269
|
+
max: 100
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
query: {
|
|
273
|
+
cacheTTL: 5000
|
|
274
|
+
},
|
|
275
|
+
create: {
|
|
276
|
+
permissions: ['product:create']
|
|
277
|
+
},
|
|
278
|
+
delete: {
|
|
279
|
+
exclude: true
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
#### Creating a resource policy
|
|
285
|
+
|
|
286
|
+
Resource policy defines row-level security for a resource: dynamic access checks against individual resource instances,
|
|
287
|
+
read restrictions that filter which records are visible to the requester, and file access control. The service layer
|
|
288
|
+
evaluates the exported policy on every CRUD operation to enforce fine-grained authorization beyond a static role or
|
|
289
|
+
permission checks.
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
// src/resources/product/policy.ts
|
|
293
|
+
import { createPolicy } from '@appweaver/core';
|
|
294
|
+
|
|
295
|
+
export default createPolicy({
|
|
296
|
+
modelName: 'Product',
|
|
297
|
+
checkAccess: (action, resource) => resource.status === 'Draft',
|
|
298
|
+
readRestrictions: (action, resource) => {
|
|
299
|
+
enabled: true;
|
|
300
|
+
},
|
|
301
|
+
files: {
|
|
302
|
+
photo: {
|
|
303
|
+
accessType: 'public'
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
#### Creating an authentication model and service
|
|
310
|
+
|
|
311
|
+
Use `createAuthModel` and `createAuthService` instead of `createModel`/`createService` when the resource represents an
|
|
312
|
+
authenticatable user. They cannot be used independently! If an auth model is created, then also auth service must exist.
|
|
313
|
+
|
|
314
|
+
`createAuthModel` extends the config with: `email`, `passwordHash`, `verifiedEmail`, `twoFactorAuth`, `enabled`,
|
|
315
|
+
`logoutAt` scalars; a virtual `password` field (write-only); a `roles` relation; and an optional `apiKeys` relation (
|
|
316
|
+
when `SECURITY_API_KEY_ENABLED` is set).
|
|
317
|
+
|
|
318
|
+
`createAuthService` extends the config with automatic password hashing on create/update and an optional
|
|
319
|
+
`registrationData` callback to customize registration payload.
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
// src/resources/user/model.ts
|
|
323
|
+
import { createAuthModel } from '@appweaver/core';
|
|
324
|
+
|
|
325
|
+
export default createAuthModel({
|
|
326
|
+
name: 'User',
|
|
327
|
+
scalars: {
|
|
328
|
+
name: {
|
|
329
|
+
type: 'string',
|
|
330
|
+
maxLength: 100
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
files: {
|
|
334
|
+
avatar: {
|
|
335
|
+
mimeType: 'image/(png|jpeg|gif)',
|
|
336
|
+
maxSize: '2 MB'
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
```ts
|
|
343
|
+
// src/resources/user/service.ts
|
|
344
|
+
import { createAuthService } from '@appweaver/core';
|
|
345
|
+
|
|
346
|
+
export default createAuthService({
|
|
347
|
+
modelName: 'User',
|
|
348
|
+
registrationData: (_, email, password) => ({ email, password, roles: [1, 2] })
|
|
349
|
+
});
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Registering a custom route
|
|
353
|
+
|
|
354
|
+
Use `registerRoute` to register a custom [Fastify route](https://fastify.dev/docs/latest/Reference/Routes/) handler. The
|
|
355
|
+
handler is a Fastify plugin function that defines one or more routes. An optional config object controls authentication,
|
|
356
|
+
caching, and reCAPTCHA behavior.
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
// src/plugins/custom-route.ts
|
|
360
|
+
import { registerRoute, Router } from '@appweaver/core';
|
|
361
|
+
import { Type } from '@sinclair/typebox';
|
|
362
|
+
|
|
363
|
+
registerRoute(
|
|
364
|
+
async function (router: Router) {
|
|
365
|
+
router.get('/search-result', {
|
|
366
|
+
schema: {
|
|
367
|
+
summary: 'Sample search result response route',
|
|
368
|
+
response: {
|
|
369
|
+
200: Type.Ref('SearchResult')
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
handler: async () => {
|
|
373
|
+
return { message: 'Hello, world!' };
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
},
|
|
377
|
+
{ public: true, cacheTTL: 15000 }
|
|
378
|
+
);
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Registering a custom model
|
|
382
|
+
|
|
383
|
+
Use `registerModel` to register a custom [TypeBox](https://github.com/sinclairzx81/typebox) schema as a named model.
|
|
384
|
+
Registered models are added to the schema registry and can be referenced by `$ref` in route schemas.
|
|
385
|
+
|
|
386
|
+
```ts
|
|
387
|
+
// src/plugins/custom-model.ts
|
|
388
|
+
import { registerModel } from '@appweaver/core';
|
|
389
|
+
import { Type } from '@sinclair/typebox';
|
|
390
|
+
|
|
391
|
+
registerModel(
|
|
392
|
+
Type.Object(
|
|
393
|
+
{
|
|
394
|
+
id: Type.Number(),
|
|
395
|
+
title: Type.String(),
|
|
396
|
+
score: Type.Number({ minimum: 0, maximum: 1 })
|
|
397
|
+
},
|
|
398
|
+
{ $id: 'SearchResult' }
|
|
399
|
+
)
|
|
400
|
+
);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Registering plugin
|
|
404
|
+
|
|
405
|
+
Use `registerPlugin` to register a custom [Fastify plugin](https://fastify.dev/docs/latest/Reference/Plugins/). Plugins
|
|
406
|
+
are registered with `fastify-plugin` so their decorators and hooks are scoped to the entire server. You can declare
|
|
407
|
+
optional dependencies on other named plugins.
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
// src/plugins/audit-log.ts
|
|
411
|
+
import { registerPlugin } from '@appweaver/core';
|
|
412
|
+
|
|
413
|
+
registerPlugin(
|
|
414
|
+
'audit-log',
|
|
415
|
+
async (server) => {
|
|
416
|
+
server.addHook('onResponse', async (request, reply) => {
|
|
417
|
+
console.log(`${request.method} ${request.url} → ${reply.statusCode}`);
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
);
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Dependency injection
|
|
424
|
+
|
|
425
|
+
Use `define` to register a value or class in the app context, and `inject` to retrieve it. Class constructors are
|
|
426
|
+
lazily instantiated as singletons on the first injection.
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
import { Cache } from '@appweaver/common';
|
|
430
|
+
import { define, inject } from '@appweaver/core';
|
|
431
|
+
|
|
432
|
+
define(RedisCacheService, Cache); // register class under abstract token
|
|
433
|
+
define('https://api.example.com', 'ApiBaseUrl'); // register plain value
|
|
434
|
+
|
|
435
|
+
const cache = inject(Cache); // resolves singleton instance
|
|
436
|
+
const url = inject<string>('ApiBaseUrl'); // resolves by string token
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Use `loadProvider` to dynamically load a class from a file path or npm package and register it under an abstract token.
|
|
440
|
+
This is the standard pattern for wiring infrastructure providers in `main.ts`.
|
|
441
|
+
|
|
442
|
+
```ts
|
|
443
|
+
import { loadProvider } from '@appweaver/core';
|
|
444
|
+
import { Database, Cache } from '@appweaver/common';
|
|
445
|
+
|
|
446
|
+
loadProvider(__dirname, config.DATABASE_PROVIDER, Database); // required provider
|
|
447
|
+
loadProvider(__dirname, config.CACHE_PROVIDER, Cache);
|
|
448
|
+
loadProvider(__dirname, config.MAILER_PROVIDER, Mailer, false); // optional (no error if provider cannot be loaded)
|
|
449
|
+
|
|
450
|
+
const cache: Mailer | undefined = inject(Mailer, false); // optional injection
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
### Writing a seeder
|
|
454
|
+
|
|
455
|
+
A seeder is a TypeScript file that must export at least one asynchronous function responsible for executing database
|
|
456
|
+
seeding logic. Seeder files follow the same conventions as migration files: they can only be executed once, and their
|
|
457
|
+
execution status is recorded in the database table `_seeders`. Seeders are executed in alphabetical order; therefore,
|
|
458
|
+
the recommended naming convention is to prefix the filename with an ordinal number (e.g., `001-create-admin-user.ts`).
|
|
459
|
+
|
|
460
|
+
During execution of seeder functions, the full application context is available, which means it is possible to inject
|
|
461
|
+
any service or model previously defined in the main application logic or exported from other NPM packages.
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
// database/seeders/001-create-admin-user.ts
|
|
465
|
+
|
|
466
|
+
import { hashPassword } from '@appweaver/core';
|
|
467
|
+
import { config, randomString } from '@appweaver/common';
|
|
468
|
+
import { db } from '@db/client';
|
|
469
|
+
|
|
470
|
+
export async function createAdminUser(): Promise<void> {
|
|
471
|
+
await db.user.create({
|
|
472
|
+
data: {
|
|
473
|
+
firstName: 'Admin',
|
|
474
|
+
lastName: 'Admin',
|
|
475
|
+
email: 'admin@appweaver.com',
|
|
476
|
+
phone: '01234435',
|
|
477
|
+
roles: {
|
|
478
|
+
connectOrCreate: [
|
|
479
|
+
{
|
|
480
|
+
where: { name: 'Admin' },
|
|
481
|
+
create: {
|
|
482
|
+
name: 'Admin',
|
|
483
|
+
permissions: {
|
|
484
|
+
connectOrCreate: [
|
|
485
|
+
{ where: { name: '*.read' }, create: { name: '*.read' } },
|
|
486
|
+
{ where: { name: '*.write' }, create: { name: '*.write' } }
|
|
487
|
+
]
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
]
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Common tasks
|
|
499
|
+
|
|
500
|
+
### Build application
|
|
501
|
+
|
|
502
|
+
```sh
|
|
503
|
+
weaver build
|
|
504
|
+
weaver build --project tsconfig.build.json # path to tsconfig build file
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
### Start application
|
|
508
|
+
|
|
509
|
+
```sh
|
|
510
|
+
weaver start # production
|
|
511
|
+
weaver start --watch # development (watch mode)
|
|
512
|
+
weaver start --project tsconfig.json # path to tsconfig file
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Generate types and schema
|
|
516
|
+
|
|
517
|
+
```sh
|
|
518
|
+
weaver generate --types # TypeScript types only
|
|
519
|
+
weaver generate --schema # Prisma schema only
|
|
520
|
+
weaver generate --types --schema # both (same as with no option flags)
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Run database migrations
|
|
524
|
+
|
|
525
|
+
```sh
|
|
526
|
+
weaver migrate # run pending migrations
|
|
527
|
+
weaver migration new <name> # create a new migration
|
|
528
|
+
weaver migration reset # reset database (prompts confirmation)
|
|
529
|
+
weaver migration reset --force --yes # force reset, skip confirmation
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
### Seed the database
|
|
533
|
+
|
|
534
|
+
```sh
|
|
535
|
+
weaver seed # run seeders
|
|
536
|
+
weaver seed --buildProject # build project first, then run seeders
|
|
537
|
+
weaver seed --continueOnError # continue if a seeder throws error
|
|
538
|
+
weaver seed --fixWarnings # fix all warnings like invalid checksum or missing seeder
|
|
539
|
+
weaver seed --project tsconfig.build.json # path to tsconfig build file
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Generate OpenAPI specification
|
|
543
|
+
|
|
544
|
+
```sh
|
|
545
|
+
weaver openapi # generate schema to ./openapi.json
|
|
546
|
+
weaver openapi --outputPath ./generated/openapi.json # generate schema to a custom path
|
|
547
|
+
weaver openapi --format yaml # generate schema in yaml format
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Update Appweaver packages
|
|
551
|
+
|
|
552
|
+
```sh
|
|
553
|
+
weaver update # update all @appweaver/* packages to latest
|
|
554
|
+
weaver update @appweaver/core @appweaver/cli # update specific packages
|
|
555
|
+
weaver update --targetVersion 1.2.3 # update to a specific version
|
|
556
|
+
weaver update --noSkill # skip updating AI agent skill files
|
|
557
|
+
weaver update --force # force update despite peerDependency mismatches
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### Run tests
|
|
561
|
+
|
|
562
|
+
```sh
|
|
563
|
+
npm run test # unit tests with coverage
|
|
564
|
+
npm run e2e # e2e tests
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### Format code
|
|
568
|
+
|
|
569
|
+
```sh
|
|
570
|
+
npm run format # prettier --write "./**/*.ts"
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
### Lint code
|
|
574
|
+
|
|
575
|
+
```sh
|
|
576
|
+
npm run lint # eslint "./**/*.ts"
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
## References
|
|
580
|
+
|
|
581
|
+
- Application CLI (weaver): [cli.md](references/cli.md)
|
|
582
|
+
- Application configuration: [configuration.md](references/configuration.md)
|
|
583
|
+
- Application resources: [resources.md](references/resources.md)
|
|
584
|
+
- Dependency injection: [dependency-injection.md](references/dependency-injection.md)
|
|
585
|
+
- Security details: [security.md](references/security.md)
|
|
586
|
+
- Storage & File management: [storage.md](references/storage.md)
|
|
587
|
+
- Database & Migrations: [database.md](references/database.md)
|
|
588
|
+
- Events & Hooks: [events.md](references/events.md)
|
|
589
|
+
- Cache management: [cache.md](references/cache.md)
|
|
590
|
+
- Queue jobs: [queue.md](references/queue.md)
|
|
591
|
+
- Scheduling jobs: [scheduler.md](references/scheduler.md)
|
|
592
|
+
- Sending emails: [mailer.md](references/mailer.md)
|
|
593
|
+
- Generating an HTTP client for using API: [client.md](references/client.md)
|