@futdevpro/nts-dynamo 1.15.119 → 1.15.121

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 (75) hide show
  1. package/.dynamo/logs/cicd-pipeline/output.log +1899 -1878
  2. package/.dynamo/logs/cicd-pipeline/status.json +37 -37
  3. package/build/_models/control-models/endpoint-params.control-model.d.ts +5 -0
  4. package/build/_models/control-models/endpoint-params.control-model.d.ts.map +1 -1
  5. package/build/_models/control-models/endpoint-params.control-model.js +41 -11
  6. package/build/_models/control-models/endpoint-params.control-model.js.map +1 -1
  7. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.d.ts +6 -1
  8. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.d.ts.map +1 -1
  9. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.js +40 -10
  10. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.js.map +1 -1
  11. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.d.ts +9 -0
  12. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.d.ts.map +1 -1
  13. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.js +12 -0
  14. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.js.map +1 -1
  15. package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.d.ts +12 -2
  16. package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.d.ts.map +1 -1
  17. package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.js +54 -7
  18. package/build/_modules/local-vector-search/_services/lvs-vector-pool.control-service.js.map +1 -1
  19. package/build/_modules/server/server-status/server-status.control-service.d.ts +6 -0
  20. package/build/_modules/server/server-status/server-status.control-service.d.ts.map +1 -1
  21. package/build/_modules/server/server-status/server-status.control-service.js +10 -0
  22. package/build/_modules/server/server-status/server-status.control-service.js.map +1 -1
  23. package/build/_modules/server/server-status/server-status.controller.d.ts.map +1 -1
  24. package/build/_modules/server/server-status/server-status.controller.js +26 -0
  25. package/build/_modules/server/server-status/server-status.controller.js.map +1 -1
  26. package/build/_modules/socket/_models/socket-server-service-params.control-model.d.ts +11 -1
  27. package/build/_modules/socket/_models/socket-server-service-params.control-model.d.ts.map +1 -1
  28. package/build/_modules/socket/_models/socket-server-service-params.control-model.js +12 -1
  29. package/build/_modules/socket/_models/socket-server-service-params.control-model.js.map +1 -1
  30. package/build/_modules/socket/_services/socket-server.service.d.ts +2 -0
  31. package/build/_modules/socket/_services/socket-server.service.d.ts.map +1 -1
  32. package/build/_modules/socket/_services/socket-server.service.js +2 -0
  33. package/build/_modules/socket/_services/socket-server.service.js.map +1 -1
  34. package/build/_modules/socket/app-extended.server.d.ts.map +1 -1
  35. package/build/_modules/socket/app-extended.server.js +13 -8
  36. package/build/_modules/socket/app-extended.server.js.map +1 -1
  37. package/build/_services/base/db.service.d.ts +14 -0
  38. package/build/_services/base/db.service.d.ts.map +1 -1
  39. package/build/_services/base/db.service.js +27 -0
  40. package/build/_services/base/db.service.js.map +1 -1
  41. package/build/_services/core/api.service.d.ts.map +1 -1
  42. package/build/_services/core/api.service.js +29 -9
  43. package/build/_services/core/api.service.js.map +1 -1
  44. package/build/_services/core/db-stats.service.d.ts +34 -0
  45. package/build/_services/core/db-stats.service.d.ts.map +1 -0
  46. package/build/_services/core/db-stats.service.js +65 -0
  47. package/build/_services/core/db-stats.service.js.map +1 -0
  48. package/build/_services/core/diagnostics.service.d.ts +43 -0
  49. package/build/_services/core/diagnostics.service.d.ts.map +1 -0
  50. package/build/_services/core/diagnostics.service.js +122 -0
  51. package/build/_services/core/diagnostics.service.js.map +1 -0
  52. package/build/index.d.ts +2 -0
  53. package/build/index.d.ts.map +1 -1
  54. package/build/index.js +2 -0
  55. package/build/index.js.map +1 -1
  56. package/package.json +2 -2
  57. package/src/_models/control-models/endpoint-params.control-model.ts +44 -16
  58. package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.spec.ts +16 -0
  59. package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.ts +50 -14
  60. package/src/_modules/local-vector-search/_services/lvs-vector-persist.data-service.ts +22 -0
  61. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.spec.ts +5 -3
  62. package/src/_modules/local-vector-search/_services/lvs-vector-pool.control-service.ts +62 -11
  63. package/src/_modules/server/server-status/server-status.control-service.ts +12 -0
  64. package/src/_modules/server/server-status/server-status.controller.ts +28 -0
  65. package/src/_modules/socket/_models/socket-server-service-params.control-model.spec.ts +23 -0
  66. package/src/_modules/socket/_models/socket-server-service-params.control-model.ts +12 -1
  67. package/src/_modules/socket/_services/socket-server.service.ts +2 -0
  68. package/src/_modules/socket/app-extended.server.ts +15 -9
  69. package/src/_services/base/db.service.ts +39 -1
  70. package/src/_services/core/api.service.spec.ts +47 -0
  71. package/src/_services/core/api.service.ts +32 -12
  72. package/src/_services/core/db-stats.service.ts +104 -0
  73. package/src/_services/core/diagnostics.service.spec.ts +44 -0
  74. package/src/_services/core/diagnostics.service.ts +158 -0
  75. package/src/index.ts +2 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.service.d.ts","sourceRoot":"","sources":["../../../src/_services/core/diagnostics.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,UAAU,CAAC;AAQrC;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAC;IAC/B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wEAAwE;AACxE,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,CAAC,iBAAiB,CAAC,CAAC;AAKnE,qBAAa,iBAAiB;IAE5B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAEjE,8EAA8E;IAC9E,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI;IAItD,iFAAiF;WACpE,SAAS,CAAC,GAAG,EAAE;QAC1B,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAC;QAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAqF/B,8GAA8G;IAC9G,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM;IAM3E,4EAA4E;IAC5E,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,iBAAiB,EAAE,GAAG,MAAM;CASzD"}
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DyNTS_Diagnostics = void 0;
4
+ const fsm_dynamo_1 = require("@futdevpro/fsm-dynamo");
5
+ const db_stats_service_1 = require("./db-stats.service");
6
+ const event_loop_diag_service_1 = require("./event-loop-diag.service");
7
+ const memory_guard_service_1 = require("./memory-guard.service");
8
+ /** Collection-méret warn-küszöb (MB) — e fölött a dbStats-check warn-ra vált. */
9
+ const DEFAULT_COLLECTION_WARN_MB = 512;
10
+ class DyNTS_Diagnostics {
11
+ static customChecks = [];
12
+ /** App-specifikus check regisztrálása (pl. env-validáció, provider-probe). */
13
+ static registerCheck(check) {
14
+ DyNTS_Diagnostics.customChecks.push(check);
15
+ }
16
+ /** A teljes doctor-riport. SOSEM dob — a hibás check `fail`-ként jelenik meg. */
17
+ static async runDoctor(set) {
18
+ const checks = [];
19
+ // 1) Mongo-probe (readiness-minta: readyState + admin ping).
20
+ try {
21
+ const readyState = set.connection?.readyState ?? 0;
22
+ let pingOk = false;
23
+ if (readyState === 1) {
24
+ await set.connection.db?.admin().ping();
25
+ pingOk = true;
26
+ }
27
+ checks.push({
28
+ name: 'mongo',
29
+ health: readyState === 1 && pingOk ? 'ok' : 'fail',
30
+ detail: { readyState: readyState, pingOk: pingOk },
31
+ fixHint: readyState === 1 && pingOk ? undefined
32
+ : 'Check MONGO_URL + DB container/network reachability (readyState 1 + ping expected).',
33
+ });
34
+ }
35
+ catch (error) {
36
+ checks.push({
37
+ name: 'mongo', health: 'fail', detail: String(error),
38
+ fixHint: 'Mongo ping threw — check DB availability/credentials.',
39
+ });
40
+ }
41
+ // 2) Memória (MemoryGuard pressure).
42
+ try {
43
+ const pressure = memory_guard_service_1.DyNTS_MemoryGuard.getInstance().pressure();
44
+ const level = String(pressure?.level ?? 'ok');
45
+ checks.push({
46
+ name: 'memory',
47
+ health: level === 'critical' ? 'fail' : level === 'warning' ? 'warn' : 'ok',
48
+ detail: pressure,
49
+ fixHint: level === 'ok' ? undefined
50
+ : 'Heap pressure — check collection sizes (/server/db-stats) + recent load; consider retention.',
51
+ });
52
+ }
53
+ catch (error) {
54
+ checks.push({ name: 'memory', health: 'warn', detail: String(error), fixHint: 'MemoryGuard snapshot failed.' });
55
+ }
56
+ // 3) Event-loop lag.
57
+ try {
58
+ const snapshot = event_loop_diag_service_1.DyNTS_EventLoopDiag.getInstance().getSnapshot();
59
+ checks.push({ name: 'eventLoop', health: 'ok', detail: snapshot });
60
+ }
61
+ catch (error) {
62
+ checks.push({ name: 'eventLoop', health: 'warn', detail: String(error), fixHint: 'EventLoopDiag snapshot failed.' });
63
+ }
64
+ // 4) DB-stats + bloat-küszöb (BFR-OVERSEER-004 early-warning).
65
+ try {
66
+ const stats = await db_stats_service_1.DyNTS_DbStats_Util.collect(set.connection);
67
+ const warnMB = set.collectionWarnMB ?? DEFAULT_COLLECTION_WARN_MB;
68
+ const bloated = stats.collections
69
+ .filter((c) => c.sizeMB + c.indexSizeMB > warnMB)
70
+ .map((c) => `${c.name} (${c.sizeMB}MB + ${c.indexSizeMB}MB idx)`);
71
+ checks.push({
72
+ name: 'dbStats',
73
+ health: bloated.length ? 'warn' : 'ok',
74
+ detail: { totalSizeMB: stats.totalSizeMB, collectionCount: stats.collections.length, bloated: bloated },
75
+ fixHint: bloated.length
76
+ ? `Collections over ${warnMB}MB — add dataParams.retention (TTL) or prune: ${bloated.join(', ')}`
77
+ : undefined,
78
+ });
79
+ }
80
+ catch (error) {
81
+ checks.push({ name: 'dbStats', health: 'warn', detail: String(error), fixHint: 'db-stats collection failed.' });
82
+ }
83
+ // 5) App-specifikus check-ek.
84
+ for (const customCheck of DyNTS_Diagnostics.customChecks) {
85
+ try {
86
+ checks.push(await customCheck());
87
+ }
88
+ catch (error) {
89
+ fsm_dynamo_1.DyFM_Log.warn('(DyNTS_Diagnostics) custom check threw (reported as fail)', error);
90
+ checks.push({ name: 'custom', health: 'fail', detail: String(error), fixHint: 'Custom check threw — see detail.' });
91
+ }
92
+ }
93
+ return {
94
+ health: DyNTS_Diagnostics.interpretHealth(checks),
95
+ checks: checks,
96
+ summary: DyNTS_Diagnostics.buildSummary(checks),
97
+ uptimeSec: Math.round(process.uptime()),
98
+ };
99
+ }
100
+ /** Aggregált health: bármely fail → fail; különben bármely warn → warn; különben ok. Pure (unit-tesztelt). */
101
+ static interpretHealth(checks) {
102
+ if (checks.some((c) => c.health === 'fail')) {
103
+ return 'fail';
104
+ }
105
+ if (checks.some((c) => c.health === 'warn')) {
106
+ return 'warn';
107
+ }
108
+ return 'ok';
109
+ }
110
+ /** Ember-olvasható összegzés a nem-ok check-ekből. Pure (unit-tesztelt). */
111
+ static buildSummary(checks) {
112
+ const notOk = checks.filter((c) => c.health !== 'ok');
113
+ if (!notOk.length) {
114
+ return 'all checks ok';
115
+ }
116
+ return notOk
117
+ .map((c) => `${c.name}: ${c.health}${c.fixHint ? ` — ${c.fixHint}` : ''}`)
118
+ .join(' | ');
119
+ }
120
+ }
121
+ exports.DyNTS_Diagnostics = DyNTS_Diagnostics;
122
+ //# sourceMappingURL=diagnostics.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.service.js","sourceRoot":"","sources":["../../../src/_services/core/diagnostics.service.ts"],"names":[],"mappings":"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"}
package/build/index.d.ts CHANGED
@@ -24,6 +24,8 @@ export * from './_collections/security-headers.util';
24
24
  export * from './_collections/client-safe-error.util';
