@breadstone/archipel-mcp 0.0.21 → 0.0.22

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 (136) hide show
  1. package/data/guides/cryptography-and-otp.md +2 -2
  2. package/data/guides/database-setup.md +4 -3
  3. package/data/guides/email-templates.md +3 -3
  4. package/data/guides/getting-started.md +6 -6
  5. package/data/guides/resource-management.md +9 -9
  6. package/data/packages/platform-blob-storage/api/Variable.AWS_S3_PROVIDER_OPTIONS.md +1 -1
  7. package/data/packages/platform-blob-storage/api/Variable.AZURE_BLOB_PROVIDER_OPTIONS.md +1 -1
  8. package/data/packages/platform-blob-storage/api/Variable.BLOB_PROVIDER.md +1 -1
  9. package/data/packages/platform-blob-storage/api/Variable.VERCEL_BLOB_PROVIDER_OPTIONS.md +1 -1
  10. package/data/packages/platform-core/api/Class.ErrorTemplateService.md +1 -1
  11. package/data/packages/platform-core/api/Class.HostService.md +1 -1
  12. package/data/packages/platform-core/api/Variable.ID_GENERATOR_TOKEN.md +1 -1
  13. package/data/packages/platform-core/api/index.md +0 -27
  14. package/data/packages/platform-core/index.md +7 -4
  15. package/data/packages/platform-cryptography/api/Class.BcryptService.md +4 -4
  16. package/data/packages/platform-cryptography/api/Class.OtpService.md +6 -6
  17. package/data/packages/platform-cryptography/api/Variable.BCRYPT_OPTIONS.md +2 -2
  18. package/data/packages/platform-cryptography/api/Variable.MAX_BCRYPT_PASSWORD_BYTES.md +1 -1
  19. package/data/packages/platform-cryptography/api/Variable.MIN_BCRYPT_ROUNDS.md +1 -1
  20. package/data/packages/platform-cryptography/api/Variable.OTP_OPTIONS.md +2 -2
  21. package/data/packages/platform-cryptography/api/Variable.OTP_SERVICE_TOKEN.md +2 -2
  22. package/data/packages/platform-cryptography/api/Variable.TOTP_EPOCH_TOLERANCE.md +1 -1
  23. package/data/packages/platform-cryptography/api/index.md +3 -3
  24. package/data/packages/platform-documents/api/Class.BaseDocumentRenderer.md +32 -1
  25. package/data/packages/platform-documents/api/Class.DocumentEngine.md +4 -4
  26. package/data/packages/platform-documents/api/Class.DocumentModule.md +2 -2
  27. package/data/packages/platform-documents/api/Class.DocxDocumentRenderer2.md +333 -0
  28. package/data/packages/platform-documents/api/Class.PdfDocumentRenderer.md +355 -0
  29. package/data/packages/platform-documents/api/Interface.IDocumentModuleOptions.md +31 -5
  30. package/data/packages/platform-documents/api/Variable.DOCUMENT_MODULE_OPTIONS.md +1 -1
  31. package/data/packages/platform-documents/api/Variable.DOCUMENT_PARSER_TOKEN.md +1 -1
  32. package/data/packages/platform-documents/api/Variable.DOCUMENT_RENDERER_TOKEN.md +1 -1
  33. package/data/packages/platform-documents/api/Variable.IMAGE_PROCESSOR_TOKEN.md +1 -1
  34. package/data/packages/platform-documents/api/index.md +2 -0
  35. package/data/packages/platform-esigning/api/Class.EsigningClientPort.md +1 -1
  36. package/data/packages/platform-health/index.md +128 -0
  37. package/data/packages/platform-mailing/api/Class.DeliveryStrategyBase.md +0 -1
  38. package/data/packages/platform-mailing/api/Class.MailModule.md +1 -1
  39. package/data/packages/platform-mailing/api/Class.TemplateFetchStrategyBase.md +0 -5
  40. package/data/packages/platform-mailing/api/Variable.SMTP_CONFIG_ENTRIES.md +14 -0
  41. package/data/packages/platform-mailing/api/Variable.SMTP_HOST.md +14 -0
  42. package/data/packages/platform-mailing/api/Variable.SMTP_PASSWORD.md +14 -0
  43. package/data/packages/platform-mailing/api/Variable.SMTP_PORT.md +14 -0
  44. package/data/packages/platform-mailing/api/Variable.SMTP_SECURE.md +14 -0
  45. package/data/packages/platform-mailing/api/Variable.SMTP_USER.md +14 -0
  46. package/data/packages/platform-mailing/api/index.md +6 -3
  47. package/data/packages/platform-mapping/index.md +121 -0
  48. package/data/packages/platform-mcp/api/Variable.MCP_MODULE_OPTIONS.md +1 -1
  49. package/data/packages/platform-openapi/api/Class.SwaggerMultiDocumentService.md +4 -4
  50. package/data/packages/platform-resources/index.md +135 -0
  51. package/data/packages/platform-telemetry/api/Variable.TELEMETRY_ENABLED.md +1 -1
  52. package/data/packages/platform-telemetry/api/Variable.TELEMETRY_FACADE.md +1 -1
  53. package/data/packages/platform-telemetry/api/Variable.TELEMETRY_OPTIONS.md +1 -1
  54. package/{src/knowledge/configPattern.js → data/patterns/config-pattern.md} +44 -47
  55. package/{src/knowledge/dtoPattern.js → data/patterns/dto-pattern.md} +58 -61
  56. package/{src/knowledge/errorHandlingPattern.js → data/patterns/error-handling-pattern.md} +35 -38
  57. package/{src/knowledge/guardPattern.js → data/patterns/guard-pattern.md} +35 -38
  58. package/{src/knowledge/mappingPattern.js → data/patterns/mapping-pattern.md} +43 -144
  59. package/data/patterns/module-pattern.md +182 -0
  60. package/data/patterns/query-pattern.md +137 -0
  61. package/data/patterns/repository-pattern.md +208 -0
  62. package/{src/knowledge/testingPattern.js → data/patterns/testing-pattern.md} +37 -40
  63. package/package.json +1 -1
  64. package/src/PatternsLoader.d.ts +12 -0
  65. package/src/PatternsLoader.js +65 -0
  66. package/src/generators/mappingPatternGenerator.d.ts +5 -0
  67. package/src/generators/mappingPatternGenerator.js +107 -0
  68. package/src/generators/modulePatternGenerator.d.ts +5 -0
  69. package/src/generators/modulePatternGenerator.js +107 -0
  70. package/src/generators/queryPatternGenerator.d.ts +4 -0
  71. package/src/generators/queryPatternGenerator.js +83 -0
  72. package/src/generators/repositoryPatternGenerator.d.ts +5 -0
  73. package/src/generators/repositoryPatternGenerator.js +165 -0
  74. package/src/main.js +15 -9
  75. package/src/models/IPatternDoc.d.ts +15 -0
  76. package/src/models/IPatternDoc.js +3 -0
  77. package/src/tools/registerGetConfigPatternTool.d.ts +2 -1
  78. package/src/tools/registerGetConfigPatternTool.js +4 -3
  79. package/src/tools/registerGetDtoPatternTool.d.ts +2 -1
  80. package/src/tools/registerGetDtoPatternTool.js +4 -3
  81. package/src/tools/registerGetErrorHandlingPatternTool.d.ts +2 -1
  82. package/src/tools/registerGetErrorHandlingPatternTool.js +4 -3
  83. package/src/tools/registerGetGuardPatternTool.d.ts +2 -1
  84. package/src/tools/registerGetGuardPatternTool.js +4 -3
  85. package/src/tools/registerGetMappingPatternTool.d.ts +2 -1
  86. package/src/tools/registerGetMappingPatternTool.js +5 -4
  87. package/src/tools/registerGetModulePatternTool.d.ts +2 -1
  88. package/src/tools/registerGetModulePatternTool.js +5 -4
  89. package/src/tools/registerGetQueryPatternTool.d.ts +2 -1
  90. package/src/tools/registerGetQueryPatternTool.js +5 -4
  91. package/src/tools/registerGetRepositoryPatternTool.d.ts +2 -1
  92. package/src/tools/registerGetRepositoryPatternTool.js +5 -4
  93. package/src/tools/registerGetTestingPatternTool.d.ts +2 -1
  94. package/src/tools/registerGetTestingPatternTool.js +4 -3
  95. package/data/packages/platform-core/api/Class.BlobResourceStrategy.md +0 -195
  96. package/data/packages/platform-core/api/Class.EmbeddedResourceStrategy.md +0 -215
  97. package/data/packages/platform-core/api/Class.FileResourceStrategy.md +0 -192
  98. package/data/packages/platform-core/api/Class.HealthModule.md +0 -42
  99. package/data/packages/platform-core/api/Class.HealthOrchestrator.md +0 -64
  100. package/data/packages/platform-core/api/Class.MappingBuilder.md +0 -110
  101. package/data/packages/platform-core/api/Class.MappingModule.md +0 -46
  102. package/data/packages/platform-core/api/Class.MappingNotRegisteredError.md +0 -56
  103. package/data/packages/platform-core/api/Class.MappingProfileBase.md +0 -52
  104. package/data/packages/platform-core/api/Class.MappingService.md +0 -284
  105. package/data/packages/platform-core/api/Class.ResourceManager.md +0 -565
  106. package/data/packages/platform-core/api/Class.ResourceModule.md +0 -46
  107. package/data/packages/platform-core/api/Class.TypeMappingNotRegisteredError.md +0 -57
  108. package/data/packages/platform-core/api/Function.createMappingKey.md +0 -39
  109. package/data/packages/platform-core/api/Interface.IBlobResourceStrategyConfig.md +0 -28
  110. package/data/packages/platform-core/api/Interface.IBlobServiceAdapter.md +0 -40
  111. package/data/packages/platform-core/api/Interface.IFileResourceStrategyConfig.md +0 -72
  112. package/data/packages/platform-core/api/Interface.IHealthCheckResult.md +0 -46
  113. package/data/packages/platform-core/api/Interface.IHealthIndicator.md +0 -41
  114. package/data/packages/platform-core/api/Interface.IMappingBuilder.md +0 -76
  115. package/data/packages/platform-core/api/Interface.IMappingKey.md +0 -58
  116. package/data/packages/platform-core/api/Interface.IMappingProfile.md +0 -32
  117. package/data/packages/platform-core/api/Interface.IResourceManagerConfig.md +0 -89
  118. package/data/packages/platform-core/api/Interface.IResourceMetadata.md +0 -94
  119. package/data/packages/platform-core/api/Interface.IResourceResult.md +0 -34
  120. package/data/packages/platform-core/api/Interface.IResourceStrategy.md +0 -134
  121. package/data/packages/platform-core/api/Variable.HEALTH_INDICATORS_TOKEN.md +0 -14
  122. package/data/packages/platform-mailing/api/Class.BlobTemplateFetchStrategy.md +0 -60
  123. package/data/packages/platform-mailing/api/Class.FileTemplateFetchStrategy.md +0 -58
  124. package/data/packages/platform-mailing/api/Class.LogDeliveryStrategy.md +0 -71
  125. package/src/knowledge/configPattern.d.ts +0 -5
  126. package/src/knowledge/dtoPattern.d.ts +0 -5
  127. package/src/knowledge/errorHandlingPattern.d.ts +0 -5
  128. package/src/knowledge/guardPattern.d.ts +0 -5
  129. package/src/knowledge/mappingPattern.d.ts +0 -6
  130. package/src/knowledge/modulePattern.d.ts +0 -6
  131. package/src/knowledge/modulePattern.js +0 -283
  132. package/src/knowledge/queryPattern.d.ts +0 -6
  133. package/src/knowledge/queryPattern.js +0 -215
  134. package/src/knowledge/repositoryPattern.d.ts +0 -6
  135. package/src/knowledge/repositoryPattern.js +0 -367
  136. package/src/knowledge/testingPattern.d.ts +0 -5
