@appweaver/create-weaver-app 1.0.15 → 1.0.17

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appweaver/create-weaver-app",
3
- "version": "1.0.15",
3
+ "version": "1.0.17",
4
4
  "description": "Appweaver - the backend framework for AI-first development (@create-weaver-app)",
5
5
  "author": "Luka Matosevic",
6
6
  "license": "MIT",
package/skill/SKILL.md CHANGED
@@ -212,7 +212,8 @@ export default createModel({
212
212
  files: {
213
213
  photo: {
214
214
  mimeType: 'image/*',
215
- maxSize: '2 MB'
215
+ maxSize: '2 MB',
216
+ image: { quality: 80, maxWidth: 1200 }
216
217
  }
217
218
  },
218
219
  create: {
@@ -333,7 +334,8 @@ export default createAuthModel({
333
334
  files: {
334
335
  avatar: {
335
336
  mimeType: 'image/(png|jpeg|gif)',
336
- maxSize: '2 MB'
337
+ maxSize: '2 MB',
338
+ image: { quality: 80, maxHeight: 800, fit: 'inside' }
337
339
  }
338
340
  }
339
341
  });
@@ -434,7 +434,13 @@ const config = {
434
434
  photo: {
435
435
  mimeType: 'image/*',
436
436
  namePattern: 'photos/{userId}-{name}-{hash}.{extension}',
437
- maxSize: '2 MB'
437
+ maxSize: '2 MB',
438
+ image: {
439
+ quality: 80,
440
+ maxWidth: 1200,
441
+ maxHeight: 1200,
442
+ fit: 'inside'
443
+ }
438
444
  },
439
445
  documents: {
440
446
  mimeType: 'application/pdf',
@@ -445,14 +451,16 @@ const config = {
445
451
  };
446
452
  ```
447
453
 
448
- | Property | Type | Description |
449
- |---------------|--------------------|-------------------------------------------------------------------------|
450
- | `mimeType` | string \| RegExp | Allowed MIME types (glob patterns like `'image/*'` supported). |
451
- | `namePattern` | string \| function | File naming pattern or function (available variables are listed below). |
452
- | `array` | boolean | Allow multiple files. |
453
- | `maxSize` | number \| string | Maximum file size (e.g. `'2 MB'`, `5242880`). |
454
- | `maxCount` | number | Maximum number of files (for array fields). |
455
- | `output` | RelationOutput | When to include file info in output. |
454
+ | Property | Type | Description |
455
+ |---------------------|------------------------|-------------------------------------------------------------------------------------------------------------|
456
+ | `mimeType` | string \| RegExp | Allowed MIME types (glob patterns like `'image/*'` supported). |
457
+ | `namePattern` | string \| function | File naming pattern or function (available variables are listed below). |
458
+ | `array` | boolean | Allow multiple files. |
459
+ | `maxSize` | number \| string | Maximum file size (e.g. `'2 MB'`, `5242880`). |
460
+ | `maxCount` | number | Maximum number of files (for array fields). |
461
+ | `output` | RelationOutput | When to include file info in output. |
462
+ | `onResourceDeleted` | `'delete'` \| `'keep'` | When the owning resource is deleted. `'delete'` (default) removes files from storage, `'keep'` leaves them. |
463
+ | `image` | ImageConfig | Image compression and resize settings. Only applies to image MIME types (excluding GIF). |
456
464
 
457
465
  #### Available namePattern variables
458
466
 
@@ -482,6 +490,49 @@ Default pattern is: `{name}-{hash}.{extension}`.
482
490
  | `uuid` | string | Generated random UUID. |
483
491
  | `hash` | string | Generated random hash (32 bytes). |
484
492
 
493
+ #### Image compression
494
+
495
+ Configure automatic image compression and resizing by adding the `image` property to a file field. Processing only
496
+ applies to supported image MIME types: `image/jpeg`, `image/png`, `image/webp`, `image/avif`, `image/tiff`. GIF files
497
+ are passed through unchanged.
498
+
499
+ | Property | Type | Description |
500
+ |-------------|----------|----------------------------------------------------------------------------------------------------------------|
501
+ | `quality` | number | Compression quality (1-100). Applies to JPEG, PNG, WebP, AVIF, and TIFF. |
502
+ | `width` | number | Exact resize width in pixels. |
503
+ | `height` | number | Exact resize height in pixels. |
504
+ | `maxWidth` | number | Maximum width. Only downscales if the image exceeds this dimension. |
505
+ | `maxHeight` | number | Maximum height. Only downscales if the image exceeds this dimension. |
506
+ | `fit` | ImageFit | How the image fits the target dimensions: `'inside'` (default), `'contain'`, `'cover'`, `'fill'`, `'outside'`. |
507
+
508
+ `width`/`height` take precedence over `maxWidth`/`maxHeight`. When using `maxWidth`/`maxHeight`, images smaller than
509
+ the specified dimensions are not enlarged.
510
+
511
+ ```ts
512
+ // Compress and limit dimensions
513
+ const config = {
514
+ files: {
515
+ avatar: {
516
+ mimeType: 'image/*',
517
+ maxSize: '5 MB',
518
+ image: { quality: 80, maxWidth: 800, maxHeight: 800 }
519
+ }
520
+ }
521
+ };
522
+ ```
523
+
524
+ ```ts
525
+ // Exact resize for thumbnails
526
+ const config = {
527
+ files: {
528
+ thumbnail: {
529
+ mimeType: 'image/jpeg',
530
+ image: { quality: 70, width: 200, height: 200, fit: 'inside' }
531
+ }
532
+ }
533
+ }
534
+ ```
535
+
485
536
  ### Virtual fields
486
537
 
487
538
  Virtual fields are computed values not stored in the database. They can appear in input DTOs (to receive data) and/or
@@ -249,3 +249,32 @@ await fileService.deleteFile(
249
249
  postClient // ResourceClient
250
250
  );
251
251
  ```
252
+
253
+ ### Deleting all files on resource deletion
254
+
255
+ When a resource is deleted, files belonging to file fields configured with `onResourceDeleted: 'delete'` can be
256
+ automatically cleaned up. This is handled by `deleteResourceFiles()`, which is called automatically by the framework's
257
+ delete route handler.
258
+
259
+ To enable automatic file cleanup, set `onResourceDeleted: 'delete'` on the file field in your model config:
260
+
261
+ ```ts
262
+ const config = {
263
+ files: {
264
+ coverImage: {
265
+ mimeType: 'image/*',
266
+ onResourceDeleted: 'delete' // default: files removed when resource is deleted
267
+ },
268
+ documents: {
269
+ array: true,
270
+ onResourceDeleted: 'keep' // opt out: files are kept
271
+ }
272
+ }
273
+ };
274
+ ```
275
+
276
+ You can also call `deleteResourceFiles` manually if needed:
277
+
278
+ ```ts
279
+ await fileService.deleteResourceFiles('Post', postId);
280
+ ```
@@ -35,6 +35,9 @@ RUN npm ci --omit=dev
35
35
  # Copy build files
36
36
  COPY --from=build /usr/app/dist /usr/app/dist
37
37
 
38
+ # Copy public static files
39
+ COPY --from=build /usr/app/public /usr/app/public
40
+
38
41
  # Copy Prisma config, database migrations, and schema file
39
42
  COPY --from=build /usr/app/prisma.config.ts /usr/app/prisma.config.ts
40
43
  COPY --from=build /usr/app/database/migrations /usr/app/database/migrations
@@ -35,6 +35,9 @@ RUN bun install --frozen-lockfile --production
35
35
  # Copy build files
36
36
  COPY --from=build /usr/app/dist /usr/app/dist
37
37
 
38
+ # Copy public static files
39
+ COPY --from=build /usr/app/public /usr/app/public
40
+
38
41
  # Copy Prisma config, database migrations, and schema file
39
42
  COPY --from=build /usr/app/prisma.config.ts /usr/app/prisma.config.ts
40
43
  COPY --from=build /usr/app/database/migrations /usr/app/database/migrations
@@ -0,0 +1,90 @@
1
+ services:
2
+ postgres:
3
+ image: postgres:18.4
4
+ container_name: {{LOWER_NAME}}-postgres
5
+ restart: unless-stopped
6
+ healthcheck:
7
+ test: "PGPASSWORD=$$POSTGRES_PASSWORD psql -U $$POSTGRES_USER -d $$POSTGRES_DB -c 'SELECT 1'"
8
+ interval: 30s
9
+ timeout: 10s
10
+ retries: 10
11
+ start_period: 5s
12
+ start_interval: 5s
13
+ ports:
14
+ - "127.0.0.1:54312:5432"
15
+ environment:
16
+ POSTGRES_DB: "${DB_NAME}"
17
+ POSTGRES_USER: "${DB_USER}"
18
+ POSTGRES_PASSWORD: "${DB_PASSWORD}"
19
+ volumes:
20
+ - postgres-data:/var/lib/postgresql/data
21
+ networks:
22
+ - {{LOWER_NAME}}
23
+
24
+ redis:
25
+ image: redis:7.4.9
26
+ container_name: {{LOWER_NAME}}-redis
27
+ restart: unless-stopped
28
+ healthcheck:
29
+ test: [ "CMD", "redis-cli", "ping" ]
30
+ interval: 30s
31
+ timeout: 10s
32
+ retries: 10
33
+ start_period: 5s
34
+ start_interval: 5s
35
+ ports:
36
+ - "127.0.0.1:6380:6379"
37
+ volumes:
38
+ - redis-data:/data
39
+ networks:
40
+ - {{LOWER_NAME}}
41
+
42
+ {{LOWER_NAME}}.migrations:
43
+ image: {{LOWER_NAME}}:latest
44
+ container_name: {{LOWER_NAME}}-migrations
45
+ restart: no
46
+ depends_on:
47
+ postgres:
48
+ condition: service_healthy
49
+ env_file:
50
+ - .env
51
+ command: [ "migrations" ]
52
+ networks:
53
+ - {{LOWER_NAME}}
54
+
55
+ {{LOWER_NAME}}:
56
+ image: {{LOWER_NAME}}:latest
57
+ container_name: {{LOWER_NAME}}
58
+ restart: unless-stopped
59
+ build:
60
+ context: .
61
+ healthcheck:
62
+ test: "wget -qO - http://127.0.0.1:3030/health/ready || exit 1"
63
+ interval: 30s
64
+ timeout: 10s
65
+ retries: 5
66
+ start_period: 5s
67
+ start_interval: 5s
68
+ depends_on:
69
+ redis:
70
+ condition: service_healthy
71
+ {{LOWER_NAME}}.migrations:
72
+ condition: service_completed_successfully
73
+ ports:
74
+ - "127.0.0.1:3030:3003"
75
+ volumes:
76
+ - ./storage:/usr/app/storage
77
+ - ./logs:/usr/app/logs
78
+ env_file:
79
+ - .env
80
+ networks:
81
+ - {{LOWER_NAME}}
82
+
83
+ networks:
84
+ {{LOWER_NAME}}:
85
+ driver: bridge
86
+ name: {{LOWER_NAME}}-network
87
+
88
+ volumes:
89
+ postgres-data:
90
+ redis-data: