@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,367 +0,0 @@
1
- "use strict";
2
- /**
3
- * Static knowledge content for the Archipel repository class pattern.
4
- * Returned by the get-repository-pattern tool.
5
- */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.REPOSITORY_PATTERN_WITH_MODEL = exports.REPOSITORY_PATTERN_KNOWLEDGE = void 0;
8
- exports.REPOSITORY_PATTERN_KNOWLEDGE = `# Archipel Repository Pattern
9
-
10
- ## Overview
11
-
12
- Every Prisma model gets a dedicated **Repository class** extending \`RepositoryBase\`.
13
- Repositories are the ONLY code that touches Prisma delegates. Services never call
14
- Prisma directly — they call \`repository.execute(someQuery(...))\` or
15
- \`repository.executeTransactional(someTxQuery(...))\`.
16
-
17
- ## RepositoryBase Signature
18
-
19
- \`\`\`typescript
20
- import { RepositoryBase } from '@breadstone/archipel-platform-database';
21
-
22
- export abstract class RepositoryBase<
23
- TDelegate extends Record<RepositoryOperations, (args: any) => Promise<any>>,
24
- TArgs extends Record<RepositoryOperations, unknown>,
25
- TReturn extends Record<RepositoryOperations, unknown>,
26
- TEntity = unknown
27
- >
28
- \`\`\`
29
-
30
- ### Generic Parameters
31
-
32
- | Param | Purpose | Example |
33
- |-------|---------|---------|
34
- | \`TDelegate\` | Prisma delegate type from generated client | \`Prisma.UserDelegate\` |
35
- | \`TArgs\` | Argument shapes for each operation | \`Prisma.UserFindManyArgs\`, etc. |
36
- | \`TReturn\` | Return shapes for each operation | \`User\`, \`User[]\`, etc. |
37
- | \`TEntity\` | Domain entity interface (optional) | \`IUserEntity\` |
38
-
39
- ### Helper Types
40
-
41
- \`\`\`typescript
42
- import { DelegateArgs, DelegateReturnTypes } from '@breadstone/archipel-platform-database';
43
-
44
- // These extract args and return types from a delegate automatically:
45
- type UserArgs = DelegateArgs<Prisma.UserDelegate>;
46
- type UserReturns = DelegateReturnTypes<Prisma.UserDelegate>;
47
- \`\`\`
48
-
49
- ## How to Create a Repository
50
-
51
- ### Step 1: Create the repository class
52
-
53
- \`\`\`typescript
54
- // repositories/UserRepository.ts
55
- import { Injectable } from '@nestjs/common';
56
- import { Prisma } from '@prisma/client';
57
- import {
58
- DatabaseService,
59
- DelegateArgs,
60
- DelegateReturnTypes,
61
- RepositoryBase,
62
- } from '@breadstone/archipel-platform-database';
63
-
64
- @Injectable()
65
- export class UserRepository extends RepositoryBase<
66
- Prisma.UserDelegate,
67
- DelegateArgs<Prisma.UserDelegate>,
68
- DelegateReturnTypes<Prisma.UserDelegate>,
69
- IUserEntity
70
- > {
71
-
72
- // #region Ctor
73
-
74
- public constructor(db: DatabaseService) {
75
- super(db, db.client.user);
76
- }
77
-
78
- // #endregion
79
-
80
- }
81
- \`\`\`
82
-
83
- The constructor receives \`DatabaseService\` and passes both the service and the
84
- Prisma delegate (\`db.client.user\`) to the base class.
85
-
86
- ### Step 2: Register as a provider in a module
87
-
88
- \`\`\`typescript
89
- @Module({
90
- imports: [DatabaseModule.register()],
91
- providers: [UserRepository, UserService],
92
- exports: [UserService],
93
- })
94
- export class UserModule {}
95
- \`\`\`
96
-
97
- ### Step 3: Inject into a service
98
-
99
- \`\`\`typescript
100
- @Injectable()
101
- export class UserService {
102
-
103
- // #region Fields
104
-
105
- private readonly _userRepository: UserRepository;
106
-
107
- // #endregion
108
-
109
- // #region Ctor
110
-
111
- public constructor(userRepository: UserRepository) {
112
- this._userRepository = userRepository;
113
- }
114
-
115
- // #endregion
116
-
117
- // #region Methods
118
-
119
- public async findById(id: string): Promise<IUserEntity | null> {
120
- return this._userRepository.execute(findUserByIdQuery(id));
121
- }
122
-
123
- public async findAll(skip = 0, take = 20): Promise<IUserEntity[]> {
124
- return this._userRepository.execute(findAllUsersQuery(skip, take));
125
- }
126
-
127
- // #endregion
128
-
129
- }
130
- \`\`\`
131
-
132
- ## Key Methods on RepositoryBase
133
-
134
- ### execute(query)
135
-
136
- Primary method for data access. Delegates to a query object.
137
-
138
- \`\`\`typescript
139
- public execute<TResult>(query: IRepositoryQuery<TDelegate, TResult>): Promise<TResult>
140
- \`\`\`
141
-
142
- ### executeTransactional(query)
143
-
144
- For multi-model operations within a transaction.
145
-
146
- \`\`\`typescript
147
- public executeTransactional<TResult>(query: ITransactionalRepositoryQuery<TResult>): Promise<TResult>
148
- \`\`\`
149
-
150
- ### Direct Methods (for legacy or internal use only)
151
-
152
- The base class also exposes \`findUnique\`, \`findMany\`, \`findFirst\`, \`create\`,
153
- \`createMany\`, \`update\`, \`updateMany\`, \`upsert\`, \`delete\`, \`deleteMany\`,
154
- \`aggregate\`, \`count\`, \`groupBy\`, \`merge\`.
155
-
156
- **Important:** New code should use \`execute(query)\` exclusively.
157
- Direct method calls are available but violate the query pattern convention.
158
-
159
- ### findMany with Pagination
160
-
161
- \`\`\`typescript
162
- // Direct method (legacy)
163
- const results = await this._repository.findMany(args, { page: 1, perPage: 20 });
164
- \`\`\`
165
-
166
- ## Error Handling
167
-
168
- All Prisma errors are caught by the base class \`tryCatch\` wrapper and re-thrown
169
- as \`RepositoryError\`:
170
-
171
- - \`PrismaClientKnownRequestError\` → \`RepositoryError\` with code \`'R_KNOWN'\`
172
- - \`PrismaClientUnknownRequestError\` → \`RepositoryError\` with code \`'R_UNKNOWN'\`
173
- - Other errors are re-thrown unchanged
174
-
175
- The global \`RepositoryExceptionFilter\` catches \`RepositoryError\` and returns
176
- HTTP 500 with a structured envelope.
177
-
178
- ## Query Integration
179
-
180
- Repositories work with query factories from the query pattern:
181
-
182
- \`\`\`typescript
183
- // queries/findUserByIdQuery.ts
184
- import { Prisma } from '@prisma/client';
185
- import { query } from '@breadstone/archipel-platform-database';
186
-
187
- export function findUserByIdQuery(id: string) {
188
- return query<Prisma.UserDelegate, IUserEntity | null>(
189
- 'findUserById',
190
- (model) => model.findFirst({
191
- where: { id },
192
- select: { id: true, email: true, name: true, createdAt: true },
193
- }),
194
- );
195
- }
196
-
197
- // Service usage:
198
- const user = await this._userRepository.execute(findUserByIdQuery(id));
199
- \`\`\`
200
-
201
- ## Rules
202
-
203
- 1. **One repository per Prisma model** — e.g. \`UserRepository\`, \`OrderRepository\`.
204
- 2. **Constructor receives \`DatabaseService\`** and passes the delegate via \`db.client.<model>\`.
205
- 3. **Use \`DelegateArgs\` and \`DelegateReturnTypes\`** helper types for the RepositoryBase generics.
206
- 4. **New code uses \`execute(query)\`** — never direct calls like \`repository.findFirst()\` from services.
207
- 5. **Register as provider** in the feature module, import \`DatabaseModule.register()\`.
208
- 6. **Repositories are \`@Injectable()\`** — they participate in NestJS DI.
209
- 7. **Domain entity interface as fourth generic** (\`TEntity\`) is optional but recommended.
210
- `;
211
- const REPOSITORY_PATTERN_WITH_MODEL = (modelName, fields) => `
212
- ## Example: Repository for "${modelName}"
213
-
214
- Given a Prisma model \`${modelName}\` with fields: ${fields.map((f) => `\`${f}\``).join(', ')}
215
-
216
- ### Repository Class
217
-
218
- \`\`\`typescript
219
- // repositories/${modelName}Repository.ts
220
- import { Injectable } from '@nestjs/common';
221
- import { Prisma } from '@prisma/client';
222
- import {
223
- DatabaseService,
224
- DelegateArgs,
225
- DelegateReturnTypes,
226
- RepositoryBase,
227
- } from '@breadstone/archipel-platform-database';
228
- import { I${modelName}Entity } from '../models/entities/I${modelName}Entity';
229
-
230
- @Injectable()
231
- export class ${modelName}Repository extends RepositoryBase<
232
- Prisma.${modelName}Delegate,
233
- DelegateArgs<Prisma.${modelName}Delegate>,
234
- DelegateReturnTypes<Prisma.${modelName}Delegate>,
235
- I${modelName}Entity
236
- > {
237
-
238
- // #region Ctor
239
-
240
- public constructor(db: DatabaseService) {
241
- super(db, db.client.${lowerFirst(modelName)});
242
- }
243
-
244
- // #endregion
245
-
246
- }
247
- \`\`\`
248
-
249
- ### Entity Interface
250
-
251
- \`\`\`typescript
252
- // models/entities/I${modelName}Entity.ts
253
- export interface I${modelName}Entity {
254
- ${fields.map((f) => ` readonly ${f}: ${inferFieldType(f)};`).join('\n')}
255
- }
256
- \`\`\`
257
-
258
- ### Query Factories
259
-
260
- \`\`\`typescript
261
- // queries/find${modelName}ByIdQuery.ts
262
- import { Prisma } from '@prisma/client';
263
- import { query } from '@breadstone/archipel-platform-database';
264
- import { I${modelName}Entity } from '../models/entities/I${modelName}Entity';
265
-
266
- export function find${modelName}ByIdQuery(id: string) {
267
- return query<Prisma.${modelName}Delegate, I${modelName}Entity | null>(
268
- 'find${modelName}ById',
269
- (model) => model.findFirst({
270
- where: { id },
271
- select: { ${fields.map((f) => `${f}: true`).join(', ')} },
272
- }),
273
- );
274
- }
275
-
276
- export function findAll${modelName}sQuery(skip = 0, take = 20) {
277
- return query<Prisma.${modelName}Delegate, I${modelName}Entity[]>(
278
- 'findAll${modelName}s',
279
- (model) => model.findMany({
280
- skip,
281
- take,
282
- select: { ${fields.map((f) => `${f}: true`).join(', ')} },
283
- orderBy: { ${fields.includes('createdAt') ? 'createdAt' : fields[0]}: 'desc' },
284
- }),
285
- );
286
- }
287
-
288
- export function count${modelName}sQuery() {
289
- return query<Prisma.${modelName}Delegate, number>(
290
- 'count${modelName}s',
291
- (model) => model.count(),
292
- );
293
- }
294
- \`\`\`
295
-
296
- ### Module Registration
297
-
298
- \`\`\`typescript
299
- import { DatabaseModule } from '@breadstone/archipel-platform-database';
300
- import { ${modelName}Repository } from './repositories/${modelName}Repository';
301
- import { ${modelName}Service } from './services/${modelName}Service';
302
-
303
- @Module({
304
- imports: [DatabaseModule.register()],
305
- providers: [${modelName}Repository, ${modelName}Service],
306
- exports: [${modelName}Service],
307
- })
308
- export class ${modelName}Module {}
309
- \`\`\`
310
-
311
- ### Service Usage
312
-
313
- \`\`\`typescript
314
- @Injectable()
315
- export class ${modelName}Service {
316
-
317
- // #region Fields
318
-
319
- private readonly _${lowerFirst(modelName)}Repository: ${modelName}Repository;
320
-
321
- // #endregion
322
-
323
- // #region Ctor
324
-
325
- public constructor(${lowerFirst(modelName)}Repository: ${modelName}Repository) {
326
- this._${lowerFirst(modelName)}Repository = ${lowerFirst(modelName)}Repository;
327
- }
328
-
329
- // #endregion
330
-
331
- // #region Methods
332
-
333
- public async findById(id: string): Promise<I${modelName}Entity | null> {
334
- return this._${lowerFirst(modelName)}Repository.execute(find${modelName}ByIdQuery(id));
335
- }
336
-
337
- public async findAll(skip = 0, take = 20): Promise<I${modelName}Entity[]> {
338
- return this._${lowerFirst(modelName)}Repository.execute(findAll${modelName}sQuery(skip, take));
339
- }
340
-
341
- public async count(): Promise<number> {
342
- return this._${lowerFirst(modelName)}Repository.execute(count${modelName}sQuery());
343
- }
344
-
345
- // #endregion
346
-
347
- }
348
- \`\`\`
349
- `;
350
- exports.REPOSITORY_PATTERN_WITH_MODEL = REPOSITORY_PATTERN_WITH_MODEL;
351
- function inferFieldType(fieldName) {
352
- if (fieldName === 'id')
353
- return 'string';
354
- if (fieldName.endsWith('Id'))
355
- return 'string';
356
- if (fieldName.endsWith('At') || fieldName === 'createdAt' || fieldName === 'updatedAt')
357
- return 'Date';
358
- if (fieldName.startsWith('is') || fieldName.startsWith('has'))
359
- return 'boolean';
360
- if (fieldName === 'count' || fieldName === 'quantity' || fieldName === 'amount' || fieldName === 'price')
361
- return 'number';
362
- return 'string';
363
- }
364
- function lowerFirst(str) {
365
- return str.charAt(0).toLowerCase() + str.slice(1);
366
- }
367
- //# sourceMappingURL=repositoryPattern.js.map
@@ -1,5 +0,0 @@
1
- /**
2
- * Static knowledge content for the Archipel testing pattern.
3
- * Returned by the get-testing-pattern tool.
4
- */
5
- export declare const TESTING_PATTERN_KNOWLEDGE = "# Archipel Testing Pattern\n\n## Overview\n\nArchipel uses **Vitest** for unit and integration tests with **vi mocking**. Tests follow\nthe Arrange-Act-Assert (AAA) pattern with descriptive `describe`/`it` blocks. Each test\nfile covers a single class or module.\n\n## Test Framework\n\n- **Runner:** Vitest\n- **Mocking:** `vi.fn()`, `vi.mock()`, `vi.spyOn()`\n- **Assertions:** Vitest built-in (`expect`)\n- **E2E:** Supertest against a bootstrapped NestJS app\n\n## File Naming & Location\n\n| Test Type | File Pattern | Location |\n|-----------|-------------|----------|\n| Unit test | `*.spec.ts` | Next to the source file |\n| E2E test | `*.e2e-spec.ts` | `test/` directory |\n\n## Basic Test Structure\n\n```typescript\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\ndescribe('UserService', () => {\n\n // #region Fields\n\n let service: UserService;\n let mockRepository: { execute: ReturnType<typeof vi.fn> };\n let mockMappingService: { map: ReturnType<typeof vi.fn> };\n\n // #endregion\n\n // #region Methods\n\n beforeEach(() => {\n vi.restoreAllMocks();\n\n mockRepository = {\n execute: vi.fn(),\n };\n\n mockMappingService = {\n map: vi.fn(),\n };\n\n service = new UserService(\n mockRepository as unknown as UserRepository,\n mockMappingService as unknown as MappingService,\n );\n });\n\n describe('findById', () => {\n it('should return entity when user exists', async () => {\n // arrange\n const mockUser = { id: '1', email: 'test@example.com', name: 'Test' };\n mockRepository.execute.mockResolvedValue(mockUser);\n\n // act\n const result = await service.findById('1');\n\n // assert\n expect(result).toEqual(mockUser);\n expect(mockRepository.execute).toHaveBeenCalledOnce();\n });\n\n it('should throw UserNotFoundError when user does not exist', async () => {\n // arrange\n mockRepository.execute.mockResolvedValue(null);\n\n // act & assert\n await expect(() => service.findById('nonexistent'))\n .rejects.toThrow(UserNotFoundError);\n });\n });\n\n // #endregion\n\n});\n```\n\n## Mocking Patterns\n\n### Mocking Prisma Delegates (for Repository Tests)\n\n```typescript\nvi.mock('@prisma/client/runtime/client', () => ({\n PrismaClientKnownRequestError: class PrismaClientKnownRequestError extends Error {\n public code: string;\n public meta?: Record<string, unknown>;\n public clientVersion: string;\n public constructor(message: string, opts: { code: string; clientVersion: string; meta?: Record<string, unknown> }) {\n super(message);\n this.name = 'PrismaClientKnownRequestError';\n this.code = opts.code;\n this.clientVersion = opts.clientVersion;\n this.meta = opts.meta;\n }\n },\n PrismaClientUnknownRequestError: class PrismaClientUnknownRequestError extends Error {\n public clientVersion: string;\n public constructor(message: string, opts: { clientVersion: string }) {\n super(message);\n this.name = 'PrismaClientUnknownRequestError';\n this.clientVersion = opts.clientVersion;\n }\n },\n}));\n```\n\n### Creating a Mock Delegate\n\n```typescript\ntype MockDelegate = Record<\n | 'aggregate' | 'count' | 'create' | 'createMany' | 'createManyAndReturn'\n | 'delete' | 'deleteMany' | 'findFirst' | 'findFirstOrThrow'\n | 'findMany' | 'findUnique' | 'findUniqueOrThrow'\n | 'groupBy' | 'update' | 'updateMany' | 'upsert',\n ReturnType<typeof vi.fn>\n>;\n\nfunction createMockDelegate(): MockDelegate {\n return {\n findUnique: vi.fn(),\n findFirst: vi.fn(),\n findMany: vi.fn(),\n create: vi.fn(),\n createMany: vi.fn(),\n createManyAndReturn: vi.fn(),\n update: vi.fn(),\n updateMany: vi.fn(),\n upsert: vi.fn(),\n delete: vi.fn(),\n deleteMany: vi.fn(),\n aggregate: vi.fn(),\n count: vi.fn(),\n groupBy: vi.fn(),\n findFirstOrThrow: vi.fn(),\n findUniqueOrThrow: vi.fn(),\n };\n}\n```\n\n### Mocking DatabaseService\n\n```typescript\nconst mockDb = {\n transactionCallback: vi.fn(),\n client: {\n user: createMockDelegate(),\n },\n} as unknown as DatabaseService;\n```\n\n### Mocking a Query\n\n```typescript\nconst mockQuery = {\n name: 'findUserById',\n run: vi.fn().mockResolvedValue({ id: '1', email: 'test@example.com' }),\n};\n```\n\n## Repository Test Pattern\n\n```typescript\nimport { beforeEach, describe, expect, it, vi } from 'vitest';\n\n// Mock Prisma runtime errors BEFORE importing test subject\nvi.mock('@prisma/client/runtime/client', () => ({ /* ... */ }));\nimport { PrismaClientKnownRequestError } from '@prisma/client/runtime/client';\n\ndescribe('UserRepository', () => {\n\n let repository: TestRepository;\n let mockModel: MockDelegate;\n let mockDb: DatabaseService;\n\n beforeEach(() => {\n vi.restoreAllMocks();\n mockModel = createMockDelegate();\n mockDb = { transactionCallback: vi.fn() } as unknown as DatabaseService;\n repository = new TestRepository(mockDb, mockModel);\n });\n\n describe('execute', () => {\n it('should execute a query against the model', async () => {\n // arrange\n const mockQuery = {\n name: 'testQuery',\n run: vi.fn().mockResolvedValue({ id: '1' }),\n };\n\n // act\n const result = await repository.execute(mockQuery);\n\n // assert\n expect(mockQuery.run).toHaveBeenCalledWith(mockModel);\n expect(result).toEqual({ id: '1' });\n });\n\n it('should wrap PrismaClientKnownRequestError as RepositoryError', async () => {\n // arrange\n const prismaError = new PrismaClientKnownRequestError('Not found', {\n code: 'P2025',\n clientVersion: '6.0.0',\n });\n const mockQuery = {\n name: 'failingQuery',\n run: vi.fn().mockRejectedValue(prismaError),\n };\n\n // act & assert\n await expect(() => repository.execute(mockQuery))\n .rejects.toThrow(RepositoryError);\n });\n });\n\n});\n```\n\n## Service Test Pattern\n\n```typescript\ndescribe('ProductService', () => {\n\n let service: ProductService;\n let mockRepo: { execute: ReturnType<typeof vi.fn> };\n\n beforeEach(() => {\n vi.restoreAllMocks();\n mockRepo = { execute: vi.fn() };\n service = new ProductService(mockRepo as unknown as ProductRepository);\n });\n\n describe('findById', () => {\n it('should return entity when found', async () => {\n // arrange\n const expected = { id: '1', name: 'Product A', barcode: '123' };\n mockRepo.execute.mockResolvedValue(expected);\n\n // act\n const result = await service.findById('1');\n\n // assert\n expect(result).toEqual(expected);\n });\n\n it('should throw domain error when not found', async () => {\n // arrange\n mockRepo.execute.mockResolvedValue(null);\n\n // act & assert\n await expect(() => service.findById('unknown'))\n .rejects.toThrow(ProductNotFoundError);\n });\n });\n\n});\n```\n\n## Mapping Profile Test Pattern\n\n```typescript\ndescribe('ProductMappingProfile', () => {\n\n let mappingService: MappingService;\n\n beforeEach(() => {\n mappingService = new MappingService();\n const profile = new ProductMappingProfile();\n mappingService.registerProfile(profile);\n });\n\n it('should map input to response correctly', () => {\n // arrange\n const input: IProductMappingInput = {\n id: '1',\n barcode: '123',\n name: 'Product A',\n categoryId: 'cat-1',\n createdAt: new Date('2026-01-01'),\n };\n\n // act\n const result = mappingService.map(PRODUCT_MAPPING_KEY, input);\n\n // assert\n expect(result).toBeInstanceOf(ProductResponse);\n expect(result.id).toBe('1');\n expect(result.barcode).toBe('123');\n expect(result.name).toBe('Product A');\n });\n\n});\n```\n\n## Test Conventions\n\n### Comments\n\n```typescript\n// Use AAA comments:\n// arrange \u2014 set up test data and mocks\n// act \u2014 call the method under test\n// act & assert \u2014 when the assertion is on the thrown error\n// assert \u2014 verify the outcome\n```\n\n### Regions\n\n```typescript\ndescribe('MyClass', () => {\n\n // #region Fields\n let service: MyService;\n // #endregion\n\n // #region Methods\n beforeEach(() => { ... });\n\n describe('methodName', () => { ... });\n // #endregion\n\n});\n```\n\n### Naming\n\n- `describe` blocks: Class name or method name\n- `it` blocks: `'should <expected behavior> when <condition>'`\n\n## Rules\n\n1. **Every public service method needs at least one happy-path and one failure-path test.**\n2. **Use `vi.restoreAllMocks()` in `beforeEach`** \u2014 prevent mock leakage between tests.\n3. **Mock at the boundary** \u2014 mock repositories in service tests, mock delegates in repository tests.\n4. **AAA pattern** \u2014 clearly separate arrange, act, assert with comments.\n5. **`vi.mock()` for modules must appear before imports** of the mocked module.\n6. **No real database in unit tests** \u2014 use mocks. Use Testcontainers for integration tests.\n7. **Assert on behavior, not implementation** \u2014 verify return values and thrown errors, not internal calls\n (unless the call IS the behavior, e.g., verifying a repository was called).\n8. **Use `mockResolvedValue` / `mockRejectedValue`** for async mocks.\n";