25
25
  export * from './_collections/load-shed.util';
26
26
  export * from './_services/core/event-loop-diag.service';
27
+ export * from './_services/core/db-stats.service';
28
+ export * from './_services/core/diagnostics.service';
27
29
  export * from './_models/control-models/api-call-params.control-model';
28
30
  export * from './_models/control-models/app-ext-system-controls.control-model';
29
31
  export * from './_models/control-models/app-params.control-model';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2BA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,qDAAqD,CAAC;AACpE,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AAIrD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAK7C,mEAAmE;AACnE,cAAc,uDAAuD,CAAC;AACtE,cAAc,qDAAqD,CAAC;AACpE,cAAc,wDAAwD,CAAC;AACvE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,wDAAwD,CAAC;AACvE,cAAc,uDAAuD,CAAC;AACtE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,iDAAiD,CAAC;AAChE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AAGzD,cAAc,wDAAwD,CAAC;AACvE,cAAc,gEAAgE,CAAA;AAC9E,cAAc,mDAAmD,CAAC;AAClE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,wDAAwD,CAAC;AACvE,cAAc,sDAAsD,CAAC;AACrE,cAAc,uDAAuD,CAAC;AAGtE,cAAc,gCAAgC,CAAC;AAG/C,cAAc,mDAAmD,CAAC;AAKlE,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oDAAoD,CAAC;AACnE,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAG1D,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yCAAyC,CAAC;AACxD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,+BAA+B,CAAC;AAG9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC;AAGzD,cAAc,mCAAmC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA2BA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+CAA+C,CAAC;AAC9D,cAAc,qDAAqD,CAAC;AACpE,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0CAA0C,CAAC;AACzD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,sCAAsC,CAAC;AAIrD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAK7C,mEAAmE;AACnE,cAAc,uDAAuD,CAAC;AACtE,cAAc,qDAAqD,CAAC;AACpE,cAAc,wDAAwD,CAAC;AACvE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,wDAAwD,CAAC;AACvE,cAAc,uDAAuD,CAAC;AACtE,cAAc,8CAA8C,CAAC;AAC7D,cAAc,0DAA0D,CAAC;AACzE,cAAc,iDAAiD,CAAC;AAChE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,sCAAsC,CAAC;AACrD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0CAA0C,CAAC;AACzD,cAAc,mCAAmC,CAAC;AAClD,cAAc,sCAAsC,CAAC;AAGrD,cAAc,wDAAwD,CAAC;AACvE,cAAc,gEAAgE,CAAA;AAC9E,cAAc,mDAAmD,CAAC;AAClE,cAAc,4DAA4D,CAAC;AAC3E,cAAc,wDAAwD,CAAC;AACvE,cAAc,sDAAsD,CAAC;AACrE,cAAc,uDAAuD,CAAC;AAGtE,cAAc,gCAAgC,CAAC;AAG/C,cAAc,mDAAmD,CAAC;AAKlE,cAAc,8BAA8B,CAAC;AAC7C,cAAc,+BAA+B,CAAC;AAE9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oDAAoD,CAAC;AACnE,cAAc,iCAAiC,CAAC;AAChD,cAAc,uCAAuC,CAAC;AAEtD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,2CAA2C,CAAC;AAG1D,cAAc,mCAAmC,CAAC;AAClD,cAAc,uCAAuC,CAAC;AACtD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yCAAyC,CAAC;AACxD,cAAc,oCAAoC,CAAC;AAGnD,cAAc,+BAA+B,CAAC;AAG9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,0CAA0C,CAAC;AAGzD,cAAc,mCAAmC,CAAC"}
