@venizia/ignis-docs 0.0.8-3 → 0.1.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/README.md +7 -7
- package/{wiki → content}/best-practices/api-usage-examples.md +15 -12
- package/{wiki → content}/best-practices/architectural-patterns.md +70 -78
- package/{wiki → content}/best-practices/architecture-decisions.md +91 -60
- package/{wiki → content}/best-practices/code-style-standards/advanced-patterns.md +56 -44
- package/{wiki → content}/best-practices/code-style-standards/constants-configuration.md +11 -11
- package/{wiki → content}/best-practices/code-style-standards/control-flow.md +5 -2
- package/{wiki → content}/best-practices/code-style-standards/documentation.md +13 -13
- package/{wiki → content}/best-practices/code-style-standards/function-patterns.md +9 -10
- package/{wiki → content}/best-practices/code-style-standards/index.md +1 -1
- package/{wiki → content}/best-practices/code-style-standards/naming-conventions.md +10 -8
- package/{wiki → content}/best-practices/code-style-standards/route-definitions.md +30 -12
- package/{wiki → content}/best-practices/code-style-standards/tooling.md +8 -5
- package/{wiki → content}/best-practices/code-style-standards/type-safety.md +13 -12
- package/{wiki → content}/best-practices/common-pitfalls.md +56 -37
- package/{wiki → content}/best-practices/contribution-workflow.md +13 -14
- package/{wiki → content}/best-practices/data-modeling.md +44 -20
- package/{wiki → content}/best-practices/deployment-strategies.md +28 -27
- package/{wiki → content}/best-practices/error-handling.md +48 -24
- package/{wiki → content}/best-practices/index.md +5 -5
- package/{wiki → content}/best-practices/performance-optimization.md +36 -28
- package/{wiki → content}/best-practices/security-guidelines.md +52 -23
- package/{wiki → content}/best-practices/testing-strategies.md +65 -51
- package/{wiki → content}/best-practices/troubleshooting-tips.md +24 -24
- package/{wiki/extensions/components/swagger.md → content/extensions/components/api-reference.md} +40 -31
- package/{wiki → content}/extensions/components/authentication/api.md +19 -19
- package/{wiki → content}/extensions/components/authentication/errors.md +7 -7
- package/{wiki → content}/extensions/components/authentication/index.md +10 -8
- package/{wiki → content}/extensions/components/authentication/usage.md +101 -6
- package/{wiki → content}/extensions/components/authorization/api.md +45 -25
- package/{wiki → content}/extensions/components/authorization/errors.md +6 -6
- package/{wiki → content}/extensions/components/authorization/index.md +11 -10
- package/{wiki → content}/extensions/components/authorization/usage.md +21 -21
- package/{wiki → content}/extensions/components/health-check.md +1 -1
- package/{wiki → content}/extensions/components/index.md +5 -5
- package/{wiki → content}/extensions/components/mail/errors.md +15 -15
- package/{wiki → content}/extensions/components/mail/index.md +1 -2
- package/{wiki → content}/extensions/components/mail/usage.md +1 -1
- package/{wiki → content}/extensions/components/request-tracker.md +1 -1
- package/{wiki → content}/extensions/components/socket-io/api.md +9 -9
- package/{wiki → content}/extensions/components/socket-io/errors.md +5 -5
- package/{wiki → content}/extensions/components/socket-io/index.md +8 -8
- package/{wiki → content}/extensions/components/socket-io/usage.md +1 -1
- package/{wiki → content}/extensions/components/static-asset/api.md +17 -4
- package/{wiki → content}/extensions/components/static-asset/errors.md +4 -4
- package/{wiki → content}/extensions/components/static-asset/index.md +26 -28
- package/{wiki → content}/extensions/components/static-asset/usage.md +13 -12
- package/{wiki → content}/extensions/components/template/index.md +2 -2
- package/{wiki → content}/extensions/components/template/setup-page.md +1 -1
- package/{wiki → content}/extensions/components/websocket/api.md +3 -3
- package/{wiki → content}/extensions/components/websocket/errors.md +5 -5
- package/{wiki → content}/extensions/components/websocket/index.md +5 -5
- package/{wiki → content}/extensions/components/websocket/usage.md +3 -3
- package/{wiki → content}/extensions/helpers/cron/index.md +2 -2
- package/{wiki → content}/extensions/helpers/crypto/index.md +1 -1
- package/{wiki → content}/extensions/helpers/env/index.md +27 -12
- package/content/extensions/helpers/error/index.md +283 -0
- package/{wiki → content}/extensions/helpers/index.md +2 -3
- package/{wiki → content}/extensions/helpers/inversion/index.md +15 -7
- package/{wiki → content}/extensions/helpers/kafka/examples.md +1 -1
- package/{wiki → content}/extensions/helpers/logger/index.md +32 -2
- package/{wiki → content}/extensions/helpers/network/index.md +6 -0
- package/{wiki → content}/extensions/helpers/queue/index.md +14 -17
- package/content/extensions/helpers/redis/index.md +713 -0
- package/{wiki → content}/extensions/helpers/socket-io/index.md +14 -10
- package/{wiki → content}/extensions/helpers/storage/api.md +44 -8
- package/{wiki → content}/extensions/helpers/storage/index.md +43 -7
- package/{wiki → content}/extensions/helpers/template/index.md +6 -3
- package/{wiki → content}/extensions/helpers/types/index.md +11 -8
- package/{wiki → content}/extensions/helpers/websocket/api.md +9 -9
- package/{wiki → content}/extensions/helpers/websocket/index.md +7 -7
- package/{wiki → content}/extensions/helpers/worker-thread/index.md +2 -2
- package/{wiki → content}/extensions/index.md +3 -4
- package/{wiki → content}/extensions/src-details/mcp-server.md +18 -24
- package/{wiki → content}/guides/core-concepts/application/bootstrapping.md +11 -14
- package/{wiki → content}/guides/core-concepts/application/index.md +3 -3
- package/{wiki → content}/guides/core-concepts/components.md +19 -10
- package/{wiki → content}/guides/core-concepts/dependency-injection.md +6 -3
- package/{wiki → content}/guides/core-concepts/grpc-controllers.md +6 -5
- package/{wiki → content}/guides/core-concepts/persistent/datasources.md +33 -27
- package/{wiki → content}/guides/core-concepts/persistent/index.md +16 -5
- package/{wiki → content}/guides/core-concepts/persistent/models.md +24 -20
- package/content/guides/core-concepts/persistent/postgres-drivers.md +167 -0
- package/{wiki → content}/guides/core-concepts/persistent/repositories.md +40 -23
- package/content/guides/core-concepts/persistent/search-meilisearch.md +183 -0
- package/content/guides/core-concepts/persistent/search-typesense.md +429 -0
- package/{wiki → content}/guides/core-concepts/persistent/transactions.md +61 -25
- package/{wiki → content}/guides/core-concepts/rest-controllers.md +12 -9
- package/content/guides/core-concepts/services.md +389 -0
- package/{wiki → content}/guides/get-started/5-minute-quickstart.md +19 -19
- package/{wiki → content}/guides/get-started/philosophy.md +36 -36
- package/{wiki → content}/guides/get-started/setup.md +3 -3
- package/{wiki → content}/guides/index.md +3 -3
- package/content/guides/migrations/redis-helpers-migration.md +177 -0
- package/{wiki → content}/guides/migrations/scoped-rbac-migration.md +17 -17
- package/content/guides/migrations/unified-connectors-migration.md +113 -0
- package/{wiki → content}/guides/reference/glossary.md +19 -12
- package/{wiki → content}/guides/reference/mcp-docs-server.md +22 -18
- package/{wiki → content}/guides/tutorials/building-a-crud-api.md +30 -33
- package/{wiki → content}/guides/tutorials/complete-installation.md +17 -17
- package/{wiki → content}/guides/tutorials/ecommerce-api.md +158 -119
- package/{wiki → content}/guides/tutorials/realtime-chat.md +176 -130
- package/content/guides/tutorials/testing.md +264 -0
- package/content/index.md +5 -0
- package/content/public/apple-touch-icon.png +0 -0
- package/content/public/og-image.png +0 -0
- package/content/public/site.webmanifest +11 -0
- package/{wiki → content}/references/base/application.md +4 -5
- package/{wiki → content}/references/base/bootstrapping.md +18 -5
- package/{wiki → content}/references/base/components.md +149 -120
- package/content/references/base/connectors.md +178 -0
- package/{wiki → content}/references/base/controllers.md +41 -30
- package/content/references/base/datasources.md +527 -0
- package/{wiki → content}/references/base/dependency-injection.md +34 -22
- package/{wiki → content}/references/base/filter-system/application-usage.md +17 -14
- package/{wiki → content}/references/base/filter-system/array-operators.md +7 -2
- package/{wiki → content}/references/base/filter-system/comparison-operators.md +3 -0
- package/{wiki → content}/references/base/filter-system/default-filter.md +89 -71
- package/{wiki → content}/references/base/filter-system/fields-order-pagination.md +22 -22
- package/{wiki → content}/references/base/filter-system/index.md +6 -3
- package/{wiki → content}/references/base/filter-system/json-filtering.md +20 -1
- package/{wiki → content}/references/base/filter-system/list-operators.md +1 -1
- package/{wiki → content}/references/base/filter-system/logical-operators.md +33 -1
- package/{wiki → content}/references/base/filter-system/null-operators.md +30 -1
- package/{wiki → content}/references/base/filter-system/quick-reference.md +23 -4
- package/{wiki → content}/references/base/filter-system/tips.md +5 -5
- package/{wiki → content}/references/base/filter-system/use-cases.md +12 -12
- package/{wiki → content}/references/base/grpc-controllers.md +13 -13
- package/{wiki → content}/references/base/index.md +24 -12
- package/{wiki/references/base/middleware.md → content/references/base/middlewares.md} +205 -24
- package/{wiki → content}/references/base/models.md +63 -49
- package/{wiki → content}/references/base/providers.md +136 -130
- package/{wiki → content}/references/base/repositories/advanced.md +59 -58
- package/{wiki → content}/references/base/repositories/index.md +115 -91
- package/content/references/base/repositories/mixins.md +99 -0
- package/{wiki → content}/references/base/repositories/relations.md +54 -64
- package/{wiki → content}/references/base/repositories/soft-deletable.md +31 -30
- package/content/references/base/services.md +404 -0
- package/{wiki → content}/references/configuration/environment-variables.md +46 -30
- package/{wiki → content}/references/configuration/index.md +6 -6
- package/{wiki → content}/references/index.md +17 -12
- package/{wiki → content}/references/quick-reference.md +65 -106
- package/content/references/utilities/crypto.md +98 -0
- package/{wiki → content}/references/utilities/index.md +3 -3
- package/{wiki → content}/references/utilities/jsx.md +6 -4
- package/content/references/utilities/module.md +90 -0
- package/{wiki → content}/references/utilities/parse.md +4 -14
- package/{wiki → content}/references/utilities/promise.md +9 -7
- package/{wiki → content}/references/utilities/schema.md +5 -3
- package/dist/mcp-server/common/guards.d.ts +8 -0
- package/dist/mcp-server/common/guards.d.ts.map +1 -0
- package/dist/mcp-server/common/guards.js +14 -0
- package/dist/mcp-server/common/guards.js.map +1 -0
- package/dist/mcp-server/common/index.d.ts +1 -0
- package/dist/mcp-server/common/index.d.ts.map +1 -1
- package/dist/mcp-server/common/index.js +1 -0
- package/dist/mcp-server/common/index.js.map +1 -1
- package/dist/mcp-server/common/paths.d.ts.map +1 -1
- package/dist/mcp-server/common/paths.js +2 -2
- package/dist/mcp-server/common/paths.js.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
- package/dist/mcp-server/helpers/docs.helper.js +4 -2
- package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
- package/dist/mcp-server/helpers/github.helper.js +1 -1
- package/dist/mcp-server/index.js +7 -2
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/mcp-server/tools/base.tool.d.ts +6 -2
- package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/base.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
- package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
- package/package.json +12 -12
- package/wiki/extensions/helpers/error/index.md +0 -227
- package/wiki/extensions/helpers/redis/index.md +0 -488
- package/wiki/extensions/helpers/testing/index.md +0 -510
- package/wiki/guides/core-concepts/services.md +0 -119
- package/wiki/guides/tutorials/testing.md +0 -722
- package/wiki/index.md +0 -183
- package/wiki/references/base/datasources.md +0 -454
- package/wiki/references/base/middlewares.md +0 -590
- package/wiki/references/base/repositories/mixins.md +0 -335
- package/wiki/references/base/services.md +0 -201
- package/wiki/references/utilities/crypto.md +0 -56
- package/wiki/references/utilities/module.md +0 -42
- /package/{wiki → content}/extensions/components/mail/api.md +0 -0
- /package/{wiki → content}/extensions/components/template/api-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/errors-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/components/template/usage-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/admin.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/consumer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/index.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/producer.md +0 -0
- /package/{wiki → content}/extensions/helpers/kafka/schema-registry.md +0 -0
- /package/{wiki → content}/extensions/helpers/network/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/socket-io/api.md +0 -0
- /package/{wiki → content}/extensions/helpers/template/single-page.md +0 -0
- /package/{wiki → content}/extensions/helpers/uid/index.md +0 -0
- /package/{wiki → content}/guides/core-concepts/components-guide.md +0 -0
- /package/{wiki → content}/public/logo.svg +0 -0
- /package/{wiki → content}/references/base/filter-system/pattern-matching.md +0 -0
- /package/{wiki → content}/references/base/filter-system/range-operators.md +0 -0
- /package/{wiki → content}/references/utilities/date.md +0 -0
- /package/{wiki → content}/references/utilities/performance.md +0 -0
- /package/{wiki → content}/references/utilities/request.md +0 -0
- /package/{wiki → content}/references/utilities/statuses.md +0 -0
|
@@ -129,16 +129,16 @@ export class Application extends BaseApplication {
|
|
|
129
129
|
The component auto-registers REST endpoints for each configured backend. No injection needed in downstream code.
|
|
130
130
|
|
|
131
131
|
```
|
|
132
|
-
GET /assets/buckets
|
|
133
|
-
GET /assets/buckets/:bucketName
|
|
134
|
-
POST /assets/buckets/:bucketName
|
|
135
|
-
DELETE /assets/buckets/:bucketName
|
|
136
|
-
POST /assets/buckets/:bucketName/upload
|
|
137
|
-
GET /assets/buckets/:bucketName/objects
|
|
138
|
-
GET /assets/buckets/:bucketName/objects/:obj
|
|
139
|
-
GET /assets/buckets/:bucketName/
|
|
140
|
-
DELETE /assets/buckets/:bucketName/objects/:obj
|
|
141
|
-
PUT /assets/buckets/:bucketName/
|
|
132
|
+
GET /assets/buckets - List all buckets
|
|
133
|
+
GET /assets/buckets/:bucketName - Get bucket details (or null)
|
|
134
|
+
POST /assets/buckets/:bucketName - Create a bucket
|
|
135
|
+
DELETE /assets/buckets/:bucketName - Delete a bucket
|
|
136
|
+
POST /assets/buckets/:bucketName/upload - Upload files
|
|
137
|
+
GET /assets/buckets/:bucketName/objects - List objects in bucket
|
|
138
|
+
GET /assets/buckets/:bucketName/objects/:obj - Stream file inline
|
|
139
|
+
GET /assets/buckets/:bucketName/download/:obj - Download file (attachment)
|
|
140
|
+
DELETE /assets/buckets/:bucketName/objects/:obj - Delete file
|
|
141
|
+
PUT /assets/buckets/:bucketName/meta-links/:obj - Sync MetaLink (MetaLink only)
|
|
142
142
|
```
|
|
143
143
|
|
|
144
144
|
Each storage backend gets its own base path (`/assets`, `/resources`, etc.) with the same endpoint structure.
|
|
@@ -237,12 +237,12 @@ Each route can be individually configured with authentication, middleware, and p
|
|
|
237
237
|
name: 'AssetController',
|
|
238
238
|
basePath: '/assets',
|
|
239
239
|
routes: {
|
|
240
|
-
getBuckets: { authenticate: { strategies: ['jwt'], mode: '
|
|
241
|
-
upload: { authenticate: { strategies: ['jwt'], mode: '
|
|
240
|
+
getBuckets: { authenticate: { strategies: ['jwt'], mode: 'any' } },
|
|
241
|
+
upload: { authenticate: { strategies: ['jwt'], mode: 'any' }, middleware: [rateLimitMw] },
|
|
242
242
|
getObjectByName: { /* public -- no authenticate */ },
|
|
243
243
|
downloadObjectByName: { /* public */ },
|
|
244
|
-
deleteObject: { authenticate: { strategies: ['jwt'], mode: '
|
|
245
|
-
deleteBucket: { authenticate: { strategies: ['jwt'], mode: '
|
|
244
|
+
deleteObject: { authenticate: { strategies: ['jwt'], mode: 'any' } },
|
|
245
|
+
deleteBucket: { authenticate: { strategies: ['jwt'], mode: 'any' } },
|
|
246
246
|
},
|
|
247
247
|
},
|
|
248
248
|
// ...
|
|
@@ -288,11 +288,13 @@ type TStaticAssetExtraOptions = {
|
|
|
288
288
|
};
|
|
289
289
|
normalizeNameFn?: (opts: { originalName: string }) => string;
|
|
290
290
|
normalizeLinkFn?: (opts: { bucketName: string; normalizeName: string }) => string;
|
|
291
|
+
/** Maximum folder nesting depth allowed in object paths. Default: 2 */
|
|
292
|
+
maxFolderDepth?: number;
|
|
291
293
|
[key: string]: any;
|
|
292
294
|
};
|
|
293
295
|
|
|
294
296
|
type TMetaLinkConfig<Schema extends TMetaLinkSchema = TMetaLinkSchema> = {
|
|
295
|
-
model: typeof
|
|
297
|
+
model: typeof BasePostgresEntity<Schema>;
|
|
296
298
|
repository: DefaultCRUDRepository<Schema>;
|
|
297
299
|
createMetaLink?: (opts: {
|
|
298
300
|
uploadResult: IUploadResult;
|
|
@@ -393,7 +395,8 @@ MetaLink is an optional feature that tracks uploaded files in a database, storin
|
|
|
393
395
|
**1. Create Model:**
|
|
394
396
|
|
|
395
397
|
```typescript
|
|
396
|
-
import { BaseMetaLinkModel
|
|
398
|
+
import { BaseMetaLinkModel } from '@venizia/ignis/static-asset';
|
|
399
|
+
import { model } from '@venizia/ignis';
|
|
397
400
|
|
|
398
401
|
@model({ type: 'entity' })
|
|
399
402
|
export class FileMetaLinkModel extends BaseMetaLinkModel {
|
|
@@ -405,18 +408,13 @@ export class FileMetaLinkModel extends BaseMetaLinkModel {
|
|
|
405
408
|
|
|
406
409
|
```typescript
|
|
407
410
|
import { BaseMetaLinkRepository } from '@venizia/ignis/static-asset';
|
|
408
|
-
import { repository
|
|
409
|
-
import
|
|
411
|
+
import { repository } from '@venizia/ignis';
|
|
412
|
+
import { FileMetaLinkModel } from './file-meta-link.model';
|
|
413
|
+
import { PostgresDataSource } from '../datasources/postgres.datasource';
|
|
410
414
|
|
|
411
|
-
@repository({})
|
|
415
|
+
@repository({ model: FileMetaLinkModel, dataSource: PostgresDataSource })
|
|
412
416
|
export class FileMetaLinkRepository extends BaseMetaLinkRepository {
|
|
413
|
-
constructor
|
|
414
|
-
super({
|
|
415
|
-
entityClass: FileMetaLinkModel,
|
|
416
|
-
relations: {},
|
|
417
|
-
dataSource,
|
|
418
|
-
});
|
|
419
|
-
}
|
|
417
|
+
// No constructor needed - dataSource auto-injected from @repository metadata
|
|
420
418
|
}
|
|
421
419
|
```
|
|
422
420
|
|
|
@@ -427,8 +425,8 @@ The model has `skipMigrate: true`, so create the table manually:
|
|
|
427
425
|
```sql
|
|
428
426
|
CREATE TABLE "MetaLink" (
|
|
429
427
|
id TEXT PRIMARY KEY,
|
|
430
|
-
created_at
|
|
431
|
-
modified_at
|
|
428
|
+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
429
|
+
modified_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
432
430
|
bucket_name TEXT NOT NULL,
|
|
433
431
|
object_name TEXT NOT NULL,
|
|
434
432
|
link TEXT NOT NULL,
|
|
@@ -15,9 +15,9 @@ The component dynamically generates REST endpoints for each configured storage b
|
|
|
15
15
|
| `POST` | <code v-pre>/{basePath}/buckets/:bucketName/upload</code> | Upload files |
|
|
16
16
|
| `GET` | <code v-pre>/{basePath}/buckets/:bucketName/objects</code> | List objects |
|
|
17
17
|
| `GET` | <code v-pre>/{basePath}/buckets/:bucketName/objects/:objectName</code> | Stream file |
|
|
18
|
-
| `GET` | <code v-pre>/{basePath}/buckets/:bucketName/
|
|
18
|
+
| `GET` | <code v-pre>/{basePath}/buckets/:bucketName/download/:objectName</code> | Download file |
|
|
19
19
|
| `DELETE` | <code v-pre>/{basePath}/buckets/:bucketName/objects/:objectName</code> | Delete object |
|
|
20
|
-
| `PUT` | <code v-pre>/{basePath}/buckets/:bucketName/
|
|
20
|
+
| `PUT` | <code v-pre>/{basePath}/buckets/:bucketName/meta-links/:objectName</code> | Sync MetaLink (MetaLink only) |
|
|
21
21
|
|
|
22
22
|
#### GET <code v-pre>/{basePath}/buckets</code>
|
|
23
23
|
**Response `200`:**
|
|
@@ -74,6 +74,7 @@ The `isDeleted` field is a boolean indicating whether the bucket was successfull
|
|
|
74
74
|
- `principalType` (optional, string): Type of the principal to associate with the uploaded files (e.g., `"user"`, `"service"`)
|
|
75
75
|
- `principalId` (optional, string or number): ID of the principal. Always coerced to a string via `String()` before storage regardless of input type
|
|
76
76
|
- `variant` (optional, string): Variant tag for the upload (e.g., `"thumbnail"`, `"original"`)
|
|
77
|
+
- `folderPath` (optional, string): Target folder path for uploaded files (e.g., `"photos/2024"`). Each segment is validated with `isValidName()` and the segment count must not exceed the configured `maxFolderDepth` (default 2); returns 400 on violation
|
|
77
78
|
|
|
78
79
|
**Validation:** Bucket name validated with `isValidName()`. Returns 400 `"Invalid bucket name"` if invalid.
|
|
79
80
|
|
|
@@ -187,7 +188,7 @@ All fields in the `IObjectInfo` response are optional. The `prefix` field is pre
|
|
|
187
188
|
- `bucketName` (path): Bucket name
|
|
188
189
|
- `objectName` (path): Object name (URL-encoded)
|
|
189
190
|
|
|
190
|
-
**Validation:**
|
|
191
|
+
**Validation:** Bucket name validated with `isValidName()`; object name validated with `isValidPath()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name or path"` respectively if either is invalid.
|
|
191
192
|
|
|
192
193
|
**Response:**
|
|
193
194
|
- Streams file content with appropriate headers
|
|
@@ -196,12 +197,12 @@ All fields in the `IObjectInfo` response are optional. The `prefix` field is pre
|
|
|
196
197
|
- `X-Content-Type-Options`: `nosniff`
|
|
197
198
|
- Additional whitelisted headers forwarded from storage metadata (see [Header Sanitization](./api#header-sanitization))
|
|
198
199
|
|
|
199
|
-
#### GET <code v-pre>/{basePath}/buckets/:bucketName/
|
|
200
|
+
#### GET <code v-pre>/{basePath}/buckets/:bucketName/download/:objectName</code>
|
|
200
201
|
**Parameters:**
|
|
201
202
|
- `bucketName` (path): Bucket name
|
|
202
203
|
- `objectName` (path): Object name (URL-encoded)
|
|
203
204
|
|
|
204
|
-
**Validation:**
|
|
205
|
+
**Validation:** Bucket name validated with `isValidName()`; object name validated with `isValidPath()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name or path"` respectively if either is invalid.
|
|
205
206
|
|
|
206
207
|
**Response:**
|
|
207
208
|
- Streams file with download headers
|
|
@@ -214,7 +215,7 @@ All fields in the `IObjectInfo` response are optional. The `prefix` field is pre
|
|
|
214
215
|
|
|
215
216
|
**Example:**
|
|
216
217
|
```typescript
|
|
217
|
-
const downloadUrl = `/assets/buckets/uploads/
|
|
218
|
+
const downloadUrl = `/assets/buckets/uploads/download/${encodeURIComponent('document.pdf')}`;
|
|
218
219
|
window.open(downloadUrl, '_blank');
|
|
219
220
|
```
|
|
220
221
|
|
|
@@ -223,7 +224,7 @@ window.open(downloadUrl, '_blank');
|
|
|
223
224
|
- `bucketName` (path): Bucket name
|
|
224
225
|
- `objectName` (path): Object to delete (URL-encoded)
|
|
225
226
|
|
|
226
|
-
**Validation:**
|
|
227
|
+
**Validation:** Bucket name validated with `isValidName()`; object name validated with `isValidPath()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name or path"` respectively if either is invalid.
|
|
227
228
|
|
|
228
229
|
**Behavior:**
|
|
229
230
|
- Deletes file from storage
|
|
@@ -248,14 +249,14 @@ await fetch(`/assets/buckets/${bucketName}/objects/${encodeURIComponent(objectNa
|
|
|
248
249
|
// MetaLink record deletion initiated (if enabled) but may complete after response
|
|
249
250
|
```
|
|
250
251
|
|
|
251
|
-
#### PUT <code v-pre>/{basePath}/buckets/:bucketName/
|
|
252
|
+
#### PUT <code v-pre>/{basePath}/buckets/:bucketName/meta-links/:objectName</code>
|
|
252
253
|
**Availability:** Only registered when `useMetaLink: true`.
|
|
253
254
|
|
|
254
255
|
**Parameters:**
|
|
255
256
|
- `bucketName` (path): Bucket name
|
|
256
257
|
- `objectName` (path): Object name (URL-encoded)
|
|
257
258
|
|
|
258
|
-
**Validation:**
|
|
259
|
+
**Validation:** Bucket name validated with `isValidName()`; object name validated with `isValidPath()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name or path"` respectively if either is invalid.
|
|
259
260
|
|
|
260
261
|
**Behavior:**
|
|
261
262
|
- Fetches current file metadata from storage via `helper.getStat()`
|
|
@@ -302,7 +303,7 @@ const bucketName = 'user-uploads';
|
|
|
302
303
|
const objectName = 'document.pdf';
|
|
303
304
|
|
|
304
305
|
const response = await fetch(
|
|
305
|
-
`/assets/buckets/${bucketName}/
|
|
306
|
+
`/assets/buckets/${bucketName}/meta-links/${encodeURIComponent(objectName)}`,
|
|
306
307
|
{ method: 'PUT' }
|
|
307
308
|
);
|
|
308
309
|
|
|
@@ -315,7 +316,7 @@ const objects = await fetch(`/assets/buckets/${bucketName}/objects`).then(r => r
|
|
|
315
316
|
|
|
316
317
|
for (const obj of objects) {
|
|
317
318
|
await fetch(
|
|
318
|
-
`/assets/buckets/${bucketName}/
|
|
319
|
+
`/assets/buckets/${bucketName}/meta-links/${encodeURIComponent(obj.name)}`,
|
|
319
320
|
{ method: 'PUT' }
|
|
320
321
|
);
|
|
321
322
|
}
|
|
@@ -345,7 +346,7 @@ async function uploadFile(file: File, principalType?: string, principalId?: stri
|
|
|
345
346
|
|
|
346
347
|
// Download file
|
|
347
348
|
function downloadFile(bucketName: string, objectName: string) {
|
|
348
|
-
const url = `/assets/buckets/${bucketName}/
|
|
349
|
+
const url = `/assets/buckets/${bucketName}/download/${encodeURIComponent(objectName)}`;
|
|
349
350
|
window.open(url, '_blank');
|
|
350
351
|
}
|
|
351
352
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Component Documentation Template
|
|
2
2
|
|
|
3
|
-
Guide for writing consistent, professional component reference docs for
|
|
3
|
+
Guide for writing consistent, professional component reference docs for IGNIS.
|
|
4
4
|
|
|
5
5
|
## Principles
|
|
6
6
|
|
|
@@ -14,7 +14,7 @@ Guide for writing consistent, professional component reference docs for Ignis.
|
|
|
14
14
|
| Tier | Structure | When to Use | Examples |
|
|
15
15
|
|------|-----------|-------------|----------|
|
|
16
16
|
| **Tier 1** | [Single page](./single-page) | 5 or fewer config options, straightforward behavior | Health Check, Request Tracker, Swagger |
|
|
17
|
-
| **Tier 2** | 4 pages | 6+ config options, multiple strategies/providers, architectural depth | Authentication, Mail, Socket.IO, WebSocket, Static Asset |
|
|
17
|
+
| **Tier 2** | 4 pages | 6+ config options, multiple strategies/providers, architectural depth | Authentication, Authorization, Mail, Socket.IO, WebSocket, Static Asset |
|
|
18
18
|
|
|
19
19
|
### Tier 1 -- Single Page
|
|
20
20
|
|
|
@@ -111,7 +111,7 @@ upgrade() fetch(req, server)
|
|
|
111
111
|
```typescript
|
|
112
112
|
interface IWebSocketEmitterOptions {
|
|
113
113
|
identifier?: string; // Default: 'WebSocketEmitter' (used as logger scope)
|
|
114
|
-
redisConnection:
|
|
114
|
+
redisConnection: IRedisHelper; // Required -- same Redis as the server(s)
|
|
115
115
|
}
|
|
116
116
|
```
|
|
117
117
|
|
|
@@ -127,7 +127,7 @@ const emitter = new WebSocketEmitter({
|
|
|
127
127
|
The constructor:
|
|
128
128
|
1. Calls `super({ scope })` with `identifier` (or `'WebSocketEmitter'` if not provided)
|
|
129
129
|
2. Validates `redisConnection` is truthy (throws `"Invalid redis connection!"` if not)
|
|
130
|
-
3. Calls `redisConnection.
|
|
130
|
+
3. Calls `redisConnection.duplicateClient()` to create an isolated pub client
|
|
131
131
|
|
|
132
132
|
### `EMITTER_SERVER_ID`
|
|
133
133
|
|
|
@@ -217,7 +217,7 @@ Reads all binding keys from the DI container and validates required ones:
|
|
|
217
217
|
| Binding | Validation | Error on Failure |
|
|
218
218
|
|---------|-----------|------------------|
|
|
219
219
|
| `SERVER_OPTIONS` | Optional, merged with `DEFAULT_SERVER_OPTIONS` via `Object.assign()` | -- |
|
|
220
|
-
| `REDIS_CONNECTION` | Must be `instanceof
|
|
220
|
+
| `REDIS_CONNECTION` | Must be `instanceof AbstractRedisHelper` | `"Invalid instance of redisConnection"` |
|
|
221
221
|
| `AUTHENTICATE_HANDLER` | Must be truthy (non-null) | `"Invalid authenticateFn to setup WebSocket server!"` |
|
|
222
222
|
| `VALIDATE_ROOM_HANDLER` | Optional, coerced `null` to `undefined` | -- |
|
|
223
223
|
| `CLIENT_CONNECTED_HANDLER` | Optional, coerced `null` to `undefined` | -- |
|
|
@@ -28,7 +28,7 @@ The server can send `error` events or close the connection under the following c
|
|
|
28
28
|
|--------|-----------|---------------|
|
|
29
29
|
| `binding()` | `application` is falsy | `"[binding] Invalid application to bind WebSocketComponent"` |
|
|
30
30
|
| `binding()` | Node.js runtime detected | `"[WebSocketComponent] Node.js runtime is not supported yet. Please use Bun runtime."` |
|
|
31
|
-
| `resolveBindings()` | `REDIS_CONNECTION` not instanceof `
|
|
31
|
+
| `resolveBindings()` | `REDIS_CONNECTION` not instanceof `AbstractRedisHelper` | `"[WebSocketComponent][resolveBindings] Invalid instance of redisConnection | Please init connection with RedisSingleHelper (single), RedisClusterHelper (cluster), or RedisSentinelHelper (sentinel)"` |
|
|
32
32
|
| `resolveBindings()` | `AUTHENTICATE_HANDLER` is falsy | `"[WebSocketComponent] Invalid authenticateFn to setup WebSocket server!"` |
|
|
33
33
|
| `registerBunHook()` | Bun server instance not available | `"[WebSocketComponent] Bun server instance not available!"` |
|
|
34
34
|
|
|
@@ -42,20 +42,20 @@ The server can send `error` events or close the connection under the following c
|
|
|
42
42
|
|
|
43
43
|
### "Invalid instance of redisConnection"
|
|
44
44
|
|
|
45
|
-
**Cause**: The value bound to `REDIS_CONNECTION` is not an instance of `
|
|
45
|
+
**Cause**: The value bound to `REDIS_CONNECTION` is not an instance of `AbstractRedisHelper` (i.e. not a `RedisSingleHelper`, `RedisClusterHelper`, or `RedisSentinelHelper`).
|
|
46
46
|
|
|
47
|
-
**Fix**: Use
|
|
47
|
+
**Fix**: Use one of the concrete topology helpers:
|
|
48
48
|
|
|
49
49
|
```typescript
|
|
50
50
|
import { WebSocketBindingKeys } from '@venizia/ignis/websocket';
|
|
51
51
|
|
|
52
52
|
// Correct
|
|
53
53
|
this.bind({ key: WebSocketBindingKeys.REDIS_CONNECTION })
|
|
54
|
-
.toValue(new
|
|
54
|
+
.toValue(new RedisSingleHelper({ name: 'websocket', host, port, password }));
|
|
55
55
|
|
|
56
56
|
// Wrong -- raw ioredis client
|
|
57
57
|
this.bind({ key: WebSocketBindingKeys.REDIS_CONNECTION })
|
|
58
|
-
.toValue(new Redis(6379)); // This is NOT
|
|
58
|
+
.toValue(new Redis(6379)); // This is NOT an AbstractRedisHelper!
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
### "Invalid authenticateFn to setup WebSocket server!"
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
WebSocketBindingKeys,
|
|
93
93
|
} from '@venizia/ignis/websocket';
|
|
94
94
|
import {
|
|
95
|
-
|
|
95
|
+
RedisSingleHelper,
|
|
96
96
|
} from '@venizia/ignis-helpers';
|
|
97
97
|
import type {
|
|
98
98
|
TWebSocketAuthenticateFn,
|
|
@@ -107,7 +107,7 @@ import type {
|
|
|
107
107
|
} from '@venizia/ignis-helpers';
|
|
108
108
|
|
|
109
109
|
export class Application extends BaseApplication {
|
|
110
|
-
private redisHelper:
|
|
110
|
+
private redisHelper: RedisSingleHelper;
|
|
111
111
|
|
|
112
112
|
preConfigure(): ValueOrPromise<void> {
|
|
113
113
|
this.setupWebSocket();
|
|
@@ -116,7 +116,7 @@ export class Application extends BaseApplication {
|
|
|
116
116
|
|
|
117
117
|
setupWebSocket() {
|
|
118
118
|
// 1. Redis connection (required for cross-instance messaging)
|
|
119
|
-
this.redisHelper = new
|
|
119
|
+
this.redisHelper = new RedisSingleHelper({
|
|
120
120
|
name: 'websocket-redis',
|
|
121
121
|
host: process.env.REDIS_HOST ?? 'localhost',
|
|
122
122
|
port: +(process.env.REDIS_PORT ?? 6379),
|
|
@@ -124,7 +124,7 @@ export class Application extends BaseApplication {
|
|
|
124
124
|
autoConnect: false,
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
this.bind<
|
|
127
|
+
this.bind<RedisSingleHelper>({
|
|
128
128
|
key: WebSocketBindingKeys.REDIS_CONNECTION,
|
|
129
129
|
}).toValue(this.redisHelper);
|
|
130
130
|
|
|
@@ -331,7 +331,7 @@ interface IServerOptions {
|
|
|
331
331
|
| Binding Key | Constant | Type | Required | Default |
|
|
332
332
|
|------------|----------|------|----------|---------|
|
|
333
333
|
| `@app/websocket/server-options` | `WebSocketBindingKeys.SERVER_OPTIONS` | `Partial<IServerOptions>` | No | See [Configuration](#configuration) |
|
|
334
|
-
| `@app/websocket/redis-connection` | `WebSocketBindingKeys.REDIS_CONNECTION` | `
|
|
334
|
+
| `@app/websocket/redis-connection` | `WebSocketBindingKeys.REDIS_CONNECTION` | `IRedisHelper` | **Yes** | `null` |
|
|
335
335
|
| `@app/websocket/authenticate-handler` | `WebSocketBindingKeys.AUTHENTICATE_HANDLER` | `TWebSocketAuthenticateFn` | **Yes** | `null` |
|
|
336
336
|
| `@app/websocket/validate-room-handler` | `WebSocketBindingKeys.VALIDATE_ROOM_HANDLER` | `TWebSocketValidateRoomFn` | No | `null` |
|
|
337
337
|
| `@app/websocket/client-connected-handler` | `WebSocketBindingKeys.CLIENT_CONNECTED_HANDLER` | `TWebSocketClientConnectedFn` | No | `null` |
|
|
@@ -109,10 +109,10 @@ It connects to Redis and publishes messages using the same `IRedisSocketMessage`
|
|
|
109
109
|
#### Emitter Setup
|
|
110
110
|
|
|
111
111
|
```typescript
|
|
112
|
-
import { WebSocketEmitter,
|
|
112
|
+
import { WebSocketEmitter, RedisSingleHelper } from '@venizia/ignis-helpers';
|
|
113
113
|
|
|
114
114
|
// 1. Create a Redis connection (same Redis instance as the WebSocket server)
|
|
115
|
-
const redisHelper = new
|
|
115
|
+
const redisHelper = new RedisSingleHelper({
|
|
116
116
|
name: 'emitter-redis',
|
|
117
117
|
host: process.env.REDIS_HOST ?? 'localhost',
|
|
118
118
|
port: +(process.env.REDIS_PORT ?? 6379),
|
|
@@ -343,7 +343,7 @@ Both `WebSocketServerHelper` and `WebSocketEmitter` support Redis single instanc
|
|
|
343
343
|
type TRedisClient = Redis | Cluster;
|
|
344
344
|
```
|
|
345
345
|
|
|
346
|
-
The Redis client is obtained via `redisConnection.
|
|
346
|
+
The Redis client is obtained via `redisConnection.duplicateClient()`. This creates a fresh connection that inherits the parent's configuration (including cluster mode). This ensures WebSocket pub/sub traffic does not interfere with application Redis usage.
|
|
347
347
|
|
|
348
348
|
### Subscription Setup
|
|
349
349
|
|
|
@@ -147,7 +147,7 @@ hourlyJob.start();
|
|
|
147
147
|
|
|
148
148
|
### Accessing the Underlying CronJob
|
|
149
149
|
|
|
150
|
-
The `instance` property exposes the underlying `CronJob` from the `cron` package, giving access to the full API (e.g., `stop()`, `
|
|
150
|
+
The `instance` property exposes the underlying `CronJob` from the `cron` package, giving access to the full API (e.g., `stop()`, `isActive`, `lastDate()`).
|
|
151
151
|
|
|
152
152
|
```typescript
|
|
153
153
|
const job = new CronHelper({
|
|
@@ -158,7 +158,7 @@ const job = new CronHelper({
|
|
|
158
158
|
job.start();
|
|
159
159
|
|
|
160
160
|
// Access the underlying CronJob directly
|
|
161
|
-
console.log(job.instance.
|
|
161
|
+
console.log(job.instance.isActive); // true
|
|
162
162
|
job.instance.stop();
|
|
163
163
|
```
|
|
164
164
|
|
|
@@ -18,7 +18,7 @@ Cryptographic utilities for AES symmetric encryption, RSA asymmetric encryption,
|
|
|
18
18
|
| Type | Symmetric | Asymmetric | Asymmetric + Symmetric |
|
|
19
19
|
| Key exchange | Shared secret | Public/private | Diffie-Hellman |
|
|
20
20
|
| Speed | Fast | Slow (large keys) | Fast (small keys) |
|
|
21
|
-
| Max message | Unlimited | ~
|
|
21
|
+
| Max message | Unlimited | ~214 bytes (2048-bit, OAEP) | Unlimited |
|
|
22
22
|
| Async | No | No | Yes (Web Crypto) |
|
|
23
23
|
| Runtime | Node.js `crypto` | Node.js `crypto` | `crypto.subtle` (Bun/Browser) |
|
|
24
24
|
|
|
@@ -8,7 +8,7 @@ Structured access to application environment variables with prefix filtering, ty
|
|
|
8
8
|
|------|-------|
|
|
9
9
|
| **Package** | `@venizia/ignis-helpers` |
|
|
10
10
|
| **Classes** | `ApplicationEnvironment`, `Environment` |
|
|
11
|
-
| **
|
|
11
|
+
| **Implements** | `IApplicationEnvironment` (interface) |
|
|
12
12
|
| **Singleton** | `applicationEnvironment` (alias `Envs`) -- auto-initialized at module load |
|
|
13
13
|
| **Runtimes** | Both |
|
|
14
14
|
|
|
@@ -129,17 +129,32 @@ if (Environment.is({ name: 'staging' })) {
|
|
|
129
129
|
|
|
130
130
|
#### Available Stages
|
|
131
131
|
|
|
132
|
-
| Constant | Value |
|
|
133
|
-
|
|
134
|
-
| `Environment.LOCAL` | `'local'` |
|
|
135
|
-
| `Environment.DEBUG` | `'debug'` |
|
|
136
|
-
| `Environment.DEVELOPMENT` | `'development'` |
|
|
137
|
-
| `Environment.
|
|
138
|
-
| `Environment.
|
|
139
|
-
| `Environment.
|
|
140
|
-
| `Environment.
|
|
141
|
-
|
|
142
|
-
|
|
132
|
+
| Constant | Value | Development stage |
|
|
133
|
+
|----------|-------|-------------------|
|
|
134
|
+
| `Environment.LOCAL` | `'local'` | yes |
|
|
135
|
+
| `Environment.DEBUG` | `'debug'` | yes |
|
|
136
|
+
| `Environment.DEVELOPMENT` | `'development'` | yes |
|
|
137
|
+
| `Environment.DEV` | `'dev'` | yes - the short spelling of `development` |
|
|
138
|
+
| `Environment.SIT` | `'sit'` | yes |
|
|
139
|
+
| `Environment.UAT` | `'uat'` | no |
|
|
140
|
+
| `Environment.ALPHA` | `'alpha'` | no |
|
|
141
|
+
| `Environment.BETA` | `'beta'` | no |
|
|
142
|
+
| `Environment.STAGING` | `'staging'` | no |
|
|
143
|
+
| `Environment.PRODUCTION` | `'production'` | no |
|
|
144
|
+
|
|
145
|
+
All stages are collected in `Environment.COMMON_ENVS` (a `Set<string>`), which is used internally by the Logger to determine whether debug logging should be active. A `NODE_ENV` outside this set silences `DEBUG=true` entirely.
|
|
146
|
+
|
|
147
|
+
#### `Environment.DEVELOPMENT_ENVS` - the error-detail boundary
|
|
148
|
+
|
|
149
|
+
The stages marked "development stage" above form `Environment.DEVELOPMENT_ENVS`. IGNIS's error handler consults this set to decide whether an error response may carry internal detail - a stack trace, a SQL constraint name, a raw driver message.
|
|
150
|
+
|
|
151
|
+
The rule is fail-closed. A leak is opt-in by an explicit development name, so **anything else is sanitized as production**, including:
|
|
152
|
+
|
|
153
|
+
- `alpha`, `beta`, `uat`, `staging` - real users reach these
|
|
154
|
+
- an unrecognized name (a typo, a stage nobody added to the set)
|
|
155
|
+
- `NODE_ENV` left unset
|
|
156
|
+
|
|
157
|
+
Running a local service under `NODE_ENV=alpha` therefore gives you the same stripped-down error responses your users see. If you want the details while developing, set `NODE_ENV` to `development`, `dev`, or `local`.
|
|
143
158
|
|
|
144
159
|
### Configuring the Prefix
|
|
145
160
|
|