nestjs-ddd-cli 2.2.1 → 3.2.1

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 (254) hide show
  1. package/README.md +247 -408
  2. package/ddd.schema.json +111 -0
  3. package/dist/commands/aggregate-validator.d.ts +9 -0
  4. package/dist/commands/aggregate-validator.js +953 -0
  5. package/dist/commands/aggregate-validator.js.map +1 -0
  6. package/dist/commands/ai-assist.d.ts +8 -0
  7. package/dist/commands/ai-assist.js +337 -0
  8. package/dist/commands/ai-assist.js.map +1 -0
  9. package/dist/commands/api-contracts.d.ts +9 -0
  10. package/dist/commands/api-contracts.js +1368 -0
  11. package/dist/commands/api-contracts.js.map +1 -0
  12. package/dist/commands/api-docs.d.ts +8 -0
  13. package/dist/commands/api-docs.js +408 -0
  14. package/dist/commands/api-docs.js.map +1 -0
  15. package/dist/commands/api-versioning.d.ts +11 -0
  16. package/dist/commands/api-versioning.js +643 -0
  17. package/dist/commands/api-versioning.js.map +1 -0
  18. package/dist/commands/audit-logging.d.ts +9 -0
  19. package/dist/commands/audit-logging.js +1129 -0
  20. package/dist/commands/audit-logging.js.map +1 -0
  21. package/dist/commands/batch-generate.d.ts +10 -0
  22. package/dist/commands/batch-generate.js +405 -0
  23. package/dist/commands/batch-generate.js.map +1 -0
  24. package/dist/commands/caching-strategies.d.ts +9 -0
  25. package/dist/commands/caching-strategies.js +874 -0
  26. package/dist/commands/caching-strategies.js.map +1 -0
  27. package/dist/commands/code-analyzer.d.ts +42 -0
  28. package/dist/commands/code-analyzer.js +474 -0
  29. package/dist/commands/code-analyzer.js.map +1 -0
  30. package/dist/commands/database-seeding.d.ts +6 -0
  31. package/dist/commands/database-seeding.js +621 -0
  32. package/dist/commands/database-seeding.js.map +1 -0
  33. package/dist/commands/db-optimization.d.ts +7 -0
  34. package/dist/commands/db-optimization.js +687 -0
  35. package/dist/commands/db-optimization.js.map +1 -0
  36. package/dist/commands/dependency-graph.d.ts +6 -0
  37. package/dist/commands/dependency-graph.js +329 -0
  38. package/dist/commands/dependency-graph.js.map +1 -0
  39. package/dist/commands/doctor-enhanced.d.ts +22 -0
  40. package/dist/commands/doctor-enhanced.js +543 -0
  41. package/dist/commands/doctor-enhanced.js.map +1 -0
  42. package/dist/commands/doctor.d.ts +4 -0
  43. package/dist/commands/doctor.js +151 -0
  44. package/dist/commands/doctor.js.map +1 -0
  45. package/dist/commands/env-manager.d.ts +6 -0
  46. package/dist/commands/env-manager.js +419 -0
  47. package/dist/commands/env-manager.js.map +1 -0
  48. package/dist/commands/event-sourcing-full.d.ts +10 -0
  49. package/dist/commands/event-sourcing-full.js +1107 -0
  50. package/dist/commands/event-sourcing-full.js.map +1 -0
  51. package/dist/commands/feature-flags.d.ts +9 -0
  52. package/dist/commands/feature-flags.js +824 -0
  53. package/dist/commands/feature-flags.js.map +1 -0
  54. package/dist/commands/filter-dsl.d.ts +10 -0
  55. package/dist/commands/filter-dsl.js +1407 -0
  56. package/dist/commands/filter-dsl.js.map +1 -0
  57. package/dist/commands/generate-all.js +485 -32
  58. package/dist/commands/generate-all.js.map +1 -1
  59. package/dist/commands/generate-deployment.d.ts +8 -0
  60. package/dist/commands/generate-deployment.js +746 -0
  61. package/dist/commands/generate-deployment.js.map +1 -0
  62. package/dist/commands/generate-domain-service.d.ts +14 -0
  63. package/dist/commands/generate-domain-service.js +796 -0
  64. package/dist/commands/generate-domain-service.js.map +1 -0
  65. package/dist/commands/generate-entity.js +82 -24
  66. package/dist/commands/generate-entity.js.map +1 -1
  67. package/dist/commands/generate-from-schema.d.ts +56 -0
  68. package/dist/commands/generate-from-schema.js +222 -0
  69. package/dist/commands/generate-from-schema.js.map +1 -0
  70. package/dist/commands/generate-orchestrator.d.ts +14 -0
  71. package/dist/commands/generate-orchestrator.js +887 -0
  72. package/dist/commands/generate-orchestrator.js.map +1 -0
  73. package/dist/commands/generate-repository.d.ts +14 -0
  74. package/dist/commands/generate-repository.js +1019 -0
  75. package/dist/commands/generate-repository.js.map +1 -0
  76. package/dist/commands/generate-shared.d.ts +4 -0
  77. package/dist/commands/generate-shared.js +388 -0
  78. package/dist/commands/generate-shared.js.map +1 -0
  79. package/dist/commands/generate-value-object.d.ts +32 -0
  80. package/dist/commands/generate-value-object.js +700 -0
  81. package/dist/commands/generate-value-object.js.map +1 -0
  82. package/dist/commands/graphql-subscriptions.d.ts +6 -0
  83. package/dist/commands/graphql-subscriptions.js +607 -0
  84. package/dist/commands/graphql-subscriptions.js.map +1 -0
  85. package/dist/commands/graphql-types.d.ts +5 -0
  86. package/dist/commands/graphql-types.js +423 -0
  87. package/dist/commands/graphql-types.js.map +1 -0
  88. package/dist/commands/health-probes-advanced.d.ts +6 -0
  89. package/dist/commands/health-probes-advanced.js +655 -0
  90. package/dist/commands/health-probes-advanced.js.map +1 -0
  91. package/dist/commands/i18n-setup.d.ts +10 -0
  92. package/dist/commands/i18n-setup.js +677 -0
  93. package/dist/commands/i18n-setup.js.map +1 -0
  94. package/dist/commands/init-config.d.ts +6 -0
  95. package/dist/commands/init-config.js +370 -0
  96. package/dist/commands/init-config.js.map +1 -0
  97. package/dist/commands/init-project.js +56 -6
  98. package/dist/commands/init-project.js.map +1 -1
  99. package/dist/commands/interactive-scaffold.d.ts +5 -0
  100. package/dist/commands/interactive-scaffold.js +271 -0
  101. package/dist/commands/interactive-scaffold.js.map +1 -0
  102. package/dist/commands/metrics-prometheus.d.ts +6 -0
  103. package/dist/commands/metrics-prometheus.js +681 -0
  104. package/dist/commands/metrics-prometheus.js.map +1 -0
  105. package/dist/commands/migration-engine.d.ts +6 -0
  106. package/dist/commands/migration-engine.js +446 -0
  107. package/dist/commands/migration-engine.js.map +1 -0
  108. package/dist/commands/migration.d.ts +12 -0
  109. package/dist/commands/migration.js +484 -0
  110. package/dist/commands/migration.js.map +1 -0
  111. package/dist/commands/monorepo.d.ts +8 -0
  112. package/dist/commands/monorepo.js +483 -0
  113. package/dist/commands/monorepo.js.map +1 -0
  114. package/dist/commands/multi-database.d.ts +5 -0
  115. package/dist/commands/multi-database.js +439 -0
  116. package/dist/commands/multi-database.js.map +1 -0
  117. package/dist/commands/observability-tracing.d.ts +10 -0
  118. package/dist/commands/observability-tracing.js +740 -0
  119. package/dist/commands/observability-tracing.js.map +1 -0
  120. package/dist/commands/openapi-export.d.ts +8 -0
  121. package/dist/commands/openapi-export.js +359 -0
  122. package/dist/commands/openapi-export.js.map +1 -0
  123. package/dist/commands/perf-analyzer.d.ts +8 -0
  124. package/dist/commands/perf-analyzer.js +423 -0
  125. package/dist/commands/perf-analyzer.js.map +1 -0
  126. package/dist/commands/rate-limiting.d.ts +10 -0
  127. package/dist/commands/rate-limiting.js +953 -0
  128. package/dist/commands/rate-limiting.js.map +1 -0
  129. package/dist/commands/recipe-plugin.d.ts +56 -0
  130. package/dist/commands/recipe-plugin.js +315 -0
  131. package/dist/commands/recipe-plugin.js.map +1 -0
  132. package/dist/commands/recipe.d.ts +6 -0
  133. package/dist/commands/recipe.js +3941 -0
  134. package/dist/commands/recipe.js.map +1 -0
  135. package/dist/commands/recipes/elasticsearch.recipe.d.ts +1 -0
  136. package/dist/commands/recipes/elasticsearch.recipe.js +761 -0
  137. package/dist/commands/recipes/elasticsearch.recipe.js.map +1 -0
  138. package/dist/commands/recipes/event-sourcing.recipe.d.ts +1 -0
  139. package/dist/commands/recipes/event-sourcing.recipe.js +889 -0
  140. package/dist/commands/recipes/event-sourcing.recipe.js.map +1 -0
  141. package/dist/commands/recipes/index.d.ts +7 -0
  142. package/dist/commands/recipes/index.js +24 -0
  143. package/dist/commands/recipes/index.js.map +1 -0
  144. package/dist/commands/recipes/message-queue.recipe.d.ts +1 -0
  145. package/dist/commands/recipes/message-queue.recipe.js +706 -0
  146. package/dist/commands/recipes/message-queue.recipe.js.map +1 -0
  147. package/dist/commands/recipes/middleware.recipe.d.ts +1 -0
  148. package/dist/commands/recipes/middleware.recipe.js +383 -0
  149. package/dist/commands/recipes/middleware.recipe.js.map +1 -0
  150. package/dist/commands/recipes/multi-tenancy.recipe.d.ts +1 -0
  151. package/dist/commands/recipes/multi-tenancy.recipe.js +520 -0
  152. package/dist/commands/recipes/multi-tenancy.recipe.js.map +1 -0
  153. package/dist/commands/recipes/oauth2.recipe.d.ts +1 -0
  154. package/dist/commands/recipes/oauth2.recipe.js +472 -0
  155. package/dist/commands/recipes/oauth2.recipe.js.map +1 -0
  156. package/dist/commands/recipes/websocket.recipe.d.ts +1 -0
  157. package/dist/commands/recipes/websocket.recipe.js +453 -0
  158. package/dist/commands/recipes/websocket.recipe.js.map +1 -0
  159. package/dist/commands/resilience-patterns.d.ts +13 -0
  160. package/dist/commands/resilience-patterns.js +1029 -0
  161. package/dist/commands/resilience-patterns.js.map +1 -0
  162. package/dist/commands/security-patterns.d.ts +11 -0
  163. package/dist/commands/security-patterns.js +2233 -0
  164. package/dist/commands/security-patterns.js.map +1 -0
  165. package/dist/commands/template-debug.d.ts +27 -0
  166. package/dist/commands/template-debug.js +388 -0
  167. package/dist/commands/template-debug.js.map +1 -0
  168. package/dist/commands/test-factory-full.d.ts +9 -0
  169. package/dist/commands/test-factory-full.js +1570 -0
  170. package/dist/commands/test-factory-full.js.map +1 -0
  171. package/dist/commands/test-scaffold.d.ts +7 -0
  172. package/dist/commands/test-scaffold.js +621 -0
  173. package/dist/commands/test-scaffold.js.map +1 -0
  174. package/dist/index.js +1088 -0
  175. package/dist/index.js.map +1 -1
  176. package/dist/templates/ai-context/CLAUDE.md.hbs +158 -0
  177. package/dist/templates/ai-context/conventions.md.hbs +154 -0
  178. package/dist/templates/command/create-command.hbs +6 -14
  179. package/dist/templates/command/delete-command.hbs +19 -0
  180. package/dist/templates/command/update-command.hbs +24 -0
  181. package/dist/templates/controller/controller.hbs +64 -17
  182. package/dist/templates/dto/create-dto.hbs +29 -5
  183. package/dist/templates/dto/filter-dto.hbs +52 -0
  184. package/dist/templates/dto/filter-query.dto.hbs +148 -0
  185. package/dist/templates/dto/paginated-response.dto.hbs +29 -0
  186. package/dist/templates/dto/pagination-query.dto.hbs +30 -0
  187. package/dist/templates/dto/response-dto.hbs +38 -0
  188. package/dist/templates/dto/update-dto.hbs +11 -0
  189. package/dist/templates/entity/entity.hbs +32 -1
  190. package/dist/templates/event/domain-event.hbs +33 -7
  191. package/dist/templates/event/event-handler.hbs +40 -0
  192. package/dist/templates/exception/base-exceptions.hbs +69 -0
  193. package/dist/templates/exception/entity-not-found.exception.hbs +7 -0
  194. package/dist/templates/mapper/mapper.hbs +49 -24
  195. package/dist/templates/module/module.hbs +34 -10
  196. package/dist/templates/orm-entity/orm-entity.hbs +63 -12
  197. package/dist/templates/prisma/prisma-mapper.hbs +71 -0
  198. package/dist/templates/prisma/prisma-repository.hbs +114 -0
  199. package/dist/templates/prisma/prisma-schema.hbs +20 -0
  200. package/dist/templates/prisma/prisma-service.hbs +51 -0
  201. package/dist/templates/query/get-all.query.hbs +50 -0
  202. package/dist/templates/query/get-by-id.query.hbs +31 -0
  203. package/dist/templates/repository/repository.hbs +55 -13
  204. package/dist/templates/resolver/graphql-input.hbs +54 -0
  205. package/dist/templates/resolver/graphql-type.hbs +58 -0
  206. package/dist/templates/resolver/pagination-args.hbs +33 -0
  207. package/dist/templates/resolver/resolver.hbs +62 -0
  208. package/dist/templates/shared/prisma-query-builder.util.hbs +189 -0
  209. package/dist/templates/shared/query-builder.util.hbs +218 -0
  210. package/dist/templates/test/controller.spec.hbs +124 -0
  211. package/dist/templates/test/repository.spec.hbs +158 -0
  212. package/dist/templates/test/usecase.spec.hbs +116 -0
  213. package/dist/templates/usecase/create-usecase.hbs +19 -7
  214. package/dist/templates/usecase/delete-usecase.hbs +17 -0
  215. package/dist/templates/usecase/update-usecase.hbs +31 -0
  216. package/dist/utils/config.utils.d.ts +45 -0
  217. package/dist/utils/config.utils.js +211 -0
  218. package/dist/utils/config.utils.js.map +1 -0
  219. package/dist/utils/error.utils.d.ts +145 -0
  220. package/dist/utils/error.utils.js +422 -0
  221. package/dist/utils/error.utils.js.map +1 -0
  222. package/dist/utils/field.utils.d.ts +54 -0
  223. package/dist/utils/field.utils.js +389 -0
  224. package/dist/utils/field.utils.js.map +1 -0
  225. package/dist/utils/file.utils.d.ts +19 -8
  226. package/dist/utils/file.utils.js +135 -4
  227. package/dist/utils/file.utils.js.map +1 -1
  228. package/dist/utils/idempotency.utils.d.ts +123 -0
  229. package/dist/utils/idempotency.utils.js +444 -0
  230. package/dist/utils/idempotency.utils.js.map +1 -0
  231. package/dist/utils/naming.utils.js +24 -5
  232. package/dist/utils/naming.utils.js.map +1 -1
  233. package/dist/utils/performance.utils.d.ts +37 -0
  234. package/dist/utils/performance.utils.js +158 -0
  235. package/dist/utils/performance.utils.js.map +1 -0
  236. package/dist/utils/relation.utils.d.ts +92 -0
  237. package/dist/utils/relation.utils.js +388 -0
  238. package/dist/utils/relation.utils.js.map +1 -0
  239. package/dist/utils/rollback.utils.d.ts +49 -0
  240. package/dist/utils/rollback.utils.js +306 -0
  241. package/dist/utils/rollback.utils.js.map +1 -0
  242. package/dist/utils/schema.utils.d.ts +123 -0
  243. package/dist/utils/schema.utils.js +419 -0
  244. package/dist/utils/schema.utils.js.map +1 -0
  245. package/dist/utils/security.utils.d.ts +57 -0
  246. package/dist/utils/security.utils.js +315 -0
  247. package/dist/utils/security.utils.js.map +1 -0
  248. package/dist/utils/template-engine.utils.d.ts +80 -0
  249. package/dist/utils/template-engine.utils.js +463 -0
  250. package/dist/utils/template-engine.utils.js.map +1 -0
  251. package/dist/utils/validation-registry.utils.d.ts +160 -0
  252. package/dist/utils/validation-registry.utils.js +526 -0
  253. package/dist/utils/validation-registry.utils.js.map +1 -0
  254. package/package.json +3 -1