package/build/index.js CHANGED
@@ -53,6 +53,8 @@ tslib_1.__exportStar(require("./_collections/security-headers.util"), exports);
53
53
  tslib_1.__exportStar(require("./_collections/client-safe-error.util"), exports);
54
54
  tslib_1.__exportStar(require("./_collections/load-shed.util"), exports);
55
55
  tslib_1.__exportStar(require("./_services/core/event-loop-diag.service"), exports);
56
+ tslib_1.__exportStar(require("./_services/core/db-stats.service"), exports);
57
+ tslib_1.__exportStar(require("./_services/core/diagnostics.service"), exports);
56
58
  // models/CONTROL MODELS
57
59
  tslib_1.__exportStar(require("./_models/control-models/api-call-params.control-model"), exports);
58
60
  tslib_1.__exportStar(require("./_models/control-models/app-ext-system-controls.control-model"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;IAsBI;;;AAEJ,cAAc;AACd,sEAA4C;AAC5C,wFAA8D;AAC9D,8FAAoE;AACpE,sFAA4D;AAC5D,mFAAyD;AACzD,uFAA6D;AAC7D,+EAAqD;AAGrD,QAAQ;AACR,wEAA8C;AAC9C,8EAAoD;AACpD,8EAAoD;AACpD,uEAA6C;AAG7C,6CAA6C;AAE7C,mEAAmE;AACnE,gGAAsE;AACtE,8FAAoE;AACpE,iGAAuE;AACvE,yFAA+D;AAC/D,iGAAuE;AACvE,gGAAsE;AACtE,uFAA6D;AAC7D,mGAAyE;AACzE,0FAAgE;AAChE,yFAA+D;AAC/D,+EAAqD;AACrD,gFAAsD;AACtD,wEAA8C;AAC9C,mFAAyD;AAEzD,wBAAwB;AACxB,iGAAuE;AACvE,yGAA8E;AAC9E,4FAAkE;AAClE,qGAA2E;AAC3E,iGAAuE;AACvE,+FAAqE;AACrE,gGAAsE;AAEtE,eAAe;AACf,yEAA+C;AAE/C,qBAAqB;AACrB,4FAAkE;AAGlE,WAAW;AACX,gBAAgB;AAChB,uEAA6C;AAC7C,wEAA8C;AAE9C,yEAA+C;AAC/C,6FAAmE;AACnE,0EAAgD;AAChD,gFAAsD;AAEtD,sFAA4D;AAC5D,oFAA0D;AAE1D,gBAAgB;AAChB,4EAAkD;AAClD,gFAAsD;AACtD,wEAA8C;AAC9C,sEAA4C;AAC5C,kFAAwD;AACxD,6EAAmD;AAEnD,kBAAkB;AAClB,wEAA8C;AAE9C,iBAAiB;AACjB,+EAAqD;AACrD,mFAAyD;AAEzD,kBAAkB;AAClB,4EAAkD"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;IAsBI;;;AAEJ,cAAc;AACd,sEAA4C;AAC5C,wFAA8D;AAC9D,8FAAoE;AACpE,sFAA4D;AAC5D,mFAAyD;AACzD,uFAA6D;AAC7D,+EAAqD;AAGrD,QAAQ;AACR,wEAA8C;AAC9C,8EAAoD;AACpD,8EAAoD;AACpD,uEAA6C;AAG7C,6CAA6C;AAE7C,mEAAmE;AACnE,gGAAsE;AACtE,8FAAoE;AACpE,iGAAuE;AACvE,yFAA+D;AAC/D,iGAAuE;AACvE,gGAAsE;AACtE,uFAA6D;AAC7D,mGAAyE;AACzE,0FAAgE;AAChE,yFAA+D;AAC/D,+EAAqD;AACrD,gFAAsD;AACtD,wEAA8C;AAC9C,mFAAyD;AACzD,4EAAkD;AAClD,+EAAqD;AAErD,wBAAwB;AACxB,iGAAuE;AACvE,yGAA8E;AAC9E,4FAAkE;AAClE,qGAA2E;AAC3E,iGAAuE;AACvE,+FAAqE;AACrE,gGAAsE;AAEtE,eAAe;AACf,yEAA+C;AAE/C,qBAAqB;AACrB,4FAAkE;AAGlE,WAAW;AACX,gBAAgB;AAChB,uEAA6C;AAC7C,wEAA8C;AAE9C,yEAA+C;AAC/C,6FAAmE;AACnE,0EAAgD;AAChD,gFAAsD;AAEtD,sFAA4D;AAC5D,oFAA0D;AAE1D,gBAAgB;AAChB,4EAAkD;AAClD,gFAAsD;AACtD,wEAA8C;AAC9C,sEAA4C;AAC5C,kFAAwD;AACxD,6EAAmD;AAEnD,kBAAkB;AAClB,wEAA8C;AAE9C,iBAAiB;AACjB,+EAAqD;AACrD,mFAAyD;AAEzD,kBAAkB;AAClB,4EAAkD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@futdevpro/nts-dynamo",
3
- "version": "01.15.119",
3
+ "version": "01.15.121",
4
4
  "description": "Dynamic NodeTS (NodeJS-Typescript), MongoDB Backend System Framework by Future Development Program Ltd.",
5
5
  "DyBu_settings": {
6
6
  "packageType": "server-package",
@@ -378,7 +378,7 @@
378
378
  "@anthropic-ai/sdk": "~0.39.0",
379
379
  "@modelcontextprotocol/sdk": "~1.29.0",
380
380
  "better-sqlite3": "~12.4.1",
381
- "@futdevpro/fsm-dynamo": "1.16.26",
381
+ "@futdevpro/fsm-dynamo": "1.16.27",
382
382
  "@types/express": "4.17.21",
383
383
  "@types/geoip-lite": "~1.4.1",
384
384
  "@types/node": "~24.1.0",
@@ -261,6 +261,18 @@ export class DyNTS_Endpoint_Params<
261
261
  return;
262
262
  }
263
263
 
264
+ // BFR-OVERSEER-010: a logResponseContent IMPLEMENTÁLVA (a korábbi "not implemented yet"
265
+ // warn-stub minden requestre spam-elt). A res.send-et wrap-eljük a küldött body
266
+ // elkapásához; a task-ok után csonkolt preview-t logolunk (log-flood ellen).
267
+ let capturedResponseBody: unknown;
268
+ if (this.logRequest && this.logResponseContent) {
269
+ const originalSend: Response['send'] = res.send.bind(res);
270
+ res.send = (body?: unknown): Response => {
271
+ capturedResponseBody = body;
272
+ return originalSend(body);
273
+ };
274
+ }
275
+
264
276
  await DyFM_Array.asyncForEach(this.tasks,
265
277
  async (
266
278
  task: (req: Request, res: Response, issuer?: string) => Promise<void>
@@ -268,13 +280,11 @@ export class DyNTS_Endpoint_Params<
268
280
  await task(req, res, issuer);
269
281
  }
270
282
  );
271
-
283
+
272
284
  if (this.logRequest) {
285
+ DyFM_Log.success(` <<<===== '${this.name}' result sent.`);
273
286
  if (this.logResponseContent) {
274
- DyFM_Log.success(` <<<===== '${this.name}' result sent.`);
275
- DyFM_Log.warn('sorry, the logResponseContent is not implemented yet.');
276
- } else {
277
- DyFM_Log.success(` <<<===== '${this.name}' result sent.`);
287
+ DyFM_Log.info(` response: ${DyNTS_Endpoint_Params.previewBody(capturedResponseBody)}`);
278
288
  }
279
289
  }
280
290
  } catch (error) {
@@ -283,6 +293,28 @@ export class DyNTS_Endpoint_Params<
283
293
  };
284
294
  }
