@zintrust/core 0.1.20 → 0.1.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 (142) hide show
  1. package/package.json +2 -1
  2. package/src/boot/Application.d.ts.map +1 -1
  3. package/src/boot/Application.js +48 -10
  4. package/src/boot/bootstrap.js +2 -0
  5. package/src/cli/commands/MigrateCommand.d.ts.map +1 -1
  6. package/src/cli/commands/MigrateCommand.js +37 -4
  7. package/src/cli/d1/D1SqlMigrations.d.ts.map +1 -1
  8. package/src/cli/d1/D1SqlMigrations.js +10 -4
  9. package/src/cli/scaffolding/ControllerGenerator.js +4 -4
  10. package/src/cli/scaffolding/GovernanceScaffolder.js +1 -1
  11. package/src/cli/scaffolding/MigrationGenerator.js +1 -1
  12. package/src/cli/scaffolding/ModelGenerator.d.ts +1 -1
  13. package/src/cli/scaffolding/ModelGenerator.d.ts.map +1 -1
  14. package/src/cli/scaffolding/ModelGenerator.js +11 -3
  15. package/src/cli/scaffolding/RouteGenerator.js +1 -1
  16. package/src/cli/scaffolding/ServiceScaffolder.js +4 -4
  17. package/src/config/broadcast.d.ts +14 -28
  18. package/src/config/broadcast.d.ts.map +1 -1
  19. package/src/config/broadcast.js +69 -35
  20. package/src/config/cache.d.ts +13 -45
  21. package/src/config/cache.d.ts.map +1 -1
  22. package/src/config/cache.js +69 -25
  23. package/src/config/database.d.ts +22 -64
  24. package/src/config/database.d.ts.map +1 -1
  25. package/src/config/database.js +99 -31
  26. package/src/config/env.d.ts +6 -0
  27. package/src/config/env.d.ts.map +1 -1
  28. package/src/config/env.js +7 -0
  29. package/src/config/index.d.ts +32 -136
  30. package/src/config/index.d.ts.map +1 -1
  31. package/src/config/mail.d.ts +19 -55
  32. package/src/config/mail.d.ts.map +1 -1
  33. package/src/config/mail.js +63 -21
  34. package/src/config/middleware.d.ts +24 -0
  35. package/src/config/middleware.d.ts.map +1 -1
  36. package/src/config/middleware.js +72 -52
  37. package/src/config/notification.d.ts +14 -27
  38. package/src/config/notification.d.ts.map +1 -1
  39. package/src/config/notification.js +82 -36
  40. package/src/config/queue.d.ts +21 -51
  41. package/src/config/queue.d.ts.map +1 -1
  42. package/src/config/queue.js +72 -27
  43. package/src/config/storage.d.ts +27 -34
  44. package/src/config/storage.d.ts.map +1 -1
  45. package/src/config/storage.js +97 -56
  46. package/src/config/type.d.ts +23 -1
  47. package/src/config/type.d.ts.map +1 -1
  48. package/src/config/type.js +10 -1
  49. package/src/http/parsers/MultipartParser.d.ts.map +1 -1
  50. package/src/http/parsers/MultipartParser.js +69 -42
  51. package/src/index.d.ts +9 -5
  52. package/src/index.d.ts.map +1 -1
  53. package/src/index.js +1 -0
  54. package/src/microservices/PostgresAdapter.d.ts.map +1 -1
  55. package/src/microservices/PostgresAdapter.js +0 -1
  56. package/src/migrations/MigrationLoader.d.ts +1 -1
  57. package/src/migrations/MigrationLoader.d.ts.map +1 -1
  58. package/src/migrations/Migrator.d.ts +3 -3
  59. package/src/migrations/Migrator.d.ts.map +1 -1
  60. package/src/migrations/Migrator.js +1 -1
  61. package/src/migrations/MigratorFactory.d.ts +1 -1
  62. package/src/migrations/MigratorFactory.d.ts.map +1 -1
  63. package/src/migrations/MigratorFactory.js +21 -5
  64. package/src/migrations/enum/index.d.ts +93 -0
  65. package/src/migrations/enum/index.d.ts.map +1 -0
  66. package/src/migrations/enum/index.js +92 -0
  67. package/src/migrations/schema/Blueprint.d.ts +1 -1
  68. package/src/migrations/schema/Blueprint.d.ts.map +1 -1
  69. package/src/migrations/schema/Blueprint.js +27 -25
  70. package/src/migrations/schema/Schema.d.ts +1 -1
  71. package/src/migrations/schema/Schema.d.ts.map +1 -1
  72. package/src/migrations/schema/Schema.js +4 -3
  73. package/src/migrations/schema/SchemaCompiler.d.ts +1 -1
  74. package/src/migrations/schema/SchemaCompiler.d.ts.map +1 -1
  75. package/src/migrations/schema/SchemaCompiler.js +99 -91
  76. package/src/migrations/schema/index.d.ts +4 -4
  77. package/src/migrations/schema/index.d.ts.map +1 -1
  78. package/src/migrations/schema/index.js +3 -3
  79. package/src/migrations/schema/types.d.ts +2 -1
  80. package/src/migrations/schema/types.d.ts.map +1 -1
  81. package/src/node-singletons/fs.d.ts +1 -1
  82. package/src/node-singletons/fs.d.ts.map +1 -1
  83. package/src/node-singletons/fs.js +1 -1
  84. package/src/orm/ConnectionManager.d.ts +6 -4
  85. package/src/orm/ConnectionManager.d.ts.map +1 -1
  86. package/src/orm/ConnectionManager.js +213 -75
  87. package/src/orm/Database.d.ts +4 -2
  88. package/src/orm/Database.d.ts.map +1 -1
  89. package/src/orm/Database.js +110 -67
  90. package/src/orm/DatabaseAdapter.d.ts +4 -2
  91. package/src/orm/DatabaseAdapter.d.ts.map +1 -1
  92. package/src/orm/DatabaseAdapter.js +17 -0
  93. package/src/orm/DatabaseRuntimeRegistration.d.ts.map +1 -1
  94. package/src/orm/DatabaseRuntimeRegistration.js +12 -0
  95. package/src/orm/Model.d.ts.map +1 -1
  96. package/src/orm/Model.js +24 -2
  97. package/src/orm/QueryBuilder.d.ts +1 -1
  98. package/src/orm/QueryBuilder.d.ts.map +1 -1
  99. package/src/orm/QueryBuilder.js +4 -3
  100. package/src/orm/adapters/D1Adapter.d.ts.map +1 -1
  101. package/src/orm/adapters/D1Adapter.js +2 -1
  102. package/src/orm/adapters/D1RemoteAdapter.d.ts.map +1 -1
  103. package/src/orm/adapters/D1RemoteAdapter.js +2 -1
  104. package/src/orm/adapters/MySQLAdapter.d.ts.map +1 -1
  105. package/src/orm/adapters/MySQLAdapter.js +2 -1
  106. package/src/orm/adapters/SQLServerAdapter.d.ts.map +1 -1
  107. package/src/orm/adapters/SQLServerAdapter.js +2 -1
  108. package/src/orm/adapters/SQLiteAdapter.d.ts.map +1 -1
  109. package/src/orm/adapters/SQLiteAdapter.js +3 -2
  110. package/src/orm/migrations/MigrationStore.d.ts.map +1 -1
  111. package/src/performance/Optimizer.d.ts +6 -6
  112. package/src/performance/Optimizer.d.ts.map +1 -1
  113. package/src/performance/Optimizer.js +174 -52
  114. package/src/profiling/RequestProfiler.d.ts.map +1 -1
  115. package/src/profiling/RequestProfiler.js +3 -1
  116. package/src/routing/doc.d.ts +4 -5
  117. package/src/routing/doc.d.ts.map +1 -1
  118. package/src/routing/doc.js +35 -20
  119. package/src/routing/publicRoot.d.ts +9 -0
  120. package/src/routing/publicRoot.d.ts.map +1 -1
  121. package/src/routing/publicRoot.js +63 -2
  122. package/src/runtime/StartupConfigFileRegistry.d.ts +21 -0
  123. package/src/runtime/StartupConfigFileRegistry.d.ts.map +1 -0
  124. package/src/runtime/StartupConfigFileRegistry.js +43 -0
  125. package/src/runtime/useFileLoader.d.ts +26 -0
  126. package/src/runtime/useFileLoader.d.ts.map +1 -0
  127. package/src/runtime/useFileLoader.js +188 -0
  128. package/src/scripts/TemplateSync.js +4 -4
  129. package/src/security/XssProtection.d.ts.map +1 -1
  130. package/src/security/XssProtection.js +62 -14
  131. package/src/templates/project/basic/config/broadcast.ts.tpl +33 -17
  132. package/src/templates/project/basic/config/cache.ts.tpl +35 -17
  133. package/src/templates/project/basic/config/database.ts.tpl +68 -32
  134. package/src/templates/project/basic/config/logging/HttpLogger.ts.tpl +7 -114
  135. package/src/templates/project/basic/config/mail.ts.tpl +59 -13
  136. package/src/templates/project/basic/config/notification.ts.tpl +28 -17
  137. package/src/templates/project/basic/config/queue.ts.tpl +49 -17
  138. package/src/templates/project/basic/config/storage.ts.tpl +55 -18
  139. package/src/templates/project/basic/config/type.ts.tpl +0 -1
  140. package/src/templates/project/basic/src/index.ts.tpl +3 -0
  141. package/src/templates/project/basic/config/logging/KvLogger.ts.tpl +0 -181
  142. package/src/templates/project/basic/config/logging/SlackLogger.ts.tpl +0 -156