@@ -0,0 +1,874 @@
1
+ "use strict";
2
+ /**
3
+ * Advanced Caching Strategies Generator
4
+ * Cache-aside, write-through, invalidation patterns
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || (function () {
23
+ var ownKeys = function(o) {
24
+ ownKeys = Object.getOwnPropertyNames || function (o) {
25
+ var ar = [];
26
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
27
+ return ar;
28
+ };
29
+ return ownKeys(o);
30
+ };
31
+ return function (mod) {
32
+ if (mod && mod.__esModule) return mod;
33
+ var result = {};
34
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
35
+ __setModuleDefault(result, mod);
36
+ return result;
37
+ };
38
+ })();
39
+ var __importDefault = (this && this.__importDefault) || function (mod) {
40
+ return (mod && mod.__esModule) ? mod : { "default": mod };
41
+ };
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.setupCachingStrategies = setupCachingStrategies;
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const chalk_1 = __importDefault(require("chalk"));
47
+ async function setupCachingStrategies(basePath, options = {}) {
48
+ console.log(chalk_1.default.bold.blue('\n💾 Setting up Advanced Caching Strategies\n'));
49
+ const sharedPath = path.join(basePath, 'src/shared/caching');
50
+ if (!fs.existsSync(sharedPath)) {
51
+ fs.mkdirSync(sharedPath, { recursive: true });
52
+ }
53
+ fs.writeFileSync(path.join(sharedPath, 'cache.service.ts'), generateCacheService());
54
+ console.log(chalk_1.default.green(` ✓ Created cache service`));
55
+ fs.writeFileSync(path.join(sharedPath, 'cache-strategies.ts'), generateCacheStrategies());
56
+ console.log(chalk_1.default.green(` ✓ Created cache strategies`));
57
+ fs.writeFileSync(path.join(sharedPath, 'cache-invalidation.ts'), generateCacheInvalidation());
58
+ console.log(chalk_1.default.green(` ✓ Created cache invalidation`));
59
+ fs.writeFileSync(path.join(sharedPath, 'cache.decorator.ts'), generateCacheDecorator());
60
+ console.log(chalk_1.default.green(` ✓ Created cache decorator`));
61
+ fs.writeFileSync(path.join(sharedPath, 'distributed-cache.ts'), generateDistributedCache());
62
+ console.log(chalk_1.default.green(` ✓ Created distributed cache`));
63
+ fs.writeFileSync(path.join(sharedPath, 'cache.module.ts'), generateCacheModule());
64
+ console.log(chalk_1.default.green(` ✓ Created cache module`));
65
+ console.log(chalk_1.default.bold.green('\n✅ Caching strategies ready!\n'));
66
+ }
67
+ function generateCacheService() {
68
+ return `/**
69
+ * Cache Service
70
+ * Unified caching interface with multiple backends
71
+ */
72
+
73
+ import { Injectable, Logger } from '@nestjs/common';
74
+
75
+ export interface CacheEntry<T> {
76
+ value: T;
77
+ expiresAt: number;
78
+ tags?: string[];
79
+ metadata?: Record<string, any>;
80
+ }
81
+
82
+ export interface CacheOptions {
83
+ ttl?: number;
84
+ tags?: string[];
85
+ refreshAhead?: boolean;
86
+ staleWhileRevalidate?: number;
87
+ }
88
+
89
+ @Injectable()
90
+ export class CacheService {
91
+ private readonly logger = new Logger(CacheService.name);
92
+ private readonly cache = new Map<string, CacheEntry<any>>();
93
+ private readonly tagIndex = new Map<string, Set<string>>();
94
+
95
+ /**
96
+ * Get value from cache
97
+ */
98
+ async get<T>(key: string): Promise<T | null> {
99
+ const entry = this.cache.get(key);
100
+
101
+ if (!entry) {
102
+ return null;
103
+ }
104
+
105
+ if (Date.now() > entry.expiresAt) {
106
+ this.cache.delete(key);
107
+ return null;
108
+ }
109
+
110
+ return entry.value;
111
+ }
112
+
113
+ /**
114
+ * Set value in cache
115
+ */
116
+ async set<T>(key: string, value: T, options: CacheOptions = {}): Promise<void> {
117
+ const ttl = options.ttl || 3600000; // 1 hour default
118
+ const entry: CacheEntry<T> = {
119
+ value,
120
+ expiresAt: Date.now() + ttl,
121
+ tags: options.tags,
122
+ };
123
+
124
+ this.cache.set(key, entry);
125
+
126
+ // Index by tags
127
+ if (options.tags) {
128
+ for (const tag of options.tags) {
129
+ let keys = this.tagIndex.get(tag);
130
+ if (!keys) {
131
+ keys = new Set();
132
+ this.tagIndex.set(tag, keys);
133
+ }
134
+ keys.add(key);
135
+ }
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Delete value from cache
141
+ */
142
+ async delete(key: string): Promise<void> {
143
+ const entry = this.cache.get(key);
144
+ if (entry?.tags) {
145
+ for (const tag of entry.tags) {
146
+ this.tagIndex.get(tag)?.delete(key);
147
+ }
148
+ }
149
+ this.cache.delete(key);
150
+ }
151
+
152
+ /**
153
+ * Delete all values with a tag
154
+ */
155
+ async deleteByTag(tag: string): Promise<number> {
156
+ const keys = this.tagIndex.get(tag);
157
+ if (!keys) return 0;
158
+
159
+ let count = 0;
160
+ for (const key of keys) {
161
+ this.cache.delete(key);
162
+ count++;
163
+ }
164
+
165
+ this.tagIndex.delete(tag);
166
+ return count;
167
+ }
168
+
169
+ /**
170
+ * Check if key exists
171
+ */
172
+ async has(key: string): Promise<boolean> {
173
+ const entry = this.cache.get(key);
174
+ if (!entry) return false;
175
+ if (Date.now() > entry.expiresAt) {
176
+ this.cache.delete(key);
177
+ return false;
178
+ }
179
+ return true;
180
+ }
181
+
182
+ /**
183
+ * Get or set (cache-aside pattern)
184
+ */
185
+ async getOrSet<T>(
186
+ key: string,
187
+ factory: () => Promise<T>,
188
+ options: CacheOptions = {},
189
+ ): Promise<T> {
190
+ const cached = await this.get<T>(key);
191
+ if (cached !== null) {
192
+ return cached;
193
+ }
194
+
195
+ const value = await factory();
196
+ await this.set(key, value, options);
197
+ return value;
198
+ }
199
+
200
+ /**
201
+ * Clear all cache
202
+ */
203
+ async clear(): Promise<void> {
204
+ this.cache.clear();
205
+ this.tagIndex.clear();
206
+ }
207
+
208
+ /**
209
+ * Get cache stats
210
+ */
211
+ getStats(): CacheStats {
212
+ let expired = 0;
213
+ let valid = 0;
214
+ const now = Date.now();
215
+
216
+ for (const entry of this.cache.values()) {
217
+ if (now > entry.expiresAt) {
218
+ expired++;
219
+ } else {
220
+ valid++;
221
+ }
222
+ }
223
+
224
+ return {
225
+ size: this.cache.size,
226
+ valid,
227
+ expired,
228
+ tags: this.tagIndex.size,
229
+ };
230
+ }
231
+ }
232
+
233
+ export interface CacheStats {
234
+ size: number;
235
+ valid: number;
236
+ expired: number;
237
+ tags: number;
238
+ }
239
+ `;
240
+ }
241
+ function generateCacheStrategies() {
242
+ return `/**
243
+ * Cache Strategies
244
+ * Different caching patterns for various use cases
245
+ */
246
+
247
+ import { CacheService, CacheOptions } from './cache.service';
248
+
249
+ /**
250
+ * Cache-Aside (Lazy Loading)
251
+ */
252
+ export class CacheAsideStrategy<T> {
253
+ constructor(
254
+ private readonly cache: CacheService,
255
+ private readonly keyPrefix: string,
256
+ ) {}
257
+
258
+ async get(id: string, loader: () => Promise<T>, options?: CacheOptions): Promise<T> {
259
+ const key = \`\${this.keyPrefix}:\${id}\`;
260
+ return this.cache.getOrSet(key, loader, options);
261
+ }
262
+
263
+ async invalidate(id: string): Promise<void> {
264
+ const key = \`\${this.keyPrefix}:\${id}\`;
265
+ await this.cache.delete(key);
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Write-Through
271
+ */
272
+ export class WriteThroughStrategy<T> {
273
+ constructor(
274
+ private readonly cache: CacheService,
275
+ private readonly keyPrefix: string,
276
+ private readonly writer: (id: string, value: T) => Promise<void>,
277
+ ) {}
278
+
279
+ async write(id: string, value: T, options?: CacheOptions): Promise<void> {
280
+ // Write to storage first
281
+ await this.writer(id, value);
282
+ // Then update cache
283
+ const key = \`\${this.keyPrefix}:\${id}\`;
284
+ await this.cache.set(key, value, options);
285
+ }
286
+
287
+ async get(id: string): Promise<T | null> {
288
+ const key = \`\${this.keyPrefix}:\${id}\`;
289
+ return this.cache.get(key);
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Write-Behind (Write-Back)
295
+ */
296
+ export class WriteBehindStrategy<T> {
297
+ private readonly pending = new Map<string, { value: T; timer: NodeJS.Timeout }>();
298
+
299
+ constructor(
300
+ private readonly cache: CacheService,
301
+ private readonly keyPrefix: string,
302
+ private readonly writer: (id: string, value: T) => Promise<void>,
303
+ private readonly delay: number = 5000,
304
+ ) {}
305
+
306
+ async write(id: string, value: T, options?: CacheOptions): Promise<void> {
307
+ const key = \`\${this.keyPrefix}:\${id}\`;
308
+
309
+ // Update cache immediately
310
+ await this.cache.set(key, value, options);
311
+
312
+ // Cancel pending write
313
+ const pending = this.pending.get(id);
314
+ if (pending) {
315
+ clearTimeout(pending.timer);
316
+ }
317
+
318
+ // Schedule write
319
+ const timer = setTimeout(async () => {
320
+ await this.writer(id, value);
321
+ this.pending.delete(id);
322
+ }, this.delay);
323
+
324
+ this.pending.set(id, { value, timer });
325
+ }
326
+
327
+ async flush(): Promise<void> {
328
+ const writes = Array.from(this.pending.entries()).map(async ([id, { value, timer }]) => {
329
+ clearTimeout(timer);
330
+ await this.writer(id, value);
331
+ });
332
+ await Promise.all(writes);
333
+ this.pending.clear();
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Read-Through
339
+ */
340
+ export class ReadThroughStrategy<T> {
341
+ constructor(
342
+ private readonly cache: CacheService,
343
+ private readonly keyPrefix: string,
344
+ private readonly loader: (id: string) => Promise<T | null>,
345
+ private readonly defaultOptions?: CacheOptions,
346
+ ) {}
347
+
348
+ async get(id: string, options?: CacheOptions): Promise<T | null> {
349
+ const key = \`\${this.keyPrefix}:\${id}\`;
350
+
351
+ const cached = await this.cache.get<T>(key);
352
+ if (cached !== null) {
353
+ return cached;
354
+ }
355
+
356
+ const value = await this.loader(id);
357
+ if (value !== null) {
358
+ await this.cache.set(key, value, options || this.defaultOptions);
359
+ }
360
+
361
+ return value;
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Refresh-Ahead
367
+ */
368
+ export class RefreshAheadStrategy<T> {
369
+ private readonly refreshing = new Set<string>();
370
+
371
+ constructor(
372
+ private readonly cache: CacheService,
373
+ private readonly keyPrefix: string,
374
+ private readonly loader: (id: string) => Promise<T>,
375
+ private readonly refreshThreshold: number = 0.8, // Refresh when 80% of TTL passed
376
+ ) {}
377
+
378
+ async get(id: string, ttl: number): Promise<T> {
379
+ const key = \`\${this.keyPrefix}:\${id}\`;
380
+
381
+ const cached = await this.cache.get<T>(key);
382
+ if (cached !== null) {
383
+ // Check if we should refresh
384
+ this.maybeRefresh(id, key, ttl);
385
+ return cached;
386
+ }
387
+
388
+ const value = await this.loader(id);
389
+ await this.cache.set(key, value, { ttl });
390
+ return value;
391
+ }
392
+
393
+ private async maybeRefresh(id: string, key: string, ttl: number): Promise<void> {
394
+ if (this.refreshing.has(key)) return;
395
+
396
+ // Refresh in background (implementation would check actual TTL remaining)
397
+ this.refreshing.add(key);
398
+
399
+ try {
400
+ const value = await this.loader(id);
401
+ await this.cache.set(key, value, { ttl });
402
+ } finally {
403
+ this.refreshing.delete(key);
404
+ }
405
+ }
406
+ }
407
+ `;
408
+ }
409
+ function generateCacheInvalidation() {
410
+ return `/**
411
+ * Cache Invalidation
412
+ * Event-driven cache invalidation patterns
413
+ */
414
+
415
+ import { Injectable, Logger } from '@nestjs/common';
416
+ import { OnEvent } from '@nestjs/event-emitter';
417
+ import { CacheService } from './cache.service';
418
+
419
+ export interface InvalidationRule {
420
+ event: string;
421
+ pattern?: string;
422
+ tags?: string[];
423
+ handler?: (payload: any) => string[];
424
+ }
425
+
426
+ @Injectable()
427
+ export class CacheInvalidationService {
428
+ private readonly logger = new Logger(CacheInvalidationService.name);
429
+ private readonly rules: InvalidationRule[] = [];
430
+
431
+ constructor(private readonly cache: CacheService) {}
432
+
433
+ /**
434
+ * Register invalidation rule
435
+ */
436
+ registerRule(rule: InvalidationRule): void {
437
+ this.rules.push(rule);
438
+ }
439
+
440
+ /**
441
+ * Handle entity created event
442
+ */
443
+ @OnEvent('entity.created')
444
+ async onEntityCreated(payload: { type: string; id: string }): Promise<void> {
445
+ await this.invalidateByTag(\`\${payload.type}:list\`);
446
+ }
447
+
448
+ /**
449
+ * Handle entity updated event
450
+ */
451
+ @OnEvent('entity.updated')
452
+ async onEntityUpdated(payload: { type: string; id: string }): Promise<void> {
453
+ await this.invalidateByTag(\`\${payload.type}:\${payload.id}\`);
454
+ await this.invalidateByTag(\`\${payload.type}:list\`);
455
+ }
456
+
457
+ /**
458
+ * Handle entity deleted event
459
+ */
460
+ @OnEvent('entity.deleted')
461
+ async onEntityDeleted(payload: { type: string; id: string }): Promise<void> {
462
+ await this.invalidateByTag(\`\${payload.type}:\${payload.id}\`);
463
+ await this.invalidateByTag(\`\${payload.type}:list\`);
464
+ }
465
+
466
+ /**
467
+ * Invalidate by tag
468
+ */
469
+ async invalidateByTag(tag: string): Promise<number> {
470
+ const count = await this.cache.deleteByTag(tag);
471
+ this.logger.debug(\`Invalidated \${count} entries with tag: \${tag}\`);
472
+ return count;
473
+ }
474
+
475
+ /**
476
+ * Invalidate by pattern
477
+ */
478
+ async invalidateByPattern(pattern: string): Promise<void> {
479
+ // For memory cache, iterate and match
480
+ // For Redis, use SCAN with pattern
481
+ this.logger.debug(\`Invalidating pattern: \${pattern}\`);
482
+ }
483
+
484
+ /**
485
+ * Process invalidation rules for an event
486
+ */
487
+ async processEvent(event: string, payload: any): Promise<void> {
488
+ for (const rule of this.rules) {
489
+ if (rule.event !== event) continue;
490
+
491
+ if (rule.tags) {
492
+ for (const tag of rule.tags) {
493
+ await this.invalidateByTag(tag);
494
+ }
495
+ }
496
+
497
+ if (rule.handler) {
498
+ const keys = rule.handler(payload);
499
+ for (const key of keys) {
500
+ await this.cache.delete(key);
501
+ }
502
+ }
503
+ }
504
+ }
505
+ }
506
+
507
+ /**
508
+ * Cache invalidation decorator
509
+ */
510
+ export function InvalidatesCache(tags: string[]): MethodDecorator {
511
+ return function (
512
+ target: any,
513
+ propertyKey: string | symbol,
514
+ descriptor: PropertyDescriptor,
515
+ ) {
516
+ const originalMethod = descriptor.value;
517
+
518
+ descriptor.value = async function (...args: any[]) {
519
+ const result = await originalMethod.apply(this, args);
520
+
521
+ // Get cache service from this context
522
+ const cacheService = (this as any).cacheService;
523
+ if (cacheService) {
524
+ for (const tag of tags) {
525
+ await cacheService.deleteByTag(tag);
526
+ }
527
+ }
528
+
529
+ return result;
530
+ };
531
+
532
+ return descriptor;
533
+ };
534
+ }
535
+ `;
536
+ }
537
+ function generateCacheDecorator() {
538
+ return `/**
539
+ * Cache Decorators
540
+ * Method-level caching with decorators
541
+ */
542
+
543
+ import { SetMetadata } from '@nestjs/common';
544
+
545
+ export const CACHE_KEY = 'cache_key';
546
+ export const CACHE_TTL = 'cache_ttl';
547
+ export const CACHE_TAGS = 'cache_tags';
548
+
549
+ export interface CacheDecoratorOptions {
550
+ key?: string | ((...args: any[]) => string);
551
+ ttl?: number;
552
+ tags?: string[];
553
+ condition?: (...args: any[]) => boolean;
554
+ }
555
+
556
+ /**
557
+ * Cache method result
558
+ */
559
+ export function Cacheable(options: CacheDecoratorOptions = {}): MethodDecorator {
560
+ return function (
561
+ target: any,
562
+ propertyKey: string | symbol,
563
+ descriptor: PropertyDescriptor,
564
+ ) {
565
+ const originalMethod = descriptor.value;
566
+ const methodName = String(propertyKey);
567
+ const cache = new Map<string, { value: any; expiresAt: number }>();
568
+
569
+ descriptor.value = async function (...args: any[]) {
570
+ // Check condition
571
+ if (options.condition && !options.condition(...args)) {
572
+ return originalMethod.apply(this, args);
573
+ }
574
+
575
+ // Generate key
576
+ const cacheKey = typeof options.key === 'function'
577
+ ? options.key(...args)
578
+ : options.key || \`\${target.constructor.name}:\${methodName}:\${JSON.stringify(args)}\`;
579
+
580
+ // Check cache
581
+ const cached = cache.get(cacheKey);
582
+ if (cached && Date.now() < cached.expiresAt) {
583
+ return cached.value;
584
+ }
585
+
586
+ // Execute and cache
587
+ const result = await originalMethod.apply(this, args);
588
+ const ttl = options.ttl || 60000;
589
+
590
+ cache.set(cacheKey, {
591
+ value: result,
592
+ expiresAt: Date.now() + ttl,
593
+ });
594
+
595
+ return result;
596
+ };
597
+
598
+ return descriptor;
599
+ };
600
+ }
601
+
602
+ /**
603
+ * Evict cache on method execution
604
+ */
605
+ export function CacheEvict(options: { key?: string; tags?: string[]; allEntries?: boolean }): MethodDecorator {
606
+ return function (
607
+ target: any,
608
+ propertyKey: string | symbol,
609
+ descriptor: PropertyDescriptor,
610
+ ) {
611
+ const originalMethod = descriptor.value;
612
+
613
+ descriptor.value = async function (...args: any[]) {
614
+ const result = await originalMethod.apply(this, args);
615
+
616
+ // Evict logic would be handled by interceptor or injected service
617
+ const cacheService = (this as any).cacheService;
618
+ if (cacheService) {
619
+ if (options.allEntries) {
620
+ await cacheService.clear();
621
+ } else if (options.key) {
622
+ await cacheService.delete(options.key);
623
+ } else if (options.tags) {
624
+ for (const tag of options.tags) {
625
+ await cacheService.deleteByTag(tag);
626
+ }
627
+ }
628
+ }
629
+
630
+ return result;
631
+ };
632
+
633
+ return descriptor;
634
+ };
635
+ }
636
+
637
+ /**
638
+ * Cache with automatic refresh
639
+ */
640
+ export function CacheRefresh(options: CacheDecoratorOptions & { refreshInterval: number }): MethodDecorator {
641
+ return function (
642
+ target: any,
643
+ propertyKey: string | symbol,
644
+ descriptor: PropertyDescriptor,
645
+ ) {
646
+ const originalMethod = descriptor.value;
647
+ let cachedValue: any = null;
648
+ let lastRefresh: number = 0;
649
+
650
+ // Background refresh
651
+ setInterval(async () => {
652
+ try {
653
+ cachedValue = await originalMethod.apply(target);
654
+ lastRefresh = Date.now();
655
+ } catch (error) {
656
+ // Keep stale value on error
657
+ }
658
+ }, options.refreshInterval);
659
+
660
+ descriptor.value = async function (...args: any[]) {
661
+ if (cachedValue !== null) {
662
+ return cachedValue;
663
+ }
664
+
665
+ cachedValue = await originalMethod.apply(this, args);
666
+ lastRefresh = Date.now();
667
+ return cachedValue;
668
+ };
669
+
670
+ return descriptor;
671
+ };
672
+ }
673
+ `;
674
+ }
675
+ function generateDistributedCache() {
676
+ return `/**
677
+ * Distributed Cache
678
+ * Multi-node cache synchronization
679
+ */
680
+
681
+ import { Injectable, Logger } from '@nestjs/common';
682
+ import { EventEmitter2 } from '@nestjs/event-emitter';
683
+
684
+ export interface DistributedCacheOptions {
685
+ nodeId: string;
686
+ syncInterval?: number;
687
+ maxNodes?: number;
688
+ }
689
+
690
+ @Injectable()
691
+ export class DistributedCacheService {
692
+ private readonly logger = new Logger(DistributedCacheService.name);
693
+ private readonly localCache = new Map<string, any>();
694
+ private readonly versions = new Map<string, number>();
695
+ private readonly nodeId: string;
696
+
697
+ constructor(
698
+ private readonly eventEmitter: EventEmitter2,
699
+ private readonly options: DistributedCacheOptions,
700
+ ) {
701
+ this.nodeId = options.nodeId;
702
+ }
703
+
704
+ /**
705
+ * Set value with distributed sync
706
+ */
707
+ async set(key: string, value: any, ttl?: number): Promise<void> {
708
+ const version = (this.versions.get(key) || 0) + 1;
709
+ this.versions.set(key, version);
710
+
711
+ this.localCache.set(key, {
712
+ value,
713
+ version,
714
+ expiresAt: ttl ? Date.now() + ttl : undefined,
715
+ });
716
+
717
+ // Broadcast to other nodes
718
+ this.eventEmitter.emit('cache.sync', {
719
+ type: 'set',
720
+ key,
721
+ value,
722
+ version,
723
+ ttl,
724
+ nodeId: this.nodeId,
725
+ });
726
+ }
727
+
728
+ /**
729
+ * Get value
730
+ */
731
+ async get<T>(key: string): Promise<T | null> {
732
+ const entry = this.localCache.get(key);
733
+
734
+ if (!entry) return null;
735
+ if (entry.expiresAt && Date.now() > entry.expiresAt) {
736
+ this.localCache.delete(key);
737
+ return null;
738
+ }
739
+
740
+ return entry.value;
741
+ }
742
+
743
+ /**
744
+ * Delete value with distributed sync
745
+ */
746
+ async delete(key: string): Promise<void> {
747
+ this.localCache.delete(key);
748
+ this.versions.delete(key);
749
+
750
+ this.eventEmitter.emit('cache.sync', {
751
+ type: 'delete',
752
+ key,
753
+ nodeId: this.nodeId,
754
+ });
755
+ }
756
+
757
+ /**
758
+ * Handle sync from other nodes
759
+ */
760
+ handleSync(message: CacheSyncMessage): void {
761
+ if (message.nodeId === this.nodeId) return;
762
+
763
+ const currentVersion = this.versions.get(message.key) || 0;
764
+
765
+ if (message.type === 'set' && message.version > currentVersion) {
766
+ this.localCache.set(message.key, {
767
+ value: message.value,
768
+ version: message.version,
769
+ expiresAt: message.ttl ? Date.now() + message.ttl : undefined,
770
+ });
771
+ this.versions.set(message.key, message.version);
772
+ } else if (message.type === 'delete') {
773
+ this.localCache.delete(message.key);
774
+ this.versions.delete(message.key);
775
+ }
776
+ }
777
+
778
+ /**
779
+ * Get cache size
780
+ */
781
+ size(): number {
782
+ return this.localCache.size;
783
+ }
784
+ }
785
+
786
+ interface CacheSyncMessage {
787
+ type: 'set' | 'delete';
788
+ key: string;
789
+ value?: any;
790
+ version?: number;
791
+ ttl?: number;
792
+ nodeId: string;
793
+ }
794
+
795
+ /**
796
+ * Two-tier cache (L1 local + L2 distributed)
797
+ */
798
+ export class TwoTierCache {
799
+ constructor(
800
+ private readonly l1: Map<string, any>,
801
+ private readonly l2: DistributedCacheService,
802
+ private readonly l1Ttl: number = 10000,
803
+ ) {}
804
+
805
+ async get<T>(key: string): Promise<T | null> {
806
+ // Check L1
807
+ const l1Entry = this.l1.get(key);
808
+ if (l1Entry && Date.now() < l1Entry.expiresAt) {
809
+ return l1Entry.value;
810
+ }
811
+
812
+ // Check L2
813
+ const value = await this.l2.get<T>(key);
814
+ if (value !== null) {
815
+ // Populate L1
816
+ this.l1.set(key, {
817
+ value,
818
+ expiresAt: Date.now() + this.l1Ttl,
819
+ });
820
+ }
821
+
822
+ return value;
823
+ }
824
+
825
+ async set(key: string, value: any, ttl?: number): Promise<void> {
826
+ // Set in both tiers
827
+ this.l1.set(key, {
828
+ value,
829
+ expiresAt: Date.now() + this.l1Ttl,
830
+ });
831
+ await this.l2.set(key, value, ttl);
832
+ }
833
+ }
834
+ `;
835
+ }
836
+ function generateCacheModule() {
837
+ return `import { Module, Global, DynamicModule } from '@nestjs/common';
838
+ import { CacheService } from './cache.service';
839
+ import { CacheInvalidationService } from './cache-invalidation';
840
+ import { DistributedCacheService, DistributedCacheOptions } from './distributed-cache';
841
+
842
+ export interface CacheModuleOptions {
843
+ provider?: 'memory' | 'redis';
844
+ distributed?: DistributedCacheOptions;
845
+ defaultTtl?: number;
846
+ }
847
+
848
+ @Global()
849
+ @Module({})
850
+ export class CacheModule {
851
+ static forRoot(options: CacheModuleOptions = {}): DynamicModule {
852
+ return {
853
+ module: CacheModule,
854
+ providers: [
855
+ {
856
+ provide: 'CACHE_OPTIONS',
857
+ useValue: options,
858
+ },
859
+ CacheService,
860
+ CacheInvalidationService,
861
+ ...(options.distributed ? [{
862
+ provide: DistributedCacheService,
863
+ useFactory: (eventEmitter: any) =>
864
+ new DistributedCacheService(eventEmitter, options.distributed!),
865
+ inject: ['EventEmitter2'],
866
+ }] : []),
867
+ ],
868
+ exports: [CacheService, CacheInvalidationService],
869
+ };
870
+ }
871
+ }
872
+ `;
873
+ }
874
+ //# sourceMappingURL=caching-strategies.js.map