@appweaver/cli 1.1.2 → 1.1.4
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
CHANGED
package/skill/GUIDELINES.md
CHANGED
|
@@ -285,6 +285,13 @@ export async function createAdminUser(): Promise<void> {
|
|
|
285
285
|
| `weaver update` | Update all @appweaver/* packages |
|
|
286
286
|
| `weaver openapi` | Generate OpenAPI specification |
|
|
287
287
|
|
|
288
|
+
## Testing
|
|
289
|
+
|
|
290
|
+
- Test files must use the **`.test.ts`** extension.
|
|
291
|
+
- Unit tests live in `test/unit/`, end-to-end tests in `test/e2e/`; name each file after the module it covers.
|
|
292
|
+
- Add or update tests whenever a feature is added or existing behaviour changes, and run `npm run test` before
|
|
293
|
+
considering the task done.
|
|
294
|
+
|
|
288
295
|
## References
|
|
289
296
|
|
|
290
297
|
- Application CLI (weaver): [cli.md](references/cli.md)
|
package/skill/SKILL.md
CHANGED
|
@@ -569,6 +569,9 @@ npm run test # unit tests with coverage
|
|
|
569
569
|
npm run e2e # e2e tests
|
|
570
570
|
```
|
|
571
571
|
|
|
572
|
+
Test files must use the **`.test.ts`** extension. Place unit tests in `test/unit/` and end-to-end tests in `test/e2e/`,
|
|
573
|
+
naming each file after its module. Add or update tests whenever a feature is added or existing behaviour changes.
|
|
574
|
+
|
|
572
575
|
### Format code
|
|
573
576
|
|
|
574
577
|
```sh
|
|
@@ -117,7 +117,7 @@ The config object is frozen with `Object.freeze()` after loading to prevent runt
|
|
|
117
117
|
| `SERVER_TRUST_PROXY` | boolean | `true` | Trust `X-Forwarded-*` headers from reverse proxies. |
|
|
118
118
|
| `SERVER_REQUEST_LOGGING_ENABLED` | boolean | `false` | Enable HTTP request/response logging. |
|
|
119
119
|
|
|
120
|
-
### Rate limiting (
|
|
120
|
+
### Rate limiting (RATE_LIMIT_\*)
|
|
121
121
|
|
|
122
122
|
| Property | Type | Default | Description |
|
|
123
123
|
|-------------------------|-----------|-----------|------------------------------------------------------------------|
|
|
@@ -135,7 +135,7 @@ The config object is frozen with `Object.freeze()` after loading to prevent runt
|
|
|
135
135
|
| `SWAGGER_PATH` | string | `'/swagger'` | URL path for the Swagger UI. |
|
|
136
136
|
| `SWAGGER_HIDE_UNTAGGED` | boolean | `false` | Hide untagged endpoints from documentation. |
|
|
137
137
|
|
|
138
|
-
### Health check (
|
|
138
|
+
### Health check (HEALTH_CHECK_\*)
|
|
139
139
|
|
|
140
140
|
| Property | Type | Default | Description |
|
|
141
141
|
|-------------------------------|-----------|-------------|---------------------------------------------------------------|
|
|
@@ -306,13 +306,14 @@ The config object is frozen with `Object.freeze()` after loading to prevent runt
|
|
|
306
306
|
|
|
307
307
|
### File storage (STORAGE\_\*)
|
|
308
308
|
|
|
309
|
-
| Property | Type | Default | Description
|
|
310
|
-
|
|
311
|
-
| `STORAGE_PATH` | string | `'./storage'` | Base directory for file storage.
|
|
312
|
-
| `
|
|
313
|
-
| `
|
|
314
|
-
| `
|
|
315
|
-
| `
|
|
309
|
+
| Property | Type | Default | Description |
|
|
310
|
+
|------------------------------|---------|------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
311
|
+
| `STORAGE_PATH` | string | `'./storage'` | Base directory for file storage. |
|
|
312
|
+
| `STORAGE_RESERVED_PATHS` | array | `['keys']` | Paths inside the storage directory that files can never be stored under. Each entry is a directory or a full file name relative to `STORAGE_PATH`, matched case-insensitively (no wildcards). Violations fail on startup for configured name patterns, and with a `400` error at runtime. |
|
|
313
|
+
| `STORAGE_NAME_PATTERN` | string | `'{name}-{hash}.{extension}'` | File naming pattern for stored files. |
|
|
314
|
+
| `STORAGE_CACHE_TTL` | integer | `86400000` | File storage cache TTL in milliseconds. (24h) |
|
|
315
|
+
| `STORAGE_FILES_ROUTE_PREFIX` | string | `/files` | URL prefix for file access routes. |
|
|
316
|
+
| `STORAGE_PROVIDER` | string | `'@appweaver/core/storage/filesystem-storage'` | Storage provider implementation path. |
|
|
316
317
|
|
|
317
318
|
### Redis (REDIS\_\*)
|
|
318
319
|
|
|
@@ -17,8 +17,8 @@ Appweaver supports four authentication methods that can be used independently or
|
|
|
17
17
|
| API Key | `SECURITY_API_KEY_ENABLED` | `x-api-key: <id><delimiter><secret>` |
|
|
18
18
|
| OAuth2 | Per-provider flags | Browser redirect flow |
|
|
19
19
|
|
|
20
|
-
When multiple methods are enabled, the authentication middleware tries each in order. A request is authenticated if
|
|
21
|
-
|
|
20
|
+
When multiple methods are enabled, the authentication middleware tries each in order. A request is authenticated if any
|
|
21
|
+
one method succeeds. If no credentials are present for any method, a 401 error is returned.
|
|
22
22
|
|
|
23
23
|
### Route authentication configuration
|
|
24
24
|
|
|
@@ -53,9 +53,11 @@ if `SECURITY_JWT_SECRET` is set.
|
|
|
53
53
|
|
|
54
54
|
### Key management
|
|
55
55
|
|
|
56
|
-
- RSA 2048-bit key pair generated automatically if `SECURITY_JWT_AUTO_GENERATE_KEYS` is `true` and key files are
|
|
57
|
-
missing
|
|
56
|
+
- RSA 2048-bit key pair generated automatically if `SECURITY_JWT_AUTO_GENERATE_KEYS` is `true` and key files are missing
|
|
58
57
|
- Keys stored at `SECURITY_JWT_PUBLIC_KEY_PATH` and `SECURITY_JWT_PRIVATE_KEY_PATH` (default: `./storage/keys/`)
|
|
58
|
+
- Generated keys are written with owner-only permissions (`0600` for the private key, `0700` for its directory)
|
|
59
|
+
- The default `STORAGE_RESERVED_PATHS` value (`['keys']`) makes the `keys` directory unusable by the file storage layer,
|
|
60
|
+
so uploads can never overwrite the default key location
|
|
59
61
|
- If `SECURITY_JWT_SECRET` is set, HMAC signing is used instead of RSA
|
|
60
62
|
|
|
61
63
|
### Token types and scopes
|
|
@@ -121,8 +123,8 @@ When enabled, requests with an `Authorization: Basic` header are authenticated a
|
|
|
121
123
|
}
|
|
122
124
|
```
|
|
123
125
|
|
|
124
|
-
Uses `@fastify/basic-auth` plugin. Extracts Base64-encoded `username:password` from the header and validates against
|
|
125
|
-
|
|
126
|
+
Uses `@fastify/basic-auth` plugin. Extracts Base64-encoded `username:password` from the header and validates against the
|
|
127
|
+
user's stored password hash.
|
|
126
128
|
|
|
127
129
|
---
|
|
128
130
|
|
|
@@ -185,8 +187,8 @@ Default delimiter is `AK`, so a key looks like: `42AKa1b2c3d4e5f6...`
|
|
|
185
187
|
|
|
186
188
|
## OAuth2 authentication
|
|
187
189
|
|
|
188
|
-
Appweaver supports OAuth2 login with Google, Facebook, and a custom OpenID Connect provider. All OAuth2 providers
|
|
189
|
-
|
|
190
|
+
Appweaver supports OAuth2 login with Google, Facebook, and a custom OpenID Connect provider. All OAuth2 providers follow
|
|
191
|
+
the same flow pattern.
|
|
190
192
|
|
|
191
193
|
### OAuth2 flow
|
|
192
194
|
|
|
@@ -385,9 +387,9 @@ export default createAuthService({
|
|
|
385
387
|
});
|
|
386
388
|
```
|
|
387
389
|
|
|
388
|
-
**User avatar** — the provider's avatar/picture URL is passed to `registrationData` as `additionalData.avatarUrl`.
|
|
389
|
-
|
|
390
|
-
|
|
390
|
+
**User avatar** — the provider's avatar/picture URL is passed to `registrationData` as `additionalData.avatarUrl`. When
|
|
391
|
+
`SECURITY_OAUTH2_FETCH_AVATAR_ENABLED=true` (JSON: `security.oauth2.fetchAvatarEnabled`), the avatar image is also
|
|
392
|
+
downloaded during registration and passed as `additionalData.avatarFile`
|
|
391
393
|
(`{ name, mimeType, size, data: Buffer }`), so it can be mapped to a model field or stored via the file service. The
|
|
392
394
|
download is best-effort: failures are logged and registration proceeds without the file.
|
|
393
395
|
|
|
@@ -716,8 +718,8 @@ Password validation is configurable via `SECURITY_PASSWORD_*` properties:
|
|
|
716
718
|
|
|
717
719
|
### Token invalidation on password change
|
|
718
720
|
|
|
719
|
-
Both `change-password` and `reset-password` set `logoutAt` to the current timestamp, which invalidates all existing
|
|
720
|
-
|
|
721
|
+
Both `change-password` and `reset-password` set `logoutAt` to the current timestamp, which invalidates all existing JWT
|
|
722
|
+
tokens across all devices. The `change-password` endpoint returns new tokens so the current session stays active.
|
|
721
723
|
|
|
722
724
|
---
|
|
723
725
|
|
|
@@ -125,23 +125,42 @@ Available placeholders:
|
|
|
125
125
|
|
|
126
126
|
Example: storing `photo.jpg` produces `photo-c7d3a1f2.jpg`.
|
|
127
127
|
|
|
128
|
+
Only the pattern itself may contain directory separators (e.g. `photos/{resourceId}/{name}.{extension}`). Every value
|
|
129
|
+
substituted into it — including the uploaded file name — is reduced to a single path segment, so an upload can never
|
|
130
|
+
introduce a subdirectory, a `..` traversal or a hidden file.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Reserved paths
|
|
135
|
+
|
|
136
|
+
`STORAGE_RESERVED_PATHS` (default `['keys']`, protecting the default JWT key location) lists paths inside
|
|
137
|
+
`STORAGE_PATH` that files can never use. An entry is a directory (blocking everything inside it) or a full file name,
|
|
138
|
+
relative to the storage root, and whole segments are matched case-insensitively.
|
|
139
|
+
|
|
140
|
+
Configured `namePattern`s are validated on startup and abort the start; file paths resolved at upload, stream, or delete
|
|
141
|
+
time are rejected with a `400` error.
|
|
142
|
+
|
|
128
143
|
---
|
|
129
144
|
|
|
130
145
|
## Configuration
|
|
131
146
|
|
|
132
|
-
| Key | Type
|
|
133
|
-
|
|
134
|
-
| `STORAGE_PATH` | `string`
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
137
|
-
| `
|
|
138
|
-
| `
|
|
147
|
+
| Key | Type | Default | Description |
|
|
148
|
+
|------------------------------|------------|------------------------------------------------|-------------------------------------------------------|
|
|
149
|
+
| `STORAGE_PATH` | `string` | `'./storage'` | Root directory where files are stored |
|
|
150
|
+
| `STORAGE_RESERVED_PATHS` | `string[]` | `['keys']` | Paths inside the storage root that files cannot use |
|
|
151
|
+
| `STORAGE_NAME_PATTERN` | `string` | `'{name}-{hash}.{extension}'` | Template for deriving the stored file name |
|
|
152
|
+
| `STORAGE_CACHE_TTL` | `int` | `86400000` | Cache TTL for storage responses in milliseconds (24h) |
|
|
153
|
+
| `STORAGE_FILES_ROUTE_PREFIX` | `string` | `/files` | URL prefix for file access routes. |
|
|
154
|
+
| `STORAGE_PROVIDER` | `string` | `'@appweaver/core/storage/filesystem-storage'` | Path to the Storage implementation |
|
|
139
155
|
|
|
140
156
|
**`appweaver.json` example:**
|
|
141
157
|
|
|
142
158
|
```json
|
|
143
159
|
{
|
|
144
160
|
"STORAGE_PATH": "./uploads",
|
|
161
|
+
"STORAGE_RESERVED_PATHS": [
|
|
162
|
+
"keys"
|
|
163
|
+
],
|
|
145
164
|
"STORAGE_NAME_PATTERN": "{name}-{hash}.{extension}"
|
|
146
165
|
}
|
|
147
166
|
```
|
|
@@ -230,8 +249,8 @@ processing), so it can be used at any later point to verify that the file on dis
|
|
|
230
249
|
|
|
231
250
|
The checksum is included in file API responses, so clients can verify downloaded content against it.
|
|
232
251
|
|
|
233
|
-
To verify a file's integrity, recalculate the checksum with the `makeHash` utility from `@appweaver/common` and
|
|
234
|
-
|
|
252
|
+
To verify a file's integrity, recalculate the checksum with the `makeHash` utility from `@appweaver/common` and compare
|
|
253
|
+
it with the stored value:
|
|
235
254
|
|
|
236
255
|
```ts
|
|
237
256
|
import { createReadStream } from 'node:fs';
|