@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.
Files changed (213) hide show
  1. package/README.md +7 -7
  2. package/{wiki → content}/best-practices/api-usage-examples.md +15 -12
  3. package/{wiki → content}/best-practices/architectural-patterns.md +70 -78
  4. package/{wiki → content}/best-practices/architecture-decisions.md +91 -60
  5. package/{wiki → content}/best-practices/code-style-standards/advanced-patterns.md +56 -44
  6. package/{wiki → content}/best-practices/code-style-standards/constants-configuration.md +11 -11
  7. package/{wiki → content}/best-practices/code-style-standards/control-flow.md +5 -2
  8. package/{wiki → content}/best-practices/code-style-standards/documentation.md +13 -13
  9. package/{wiki → content}/best-practices/code-style-standards/function-patterns.md +9 -10
  10. package/{wiki → content}/best-practices/code-style-standards/index.md +1 -1
  11. package/{wiki → content}/best-practices/code-style-standards/naming-conventions.md +10 -8
  12. package/{wiki → content}/best-practices/code-style-standards/route-definitions.md +30 -12
  13. package/{wiki → content}/best-practices/code-style-standards/tooling.md +8 -5
  14. package/{wiki → content}/best-practices/code-style-standards/type-safety.md +13 -12
  15. package/{wiki → content}/best-practices/common-pitfalls.md +56 -37
  16. package/{wiki → content}/best-practices/contribution-workflow.md +13 -14
  17. package/{wiki → content}/best-practices/data-modeling.md +44 -20
  18. package/{wiki → content}/best-practices/deployment-strategies.md +28 -27
  19. package/{wiki → content}/best-practices/error-handling.md +48 -24
  20. package/{wiki → content}/best-practices/index.md +5 -5
  21. package/{wiki → content}/best-practices/performance-optimization.md +36 -28
  22. package/{wiki → content}/best-practices/security-guidelines.md +52 -23
  23. package/{wiki → content}/best-practices/testing-strategies.md +65 -51
  24. package/{wiki → content}/best-practices/troubleshooting-tips.md +24 -24
  25. package/{wiki/extensions/components/swagger.md → content/extensions/components/api-reference.md} +40 -31
  26. package/{wiki → content}/extensions/components/authentication/api.md +19 -19
  27. package/{wiki → content}/extensions/components/authentication/errors.md +7 -7
  28. package/{wiki → content}/extensions/components/authentication/index.md +10 -8
  29. package/{wiki → content}/extensions/components/authentication/usage.md +101 -6
  30. package/{wiki → content}/extensions/components/authorization/api.md +45 -25
  31. package/{wiki → content}/extensions/components/authorization/errors.md +6 -6
  32. package/{wiki → content}/extensions/components/authorization/index.md +11 -10
  33. package/{wiki → content}/extensions/components/authorization/usage.md +21 -21
  34. package/{wiki → content}/extensions/components/health-check.md +1 -1
  35. package/{wiki → content}/extensions/components/index.md +5 -5
  36. package/{wiki → content}/extensions/components/mail/errors.md +15 -15
  37. package/{wiki → content}/extensions/components/mail/index.md +1 -2
  38. package/{wiki → content}/extensions/components/mail/usage.md +1 -1
  39. package/{wiki → content}/extensions/components/request-tracker.md +1 -1
  40. package/{wiki → content}/extensions/components/socket-io/api.md +9 -9
  41. package/{wiki → content}/extensions/components/socket-io/errors.md +5 -5
  42. package/{wiki → content}/extensions/components/socket-io/index.md +8 -8
  43. package/{wiki → content}/extensions/components/socket-io/usage.md +1 -1
  44. package/{wiki → content}/extensions/components/static-asset/api.md +17 -4
  45. package/{wiki → content}/extensions/components/static-asset/errors.md +4 -4
  46. package/{wiki → content}/extensions/components/static-asset/index.md +26 -28
  47. package/{wiki → content}/extensions/components/static-asset/usage.md +13 -12
  48. package/{wiki → content}/extensions/components/template/index.md +2 -2
  49. package/{wiki → content}/extensions/components/template/setup-page.md +1 -1
  50. package/{wiki → content}/extensions/components/websocket/api.md +3 -3
  51. package/{wiki → content}/extensions/components/websocket/errors.md +5 -5
  52. package/{wiki → content}/extensions/components/websocket/index.md +5 -5
  53. package/{wiki → content}/extensions/components/websocket/usage.md +3 -3
  54. package/{wiki → content}/extensions/helpers/cron/index.md +2 -2
  55. package/{wiki → content}/extensions/helpers/crypto/index.md +1 -1
  56. package/{wiki → content}/extensions/helpers/env/index.md +27 -12
  57. package/content/extensions/helpers/error/index.md +283 -0
  58. package/{wiki → content}/extensions/helpers/index.md +2 -3
  59. package/{wiki → content}/extensions/helpers/inversion/index.md +15 -7
  60. package/{wiki → content}/extensions/helpers/kafka/examples.md +1 -1
  61. package/{wiki → content}/extensions/helpers/logger/index.md +32 -2
  62. package/{wiki → content}/extensions/helpers/network/index.md +6 -0
  63. package/{wiki → content}/extensions/helpers/queue/index.md +14 -17
  64. package/content/extensions/helpers/redis/index.md +713 -0
  65. package/{wiki → content}/extensions/helpers/socket-io/index.md +14 -10
  66. package/{wiki → content}/extensions/helpers/storage/api.md +44 -8
  67. package/{wiki → content}/extensions/helpers/storage/index.md +43 -7
  68. package/{wiki → content}/extensions/helpers/template/index.md +6 -3
  69. package/{wiki → content}/extensions/helpers/types/index.md +11 -8
  70. package/{wiki → content}/extensions/helpers/websocket/api.md +9 -9
  71. package/{wiki → content}/extensions/helpers/websocket/index.md +7 -7
  72. package/{wiki → content}/extensions/helpers/worker-thread/index.md +2 -2
  73. package/{wiki → content}/extensions/index.md +3 -4
  74. package/{wiki → content}/extensions/src-details/mcp-server.md +18 -24
  75. package/{wiki → content}/guides/core-concepts/application/bootstrapping.md +11 -14
  76. package/{wiki → content}/guides/core-concepts/application/index.md +3 -3
  77. package/{wiki → content}/guides/core-concepts/components.md +19 -10
  78. package/{wiki → content}/guides/core-concepts/dependency-injection.md +6 -3
  79. package/{wiki → content}/guides/core-concepts/grpc-controllers.md +6 -5
  80. package/{wiki → content}/guides/core-concepts/persistent/datasources.md +33 -27
  81. package/{wiki → content}/guides/core-concepts/persistent/index.md +16 -5
  82. package/{wiki → content}/guides/core-concepts/persistent/models.md +24 -20
  83. package/content/guides/core-concepts/persistent/postgres-drivers.md +167 -0
  84. package/{wiki → content}/guides/core-concepts/persistent/repositories.md +40 -23
  85. package/content/guides/core-concepts/persistent/search-meilisearch.md +183 -0
  86. package/content/guides/core-concepts/persistent/search-typesense.md +429 -0
  87. package/{wiki → content}/guides/core-concepts/persistent/transactions.md +61 -25
  88. package/{wiki → content}/guides/core-concepts/rest-controllers.md +12 -9
  89. package/content/guides/core-concepts/services.md +389 -0
  90. package/{wiki → content}/guides/get-started/5-minute-quickstart.md +19 -19
  91. package/{wiki → content}/guides/get-started/philosophy.md +36 -36
  92. package/{wiki → content}/guides/get-started/setup.md +3 -3
  93. package/{wiki → content}/guides/index.md +3 -3
  94. package/content/guides/migrations/redis-helpers-migration.md +177 -0
  95. package/{wiki → content}/guides/migrations/scoped-rbac-migration.md +17 -17
  96. package/content/guides/migrations/unified-connectors-migration.md +113 -0
  97. package/{wiki → content}/guides/reference/glossary.md +19 -12
  98. package/{wiki → content}/guides/reference/mcp-docs-server.md +22 -18
  99. package/{wiki → content}/guides/tutorials/building-a-crud-api.md +30 -33
  100. package/{wiki → content}/guides/tutorials/complete-installation.md +17 -17
  101. package/{wiki → content}/guides/tutorials/ecommerce-api.md +158 -119
  102. package/{wiki → content}/guides/tutorials/realtime-chat.md +176 -130
  103. package/content/guides/tutorials/testing.md +264 -0
  104. package/content/index.md +5 -0
  105. package/content/public/apple-touch-icon.png +0 -0
  106. package/content/public/og-image.png +0 -0
  107. package/content/public/site.webmanifest +11 -0
  108. package/{wiki → content}/references/base/application.md +4 -5
  109. package/{wiki → content}/references/base/bootstrapping.md +18 -5
  110. package/{wiki → content}/references/base/components.md +149 -120
  111. package/content/references/base/connectors.md +178 -0
  112. package/{wiki → content}/references/base/controllers.md +41 -30
  113. package/content/references/base/datasources.md +527 -0
  114. package/{wiki → content}/references/base/dependency-injection.md +34 -22
  115. package/{wiki → content}/references/base/filter-system/application-usage.md +17 -14
  116. package/{wiki → content}/references/base/filter-system/array-operators.md +7 -2
  117. package/{wiki → content}/references/base/filter-system/comparison-operators.md +3 -0
  118. package/{wiki → content}/references/base/filter-system/default-filter.md +89 -71
  119. package/{wiki → content}/references/base/filter-system/fields-order-pagination.md +22 -22
  120. package/{wiki → content}/references/base/filter-system/index.md +6 -3
  121. package/{wiki → content}/references/base/filter-system/json-filtering.md +20 -1
  122. package/{wiki → content}/references/base/filter-system/list-operators.md +1 -1
  123. package/{wiki → content}/references/base/filter-system/logical-operators.md +33 -1
  124. package/{wiki → content}/references/base/filter-system/null-operators.md +30 -1
  125. package/{wiki → content}/references/base/filter-system/quick-reference.md +23 -4
  126. package/{wiki → content}/references/base/filter-system/tips.md +5 -5
  127. package/{wiki → content}/references/base/filter-system/use-cases.md +12 -12
  128. package/{wiki → content}/references/base/grpc-controllers.md +13 -13
  129. package/{wiki → content}/references/base/index.md +24 -12
  130. package/{wiki/references/base/middleware.md → content/references/base/middlewares.md} +205 -24
  131. package/{wiki → content}/references/base/models.md +63 -49
  132. package/{wiki → content}/references/base/providers.md +136 -130
  133. package/{wiki → content}/references/base/repositories/advanced.md +59 -58
  134. package/{wiki → content}/references/base/repositories/index.md +115 -91
  135. package/content/references/base/repositories/mixins.md +99 -0
  136. package/{wiki → content}/references/base/repositories/relations.md +54 -64
  137. package/{wiki → content}/references/base/repositories/soft-deletable.md +31 -30
  138. package/content/references/base/services.md +404 -0
  139. package/{wiki → content}/references/configuration/environment-variables.md +46 -30
  140. package/{wiki → content}/references/configuration/index.md +6 -6
  141. package/{wiki → content}/references/index.md +17 -12
  142. package/{wiki → content}/references/quick-reference.md +65 -106
  143. package/content/references/utilities/crypto.md +98 -0
  144. package/{wiki → content}/references/utilities/index.md +3 -3
  145. package/{wiki → content}/references/utilities/jsx.md +6 -4
  146. package/content/references/utilities/module.md +90 -0
  147. package/{wiki → content}/references/utilities/parse.md +4 -14
  148. package/{wiki → content}/references/utilities/promise.md +9 -7
  149. package/{wiki → content}/references/utilities/schema.md +5 -3
  150. package/dist/mcp-server/common/guards.d.ts +8 -0
  151. package/dist/mcp-server/common/guards.d.ts.map +1 -0
  152. package/dist/mcp-server/common/guards.js +14 -0
  153. package/dist/mcp-server/common/guards.js.map +1 -0
  154. package/dist/mcp-server/common/index.d.ts +1 -0
  155. package/dist/mcp-server/common/index.d.ts.map +1 -1
  156. package/dist/mcp-server/common/index.js +1 -0
  157. package/dist/mcp-server/common/index.js.map +1 -1
  158. package/dist/mcp-server/common/paths.d.ts.map +1 -1
  159. package/dist/mcp-server/common/paths.js +2 -2
  160. package/dist/mcp-server/common/paths.js.map +1 -1
  161. package/dist/mcp-server/helpers/docs.helper.d.ts.map +1 -1
  162. package/dist/mcp-server/helpers/docs.helper.js +4 -2
  163. package/dist/mcp-server/helpers/docs.helper.js.map +1 -1
  164. package/dist/mcp-server/helpers/github.helper.js +1 -1
  165. package/dist/mcp-server/index.js +7 -2
  166. package/dist/mcp-server/index.js.map +1 -1
  167. package/dist/mcp-server/tools/base.tool.d.ts +6 -2
  168. package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
  169. package/dist/mcp-server/tools/base.tool.js.map +1 -1
  170. package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +1 -1
  171. package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
  172. package/dist/mcp-server/tools/github/search-code.tool.d.ts +1 -1
  173. package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
  174. package/dist/mcp-server/tools/github/search-code.tool.js +4 -1
  175. package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
  176. package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
  177. package/dist/mcp-server/tools/github/verify-dependencies.tool.js +3 -1
  178. package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
  179. package/package.json +12 -12
  180. package/wiki/extensions/helpers/error/index.md +0 -227
  181. package/wiki/extensions/helpers/redis/index.md +0 -488
  182. package/wiki/extensions/helpers/testing/index.md +0 -510
  183. package/wiki/guides/core-concepts/services.md +0 -119
  184. package/wiki/guides/tutorials/testing.md +0 -722
  185. package/wiki/index.md +0 -183
  186. package/wiki/references/base/datasources.md +0 -454
  187. package/wiki/references/base/middlewares.md +0 -590
  188. package/wiki/references/base/repositories/mixins.md +0 -335
  189. package/wiki/references/base/services.md +0 -201
  190. package/wiki/references/utilities/crypto.md +0 -56
  191. package/wiki/references/utilities/module.md +0 -42
  192. /package/{wiki → content}/extensions/components/mail/api.md +0 -0
  193. /package/{wiki → content}/extensions/components/template/api-page.md +0 -0
  194. /package/{wiki → content}/extensions/components/template/errors-page.md +0 -0
  195. /package/{wiki → content}/extensions/components/template/single-page.md +0 -0
  196. /package/{wiki → content}/extensions/components/template/usage-page.md +0 -0
  197. /package/{wiki → content}/extensions/helpers/kafka/admin.md +0 -0
  198. /package/{wiki → content}/extensions/helpers/kafka/consumer.md +0 -0
  199. /package/{wiki → content}/extensions/helpers/kafka/index.md +0 -0
  200. /package/{wiki → content}/extensions/helpers/kafka/producer.md +0 -0
  201. /package/{wiki → content}/extensions/helpers/kafka/schema-registry.md +0 -0
  202. /package/{wiki → content}/extensions/helpers/network/api.md +0 -0
  203. /package/{wiki → content}/extensions/helpers/socket-io/api.md +0 -0
  204. /package/{wiki → content}/extensions/helpers/template/single-page.md +0 -0
  205. /package/{wiki → content}/extensions/helpers/uid/index.md +0 -0
  206. /package/{wiki → content}/guides/core-concepts/components-guide.md +0 -0
  207. /package/{wiki → content}/public/logo.svg +0 -0
  208. /package/{wiki → content}/references/base/filter-system/pattern-matching.md +0 -0
  209. /package/{wiki → content}/references/base/filter-system/range-operators.md +0 -0
  210. /package/{wiki → content}/references/utilities/date.md +0 -0
  211. /package/{wiki → content}/references/utilities/performance.md +0 -0
  212. /package/{wiki → content}/references/utilities/request.md +0 -0
  213. /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 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/objects/:obj/download Download file (attachment)