@@ -59,8 +59,52 @@ function createCacheState(cacheDir, ttlMs, maxEntries) {
59
59
  cacheDir,
60
60
  ttlMs,
61
61
  maxEntries,
62
+ pendingWrites: new Map(),
62
63
  };
63
64
  }
65
+ async function ensureCacheDir(cacheDir) {
66
+ try {
67
+ await fs.fsPromises.access(cacheDir);
68
+ }
69
+ catch {
70
+ await fs.fsPromises.mkdir(cacheDir, { recursive: true });
71
+ }
72
+ }
73
+ async function flushPendingWrites(state) {
74
+ if (state.pendingWrites.size === 0) {
75
+ state.flushTimer = undefined;
76
+ return false;
77
+ }
78
+ const pending = state.pendingWrites;
79
+ state.pendingWrites = new Map();
80
+ state.flushTimer = undefined;
81
+ try {
82
+ await ensureCacheDir(state.cacheDir);
83
+ }
84
+ catch (error) {
85
+ Logger.error('Failed to ensure cache directory before flush', error);
86
+ return false;
87
+ }
88
+ const writes = Array.from(pending.entries()).map(async ([key, entry]) => {
89
+ const file = path.join(state.cacheDir, `${key}.json`);
90
+ await fs.fsPromises.writeFile(file, entry.payload);
91
+ });
92
+ await Promise.all(writes);
93
+ return true;
94
+ }
95
+ function scheduleCacheWrite(state, key, payload) {
96
+ state.pendingWrites.set(key, { payload });
97
+ if (state.flushTimer !== undefined)
98
+ return;
99
+ state.flushTimer = setTimeout(() => {
100
+ void flushPendingWrites(state).catch((error) => {
101
+ Logger.error('Failed to flush generation cache writes', error);
102
+ });
103
+ }, 50);
104
+ if (isUnrefableTimer(state.flushTimer)) {
105
+ state.flushTimer.unref();
106
+ }
107
+ }
64
108
  function initializeCacheState(state) {
65
109
  loadFromDisk(state);
66
110
  }