285
295
 
296
+ /**
297
+ * BFR-OVERSEER-010: csonkolt, safe response-preview a logResponseContent-hez —
298
+ * nem-parseolható/circular body-ra nem dob, hosszú body-t levág (log-flood ellen).
299
+ */
300
+ private static previewBody(body: unknown): string {
301
+ const maxLength: number = 2000;
302
+ let text: string;
303
+ if (body === undefined) {
304
+ return '-no body captured-';
305
+ }
306
+ if (typeof body === 'string') {
307
+ text = body;
308
+ } else {
309
+ try {
310
+ text = JSON.stringify(body);
311
+ } catch {
312
+ text = String(body);
313
+ }
314
+ }
315
+ return text.length > maxLength ? `${text.slice(0, maxLength)}…(truncated ${text.length} chars)` : text;
316
+ }
317
+
286
318
  /**
287
319
  *
288
320
  * @param res
@@ -492,20 +524,16 @@ export class DyNTS_Endpoint_Params<
492
524
  // test/dev környezetben TELJES DyFM-leaket hagyott (__localStack + ___systemVersion + issuer).
493
525
  // A szabályok (mindig-strip / prod-only additionalContent / kliens-mezők megtartása) SSOT-ja
494
526
  // a DyNTS_ClientSafeError_Util.
495
- res.send(DyNTS_ClientSafeError_Util.toClientSafe(error));
527
+ // BFR-OVERSEER-010: a kiküldött client-safe error megőrzése a logResponseContent-hez.
528
+ const clientSafeError: unknown = DyNTS_ClientSafeError_Util.toClientSafe(error);
529
+ res.send(clientSafeError);
496
530
 
497
531
  if (this.logRequest) {
532
+ DyFM_Log.error(
533
+ ` <<<===== '${this.name}' error sent: ${(error as DyFM_Error)?._message ?? ''}`
534
+ );
498
535
  if (this.logResponseContent) {
499
- DyFM_Log.error(
500
- ` <<<===== '${this.name}' error sent: ${(error as DyFM_Error)?._message ?? ''}`
501
- );
502
- DyFM_Log.error(
503
- 'sorry, the logResponseContent is not implemented yet.'
504
- );
505
- } else {
506
- DyFM_Log.error(
507
- ` <<<===== '${this.name}' error sent: ${(error as DyFM_Error)?._message ?? ''}`
508
- );
536
+ DyFM_Log.error(` error response: ${DyNTS_Endpoint_Params.previewBody(clientSafeError)}`);
509
537
  }
510
538
  }
511
539
 
@@ -75,6 +75,22 @@ describe('| DyNTS_LVS_PersistentVectorPool_ControlService', () => {
75
75
  (collectionKey: string) =>
76
76
  Promise.resolve(Array.from(store.get(collectionKey)?.values() ?? [])),
77
77
  );
78
+
79
+ // BFR-AM-013 (hydration-paging): a batch-elt lean-scan fake-je — a fake-store tartalmát
80
+ // batch-enként adagolja a handler-nek (a valós cursor-viselkedés memóriában modellezve).
81
+ spyOn(DyNTS_LVS_VectorPersist_DataService.prototype, 'findLeanBatchedByCollectionKey').and.callFake(
82
+ async (
83
+ collectionKey: string,
84
+ set: { batchSize?: number; handler: (batch: Partial<DyNTS_LVS_VectorPersist>[]) => Promise<void> | void },
85
+ ): Promise<number> => {
86
+ const all: DyNTS_LVS_VectorPersist[] = Array.from(store.get(collectionKey)?.values() ?? []);
87
+ const batchSize: number = set.batchSize && set.batchSize > 0 ? set.batchSize : 500;
88
+ for (let i: number = 0; i < all.length; i += batchSize) {
89
+ await set.handler(all.slice(i, i + batchSize));
90
+ }
91
+ return all.length;
92
+ },
93
+ );
78
94
  });
79
95
 
80
96
  /** Egy egységvektor a tengely-irányba (cosine-self = 1) — determinisztikus keresés-ellenőrzéshez. */