140
- DELETE /assets/buckets/:bucketName/objects/:obj Delete file
141
- PUT /assets/buckets/:bucketName/objects/:obj/meta-links Sync MetaLink (MetaLink only)
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: 'required' } },
241
- upload: { authenticate: { strategies: ['jwt'], mode: 'required' }, middleware: [rateLimitMw] },
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: 'required' } },
245
- deleteBucket: { authenticate: { strategies: ['jwt'], mode: 'required' } },
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 BaseEntity<Schema>;
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, model } from '@venizia/ignis/static-asset';
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, inject } from '@venizia/ignis';
409
- import type { IDataSource } from '@venizia/ignis';
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(@inject({ key: 'datasources.postgres' }) dataSource: IDataSource) {
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 TIMESTAMP NOT NULL DEFAULT NOW(),
431
- modified_at TIMESTAMP NOT NULL DEFAULT NOW(),
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/objects/:objectName/download</code> | Download file |
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/objects/:objectName/meta-links</code> | Sync MetaLink (MetaLink only) |
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:** Both bucket and object names validated with `isValidName()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name"` respectively if either is invalid.
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/objects/:objectName/download</code>
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:** Both bucket and object names validated with `isValidName()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name"` respectively if either is invalid.
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/objects/${encodeURIComponent('document.pdf')}/download`;
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:** Both bucket and object names validated with `isValidName()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name"` respectively if either is invalid.
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/objects/:objectName/meta-links</code>
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:** Both bucket and object names validated with `isValidName()`. Returns 400 `"Invalid bucket name"` or `"Invalid object name"` respectively if either is invalid.
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}/objects/${encodeURIComponent(objectName)}/meta-links`,
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}/objects/${encodeURIComponent(obj.name)}/meta-links`,
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}/objects/${encodeURIComponent(objectName)}/download`;
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 Ignis.
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
 
@@ -13,7 +13,7 @@ Paired with [Usage](./usage-page), [API Reference](./api-page), and [Error Refer
13
13
  ## Page Structure
14
14
 
15
15
  ```markdown