@@ -95,26 +139,26 @@ function startCacheCleanup(state) {
95
139
  function createCacheInstance(state) {
96
140
  return {
97
141
  /**
98
- * Get from cache
142
+ * Get from cache (async)
99
143
  */
100
- get(type, params) {
144
+ async get(type, params) {
101
145
  const key = getCacheKey(type, params);
102
146
  const entry = state.cache.get(key);
103
147
  if (entry === undefined)
104
- return null;
148
+ return Promise.resolve(null); //NoSONAR
105
149
  // Check TTL
106
150
  if (Date.now() - entry.timestamp > state.ttlMs) {
107
151
  state.cache.delete(key);
108
152
  const file = path.join(state.cacheDir, `${key}.json`);
109
153
  deleteFileNonBlocking(file);
110
- return null;
154
+ return Promise.resolve(null); //NoSONAR
111
155
  }
112
- return entry.code;
156
+ return Promise.resolve(entry.code); //NoSONAR
113
157
  },
114
158
  /**
115
- * Set in cache
159
+ * Set in cache (async)
116
160
  */
117
- set(type, params, code) {
161
+ async set(type, params, code) {
118
162
  const key = getCacheKey(type, params);
119
163
  // If key already exists, delete first so insertion order updates for LRU
120
164
  if (state.cache.has(key))
@@ -134,27 +178,34 @@ function createCacheInstance(state) {
134
178
  deleteFileNonBlocking(file);
135
179
  }
136
180
  }
181
+ const payload = JSON.stringify({ code, timestamp: Date.now() }, null, 2);
182
+ scheduleCacheWrite(state, key, payload);
137
183
  },
138
184
  /**
139
- * Save cache to disk
185
+ * Save cache to disk (async)
140
186
  */
141
- save() {
142
- saveCacheToDisk(state);
187
+ async save() {
188
+ await saveCacheToDisk(state);
143
189
  },
144
190
  /**
145
- * Clear cache
191
+ * Clear cache (async)
146
192
  */
147
- clear() {
193
+ async clear() {
148
194
  if (state.cleanupInterval) {
149
195
  clearInterval(state.cleanupInterval);
150
196
  state.cleanupInterval = undefined;
151
197
  }
152
- clearCache(state);
198
+ if (state.flushTimer) {
199
+ clearTimeout(state.flushTimer);
200
+ state.flushTimer = undefined;
201
+ }
202
+ state.pendingWrites.clear();
203
+ await clearCache(state);
153
204
  },
154
205
  /**
155
- * Get cache statistics
206
+ * Get cache statistics (async)
156
207
  */
157
- getStats() {
208
+ async getStats() {
158
209
  return getCacheStats(state);
159
210
  },
160
211
  };
@@ -166,38 +217,65 @@ function attachCacheStateForTests(instance, state) {
166
217
  });
167
218
  }
168
219
  /**
169
- * Save cache to disk
220
+ * Save cache to disk (async)
170
221
  */
171
- function saveCacheToDisk(state) {
172
- if (fs.existsSync(state.cacheDir) === false) {
173
- fs.mkdirSync(state.cacheDir, { recursive: true });
222
+ async function saveCacheToDisk(state) {
223
+ try {
224
+ const flushedEnsured = await flushPendingWrites(state);
225
+ if (!flushedEnsured) {
226
+ await ensureCacheDir(state.cacheDir);
227
+ }
228
+ const writes = Array.from(state.cache.entries()).map(async ([key, entry]) => {
229
+ const file = path.join(state.cacheDir, `${key}.json`);
230
+ await fs.fsPromises.writeFile(file, JSON.stringify(entry, null, 2));
231
+ });
232
+ await Promise.all(writes);
174
233
  }
175
- for (const [key, entry] of state.cache.entries()) {
176
- const file = path.join(state.cacheDir, `${key}.json`);
177
- fs.writeFileSync(file, JSON.stringify(entry, null, 2));
234
+ catch (error) {
235
+ Logger.error('Failed to save cache to disk', error);
178
236
  }
179
237
  }
180
238
  /**
181
- * Clear cache
239
+ * Clear cache (async)
182
240
  */
183
- function clearCache(state) {
241
+ async function clearCache(state) {
184
242
  state.cache.clear();
185
- if (fs.existsSync(state.cacheDir) === true) {
186
- fs.rmSync(state.cacheDir, { recursive: true });
243
+ state.pendingWrites.clear();
244
+ try {
245
+ try {
246
+ await fs.fsPromises.access(state.cacheDir);
247
+ }
248
+ catch {
249
+ return; // Dir doesn't exist
250
+ }
251
+ await fs.fsPromises.rm(state.cacheDir, { recursive: true });
252
+ }
253
+ catch (error) {
254
+ Logger.error('Failed to clear cache', error);
187
255
  }
188
256
  }
189
257
  /**
190
- * Get cache statistics
258
+ * Get cache statistics (async)
191
259
  */
192
- function getCacheStats(state) {
260
+ async function getCacheStats(state) {
193
261
  let diskUsage = 0;
194
- if (fs.existsSync(state.cacheDir) === true) {
195
- const files = fs.readdirSync(state.cacheDir);
196
- for (const file of files) {
197
- const stats = fs.statSync(path.join(state.cacheDir, file));
198
- diskUsage += stats.size;
262
+ try {
263
+ try {
264
+ await fs.fsPromises.access(state.cacheDir);
265
+ const files = await fs.fsPromises.readdir(state.cacheDir);
266
+ const sizes = await Promise.all(files.map(async (file) => {
267
+ const stats = await fs.fsPromises.stat(path.join(state.cacheDir, file));
268
+ return stats.size;
269
+ }));
270
+ diskUsage = sizes.reduce((sum, size) => sum + size, 0);
271
+ }
272
+ catch {
273
+ // ignore
199
274
  }
200
275
  }
276
+ catch {
277
+ // ignore
278
+ }
201
279
  return {
202
280
  size: diskUsage,
203
281
  entries: state.cache.size,
@@ -242,24 +320,39 @@ function toInt32(value) {
242
320
  return uint32 > 2147483647 ? uint32 - 4294967296 : uint32;
243
321
  }
244
322
  /**
245
- * Load cache from disk
323
+ * Load cache from disk (async)
246
324
  */
247
- function loadFromDisk(state) {
248
- if (fs.existsSync(state.cacheDir) === true) {
325
+ async function loadFromDisk(state) {
326
+ try {
249
327
  try {
250
- const files = fs.readdirSync(state.cacheDir);
251
- for (const file of files) {
252
- if (file.endsWith('.json') === true) {
253
- const content = fs.readFileSync(path.join(state.cacheDir, file), 'utf-8');
254
- const data = JSON.parse(content);
255
- state.cache.set(file.replace('.json', ''), data);
256
- }
257
- }
328
+ await fs.fsPromises.access(state.cacheDir);
258
329
  }
259
- catch (err) {
260
- Logger.error(`Failed to load cache from disk: ${err instanceof Error ? err.message : String(err)}`);
330
+ catch {
331
+ return;
332
+ }
333
+ const files = await fs.fsPromises.readdir(state.cacheDir);
334
+ const jsonFiles = files.filter((file) => file.endsWith('.json') === true);
335
+ const parsedEntries = await Promise.all(jsonFiles.map(async (file) => {
336
+ const filePath = path.join(state.cacheDir, file);
337
+ const content = await fs.fsPromises.readFile(filePath, 'utf-8');
338
+ try {
339
+ const data = JSON.parse(content);
340
+ return { key: file.replace('.json', ''), data };
341
+ }
342
+ catch {
343
+ // ignore corrupted files
344
+ return null;
345
+ }
346
+ }));
347
+ for (const entry of parsedEntries) {
348
+ if (entry !== null) {
349
+ state.cache.set(entry.key, entry.data);
350
+ }
261
351
  }
262
352
  }
353
+ catch (err) {
354
+ Logger.error(`Failed to load cache from disk: ${err instanceof Error ? err.message : String(err)}`);
355
+ }
263
356
  }
264
357
  /**
265
358
  * Lazy Module Loader - Load dependencies only when needed
@@ -474,17 +567,36 @@ async function generateInParallel(stats, generators, batchSize) {
474
567
  */
475
568
  async function generateWithCache(cache, stats, type, params, generatorFn) {
476
569
  // Try cache
477
- const cached = cache.get(type, params);
570
+ let cached = null;
571
+ try {
572
+ cached = await cache.get(type, params);
573
+ }
574
+ catch (err) {
575
+ Logger.warn('GenerationCache.get failed; treating as cache miss', {
576
+ type,
577
+ error: err instanceof Error ? err.message : String(err),
578
+ });
579
+ }
478
580
  if (cached !== null) {
479
- stats.cacheHits++;
480
- return JSON.parse(cached);
581
+ try {
582
+ stats.cacheHits++;
583
+ return JSON.parse(cached);
584
+ }
585
+ catch (err) {
586
+ Logger.warn('Failed to parse cached generation result; treating as cache miss', {
587
+ type,
588
+ error: err instanceof Error ? err.message : String(err),
589
+ });
590
+ }
481
591
  }
482
592
  // Generate
483
593
  const startTime = performance.now();
484
594
  const result = await generatorFn();
485
595
  const duration = performance.now() - startTime;
486
- // Cache result
487
- cache.set(type, params, JSON.stringify(result));
596
+ // Cache result (fire-and-forget)
597
+ void cache
598
+ .set(type, params, JSON.stringify(result))
599
+ .catch((err) => Logger.error('GenerationCache.set failed', err));
488
600
  stats.cacheMisses++;
489
601
  stats.savedTime += duration;
490
602
  return result;
@@ -492,6 +604,16 @@ async function generateWithCache(cache, stats, type, params, generatorFn) {
492
604
  /**
493
605
  * Get optimization statistics
494
606
  */
607
+ function getCacheStatusSync(cache) {
608
+ const state = cache[GENERATION_CACHE_STATE_SYMBOL];
609
+ const map = state?.cache;
610
+ if (!(map instanceof Map))
611
+ return { size: 0, keys: [] };
612
+ return {
613
+ size: map.size,
614
+ keys: Array.from(map.keys()),
615
+ };
616
+ }
495
617
  function getOptimizerStats(cache, stats) {
496
618
  const total = stats.cacheHits + stats.cacheMisses;
497
619
  const hitRate = total > 0 ? (stats.cacheHits / total) * 100 : 0;
@@ -501,7 +623,7 @@ function getOptimizerStats(cache, stats) {
501
623
  hitRate: `${hitRate.toFixed(1)}%`,
502
624
  parallelRuns: stats.parallelRuns,
503
625
  estimatedSavedTime: `${stats.savedTime.toFixed(2)}ms`,
504
- cacheStatus: cache.getStats(),
626
+ cacheStatus: getCacheStatusSync(cache),
505
627
  };
506
628
  }
507
629
  export default PerformanceOptimizer;
@@ -1 +1 @@
1
- {"version":3,"file":"RequestProfiler.d.ts","sourceRoot":"","sources":["../../../src/profiling/RequestProfiler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAGhE,OAAO,KAAK,EAAE,YAAY,EAAC,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,WAAW,EAAa,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE9E,MAAM,WAAW,gBAAgB;IAC/B,cAAc,IAAI,YAAY,CAAC;IAC/B,aAAa,IAAI,WAAW,CAAC;IAC7B,iBAAiB,IAAI,eAAe,CAAC;IACrC,cAAc,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC;CAChD;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;IAC1B;;OAEG;cACO,gBAAgB;EAkE1B,CAAC;AAmBH;;GAEG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"RequestProfiler.d.ts","sourceRoot":"","sources":["../../../src/profiling/RequestProfiler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAGjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAa,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE9E,MAAM,WAAW,gBAAgB;IAC/B,cAAc,IAAI,YAAY,CAAC;IAC/B,aAAa,IAAI,WAAW,CAAC;IAC7B,iBAAiB,IAAI,eAAe,CAAC;IACrC,cAAc,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IACnE,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CAAC;CAChD;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;IAC1B;;OAEG;cACO,gBAAgB;EAsE1B,CAAC;AAmBH;;GAEG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,eAAe,eAAe,CAAC"}
@@ -49,13 +49,15 @@ export const RequestProfiler = Object.freeze({
49
49
  const queriesExecuted = queryLog.length;
50
50
  const patterns = n1Detector.detect(queryLog);
51
51
  const memoryDelta = memoryProfiler.delta();
52
- return {
52
+ const report = {
53
53
  duration,
54
54
  queriesExecuted,
55
55
  n1Patterns: patterns,
56
56
  memoryDelta,
57
57
  timestamp: new Date(),
58
58
  };
59
+ queryLogger.clear('profiling');
60
+ return report;
59
61
  },
60
62
  generateReport(profile) {
61
63
  const n1Section = formatN1Section(profile.n1Patterns);
@@ -8,21 +8,20 @@ export { MIME_TYPES_MAP } from './common';
8
8
  /**
9
9
  * Find the package root directory
10
10
  */
11
- export { findPackageRoot, getFrameworkPublicRoots, getPublicRoot } from './publicRoot';
11
+ export { findPackageRoot, findPackageRootAsync, getFrameworkPublicRoots, getFrameworkPublicRootsAsync, getPublicRoot, getPublicRootAsync, } from './publicRoot';
12
12
  /**
13
13
  * Set relaxed CSP headers for docs (allows external assets like Tailwind CDN, Google Fonts)
14
14
  */
15
15
  export declare const setDocumentationCSPHeaders: (response: IResponse) => void;
16
16
  /**
17
- * Serve a documentation static file
18
- * Returns true if file was served, false if not found
17
+ * Serve a documentation static file (async)
19
18
  */
20
- export declare const serveDocumentationFile: (urlPath: string, response: IResponse) => boolean;
19
+ export declare const serveDocumentationFileAsync: (urlPath: string, response: IResponse) => Promise<boolean>;
21
20
  export declare const registerDocRoutes: (router: IRouter) => void;
22
21
  declare const _default: {
23
22
  registerDocRoutes: (router: IRouter) => void;
24
23
  setDocumentationCSPHeaders: (response: IResponse) => void;
25
- serveDocumentationFile: (urlPath: string, response: IResponse) => boolean;
24
+ serveDocumentationFileAsync: (urlPath: string, response: IResponse) => Promise<boolean>;
26
25
  };
27
26
  export default _default;
28
27
  //# sourceMappingURL=doc.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doc.d.ts","sourceRoot":"","sources":["../../../src/routing/doc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAoB9F;;GAEG;AACH,eAAO,MAAM,0BAA0B,GAAI,UAAU,SAAS,KAAG,IAWhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,EAAE,UAAU,SAAS,KAAG,OAkC7E,CAAC;AASF,eAAO,MAAM,iBAAiB,GAAI,QAAQ,OAAO,KAAG,IAMnD,CAAC;;gCANwC,OAAO,KAAG,IAAI;2CA5DH,SAAS,KAAG,IAAI;sCAiBrB,MAAM,YAAY,SAAS,KAAG,OAAO;;AAmDrF,wBAAyF"}
1
+ {"version":3,"file":"doc.d.ts","sourceRoot":"","sources":["../../../src/routing/doc.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMhD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG/C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;GAEG;AAEH,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,uBAAuB,EACvB,4BAA4B,EAC5B,aAAa,EACb,kBAAkB,GACnB,MAAM,qBAAqB,CAAC;AAiB7B;;GAEG;AACH,eAAO,MAAM,0BAA0B,GAAI,UAAU,SAAS,KAAG,IAWhE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,2BAA2B,GACtC,SAAS,MAAM,EACf,UAAU,SAAS,KAClB,OAAO,CAAC,OAAO,CAgDjB,CAAC;AASF,eAAO,MAAM,iBAAiB,GAAI,QAAQ,OAAO,KAAG,IAMnD,CAAC;;gCANwC,OAAO,KAAG,IAAI;2CA5EH,SAAS,KAAG,IAAI;2CAiB1D,MAAM,YACL,SAAS,KAClB,OAAO,CAAC,OAAO,CAAC;;AAiEnB,wBAIE"}
@@ -8,19 +8,16 @@ import * as fs from '../node-singletons/fs.js';
8
8
  import * as path from '../node-singletons/path.js';
9
9
  import { MIME_TYPES_MAP, resolveSafePath, tryDecodeURIComponent } from './common.js';
10
10
  import { ErrorRouting } from './error.js';
11
- import { getPublicRoot } from './publicRoot.js';
11
+ import { getPublicRootAsync } from './publicRoot.js';
12
12
  import { Router } from './Router.js';
13
13
  export { MIME_TYPES_MAP } from './common.js';
14
14
  /**
15
15
  * Find the package root directory
16
16
  */
17
17
  // Backward-compatible re-exports
18
- export { findPackageRoot, getFrameworkPublicRoots, getPublicRoot } from './publicRoot.js';
19
- /**
20
- * Map URL path to physical file path for /doc routes
21
- */
22
- const mapStaticPath = (urlPath) => {
23
- const publicRoot = getPublicRoot();
18
+ export { findPackageRoot, findPackageRootAsync, getFrameworkPublicRoots, getFrameworkPublicRootsAsync, getPublicRoot, getPublicRootAsync, } from './publicRoot.js';
19
+ const mapStaticPathAsync = async (urlPath) => {
20
+ const publicRoot = await getPublicRootAsync();
24
21
  const normalize = (p) => (p.startsWith('/') ? p.slice(1) : p);
25
22
  if (urlPath === '/doc' || urlPath === '/doc/')
26
23
  return publicRoot;
@@ -45,28 +42,42 @@ export const setDocumentationCSPHeaders = (response) => {
45
42
  "font-src 'self' data: https://fonts.gstatic.com;");
46
43
  };
47
44
  /**
48
- * Serve a documentation static file
49
- * Returns true if file was served, false if not found
45
+ * Serve a documentation static file (async)
50
46
  */
51
- export const serveDocumentationFile = (urlPath, response) => {
52
- let filePath = mapStaticPath(urlPath);
47
+ export const serveDocumentationFileAsync = async (urlPath, response) => {
48
+ let filePath = await mapStaticPathAsync(urlPath);
53
49
  if (filePath === undefined) {
54
50
  return false;
55
51
  }
56
52
  try {
57
- if (fs.existsSync(filePath) && fs.statSync(filePath).isDirectory()) {
58
- filePath = path.join(filePath, 'index.html');
53
+ try {
54
+ const stats = await fs.fsPromises.stat(filePath);
55
+ if (stats.isDirectory()) {
56
+ filePath = path.join(filePath, 'index.html');
57
+ }
58
+ }
59
+ catch {
60
+ // ignore
59
61
  }
60
- if (!fs.existsSync(filePath) && !path.extname(filePath)) {
62
+ const exists = async (p) => {
63
+ try {
64
+ await fs.fsPromises.access(p);
65
+ return true;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ };
71
+ if (!(await exists(filePath)) && !path.extname(filePath)) {
61
72
  const htmlPath = `${filePath}.html`;
62
- if (fs.existsSync(htmlPath)) {
73
+ if (await exists(htmlPath)) {
63
74
  filePath = htmlPath;
64
75
  }
65
76
  }
66
- if (fs.existsSync(filePath)) {
77
+ if (await exists(filePath)) {
67
78
  const ext = path.extname(filePath).toLowerCase();
68
79
  const contentType = MIME_TYPES_MAP[ext] || 'application/octet-stream';
69
- const content = fs.readFileSync(filePath);
80
+ const content = await fs.fsPromises.readFile(filePath);
70
81
  response.setStatus(200);
71
82
  response.setHeader('Content-Type', contentType);
72
83
  response.send(content);
@@ -78,10 +89,10 @@ export const serveDocumentationFile = (urlPath, response) => {
78
89
  }
79
90
  return false;
80
91
  };
81
- const handleDocRequest = (req, res) => {
92
+ const handleDocRequest = async (req, res) => {
82
93
  setDocumentationCSPHeaders(res);
83
94
  const urlPath = req.getPath();
84
- if (serveDocumentationFile(urlPath, res))
95
+ if (await serveDocumentationFileAsync(urlPath, res))
85
96
  return;
86
97
  ErrorRouting.handleNotFound(req, res);
87
98
  };
@@ -92,4 +103,8 @@ export const registerDocRoutes = (router) => {
92
103
  // Greedy path match for nested assets like /doc/assets/app.js
93
104
  Router.get(router, '/doc/:path*', handleDocRequest);
94
105
  };
95
- export default { registerDocRoutes, setDocumentationCSPHeaders, serveDocumentationFile };
106
+ export default {
107
+ registerDocRoutes,
108
+ setDocumentationCSPHeaders,
109
+ serveDocumentationFileAsync,
110
+ };
@@ -6,13 +6,22 @@
6
6
  * Find the package root directory.
7
7
  */
8
8
  export declare const findPackageRoot: (startDir: string) => string;
9
+ /**
10
+ * Find the package root directory (async).
11
+ */
12
+ export declare const findPackageRootAsync: (startDir: string) => Promise<string>;
9
13
  /**
10
14
  * Framework public roots (dist/public preferred).
11
15
  */
12
16
  export declare const getFrameworkPublicRoots: () => string[];
17
+ export declare const getFrameworkPublicRootsAsync: () => Promise<string[]>;
13
18
  /**
14
19
  * Resolve the effective public root.
15
20
  * Prefers app-local `public/` when present; otherwise falls back to framework public roots.
16
21
  */
17
22
  export declare const getPublicRoot: () => string;
23
+ /**
24
+ * Resolve the effective public root (async).
25
+ */
26
+ export declare const getPublicRootAsync: () => Promise<string>;
18
27
  //# sourceMappingURL=publicRoot.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"publicRoot.d.ts","sourceRoot":"","sources":["../../../src/routing/publicRoot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,KAAG,MASlD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,QAAO,MAAM,EAIhD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,QAAO,MAgBhC,CAAC"}
1
+ {"version":3,"file":"publicRoot.d.ts","sourceRoot":"","sources":["../../../src/routing/publicRoot.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,UAAU,MAAM,KAAG,MAalD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAkB3E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,QAAO,MAAM,EAIhD,CAAC;AAEF,eAAO,MAAM,4BAA4B,QAAa,OAAO,CAAC,MAAM,EAAE,CAIrE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,aAAa,QAAO,MAgBhC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,QAAa,OAAO,CAAC,MAAM,CA+BzD,CAAC"}
@@ -11,8 +11,13 @@ import * as path from '../node-singletons/path.js';
11
11
  export const findPackageRoot = (startDir) => {
12
12
  let current = startDir;
13
13
  for (let i = 0; i < 10; i++) {
14
- if (fs.existsSync(path.join(current, 'package.json')))
15
- return current;
14
+ try {
15
+ if (fs.existsSync(path.join(current, 'package.json')))
16
+ return current;
17
+ }
18
+ catch {
19
+ // ignore access errors
20
+ }
16
21
  const parent = path.dirname(current);
17
22
  if (parent === current)
18
23
  break;
@@ -20,6 +25,27 @@ export const findPackageRoot = (startDir) => {
20
25
  }
21
26
  return startDir;
22
27
  };
28
+ /**
29
+ * Find the package root directory (async).
30
+ */
31
+ export const findPackageRootAsync = async (startDir) => {
32
+ const findUp = async (current, depth) => {
33
+ if (depth >= 10)
34
+ return startDir;
35
+ try {
36
+ await fs.fsPromises.access(path.join(current, 'package.json'));
37
+ return current;
38
+ }
39
+ catch {
40
+ // ignore
41
+ }
42
+ const parent = path.dirname(current);
43
+ if (parent === current)
44
+ return startDir;
45
+ return findUp(parent, depth + 1);
46
+ };
47
+ return findUp(startDir, 0);
48
+ };
23
49
  /**
24
50
  * Framework public roots (dist/public preferred).
25
51
  */
@@ -28,6 +54,11 @@ export const getFrameworkPublicRoots = () => {
28
54
  const packageRoot = findPackageRoot(thisDir);
29
55
  return [path.join(packageRoot, 'dist/public'), path.join(packageRoot, 'public')];
30
56
  };
57
+ export const getFrameworkPublicRootsAsync = async () => {
58
+ const thisDir = esmDirname(import.meta.url);
59
+ const packageRoot = await findPackageRootAsync(thisDir);
60
+ return [path.join(packageRoot, 'dist/public'), path.join(packageRoot, 'public')];
61
+ };
31
62
  /**
32
63
  * Resolve the effective public root.
33
64
  * Prefers app-local `public/` when present; otherwise falls back to framework public roots.
@@ -47,3 +78,33 @@ export const getPublicRoot = () => {
47
78
  }
48
79
  return candidates[0];
49
80
  };
81
+ /**
82
+ * Resolve the effective public root (async).
83
+ */
84
+ export const getPublicRootAsync = async () => {
85
+ const appRoots = [path.join(process.cwd(), 'public')];
86
+ const fwRoots = await getFrameworkPublicRootsAsync();
87
+ const candidates = [...appRoots, ...fwRoots];
88
+ const exists = async (p) => {
89
+ try {
90
+ await fs.fsPromises.access(p);
91
+ return true;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ };
97
+ const hasIndex = async (root) => exists(path.join(root, 'index.html'));
98
+ const checks = await Promise.all(candidates.map(async (candidate) => {
99
+ const rootExists = await exists(candidate);
100
+ const indexExists = rootExists ? await hasIndex(candidate) : false;
101
+ return { candidate, rootExists, indexExists };
102
+ }));
103
+ const withIndex = checks.find((c) => c.indexExists);
104
+ if (withIndex)
105
+ return withIndex.candidate;
106
+ const firstExisting = checks.find((c) => c.rootExists);
107
+ if (firstExisting)
108
+ return firstExisting.candidate;
109
+ return candidates[0];
110
+ };
@@ -0,0 +1,21 @@
1
+ export declare const StartupConfigFile: {
2
+ readonly Broadcast: "config/broadcast.ts";
3
+ readonly Cache: "config/cache.ts";
4
+ readonly Database: "config/database.ts";
5
+ readonly Mail: "config/mail.ts";
6
+ readonly Middleware: "config/middleware.ts";
7
+ readonly Notification: "config/notification.ts";
8
+ readonly Queue: "config/queue.ts";
9
+ readonly Storage: "config/storage.ts";
10
+ };
11
+ export type StartupConfigFileTyps = typeof StartupConfigFile.Broadcast | typeof StartupConfigFile.Cache | typeof StartupConfigFile.Database | typeof StartupConfigFile.Mail | typeof StartupConfigFile.Middleware | typeof StartupConfigFile.Notification | typeof StartupConfigFile.Queue | typeof StartupConfigFile.Storage;
12
+ export declare const StartupConfigFileRegistry: Readonly<{
13
+ preload(files: readonly StartupConfigFileTyps[]): Promise<void>;
14
+ isPreloaded(): boolean;
15
+ get<T>(file: StartupConfigFileTyps): T | undefined;
16
+ has(file: StartupConfigFileTyps): boolean;
17
+ /** Intended for tests only. */
18
+ clear(): void;
19
+ }>;
20
+ export default StartupConfigFileRegistry;
21
+ //# sourceMappingURL=StartupConfigFileRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StartupConfigFileRegistry.d.ts","sourceRoot":"","sources":["../../../src/runtime/StartupConfigFileRegistry.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB;;;;;;;;;CASpB,CAAC;AAEX,MAAM,MAAM,qBAAqB,GAC7B,OAAO,iBAAiB,CAAC,SAAS,GAClC,OAAO,iBAAiB,CAAC,KAAK,GAC9B,OAAO,iBAAiB,CAAC,QAAQ,GACjC,OAAO,iBAAiB,CAAC,IAAI,GAC7B,OAAO,iBAAiB,CAAC,UAAU,GACnC,OAAO,iBAAiB,CAAC,YAAY,GACrC,OAAO,iBAAiB,CAAC,KAAK,GAC9B,OAAO,iBAAiB,CAAC,OAAO,CAAC;AAKrC,eAAO,MAAM,yBAAyB;mBACf,SAAS,qBAAqB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;mBAetD,OAAO;QAIlB,CAAC,QAAQ,qBAAqB,GAAG,CAAC,GAAG,SAAS;cAIxC,qBAAqB,GAAG,OAAO;IAIzC,+BAA+B;aACtB,IAAI;EAIb,CAAC;AAEH,eAAe,yBAAyB,CAAC"}