@@ -1,5 +1,5 @@
1
1
 
2
- import { DyFM_Log } from '@futdevpro/fsm-dynamo';
2
+ import { DyFM_Error, DyFM_Log } from '@futdevpro/fsm-dynamo';
3
3
 
4
4
  import { LVS_Search_Mode } from '../_enums/lvs-search-mode.enum';
5
5
  import { LVS_SearchResult } from '../_models/lvs-search-result.interface';
@@ -97,24 +97,60 @@ export class DyNTS_LVS_PersistentVectorPool_ControlService {
97
97
  * előbb üríti (idempotens hidratálás). A hiányos (üres `vectorId`/`embedding`) rekordokat átugorja.
98
98
  * Visszaadja a betöltött vektorok számát. **NEM** Atlas — saját Mongo + in-memory pool.
99
99
  */
100
- async hydrateFromMongo(): Promise<number> {
101
- const records: DyNTS_LVS_VectorPersist[] =
102
- await this.getPersistService().findByCollectionKey(this.collectionKey);
103
-
100
+ async hydrateFromMongo(set?: {
101
+ /** Cursor-batch méret (default 500) — a heap-tranziens felső korlátja egy batch. */
102
+ batchSize?: number,
103
+ /** Opcionális felső korlát a pool-méretre; elérésekor a hidratálás áll + WARN (no-silent-cap). */
104
+ maxVectors?: number,
105
+ }): Promise<number> {
106
+ // BFR-AM-013 (hydration-paging): a korábbi impl a TELJES collection-t egyetlen
107
+ // `findByCollectionKey`-jel (Mongoose-doc-tömb) töltötte memóriába → 32k×2560-dim vektornál
108
+ // RUNTIME-IGAZOLT 93% heap-spike (OOM-közeli). Mostantól LEAN + projektált (vectorId+embedding,
109
+ // a content-szöveg NÉLKÜL) CURSOR-batch — a tranziens felső korlátja EGY batch.
104
110
  this.pool.clearPool();
105
111
 
106
112
  let loaded: number = 0;
107
-
108
- for (const record of records) {
109
- if (!record.vectorId || !record.embedding?.length) {
110
- continue;
111
- }
112
- this.pool.addVector(record.vectorId, record.embedding);
113
- loaded++;
114
- }
113
+ let skipped: number = 0;
114
+ let truncated: boolean = false;
115
+
116
+ await this.getPersistService().findLeanBatchedByCollectionKey(this.collectionKey, {
117
+ batchSize: set?.batchSize,
118
+ handler: (batch: Partial<DyNTS_LVS_VectorPersist>[]): void => {
119
+ for (const record of batch) {
120
+ if (truncated) {
121
+ return;
122
+ }
123
+ if (set?.maxVectors !== undefined && loaded >= set.maxVectors) {
124
+ truncated = true;
125
+ DyFM_Log.warn(
126
+ `[DyNTS LVS hydrate] '${this.collectionKey}': maxVectors (${set.maxVectors}) elérve — ` +
127
+ 'a hidratálás CSONKOLVA (no-silent-cap; a maradék vektor NEM került a poolba).',
128
+ );
129
+ return;
130
+ }
131
+ if (!record.vectorId || !record.embedding?.length) {
132
+ continue;
133
+ }
134
+ try {
135
+ this.pool.addVector(record.vectorId, record.embedding);
136
+ loaded++;
137
+ } catch (error) {
138
+ // BFR-AM-013 (NaN/±Inf-guard a hidratálásban): EGY hibás (nem-véges elemű) perzistált
139
+ // vektor NEM boríthatja a teljes boot-hidratálást — skip + warn (nem néma).
140
+ skipped++;
141
+ DyFM_Log.warn(
142
+ `[DyNTS LVS hydrate] '${this.collectionKey}': vektor kihagyva ("${record.vectorId}") — ` +
143
+ `${DyFM_Error.getErrorMessage(error)}`,
144
+ );
145
+ }
146
+ }
147
+ },
148
+ });
115
149
 
116
150
  DyFM_Log.log(
117
- `[DyNTS LVS hydrate] '${this.collectionKey}' pool: ${loaded} vektor betöltve az in-memory pool-ba.`,
151
+ `[DyNTS LVS hydrate] '${this.collectionKey}' pool: ${loaded} vektor betöltve az in-memory pool-ba` +
152
+ (skipped ? ` (${skipped} hibás vektor kihagyva)` : '') +
153
+ (truncated ? ' (CSONKOLT — maxVectors)' : '') + '.',
118
154
  );
119
155
 
120
156
  return loaded;
@@ -48,6 +48,28 @@ export class DyNTS_LVS_VectorPersist_DataService extends DyNTS_DataService<DyNTS
48
48
  );
49
49
  }
50
50
 
51
+ /**
52
+ * BFR-AM-013 (hydration-paging): LEAN + projektált (CSAK `vectorId` + `embedding` — a content-szöveg
53
+ * és metadata NÉLKÜL) cursor-batch scan a boot-hidratáláshoz. A heap-tranziens felső korlátja EGY batch
54
+ * (a teljes result-set + Mongoose-doc-boxing kimarad). Soft-delete-elt rekordok kihagyva.
55
+ */
56
+ async findLeanBatchedByCollectionKey(
57
+ collectionKey: string,
58
+ set: {
59
+ batchSize?: number,
60
+ handler: (batch: Partial<DyNTS_LVS_VectorPersist>[]) => Promise<void> | void,
61
+ }
62
+ ): Promise<number> {
63
+ return this.dataDBService.findLeanBatched(
64
+ { collectionKey: collectionKey, _deleted: undefined },
65
+ {
66
+ projection: { vectorId: 1, embedding: 1 },
67
+ batchSize: set.batchSize,
68
+ handler: set.handler,
69
+ }
70
+ );
71
+ }
72
+
51
73
  /**
52
74
  * Egy vektor ATOMIKUS upsert-je a `(collectionKey, vectorId)` logikai-kulcson. MEGLÉVŐ rekordnál
53
75
  * `$set` (a Mixed `metadata` silent-drop ellen — memory: mongoose_mixed_atomic_write); ÚJ rekordnál
@@ -374,9 +374,11 @@ describe('| LVS_VectorPool_ControlService', () => {
374
374
  expect(vec1Result!.score).toBeCloseTo(1, 10);
375
375
  });
376
376
 
377
- it('| should produce cosine scores IDENTICAL to static cosineSimilarity (precomputed-normalized perf optimization, BFR-AM-013)', () => {
377
+ it('| should produce cosine scores EQUIVALENT to static cosineSimilarity (precomputed-normalized + Float32 storage, BFR-AM-013)', () => {
378
378
  // Regression-guard: a search optimalizalt (precomputed-normalized + alloc-mentes) cosine-ja
379
- // viselkedes-identikus a regi per-osszehasonlitas `cosineSimilarity(query, vector)`-ral.
379
+ // viselkedes-EKVIVALENS a regi per-osszehasonlitas `cosineSimilarity(query, vector)`-ral.
380
+ // Tolerancia 6 tizedes (nem 10): a pool BELSŐ tárolása Float32Array (BFR-AM-013 Tier-1,
381
+ // ~2-4× memória) → ~1e-7 kerekítési eltérés — a similarity-RANGSORT nem érinti.
380
382
  const query: number[] = [0.3, 0.7, 0.2];
381
383
  const results: LVS_SearchResult[] = vectorPool.search(query, 4, LVS_Search_Mode.cosineSimilarity);
382
384
 
@@ -386,7 +388,7 @@ describe('| LVS_VectorPool_ControlService', () => {
386
388
  const original: number[] | undefined = originals.get(result.id);
387
389
  expect(original).toBeDefined();
388
390
  const expected: number = LVS_VectorPool_ControlService.cosineSimilarity(query, original!);
389
- expect(result.score).toBeCloseTo(expected, 10);
391
+ expect(result.score).toBeCloseTo(expected, 6);
390
392
  }
391
393
  });
392
394
 
@@ -1,3 +1,5 @@
1
+ import { DyFM_Log } from '@futdevpro/fsm-dynamo';
2
+
1
3
  import { LVS_Search_Mode } from '../_enums/lvs-search-mode.enum';
2
4
  import { LVS_SearchResult } from '../_models/lvs-search-result.interface';
3
5
 
@@ -10,14 +12,19 @@ export class LVS_VectorPool_ControlService {
10
12
  /**
11
13
  * In-memory vektor pool tárolás
12
14
  * Key: vektor ID, Value: vektor értékek
15
+ *
16
+ * BFR-AM-013 (Tier-1 memória): a belső tárolás `Float32Array` (4 byte/elem, boxing nélkül) a
17
+ * korábbi `number[]` (8 byte + array-boxing) helyett → ~2–4× kisebb PERSISTENS pool-footprint
18
+ * (2560-dim × 32k vektornál a heap érdemi része). A cosine/l2 index-alapú loopjai változatlanul
19
+ * futnak rajta; a publikus `getAll()` kontraktja (number[]) konverzióval megőrzött.
13
20
  */
14
- private vectorPool: Map<string, number[]> = new Map<string, number[]>();
21
+ private vectorPool: Map<string, Float32Array> = new Map<string, Float32Array>();
15
22
 
16
23
  /**
17
24
  * Normalizált vektor pool tárolás (L2 normalizált másolatok)
18
- * Key: vektor ID, Value: L2 normalizált vektor értékek
25
+ * Key: vektor ID, Value: L2 normalizált vektor értékek (Float32Array — l. fent)
19
26
  */
20
- private normalizedVectorPool: Map<string, number[]> = new Map<string, number[]>();
27
+ private normalizedVectorPool: Map<string, Float32Array> = new Map<string, Float32Array>();
21
28
 
22
29
  /**
23
30
  * `normalizedOnly` mód: ha `true`, a pool NEM tárolja a nyers vektorokat (`vectorPool`) — CSAK a
@@ -52,13 +59,13 @@ export class LVS_VectorPool_ControlService {
52
59
  }
53
60
 
54
61
  // Tároljuk az eredeti vektort — KIVÉVE normalizedOnly módban (akkor a nyers pool kihagyva, ~50% memória).
62
+ // Float32Array-ként (BFR-AM-013 Tier-1) — a number[]-boxing nélkül.
55
63
  if (!this.normalizedOnly) {
56
- this.vectorPool.set(id, vector);
64
+ this.vectorPool.set(id, Float32Array.from(vector));
57
65
  }
58
66
 
59
67
  // L2 normalizált másolatot is tárolunk a cosine similarity számításokhoz
60
- const normalized: number[] = LVS_VectorPool_ControlService.l2Normalize(vector);
61
- this.normalizedVectorPool.set(id, normalized);
68
+ this.normalizedVectorPool.set(id, LVS_VectorPool_ControlService.l2NormalizeFloat32(vector));
62
69
  }
63
70
 
64
71
  /**
@@ -102,7 +109,33 @@ export class LVS_VectorPool_ControlService {
102
109
  * Debugging és export céljára
103
110
  */
104
111
  getAll(): Map<string, number[]> {
105
- return new Map<string, number[]>(this.vectorPool);
112
+ // A publikus kontrakt (number[]) megőrzése — a belső Float32Array-ből konvertálva.
113
+ const result: Map<string, number[]> = new Map<string, number[]>();
114
+ for (const [ id, vector ] of this.vectorPool.entries()) {
115
+ result.set(id, Array.from(vector));
116
+ }
117
+ return result;
118
+ }
119
+
120
+ /**
121
+ * BFR-AM-013 (Tier-1): L2-normalizálás Float32Array-be, explicit loopokkal (allokáció-minimális) —
122
+ * a pool BELSŐ tárolási formátumához. Nullvektor → csupa-0 Float32Array.
123
+ */
124
+ private static l2NormalizeFloat32(vector: ArrayLike<number>): Float32Array {
125
+ let sumSquares: number = 0;
126
+ for (let i: number = 0; i < vector.length; i++) {
127
+ sumSquares += vector[i] * vector[i];
128
+ }
129
+ const magnitude: number = Math.sqrt(sumSquares);
130
+
131
+ const normalized: Float32Array = new Float32Array(vector.length);
132
+ if (magnitude === 0) {
133
+ return normalized;
134
+ }
135
+ for (let i: number = 0; i < vector.length; i++) {
136
+ normalized[i] = vector[i] / magnitude;
137
+ }
138
+ return normalized;
106
139
  }
107
140
 
108
141
  /**
@@ -156,7 +189,7 @@ export class LVS_VectorPool_ControlService {
156
189
  * Eredmény: 0 vagy pozitív érték, ahol 0 a legkisebb távolság
157
190
  * Statikus metódus, mivel nincs szüksége instance state-re
158
191
  */
159
- static l2Distance(a: number[], b: number[]): number {
192
+ static l2Distance(a: ArrayLike<number>, b: ArrayLike<number>): number {
160
193
  if (a.length !== b.length) {
161
194
  throw new Error(
162
195
  `Vectors must have the same dimension. Got ${a.length} and ${b.length}`
@@ -200,6 +233,14 @@ export class LVS_VectorPool_ControlService {
200
233
  throw new Error('Query vector must be a non-empty array');
201
234
  }
202
235
 
236
+ // BFR-AM-013 (NaN/±Inf-guard): nem-véges query-elem NÉMÁN mérgezné a TELJES rangsort
237
+ // (minden dot-product NaN → a valódi találatok kiesnek, hiba nélkül) → fail-closed throw.
238
+ for (let i: number = 0; i < query.length; i++) {
239
+ if (!Number.isFinite(query[i])) {
240
+ throw new Error(`Query vector must contain only finite numbers (non-finite at index ${i})`);
241
+ }
242
+ }
243
+
203
244
  if (k <= 0) {
204
245
  throw new Error('k must be a positive number');
205
246
  }
@@ -217,9 +258,9 @@ export class LVS_VectorPool_ControlService {
217
258
 
218
259
  // Validáljuk, hogy minden vektor ugyanolyan dimenziójú-e. A referencia-pool mód-függő: l2 a nyers,
219
260
  // cosine a normalizált (azonos dimenzió, de `normalizedOnly`-ban a nyers pool üres).
220
- const referencePool: Map<string, number[]> =
261
+ const referencePool: Map<string, Float32Array> =
221
262
  mode === LVS_Search_Mode.l2Distance ? this.vectorPool : this.normalizedVectorPool;
222
- const firstVector: number[] | undefined = Array.from(referencePool.values())[0];
263
+ const firstVector: Float32Array | undefined = referencePool.values().next().value;
223
264
  if (firstVector && firstVector.length !== query.length) {
224
265
  throw new Error(
225
266
  `Query vector dimension (${query.length}) does not match pool vector ` +
@@ -239,7 +280,10 @@ export class LVS_VectorPool_ControlService {
239
280
  // (2) a per-összehasonlítás dot-product ALLOKÁCIÓ-MENTES (a régi `l2Normalize` hívásonként KÉT új
240
281
  // tömböt allokált → egy 24k-vektoros keresés ~48k tömb-allokáció + GC-spike-ot okozott).
241
282
  // A drágán eltárolt `normalizedVectorPool` korábban SOHA nem volt használva a keresésben.
242
- const queryNormalized: number[] = LVS_VectorPool_ControlService.l2Normalize(query);
283
+ const queryNormalized: Float32Array = LVS_VectorPool_ControlService.l2NormalizeFloat32(query);
284
+ // BFR-AM-013 (NaN-guard, defensive): ha egy tárolt vektor mégis NaN-score-t adna (elvileg az
285
+ // addVector-guard kizárja), a találat KIESIK — nem mérgezi a rangsort — és warn-t adunk (nem néma).
286
+ let nanScoreCount: number = 0;
243
287
  for (const [id, normalizedVector] of this.normalizedVectorPool.entries()) {
244
288
  if (candidateIds && !candidateIds.has(id)) {
245
289
  continue;
@@ -248,8 +292,15 @@ export class LVS_VectorPool_ControlService {
248
292
  for (let i: number = 0; i < queryNormalized.length; i++) {
249
293
  dotProduct += queryNormalized[i] * normalizedVector[i];
250
294
  }
295
+ if (!Number.isFinite(dotProduct)) {
296
+ nanScoreCount++;
297
+ continue;
298
+ }
251
299
  results.push({ id, score: dotProduct });
252
300
  }
301
+ if (nanScoreCount) {
302
+ DyFM_Log.warn(`[LVS search] ${nanScoreCount} vector(s) produced non-finite scores and were skipped.`);
303
+ }
253
304
  // Cosine similarity: csökkenő sorrend (legnagyobb hasonlóság először)
254
305
  results.sort((a: LVS_SearchResult, b: LVS_SearchResult) => b.score - a.score);
255
306
  } else if (mode === LVS_Search_Mode.l2Distance) {
@@ -14,6 +14,8 @@ import * as mongoose from 'mongoose';
14
14
 
15
15
  import { version as _serverVersion } from '../../../../package.json';
16
16
  import { DyNTS_SingletonService } from '../../../_services/base/singleton.service';
17
+ import { DyNTS_DbStats, DyNTS_DbStats_Util } from '../../../_services/core/db-stats.service';
18
+ import { DyNTS_Diagnostics, DyNTS_DoctorReport } from '../../../_services/core/diagnostics.service';
17
19
  import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
18
20
  import { DyNTS_Errors_ControlService } from '../errors/errors.control-service';
19
21
  import { DyNTS_ServerStatusSnapshot_ControlService } from './server-status-snapshot.control-service';
@@ -221,6 +223,16 @@ export abstract class DyNTS_ServerStatus_ControlService<
221
223
  * A mongoose default-connection. Külön metódus = teszt-seam (spy-jal felülírható, hogy a
222
224
  * {@link checkDbReadiness} DB nélkül is tesztelhető legyen).
223
225
  */
226
+ /** BFR-OVERSEER-004 — stats-only DB-diagnosztika a `/server/db-stats` endpointnak (metaadat-only). */
227
+ async getDbStats(): Promise<DyNTS_DbStats> {
228
+ return DyNTS_DbStats_Util.collect(this.getMongooseConnection());
229
+ }
230
+
231
+ /** BFR-AM-015 — aggregált doctor-riport a `/server/doctor` endpointnak (sosem dob). */
232
+ async runDoctor(): Promise<DyNTS_DoctorReport> {
233
+ return DyNTS_Diagnostics.runDoctor({ connection: this.getMongooseConnection() });
234
+ }
235
+
224
236
  protected getMongooseConnection(): mongoose.Connection {
225
237
  // FIX (2026-07-22) — a `mongoose.connection` NEM feltetlenul az a handle, amit a data-layer hasznal.
226
238
  //
@@ -252,6 +252,34 @@ export abstract class DyNTS_ServerStatus_Controller<
252
252
  ],
253
253
  }),
254
254
 
255
+ // BFR-OVERSEER-004 — stats-only DB-diagnosztika (per-collection count + méret + index-méret;
256
+ // metaadat-only, SOHA nem dokumentum-tartalom). App-auth-tal gate-elhető (lazyPreProcessesFor).
257
+ new DyNTS_Endpoint_Params({
258
+ name: 'getDbStats',
259
+ type: DyFM_HttpCallType.get,
260
+ endpoint: '/db-stats',
261
+ preProcesses: this.lazyPreProcessesFor('getDbStats'),
262
+ tasks: [
263
+ async (req: Request, res: Response): Promise<void> => {
264
+ res.send(await this.server_CS.getDbStats());
265
+ },
266
+ ],
267
+ }),
268
+
269
+ // BFR-AM-015 — aggregált doctor (mongo-probe + memory + event-loop + db-stats + app-checkek;
270
+ // health: ok|warn|fail + per-check fixHint). App-auth-tal gate-elhető.
271
+ new DyNTS_Endpoint_Params({
272
+ name: 'getDoctor',
273
+ type: DyFM_HttpCallType.get,
274
+ endpoint: '/doctor',
275
+ preProcesses: this.lazyPreProcessesFor('getDoctor'),
276
+ tasks: [
277
+ async (req: Request, res: Response): Promise<void> => {
278
+ res.send(await this.server_CS.runDoctor());
279
+ },
280
+ ],
281
+ }),
282
+
255
283
  // Readiness-probe: a /health-tel (liveness) szemben a DB-elérhetőséget is ellenőrzi.
256
284
  // Public (mint a /health) — orchestrátor/LB hívja; 503 ha a DB nem ready → no traffic.
257
285
  new DyNTS_Endpoint_Params({