@@ -1,18 +1,17 @@
1
- "use strict";
2
- /**
3
- * Static knowledge content for the Archipel mapping pattern.
4
- * Returned by the get-mapping-pattern tool.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.MAPPING_PATTERN_WITH_CONTEXT = exports.MAPPING_PATTERN_KNOWLEDGE = void 0;
8
- exports.MAPPING_PATTERN_KNOWLEDGE = `# Archipel Mapping Pattern
1
+ ---
2
+ title: Mapping Pattern
3
+ description: Branded type-safe mapping keys, MappingProfileBase, MappingService, and MappingModule registration.
4
+ order: 5
5
+ ---
6
+
7
+ # Archipel Mapping Pattern
9
8
 
10
9
  ## Overview
11
10
 
12
11
  In Archipel, all object-to-object mapping goes through a central **MappingService** with
13
12
  **branded, type-safe mapping keys**. This guarantees compile-time type safety: the key
14
- encodes both the input and output type, so calling \`mappingService.map(KEY, input)\` is
15
- statically checked — the compiler verifies that \`input\` matches the key's input type and
13
+ encodes both the input and output type, so calling `mappingService.map(KEY, input)` is
14
+ statically checked — the compiler verifies that `input` matches the key's input type and
16
15
  infers the return type automatically.
17
16
 
18
17
  **Rule:** Services MUST NOT inline-create response objects. They return entities.
@@ -22,32 +21,32 @@ Controllers use the MappingService to convert entities to response DTOs.
22
21
 
23
22
  ### IMappingKey<TInput, TOutput>
24
23
 
25
- \`\`\`typescript
24
+ ```typescript
26
25
  export interface IMappingKey<TInput, TOutput> {
27
26
  readonly _brand: 'MappingKey';
28
27
  readonly _input: TInput;
29
28
  readonly _output: TOutput;
30
29
  readonly key: string;
31
30
  }
32
- \`\`\`
31
+ ```
33
32
 
34
- The \`_input\` and \`_output\` fields are phantom types — they exist only for compile-time
33
+ The `_input` and `_output` fields are phantom types — they exist only for compile-time
35
34
  type encoding and are never accessed at runtime.
36
35
 
37
36
  ### createMappingKey<TInput, TOutput>
38
37
 
39
- \`\`\`typescript
40
- import { createMappingKey } from '@breadstone/archipel-platform-core';
38
+ ```typescript
39
+ import { createMappingKey } from '@breadstone/archipel-platform-mapping';
41
40
 
42
41
  export const PRODUCT_MAPPING_KEY = createMappingKey<IProductMappingInput, ProductResponse>('food.product');
43
- \`\`\`
42
+ ```
44
43
 
45
- The string argument \`'food.product'\` is the unique registry key. Convention:
46
- \`<domain>.<entity>\` in lowercase dot-notation.
44
+ The string argument `'food.product'` is the unique registry key. Convention:
45
+ `<domain>.<entity>` in lowercase dot-notation.
47
46
 
48
47
  ## MappingService API
49
48
 
50
- \`\`\`typescript
49
+ ```typescript
51
50
  // Key-based mapping (preferred)
52
51
  const response = mappingService.map(PRODUCT_MAPPING_KEY, input);
53
52
  // → TOutput is inferred from the key, TInput is validated
@@ -58,7 +57,7 @@ const maybeResponse = mappingService.tryMap(PRODUCT_MAPPING_KEY, input);
58
57
  // Type-based mapping (alternative)
59
58
  const response = mappingService.mapTypes(sourceInstance, DestinationClass);
60
59
  const responses = mappingService.mapTypesArray(sourceArray, DestinationClass);
61
- \`\`\`
60
+ ```
62
61
 
63
62
  ## How to Create a Mapping
64
63
 
@@ -67,7 +66,7 @@ const responses = mappingService.mapTypesArray(sourceArray, DestinationClass);
67
66
  The input interface represents the shape of data coming from the repository query.
68
67
  Property names MUST match the Prisma select shape exactly.
69
68
 
70
- \`\`\`typescript
69
+ ```typescript
71
70
  // models/mapping-inputs/IProductMappingInput.ts
72
71
  export interface IProductMappingInput {
73
72
  readonly id: string;
@@ -76,28 +75,28 @@ export interface IProductMappingInput {
76
75
  readonly categoryId: string;
77
76
  readonly createdAt: Date;
78
77
  }
79
- \`\`\`
78
+ ```
80
79
 
81
80
  ### Step 2: Create a branded mapping key
82
81
 
83
82
  Each key is an **exported constant** — never inline magic strings.
84
83
 
85
- \`\`\`typescript
84
+ ```typescript
86
85
  // constants/MappingKeys.ts
87
- import { createMappingKey } from '@breadstone/archipel-platform-core';
86
+ import { createMappingKey } from '@breadstone/archipel-platform-mapping';
88
87
  import { IProductMappingInput } from '../models/mapping-inputs/IProductMappingInput';
89
88
  import { ProductResponse } from '../dtos/ProductResponse';
90
89
 
91
90
  export const PRODUCT_MAPPING_KEY = createMappingKey<IProductMappingInput, ProductResponse>('food.product');
92
- \`\`\`
91
+ ```
93
92
 
94
93
  ### Step 3: Create a mapping profile
95
94
 
96
- A profile extends \`MappingProfileBase\` and registers one or more mappings via the builder.
95
+ A profile extends `MappingProfileBase` and registers one or more mappings via the builder.
97
96
 
98
- \`\`\`typescript
97
+ ```typescript
99
98
  // mappers/ProductMappingProfile.ts
100
- import { MappingProfileBase, IMappingBuilder } from '@breadstone/archipel-platform-core';
99
+ import { MappingProfileBase, IMappingBuilder } from '@breadstone/archipel-platform-mapping';
101
100
  import { PRODUCT_MAPPING_KEY } from '../constants/MappingKeys';
102
101
  import { IProductMappingInput } from '../models/mapping-inputs/IProductMappingInput';
103
102
  import { ProductResponse } from '../dtos/ProductResponse';
@@ -122,12 +121,12 @@ export class ProductMappingProfile extends MappingProfileBase {
122
121
  // #endregion
123
122
 
124
123
  }
125
- \`\`\`
124
+ ```
126
125
 
127
126
  ### Step 4: Register the profile in the module
128
127
 
129
- \`\`\`typescript
130
- import { MappingModule } from '@breadstone/archipel-platform-core';
128
+ ```typescript
129
+ import { MappingModule } from '@breadstone/archipel-platform-mapping';
131
130
  import { ProductMappingProfile } from './mappers/ProductMappingProfile';
132
131
 
133
132
  @Module({
@@ -136,11 +135,11 @@ import { ProductMappingProfile } from './mappers/ProductMappingProfile';
136
135
  ],
137
136
  })
138
137
  export class ProductModule {}
139
- \`\`\`
138
+ ```
140
139
 
141
140
  ### Step 5: Use in controller (NOT in service)
142
141
 
143
- \`\`\`typescript
142
+ ```typescript
144
143
  @Controller('/products')
145
144
  export class ProductController {
146
145
 
@@ -179,7 +178,7 @@ export class ProductController {
179
178
  // #endregion
180
179
 
181
180
  }
182
- \`\`\`
181
+ ```
183
182
 
184
183
  ## MappingBuilder Methods
185
184
 
@@ -187,29 +186,29 @@ The builder supports two registration flavors:
187
186
 
188
187
  ### createKeyedMap (preferred)
189
188
 
190
- \`\`\`typescript
189
+ ```typescript
191
190
  builder.createKeyedMap(SOME_MAPPING_KEY, (input: TInput) => {
192
191
  const output = new TOutput();
193
192
  // ... map fields
194
193
  return output;
195
194
  });
196
- \`\`\`
195
+ ```
197
196
 
198
197
  ### createMap (type-based)
199
198
 
200
- \`\`\`typescript
199
+ ```typescript
201
200
  builder.createMap(SourceClass, DestinationClass, (source: SourceClass) => {
202
201
  const dest = new DestinationClass();
203
202
  // ... map fields
204
203
  return dest;
205
204
  });
206
- \`\`\`
205
+ ```
207
206
 
208
207
  ## Error Handling
209
208
 
210
- - \`MappingNotRegisteredError\` — thrown when a keyed mapping is not found
211
- - \`TypeMappingNotRegisteredError\` — thrown when a type-based mapping is not found
212
- - Both extend \`MappingError\` with a machine-readable \`code\` field
209
+ - `MappingNotRegisteredError` — thrown when a keyed mapping is not found
210
+ - `TypeMappingNotRegisteredError` — thrown when a type-based mapping is not found
211
+ - Both extend `MappingError` with a machine-readable `code` field
213
212
 
214
213
  ## Rules
215
214
 
@@ -217,106 +216,6 @@ builder.createMap(SourceClass, DestinationClass, (source: SourceClass) => {
217
216
  2. **Services return entities, controllers map to responses** — services MUST NOT create response objects.
218
217
  3. **One mapping key per entity→response pair** — use descriptive dot notation for the key string.
219
218
  4. **Input interfaces match Prisma select shape** — property names must align exactly.
220
- 5. **Profiles extend MappingProfileBase** and are registered via \`MappingModule.withProfiles()\`.
221
- 6. **Use \`createKeyedMap\` over \`createMap\`** — branded keys provide better type safety.
222
- 7. **Mapping functions instantiate response classes** — use \`new ResponseClass()\` and assign fields.
223
- `;
224
- const MAPPING_PATTERN_WITH_CONTEXT = (entityName, fields, responseName) => `
225
- ## Example: Mapping for "${entityName}" → "${responseName}"
226
-
227
- Given an entity \`${entityName}\` with fields: ${fields.map((f) => `\`${f}\``).join(', ')}
228
-
229
- ### 1. Input Interface
230
-
231
- \`\`\`typescript
232
- // models/mapping-inputs/I${entityName}MappingInput.ts
233
-
234
- export interface I${entityName}MappingInput {
235
- ${fields.map((f) => ` readonly ${f}: ${inferMappingFieldType(f)};`).join('\n')}
236
- }
237
- \`\`\`
238
-
239
- ### 2. Mapping Key
240
-
241
- \`\`\`typescript
242
- // constants/MappingKeys.ts
243
- import { createMappingKey } from '@breadstone/archipel-platform-core';
244
- import { I${entityName}MappingInput } from '../models/mapping-inputs/I${entityName}MappingInput';
245
- import { ${responseName} } from '../dtos/${responseName}';
246
-
247
- export const ${toConstantCase(entityName)}_MAPPING_KEY = createMappingKey<I${entityName}MappingInput, ${responseName}>('${toDotNotation(entityName)}');
248
- \`\`\`
249
-
250
- ### 3. Mapping Profile
251
-
252
- \`\`\`typescript
253
- // mappers/${entityName}MappingProfile.ts
254
- import { MappingProfileBase, IMappingBuilder } from '@breadstone/archipel-platform-core';
255
- import { ${toConstantCase(entityName)}_MAPPING_KEY } from '../constants/MappingKeys';
256
- import { I${entityName}MappingInput } from '../models/mapping-inputs/I${entityName}MappingInput';
257
- import { ${responseName} } from '../dtos/${responseName}';
258
-
259
- export class ${entityName}MappingProfile extends MappingProfileBase {
260
-
261
- // #region Methods
262
-
263
- public configure(builder: IMappingBuilder): void {
264
- builder.createKeyedMap(${toConstantCase(entityName)}_MAPPING_KEY, (input: I${entityName}MappingInput) => {
265
- const response = new ${responseName}();
266
- ${fields.map((f) => ` response.${f} = input.${f};`).join('\n')}
267
-
268
- return response;
269
- });
270
- }
271
-
272
- // #endregion
273
-
274
- }
275
- \`\`\`
276
-
277
- ### 4. Module Registration
278
-
279
- \`\`\`typescript
280
- import { MappingModule } from '@breadstone/archipel-platform-core';
281
- import { ${entityName}MappingProfile } from './mappers/${entityName}MappingProfile';
282
-
283
- @Module({
284
- imports: [
285
- MappingModule.withProfiles([${entityName}MappingProfile]),
286
- ],
287
- })
288
- export class ${entityName}Module {}
289
- \`\`\`
290
-
291
- ### 5. Controller Usage
292
-
293
- \`\`\`typescript
294
- // In a controller method:
295
- const entity = await this._${lowerFirst(entityName)}Service.findById(id);
296
- const response = this._mappingService.map(${toConstantCase(entityName)}_MAPPING_KEY, entity);
297
- \`\`\`
298
- `;
299
- exports.MAPPING_PATTERN_WITH_CONTEXT = MAPPING_PATTERN_WITH_CONTEXT;
300
- function inferMappingFieldType(fieldName) {
301
- if (fieldName === 'id')
302
- return 'string';
303
- if (fieldName.endsWith('Id'))
304
- return 'string';
305
- if (fieldName.endsWith('At') || fieldName === 'createdAt' || fieldName === 'updatedAt')
306
- return 'Date';
307
- if (fieldName.startsWith('is') || fieldName.startsWith('has'))
308
- return 'boolean';
309
- if (fieldName === 'count' || fieldName === 'quantity' || fieldName === 'amount' || fieldName === 'price')
310
- return 'number';
311
- return 'string';
312
- }
313
- function toConstantCase(name) {
314
- return name.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase();
315
- }
316
- function toDotNotation(name) {
317
- return name.replace(/([a-z])([A-Z])/g, '$1.$2').toLowerCase();
318
- }
319
- function lowerFirst(str) {
320
- return str.charAt(0).toLowerCase() + str.slice(1);
321
- }
322
- //# sourceMappingURL=mappingPattern.js.map
219
+ 5. **Profiles extend MappingProfileBase** and are registered via `MappingModule.withProfiles()`.
220
+ 6. **Use `createKeyedMap` over `createMap`** — branded keys provide better type safety.
221
+ 7. **Mapping functions instantiate response classes** — use `new ResponseClass()` and assign fields.
@@ -0,0 +1,182 @@
1
+ ---
2
+ title: Dynamic Module Pattern
3
+ description: NestJS dynamic modules with register(), port/adapter dependency inversion, and ConfigModule integration.
4
+ order: 6
5
+ ---
6
+
7
+ # Archipel Dynamic Module Pattern
8
+
9
+ ## Overview
10
+
11
+ Archipel platform libraries use **NestJS dynamic modules** with a `register()` factory
12
+ method and **port/adapter dependency inversion**. Each library defines abstract port
13
+ classes. The consuming application provides concrete implementations at registration time.
14
+
15
+ This pattern keeps platform libraries free of product-specific logic while allowing
16
+ full customization through dependency injection.
17
+
18
+ ## Pattern Structure
19
+
20
+ ### 1. Abstract Port (Contract)
21
+
22
+ ```typescript
23
+ // contracts/FeatureAccessPort.ts
24
+
25
+ export abstract class FeatureAccessPort {
26
+
27
+ public abstract checkAccess(userId: string, featureKey: string): Promise<IFeatureAccessResult>;
28
+
29
+ public abstract recordUsage(userId: string, featureKey: string): Promise<void>;
30
+
31
+ }
32
+ ```
33
+
34
+ Ports are **abstract classes** (not interfaces) so they can serve as NestJS injection tokens.
35
+
36
+ ### 2. Options Interface
37
+
38
+ ```typescript
39
+ // interfaces/IPaymentModuleOptions.ts
40
+
41
+ export interface IPaymentModuleOptions {
42
+ /**
43
+ * Concrete implementation of the FeatureAccessPort.
44
+ */
45
+ featureAccess?: Type<FeatureAccessPort>;
46
+
47
+ /**
48
+ * When true the module is registered globally.
49
+ */
50
+ isGlobal?: boolean;
51
+ }
52
+ ```
53
+
54
+ ### 3. Dynamic Module with register()
55
+
56
+ ```typescript
57
+ // PaymentModule.ts
58
+ import { ConfigModule } from '@breadstone/archipel-platform-core';
59
+ import { type DynamicModule, Module, type Type } from '@nestjs/common';
60
+
61
+ @Module({})
62
+ export class PaymentModule {
63
+
64
+ public static register(options?: IPaymentModuleOptions): DynamicModule {
65
+ const providers = [StripeClient, FeatureGuard, FeatureUsageInterceptor];
66
+
67
+ if (options?.featureAccess) {
68
+ providers.push({
69
+ provide: FeatureAccessPort,
70
+ useClass: options.featureAccess,
71
+ } as never);
72
+ }
73
+
74
+ return {
75
+ global: options?.isGlobal ?? false,
76
+ module: PaymentModule,
77
+ imports: [ConfigModule.register('platform-payments', PLATFORM_PAYMENTS_CONFIG_ENTRIES)],
78
+ providers: providers,
79
+ exports: [StripeClient, FeatureGuard, FeatureUsageInterceptor],
80
+ };
81
+ }
82
+
83
+ }
84
+ ```
85
+
86
+ ### 4. Consumer Registration
87
+
88
+ ```typescript
89
+ // In the consuming application:
90
+ @Module({
91
+ imports: [
92
+ PaymentModule.register({
93
+ featureAccess: MyFeatureAccessAdapter,
94
+ isGlobal: true,
95
+ }),
96
+ ],
97
+ })
98
+ export class AppModule {}
99
+ ```
100
+
101
+ ## Variants in the Codebase
102
+
103
+ ### Simple: PaymentModule
104
+
105
+ - 1 optional port (`featureAccess`)
106
+ - Optional `isGlobal` flag
107
+ - Config via `ConfigModule.register()`
108
+
109
+ ### Complex: AuthModule
110
+
111
+ - 4 required ports (`authSubject`, `mfaSubject`, `sessionPersistence`, `verificationSubject`)
112
+ - 2 optional ports (`socialAuth`, `tokenEnricher`)
113
+ - Conditional strategy registration (social OAuth only when `socialAuth` provided)
114
+ - Imports: PassportModule, JwtModule, MappingModule, EventModule, IdentifierModule
115
+ - Middleware configuration via `configure(consumer)`
116
+
117
+ ### Provider-based: BlobModule
118
+
119
+ - Uses `forRoot()` instead of `register()` (global by default)
120
+ - Discriminated union for provider selection: `{ kind: 'Vercel' }` or `{ kind: 'Custom', useClass: ... }`
121
+ - Optional persistence ports (`objectPersistence`, `variantPersistence`)
122
+
123
+ ### Infrastructure: DatabaseModule
124
+
125
+ - Both `forRoot()` (global) and `register()` (scoped) variants
126
+ - Factory provider for PrismaService with extensions
127
+ - Health indicator bootstrapping
128
+
129
+ ### Async: McpModule
130
+
131
+ - `register(options)` for synchronous configuration
132
+ - `registerAsync({ useFactory, inject })` for async (e.g., reading config at runtime)
133
+ - `registerAsync({ useClass })` for factory class pattern
134
+ - `registerAsync({ useExisting })` for reusing an existing factory
135
+
136
+ ## ConfigModule Integration
137
+
138
+ Every library module imports `ConfigModule.register()` to declare its configuration
139
+ dependencies:
140
+
141
+ ```typescript
142
+ imports: [ConfigModule.register('platform-payments', PLATFORM_PAYMENTS_CONFIG_ENTRIES)]
143
+ ```
144
+
145
+ This registers typed config keys into the global `ConfigRegistry` for validation
146
+ and discovery.
147
+
148
+ ## MappingModule Integration
149
+
150
+ Modules that need object mapping import `MappingModule.withProfiles()`:
151
+
152
+ ```typescript
153
+ imports: [MappingModule.withProfiles([SessionMappingProfile])]
154
+ ```
155
+
156
+ ## Health Indicator Pattern
157
+
158
+ Infrastructure modules (Database, Blob) register health indicators:
159
+
160
+ ```typescript
161
+ providers: [
162
+ BlobHealthIndicator,
163
+ {
164
+ provide: 'BLOB_HEALTH_INDICATOR_BOOTSTRAP',
165
+ useFactory: (orchestrator: HealthOrchestrator, indicator: BlobHealthIndicator) => {
166
+ orchestrator.registerIndicator(indicator);
167
+ return true;
168
+ },
169
+ inject: [HealthOrchestrator, BlobHealthIndicator],
170
+ },
171
+ ]
172
+ ```
173
+
174
+ ## Rules
175
+
176
+ 1. **Ports are abstract classes** — not interfaces — so they work as DI tokens.
177
+ 2. **`register()` for stateless config**, `registerAsync()` when config depends on runtime values.
178
+ 3. **`forRoot()` for global singletons** (database, blob storage), `register()` for scoped modules.
179
+ 4. **Always import ConfigModule.register()** to declare environment dependencies.
180
+ 5. **Optional ports use conditional provider registration** (`if (options?.port)`).
181
+ 6. **Required ports are listed in the options interface** without optional markers.
182
+ 7. **Exports should list concrete services, guards, interceptors** — not internal implementation details.
@@ -0,0 +1,137 @@
1
+ ---
2
+ title: Query Pattern
3
+ description: Repository + Query pattern with IRepositoryQuery, factory functions, transactional queries, and rules.
4
+ order: 7
5
+ ---
6
+
7
+ # Archipel Query Pattern (v1)
8
+
9
+ ## Overview
10
+
11
+ In Archipel, data access follows the **Repository + Query** pattern. Repositories never expose
12
+ raw Prisma delegate methods to services. Instead, every data operation is wrapped in a
13
+ **query factory function** that returns an `IRepositoryQuery` object. Services call
14
+ `repository.execute(someQuery(...))` — never `repository.findFirst(...)` directly.
15
+
16
+ ## Core Interface
17
+
18
+ ```typescript
19
+ export interface IRepositoryQuery<TDelegate, TResult> {
20
+ readonly name: string;
21
+ run(model: TDelegate): Promise<TResult>;
22
+ }
23
+ ```
24
+
25
+ - `TDelegate` — the Prisma delegate type (e.g. `Prisma.UserDelegate`)
26
+ - `TResult` — the query's return type
27
+ - `name` — identifier used for logging and debugging
28
+
29
+ ## Factory Function
30
+
31
+ ```typescript
32
+ import { IRepositoryQuery } from '@breadstone/archipel-platform-database';
33
+
34
+ export function query<TDelegate, TResult>(
35
+ name: string,
36
+ run: (model: TDelegate) => Promise<TResult>,
37
+ ): IRepositoryQuery<TDelegate, TResult> {
38
+ return { name, run };
39
+ }
40
+ ```
41
+
42
+ ## Type Extraction
43
+
44
+ ```typescript
45
+ export type QueryResultType<T> = T extends IRepositoryQuery<unknown, infer R> ? R : never;
46
+ ```
47
+
48
+ Use this to derive the result type from a query factory without duplicating types:
49
+ ```typescript
50
+ type UserProfileResult = QueryResultType<ReturnType<typeof findUserProfileQuery>>;
51
+ ```
52
+
53
+ ## How to Write a Query
54
+
55
+ ### Step 1: Define the query factory function
56
+
57
+ Each query is a **named function** that returns an `IRepositoryQuery`. The function may accept
58
+ parameters — these become the query's runtime arguments.
59
+
60
+ ```typescript
61
+ import { Prisma } from '@prisma/client';
62
+ import { query } from '@breadstone/archipel-platform-database';
63
+
64
+ export function findUserByEmailQuery(email: string) {
65
+ return query<Prisma.UserDelegate, { id: string; email: string; name: string } | null>(
66
+ 'findUserByEmail',
67
+ (model) =>
68
+ model.findFirst({
69
+ where: { email },
70
+ select: { id: true, email: true, name: true },
71
+ }),
72
+ );
73
+ }
74
+ ```
75
+
76
+ ### Step 2: Call from a service via repository.execute()
77
+
78
+ ```typescript
79
+ // In the service:
80
+ const user = await this._userRepository.execute(findUserByEmailQuery(email));
81
+ ```
82
+
83
+ ### Step 3: Extract result type if needed for mapping
84
+
85
+ ```typescript
86
+ type FindUserByEmailResult = QueryResultType<ReturnType<typeof findUserByEmailQuery>>;
87
+ ```
88
+
89
+ ## Transactional Queries
90
+
91
+ For operations that span multiple models, use `transactionalQuery`:
92
+
93
+ ```typescript
94
+ import { Prisma } from '@prisma/client';
95
+ import { transactionalQuery } from '@breadstone/archipel-platform-database';
96
+
97
+ export function createOrderWithItemsQuery(data: { userId: string; items: Array<{ productId: string; quantity: number }> }) {
98
+ return transactionalQuery<{ orderId: string }>(
99
+ 'createOrderWithItems',
100
+ async (tx: Prisma.TransactionClient) => {
101
+ const order = await tx.order.create({
102
+ data: { userId: data.userId },
103
+ select: { id: true },
104
+ });
105
+
106
+ await tx.orderItem.createMany({
107
+ data: data.items.map((item) => ({
108
+ orderId: order.id,
109
+ productId: item.productId,
110
+ quantity: item.quantity,
111
+ })),
112
+ });
113
+
114
+ return { orderId: order.id };
115
+ },
116
+ );
117
+ }
118
+ ```
119
+
120
+ Called via:
121
+ ```typescript
122
+ const result = await this._orderRepository.executeTransactional(
123
+ createOrderWithItemsQuery({ userId, items }),
124
+ );
125
+ ```
126
+
127
+ ## Rules
128
+
129
+ 1. **Never call Prisma delegate methods directly from services.** Always go through `execute(query)`.
130
+ 2. **Always select only the fields you need.** Use `select` — never return full records.
131
+ 3. **Query names must be descriptive.** Use the pattern: `verbModelByConditionQuery`
132
+ (e.g. `findUserByEmailQuery`, `countOrdersByStatusQuery`, `updateUserNameQuery`).
133
+ 4. **One query per file** for non-trivial queries. Small related queries may share a file.
134
+ 5. **Type the result explicitly.** The second generic parameter of `query()` should be an inline
135
+ object type or a dedicated interface matching the `select` shape.
136
+ 6. **Each query factory is a standalone function** (not a class method). Import `query` from
137
+ `@breadstone/archipel-platform-database`.