16
- # {Component Name}
16
+ # {Component Name} -- Setup & Configuration
17
17
 
18
18
  {One-line description of what this component does.}
19
19
 
@@ -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: DefaultRedisHelper; // Required -- same Redis as the server(s)
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.getClient().duplicate()` to create an isolated pub client
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 DefaultRedisHelper` | `"Invalid instance of redisConnection"` |
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 `DefaultRedisHelper` | `"[WebSocketComponent][resolveBindings] Invalid instance of redisConnection | Please init connection with RedisHelper for single redis connection or RedisClusterHelper for redis cluster mode!"` |
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 `DefaultRedisHelper` (or its subclasses `RedisHelper` / `RedisClusterHelper`).
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 `RedisHelper` (single instance) or `RedisClusterHelper` (cluster mode):
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 RedisHelper({ name: 'websocket', host, port, password }));
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 a DefaultRedisHelper!
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
- RedisHelper,
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: 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 RedisHelper({
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<RedisHelper>({
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` | `DefaultRedisHelper` | **Yes** | `null` |
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, RedisHelper } from '@venizia/ignis-helpers';
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 RedisHelper({
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.getClient().duplicate()`. The `duplicate()` call 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.
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()`, `running`, `lastDate()`).
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.running); // true
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 | ~190 bytes (2048-bit) | 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
- | **Extends** | `IApplicationEnvironment` (interface) |
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.ALPHA` | `'alpha'` |
138
- | `Environment.BETA` | `'beta'` |
139
- | `Environment.STAGING` | `'staging'` |
140
- | `Environment.PRODUCTION` | `'production'` |
141
-
142
- 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.
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