@futdevpro/nts-dynamo 1.15.58 → 1.15.64

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 (108) hide show
  1. package/.dynamo/logs/cicd-pipeline/output.log +1746 -1819
  2. package/.dynamo/logs/cicd-pipeline/status.json +37 -37
  3. package/.github/workflows/main.yml +432 -426
  4. package/build/_collections/global-settings.const.d.ts.map +1 -1
  5. package/build/_collections/global-settings.const.js +6 -0
  6. package/build/_collections/global-settings.const.js.map +1 -1
  7. package/build/_collections/mongo-reconnect-guard.util.d.ts +74 -0
  8. package/build/_collections/mongo-reconnect-guard.util.d.ts.map +1 -0
  9. package/build/_collections/mongo-reconnect-guard.util.js +111 -0
  10. package/build/_collections/mongo-reconnect-guard.util.js.map +1 -0
  11. package/build/_models/interfaces/global-settings.interface.d.ts +21 -0
  12. package/build/_models/interfaces/global-settings.interface.d.ts.map +1 -1
  13. package/build/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.d.ts.map +1 -1
  14. package/build/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.js +2 -2
  15. package/build/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.js.map +1 -1
  16. package/build/_modules/ai/_services/ai-embedding-mock.service.d.ts +1 -1
  17. package/build/_modules/ai/_services/ai-embedding-mock.service.d.ts.map +1 -1
  18. package/build/_modules/ai/_services/ai-embedding-mock.service.js.map +1 -1
  19. package/build/_modules/ai/_services/ai-embedding-provider.registry.d.ts.map +1 -1
  20. package/build/_modules/ai/_services/ai-embedding-provider.registry.js.map +1 -1
  21. package/build/_modules/ai/_services/lmstudio-embedding.control-service.d.ts +1 -1
  22. package/build/_modules/ai/_services/lmstudio-embedding.control-service.d.ts.map +1 -1
  23. package/build/_modules/ai/_services/lmstudio-embedding.control-service.js +3 -3
  24. package/build/_modules/ai/_services/lmstudio-embedding.control-service.js.map +1 -1
  25. package/build/_modules/ai/index.d.ts +2 -0
  26. package/build/_modules/ai/index.d.ts.map +1 -1
  27. package/build/_modules/ai/index.js +4 -0
  28. package/build/_modules/ai/index.js.map +1 -1
  29. package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.d.ts +17 -17
  30. package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.d.ts.map +1 -1
  31. package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.js +21 -21
  32. package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.js.map +1 -1
  33. package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.d.ts +4 -4
  34. package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.d.ts.map +1 -1
  35. package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.js +5 -5
  36. package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.js.map +1 -1
  37. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.d.ts +4 -4
  38. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.d.ts.map +1 -1
  39. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.js +4 -4
  40. package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.js.map +1 -1
  41. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.d.ts +6 -6
  42. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.d.ts.map +1 -1
  43. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.js +5 -5
  44. package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.js.map +1 -1
  45. package/build/_modules/mcp/_models/interfaces/dynts-mcp.interface.d.ts +1 -1
  46. package/build/_modules/mcp/_models/interfaces/dynts-mcp.interface.js +1 -1
  47. package/build/_modules/mcp/_services/dynts-mcp-server.service-base.d.ts +4 -4
  48. package/build/_modules/mcp/_services/dynts-mcp-server.service-base.d.ts.map +1 -1
  49. package/build/_modules/mcp/_services/dynts-mcp-server.service-base.js +6 -6
  50. package/build/_modules/mcp/_services/dynts-mcp-server.service-base.js.map +1 -1
  51. package/build/_modules/mcp/_services/dynts-mcp.adapter.d.ts +11 -11
  52. package/build/_modules/mcp/_services/dynts-mcp.adapter.d.ts.map +1 -1
  53. package/build/_modules/mcp/_services/dynts-mcp.adapter.js +16 -11
  54. package/build/_modules/mcp/_services/dynts-mcp.adapter.js.map +1 -1
  55. package/build/_modules/mcp/index.js +1 -1
  56. package/build/_modules/mcp/index.js.map +1 -1
  57. package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.d.ts +3 -3
  58. package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.d.ts.map +1 -1
  59. package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.js +4 -4
  60. package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.js.map +1 -1
  61. package/build/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.d.ts.map +1 -1
  62. package/build/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.js +9 -0
  63. package/build/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.js.map +1 -1
  64. package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.d.ts +3 -3
  65. package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.d.ts.map +1 -1
  66. package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.js +1 -1
  67. package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.js.map +1 -1
  68. package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.d.ts +7 -7
  69. package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.d.ts.map +1 -1
  70. package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.js +2 -2
  71. package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.js.map +1 -1
  72. package/build/_services/core/global.service.d.ts.map +1 -1
  73. package/build/_services/core/global.service.js +15 -2
  74. package/build/_services/core/global.service.js.map +1 -1
  75. package/build/_services/server/app.server.d.ts.map +1 -1
  76. package/build/_services/server/app.server.js +21 -0
  77. package/build/_services/server/app.server.js.map +1 -1
  78. package/package.json +1 -1
  79. package/src/_collections/global-settings.const.ts +7 -0
  80. package/src/_collections/mongo-reconnect-guard.util.spec.ts +52 -0
  81. package/src/_collections/mongo-reconnect-guard.util.ts +172 -0
  82. package/src/_models/interfaces/global-settings.interface.ts +22 -0
  83. package/src/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.ts +39 -7
  84. package/src/_modules/ai/_services/ai-embedding-mock.service.ts +18 -4
  85. package/src/_modules/ai/_services/ai-embedding-provider.registry.ts +4 -0
  86. package/src/_modules/ai/_services/lmstudio-embedding.control-service.ts +26 -5
  87. package/src/_modules/ai/index.ts +5 -0
  88. package/src/_modules/data-readers/_collections/dynts-sqlite-reader.util.spec.ts +145 -130
  89. package/src/_modules/data-readers/_collections/dynts-sqlite-reader.util.ts +131 -120
  90. package/src/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.ts +6 -5
  91. package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.spec.ts +35 -35
  92. package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.ts +9 -5
  93. package/src/_modules/local-vector-search/_services/lvs-vector-persist.data-service.spec.ts +11 -11
  94. package/src/_modules/local-vector-search/_services/lvs-vector-persist.data-service.ts +19 -17
  95. package/src/_modules/mcp/_models/interfaces/dynts-mcp.interface.ts +1 -1
  96. package/src/_modules/mcp/_services/dynts-mcp-server.service-base.spec.ts +123 -114
  97. package/src/_modules/mcp/_services/dynts-mcp-server.service-base.ts +44 -39
  98. package/src/_modules/mcp/_services/dynts-mcp.adapter.ts +114 -103
  99. package/src/_modules/mcp/index.ts +1 -1
  100. package/src/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.ts +5 -4
  101. package/src/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.ts +0 -2
  102. package/src/_modules/scoped-config/_services/dynts-scoped-config.control-service.spec.ts +19 -13
  103. package/src/_modules/scoped-config/_services/dynts-scoped-config.control-service.ts +37 -21
  104. package/src/_modules/scoped-config/_services/dynts-scoped-config.data-service.spec.ts +11 -6
  105. package/src/_modules/scoped-config/_services/dynts-scoped-config.data-service.ts +17 -14
  106. package/src/_services/core/global.service.spec.ts +17 -0
  107. package/src/_services/core/global.service.ts +19 -5
  108. package/src/_services/server/app.server.ts +22 -1
@@ -1,20 +1,25 @@
1
+ // A `@modelcontextprotocol/sdk` ESM-only csomag; a deep subpath-importjai (server/index, server/stdio,
2
+ // types) KÖTELEZŐEN `.js`-suffixet igényelnek (az SDK `exports`-map így oldja fel) — ezért a `no-js-import`
3
+ // szabály ITT indokoltan kikapcsolva (C2, FAM-REV bedrock-fix). Suffix-strip → resolve-hiba.
4
+ /* eslint-disable @futdevpro/dynamo/no-js-import */
1
5
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
6
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
7
  import { CallToolRequestSchema, CallToolResult, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
8
+ /* eslint-enable @futdevpro/dynamo/no-js-import */
4
9
 
5
10
  import { DyFM_Error } from '@futdevpro/fsm-dynamo';
6
11
 
7
12
  import {
8
- DyNTS_Mcp_CallResult,
9
- DyNTS_Mcp_ServerInfo,
10
- DyNTS_Mcp_ToolDefinition,
11
- DyNTS_Mcp_ToolOutcome,
13
+ DyNTS_Mcp_CallResult,
14
+ DyNTS_Mcp_ServerInfo,
15
+ DyNTS_Mcp_ToolDefinition,
16
+ DyNTS_Mcp_ToolOutcome
12
17
  } from '../_models/interfaces/dynts-mcp.interface';
13
18
 
14
19
  /**
15
20
  * `DyNTS_Mcp_Adapter` (BFR-AM-003) — a hivatalos `@modelcontextprotocol/sdk` köré épített **vékony
16
21
  * adaptor-réteg**. EZ az EGYETLEN hely a `/mcp` submodule-ban, ahol a SDK-típusok megjelennek — a
17
- * `DyNTS_Mcp_ServerBase` + a consumer tool-jai SDK-mentesek, így egy jövőbeli transport-/SDK-csere
22
+ * `DyNTS_Mcp_Server_ServiceBase` + a consumer tool-jai SDK-mentesek, így egy jövőbeli transport-/SDK-csere
18
23
  * NON-breaking (csak ez az osztály cserélődik).
19
24
  *
20
25
  * Felelősség (3 dolog, semmi domain-logika):
@@ -28,130 +33,136 @@ import {
28
33
  */
29
34
  export class DyNTS_Mcp_Adapter {
30
35
 
31
- /** A SDK MCP-szerver (a transport-agnosztikus protocol-réteg). */
32
- private readonly server: Server;
36
+ /** A SDK MCP-szerver (a transport-agnosztikus protocol-réteg). */
37
+ private readonly server: Server;
33
38
 
34
- /** A regisztrált tool-definíciók `name` → def map-je (a `tools/call` dispatch-hez). */
35
- private readonly tools: Map<string, DyNTS_Mcp_ToolDefinition> =
36
- new Map<string, DyNTS_Mcp_ToolDefinition>();
39
+ /** A regisztrált tool-definíciók `name` → def map-je (a `tools/call` dispatch-hez). */
40
+ private readonly tools: Map<string, DyNTS_Mcp_ToolDefinition> =
41
+ new Map<string, DyNTS_Mcp_ToolDefinition>();
37
42
 
38
- constructor(set: DyNTS_Mcp_ServerInfo) {
39
- this.server = new Server(
40
- { name: set.name, version: set.version },
41
- { capabilities: { tools: {} } },
42
- );
43
- this.installHandlers();
44
- }
43
+ constructor(set: DyNTS_Mcp_ServerInfo) {
44
+ this.server = new Server(
45
+ { name: set.name, version: set.version },
46
+ { capabilities: { tools: {} } },
47
+ );
48
+ this.installHandlers();
49
+ }
45
50
 
46
- /**
51
+ /**
47
52
  * Az EGYETLEN tool-regisztrációs choke-pont. A regisztrált tool-ok hirdetődnek a `tools/list`-ben
48
53
  * és dispatch-elhetők a `tools/call`-on. Az azonos nevű ismételt regisztráció felülír (last-wins).
49
54
  */
50
- public registerTool(definition: DyNTS_Mcp_ToolDefinition): void {
51
- this.tools.set(definition.name, definition);
52
- }
55
+ public registerTool(definition: DyNTS_Mcp_ToolDefinition): void {
56
+ this.tools.set(definition.name, definition);
57
+ }
53
58
 
54
- /** A hirdetett (regisztrált) tool-nevek (a contract/diszjunkció-teszthez). */
55
- public getAdvertisedToolNames(): string[] {
56
- return Array.from(this.tools.keys());
57
- }
59
+ /** A hirdetett (regisztrált) tool-nevek (a contract/diszjunkció-teszthez). */
60
+ public getAdvertisedToolNames(): string[] {
61
+ return Array.from(this.tools.keys());
62
+ }
58
63
 
59
- /**
64
+ /**
60
65
  * A stdio transport csatlakoztatása + a szerver indítása. A `connect` után a `tools/list` a
61
66
  * regisztrált tool-okat hirdeti. A boot-üzenetek a stderr-en (a hívó App felel).
62
67
  */
63
- public async startStdio(): Promise<void> {
64
- const transport: StdioServerTransport = new StdioServerTransport();
65
- await this.server.connect(transport);
66
- }
68
+ public async startStdio(): Promise<void> {
69
+ const transport: StdioServerTransport = new StdioServerTransport();
67
70
 
68
- /** A szerver leállítása (graceful close — teszt-/shutdown-úthoz). */
69
- public async close(): Promise<void> {
70
- await this.server.close();
71
- }
71
+ await this.server.connect(transport);
72
+ }
73
+
74
+ /** A szerver leállítása (graceful close — teszt-/shutdown-úthoz). */
75
+ public async close(): Promise<void> {
76
+ await this.server.close();
77
+ }
72
78
 
73
- /**
79
+ /**
74
80
  * Egy tool-hívás KÖZVETLEN dispatch-elése (a transport-megkerülésével) — a contract/registry-teszt
75
81
  * ezt hívja a stdio-szerver indítása nélkül. Ugyanaz a logika fut, mint a SDK `tools/call`-on:
76
82
  * ismeretlen tool → strukturált hiba; handler-hiba → `isError:true` fordítás.
77
83
  */
78
- public async dispatchToolCall(set: { name: string; arguments?: unknown }): Promise<DyNTS_Mcp_CallResult> {
79
- const definition: DyNTS_Mcp_ToolDefinition | undefined = this.tools.get(set.name);
80
- if (!definition) {
81
- return this.errorResult(`Unknown tool: '${set.name}'. Advertised tools: `
84
+ public async dispatchToolCall(set: { name: string; arguments?: unknown }): Promise<DyNTS_Mcp_CallResult> {
85
+ const definition: DyNTS_Mcp_ToolDefinition | undefined = this.tools.get(set.name);
86
+
87
+ if (!definition) {
88
+ return this.errorResult(`Unknown tool: '${set.name}'. Advertised tools: `
82
89
  + `${this.getAdvertisedToolNames().join(', ')}.`);
83
- }
84
- try {
85
- const outcome: DyNTS_Mcp_ToolOutcome = await definition.handler(set.arguments);
86
- return this.toCallResult(outcome);
87
- } catch (error) {
88
- return this.errorResult(this.describeError(error), error);
89
- }
90
90
  }
91
+ try {
92
+ const outcome: DyNTS_Mcp_ToolOutcome = await definition.handler(set.arguments);
91
93
 
92
- // =========================================================================
93
- // SDK request-handler bekötés (tools/list + tools/call)
94
- // =========================================================================
95
-
96
- /** A `tools/list` és a `tools/call` JSON-RPC handler bekötése a SDK-szerverre. */
97
- private installHandlers(): void {
98
- // tools/list — PONTOSAN a regisztrált (advertised) tool-okat hirdeti.
99
- this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
100
- tools: Array.from(this.tools.values()).map((definition) => ({
101
- name: definition.name,
102
- description: definition.description,
103
- inputSchema: definition.inputSchema,
104
- })),
105
- }));
106
-
107
- // tools/call — a megfelelő handler futtatása + egységes hiba-fordítás (a közös dispatch-en át).
108
- // A `DyNTS_Mcp_CallResult` a SDK `CallToolResult` egy al-shape-je (text-content + isError) — a
109
- // SDK-cast KIZÁRÓLAG itt, az adaptor-boundary-n él (a SDK izolálva marad).
110
- this.server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> =>
94
+ return this.toCallResult(outcome);
95
+ } catch (error) {
96
+ return this.errorResult(this.describeError(error), error);
97
+ }
98
+ }
99
+
100
+ // =========================================================================
101
+ // SDK request-handler bekötés (tools/list + tools/call)
102
+ // =========================================================================
103
+
104
+ /** A `tools/list` és a `tools/call` JSON-RPC handler bekötése a SDK-szerverre. */
105
+ private installHandlers(): void {
106
+ // tools/list — PONTOSAN a regisztrált (advertised) tool-okat hirdeti.
107
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
108
+ tools: Array.from(this.tools.values()).map((definition) => ({
109
+ name: definition.name,
110
+ description: definition.description,
111
+ inputSchema: definition.inputSchema,
112
+ })),
113
+ }));
114
+
115
+ // tools/call — a megfelelő handler futtatása + egységes hiba-fordítás (a közös dispatch-en át).
116
+ // A `DyNTS_Mcp_CallResult` a SDK `CallToolResult` egy al-shape-je (text-content + isError) — a
117
+ // SDK-cast KIZÁRÓLAG itt, az adaptor-boundary-n él (a SDK izolálva marad).
118
+ this.server.setRequestHandler(CallToolRequestSchema, async (request): Promise<CallToolResult> =>
111
119
  (await this.dispatchToolCall({
112
- name: request.params.name,
113
- arguments: request.params.arguments,
120
+ name: request.params.name,
121
+ arguments: request.params.arguments,
114
122
  })) as CallToolResult);
123
+ }
124
+
125
+ // =========================================================================
126
+ // CallToolResult fordítás (a transport-payload — text-JSON; egységes hiba-fordítás)
127
+ // =========================================================================
128
+
129
+ /** Egy sikeres (vagy strukturált-hiba) handler-outcome → `CallToolResult` (text-JSON content). */
130
+ private toCallResult(outcome: DyNTS_Mcp_ToolOutcome): DyNTS_Mcp_CallResult {
131
+ return {
132
+ content: [{ type: 'text', text: this.stringify(outcome.data) }],
133
+ isError: outcome.isError === true,
134
+ };
135
+ }
136
+
137
+ /** Egy hiba → `CallToolResult { isError:true }` strukturált hiba-payload-dal (soha nem néma). */
138
+ private errorResult(message: string, error?: unknown): DyNTS_Mcp_CallResult {
139
+ const errorCode: string | undefined = error instanceof DyFM_Error
140
+ ? DyFM_Error.getErrorCode(error)
141
+ : undefined;
142
+ const payload: object = { ok: false, error: { errorCode: errorCode, message: message } };
143
+
144
+ return { content: [{ type: 'text', text: this.stringify(payload) }], isError: true };
145
+ }
146
+
147
+ /** Egy hiba ember-olvasható üzenete (DyFM_Error → message; Error → message; egyéb → fallback). */
148
+ private describeError(error: unknown): string {
149
+ if (error instanceof DyFM_Error) {
150
+ return DyFM_Error.getErrorMessage(error) || 'Unknown DyFM error.';
115
151
  }
116
152
 
117
- // =========================================================================
118
- // CallToolResult fordítás (a transport-payload — text-JSON; egységes hiba-fordítás)
119
- // =========================================================================
120
-
121
- /** Egy sikeres (vagy strukturált-hiba) handler-outcome → `CallToolResult` (text-JSON content). */
122
- private toCallResult(outcome: DyNTS_Mcp_ToolOutcome): DyNTS_Mcp_CallResult {
123
- return {
124
- content: [{ type: 'text', text: this.stringify(outcome.data) }],
125
- isError: outcome.isError === true,
126
- };
127
- }
128
-
129
- /** Egy hiba → `CallToolResult { isError:true }` strukturált hiba-payload-dal (soha nem néma). */
130
- private errorResult(message: string, error?: unknown): DyNTS_Mcp_CallResult {
131
- const errorCode: string | undefined = error instanceof DyFM_Error
132
- ? DyFM_Error.getErrorCode(error)
133
- : undefined;
134
- const payload: object = { ok: false, error: { errorCode: errorCode, message: message } };
135
- return { content: [{ type: 'text', text: this.stringify(payload) }], isError: true };
153
+ if (error instanceof Error) {
154
+ return error.message;
136
155
  }
137
156
 
138
- /** Egy hiba ember-olvasható üzenete (DyFM_Error → message; Error → message; egyéb → fallback). */
139
- private describeError(error: unknown): string {
140
- if (error instanceof DyFM_Error) {
141
- return DyFM_Error.getErrorMessage(error) || 'Unknown DyFM error.';
142
- }
143
- if (error instanceof Error) {
144
- return error.message;
145
- }
146
- return 'Unknown error during tool execution.';
147
- }
157
+ return 'Unknown error during tool execution.';
158
+ }
148
159
 
149
- /** JSON-stringify (a transport text-content payload-ja); szerializálás-hiba → strukturált hiba. */
150
- private stringify(data: unknown): string {
151
- try {
152
- return JSON.stringify(data);
153
- } catch {
154
- return JSON.stringify({ ok: false, error: { message: 'The response is not JSON-serializable.' } });
155
- }
160
+ /** JSON-stringify (a transport text-content payload-ja); szerializálás-hiba → strukturált hiba. */
161
+ private stringify(data: unknown): string {
162
+ try {
163
+ return JSON.stringify(data);
164
+ } catch {
165
+ return JSON.stringify({ ok: false, error: { message: 'The response is not JSON-serializable.' } });
156
166
  }
167
+ }
157
168
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  // MCP MODULE (BFR-AM-003) — domain-agnosztikus Model Context Protocol szerver-base + transport +
4
4
  // tool-registry, a hivatalos `@modelcontextprotocol/sdk` köré izolált adaptorral. A consumer
5
- // leszármazik a `DyNTS_Mcp_ServerBase`-ből + a SAJÁT tool-jait regisztrálja (a bedrock NEM definiál
5
+ // leszármazik a `DyNTS_Mcp_Server_ServiceBase`-ből + a SAJÁT tool-jait regisztrálja (a bedrock NEM definiál
6
6
  // domain-tool-t). A SDK KIZÁRÓLAG a `DyNTS_Mcp_Adapter` mögött él (transport-csere NON-breaking).
7
7
 
8
8
  // INTERFACES
@@ -17,7 +17,7 @@ import { DyNTS_ScopedConfig_Level } from '../../_enums/dynts-scoped-config-level
17
17
  * dolga. A `value` írása **`$set`-tel atomikus** (Mongoose Mixed silent-drop ellen — lásd
18
18
  * `DyNTS_ScopedConfig_DataService.setValue`).
19
19
  */
20
- export class DyNTS_ScopedConfig_DataModel extends DyFM_Metadata {
20
+ export class DyNTS_ScopedConfig extends DyFM_Metadata {
21
21
 
22
22
  // --- a feloldási kulcs ---
23
23
 
@@ -49,8 +49,9 @@ export class DyNTS_ScopedConfig_DataModel extends DyFM_Metadata {
49
49
  /** Opcionális indoklás. */
50
50
  note?: string;
51
51
 
52
- constructor(set?: Partial<DyNTS_ScopedConfig_DataModel>) {
52
+ constructor(set?: Partial<DyNTS_ScopedConfig>) {
53
53
  super(set);
54
+
54
55
  if (set) {
55
56
  DyFM_Object.cleanAssign(this, set);
56
57
  }
@@ -64,8 +65,8 @@ export class DyNTS_ScopedConfig_DataModel extends DyFM_Metadata {
64
65
  * A `value` `type:'object'` (Mongoose `Mixed`) — a séma NEM validál; a típushelyesség a fogyasztó
65
66
  * katalógusának + set-kori validációjának dolga.
66
67
  */
67
- export const dyNTS_scopedConfig_dataParams: DyFM_DataModel_Params<DyNTS_ScopedConfig_DataModel> =
68
- new DyFM_DataModel_Params<DyNTS_ScopedConfig_DataModel>({
68
+ export const DyNTS_scopedConfig_dataParams: DyFM_DataModel_Params<DyNTS_ScopedConfig> =
69
+ new DyFM_DataModel_Params<DyNTS_ScopedConfig>({
69
70
  dataName: 'dynts_scoped_config',
70
71
  addArchive: true,
71
72
  properties: {
@@ -1,6 +1,4 @@
1
1
 
2
- import { DyNTS_ScopedConfig_Level } from '../../_enums/dynts-scoped-config-level.enum';
3
-
4
2
  /**
5
3
  * Scoped-config shared vokabulár (BFR-AM-004). Egy fájlban a szorosan összetartozó típusok
6
4
  * (a `*.interface.ts` az egy-export-per-file konvenció ismert kivétele — mint a FAM `fam-config.interface.ts`).
@@ -4,9 +4,9 @@ import { DyFM_EnvironmentFlag } from '@futdevpro/fsm-dynamo';
4
4
  import { DyNTS_global_settings } from '../../../_collections/global-settings.const';
5
5
  import { DyNTS_GlobalService } from '../../../_services/core/global.service';
6
6
  import { DyNTS_ScopedConfig_Level } from '../_enums/dynts-scoped-config-level.enum';
7
- import { DyNTS_ScopedConfig_DataModel } from '../_models/data-models/dynts-scoped-config.data-model';
7
+ import { DyNTS_ScopedConfig } from '../_models/data-models/dynts-scoped-config.data-model';
8
8
  import {
9
- DyNTS_ScopedConfigResolvedValue,
9
+ DyNTS_ScopedConfigResolvedValue
10
10
  } from '../_models/interfaces/dynts-scoped-config.interface';
11
11
  import { DyNTS_ScopedConfig_DataService } from './dynts-scoped-config.data-service';
12
12
  import { DyNTS_ScopedConfig_ControlService } from './dynts-scoped-config.control-service';
@@ -27,13 +27,14 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
27
27
  let mockDBService: jasmine.SpyObj<{ find: () => Promise<unknown[]>; findOne: () => Promise<unknown> }>;
28
28
 
29
29
  /** Egy aktív rekord gyors gyártása a kontrollált rekord-halmazhoz. */
30
- const makeRecord = (set: Partial<DyNTS_ScopedConfig_DataModel>): DyNTS_ScopedConfig_DataModel =>
31
- new DyNTS_ScopedConfig_DataModel(set);
30
+ const makeRecord = (set: Partial<DyNTS_ScopedConfig>): DyNTS_ScopedConfig =>
31
+ new DyNTS_ScopedConfig(set);
32
32
 
33
33
  beforeAll(() => {
34
34
  if (!DyNTS_global_settings.systemShortCodeName) {
35
35
  (DyNTS_global_settings as { systemShortCodeName?: string }).systemShortCodeName = 'TEST';
36
36
  }
37
+
37
38
  if (!DyNTS_global_settings.env_settings) {
38
39
  (DyNTS_global_settings as { env_settings?: unknown }).env_settings = {
39
40
  environment: DyFM_EnvironmentFlag.local,
@@ -43,7 +44,7 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
43
44
 
44
45
  beforeEach(() => {
45
46
  // A base-ctor eager getDBService-jét stub-oljuk, hogy a lazy DataService-példányok ne dobjanak.
46
- mockDBService = jasmine.createSpyObj('DyNTS_DBService', ['find', 'findOne']);
47
+ mockDBService = jasmine.createSpyObj('DyNTS_DBService', [ 'find', 'findOne' ]);
47
48
  mockDBService.find.and.returnValue(Promise.resolve([]));
48
49
  mockDBService.findOne.and.returnValue(Promise.resolve(null));
49
50
  spyOn(DyNTS_GlobalService, 'getDBService').and.returnValue(mockDBService as never);
@@ -55,7 +56,7 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
55
56
  });
56
57
 
57
58
  /** A kontrollált aktív rekord-halmaz beállítása (a `loadEffectiveRecords` ezt kapja vissza). */
58
- const stubRecords = (records: DyNTS_ScopedConfig_DataModel[]): void => {
59
+ const stubRecords = (records: DyNTS_ScopedConfig[]): void => {
59
60
  spyOn(DyNTS_ScopedConfig_DataService.prototype, 'findActiveList').and.returnValue(Promise.resolve(records));
60
61
  };
61
62
 
@@ -188,7 +189,8 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
188
189
  describe('| resolve — Mixed value get', () => {
189
190
 
190
191
  it('| should resolve a string[] (Mixed) value intact', async () => {
191
- const patterns: string[] = ['**/node_modules/**', '**/.git/**'];
192
+ const patterns: string[] = [ '**/node_modules/**', '**/.git/**' ];
193
+
192
194
  stubRecords([
193
195
  makeRecord({ level: DyNTS_ScopedConfig_Level.global, key: 'scan.ignorePatterns', value: patterns }),
194
196
  ]);
@@ -202,6 +204,7 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
202
204
 
203
205
  it('| should resolve an object (Mixed) value intact', async () => {
204
206
  const obj = { provider: 'openai', model: 'text-embedding-3-large' };
207
+
205
208
  stubRecords([
206
209
  makeRecord({ level: DyNTS_ScopedConfig_Level.global, key: 'embedding.config', value: obj }),
207
210
  ]);
@@ -239,6 +242,7 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
239
242
  it('| should return empty object when no records configured', async () => {
240
243
  stubRecords([]);
241
244
  const all = await control.resolveAll({ table: 'documents' });
245
+
242
246
  expect(Object.keys(all).length).toBe(0);
243
247
  });
244
248
  });
@@ -246,9 +250,9 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
246
250
  describe('| set', () => {
247
251
 
248
252
  it('| should archive an existing active record then write the new one', async () => {
249
- const existing: DyNTS_ScopedConfig_DataModel =
253
+ const existing: DyNTS_ScopedConfig =
250
254
  makeRecord({ _id: 'old-id', level: DyNTS_ScopedConfig_Level.global, key: 'read.topK', value: 10 });
251
- const savedNew: DyNTS_ScopedConfig_DataModel =
255
+ const savedNew: DyNTS_ScopedConfig =
252
256
  makeRecord({ _id: 'new-id', level: DyNTS_ScopedConfig_Level.global, key: 'read.topK', value: 25 });
253
257
 
254
258
  const findActiveSpy = spyOn(DyNTS_ScopedConfig_DataService.prototype, 'findActive')
@@ -258,14 +262,15 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
258
262
  const saveSpy = spyOn(DyNTS_ScopedConfig_DataService.prototype, 'saveData')
259
263
  .and.returnValue(Promise.resolve(savedNew));
260
264
 
261
- const result: DyNTS_ScopedConfig_DataModel =
265
+ const result: DyNTS_ScopedConfig =
262
266
  await control.set(DyNTS_ScopedConfig_Level.global, 'read.topK', 25, { setBy: 'cli' });
263
267
 
264
268
  expect(findActiveSpy).toHaveBeenCalled();
265
269
  expect(deleteSpy).toHaveBeenCalledWith('old-id');
266
270
  expect(saveSpy).toHaveBeenCalled();
267
271
  // A kiírt rekord a helyes kulcsot + értéket + audit-ot hordozza.
268
- const written: DyNTS_ScopedConfig_DataModel = saveSpy.calls.mostRecent().args[0] as DyNTS_ScopedConfig_DataModel;
272
+ const written: DyNTS_ScopedConfig = saveSpy.calls.mostRecent().args[0];
273
+
269
274
  expect(written.key).toBe('read.topK');
270
275
  expect(written.value).toBe(25);
271
276
  expect(written.setBy).toBe('cli');
@@ -275,10 +280,11 @@ describe('| DyNTS_ScopedConfig_ControlService', () => {
275
280
  it('| should write a new record without deleting when no active record exists', async () => {
276
281
  spyOn(DyNTS_ScopedConfig_DataService.prototype, 'findActive').and.returnValue(Promise.resolve(null));
277
282
  const deleteSpy = spyOn(DyNTS_ScopedConfig_DataService.prototype, 'deleteData').and.returnValue(Promise.resolve());
283
+
278
284
  spyOn(DyNTS_ScopedConfig_DataService.prototype, 'saveData')
279
- .and.callFake((data?: DyNTS_ScopedConfig_DataModel) => Promise.resolve(data as DyNTS_ScopedConfig_DataModel));
285
+ .and.callFake((data?: DyNTS_ScopedConfig) => Promise.resolve(data));
280
286
 
281
- const result: DyNTS_ScopedConfig_DataModel = await control.set(
287
+ const result: DyNTS_ScopedConfig = await control.set(
282
288
  DyNTS_ScopedConfig_Level.table,
283
289
  'read.topK',
284
290
  20,
@@ -2,14 +2,14 @@
2
2
  import { DyFM_DBFilterSimple } from '@futdevpro/fsm-dynamo';
3
3
 
4
4
  import { DyNTS_ScopedConfig_Level } from '../_enums/dynts-scoped-config-level.enum';
5
- import { DyNTS_ScopedConfig_DataModel } from '../_models/data-models/dynts-scoped-config.data-model';
5
+ import { DyNTS_ScopedConfig } from '../_models/data-models/dynts-scoped-config.data-model';
6
6
  import {
7
7
  DyNTS_ScopedConfigResolveContext,
8
8
  DyNTS_ScopedConfigResolvedFrom,
9
9
  DyNTS_ScopedConfigResolvedValue,
10
10
  DyNTS_ScopedConfigResolveOptions,
11
11
  DyNTS_ScopedConfigSetOptions,
12
- DyNTS_ScopedConfigValue,
12
+ DyNTS_ScopedConfigValue
13
13
  } from '../_models/interfaces/dynts-scoped-config.interface';
14
14
  import { DyNTS_ScopedConfig_DataService } from './dynts-scoped-config.data-service';
15
15
 
@@ -18,7 +18,7 @@ import { DyNTS_ScopedConfig_DataService } from './dynts-scoped-config.data-servi
18
18
  */
19
19
  interface DyNTS_ScopedConfigCacheEntry {
20
20
  /** A cache-elt aktív rekordok (egy kontextus-szeletre). */
21
- records: DyNTS_ScopedConfig_DataModel[];
21
+ records: DyNTS_ScopedConfig[];
22
22
  /** Lejárati timestamp (epoch ms). */
23
23
  expiresAt: number;
24
24
  }
@@ -55,6 +55,7 @@ export class DyNTS_ScopedConfig_ControlService {
55
55
  if (!DyNTS_ScopedConfig_ControlService._instance) {
56
56
  DyNTS_ScopedConfig_ControlService._instance = new DyNTS_ScopedConfig_ControlService();
57
57
  }
58
+
58
59
  return DyNTS_ScopedConfig_ControlService._instance;
59
60
  }
60
61
 
@@ -77,7 +78,8 @@ export class DyNTS_ScopedConfig_ControlService {
77
78
  table: options?.table,
78
79
  scopePath: options?.scopePath,
79
80
  };
80
- const records: DyNTS_ScopedConfig_DataModel[] = await this.loadEffectiveRecords(context);
81
+ const records: DyNTS_ScopedConfig[] = await this.loadEffectiveRecords(context);
82
+
81
83
  return this.resolveFromRecords<T>(key, records, context, options?.builtinDefault);
82
84
  }
83
85
 
@@ -88,12 +90,14 @@ export class DyNTS_ScopedConfig_ControlService {
88
90
  * — azokat a fogyasztó iterálja a saját katalógusából a `resolve`-on át).
89
91
  */
90
92
  async resolveAll(context?: DyNTS_ScopedConfigResolveContext): Promise<{ [key: string]: DyNTS_ScopedConfigResolvedValue }> {
91
- const records: DyNTS_ScopedConfig_DataModel[] = await this.loadEffectiveRecords(context);
93
+ const records: DyNTS_ScopedConfig[] = await this.loadEffectiveRecords(context);
92
94
  const result: { [key: string]: DyNTS_ScopedConfigResolvedValue } = {};
93
95
  const keys: Set<string> = new Set<string>(records.map((record) => record.key));
96
+
94
97
  for (const key of keys) {
95
98
  result[key] = this.resolveFromRecords(key, records, context);
96
99
  }
100
+
97
101
  return result;
98
102
  }
99
103
 
@@ -103,7 +107,7 @@ export class DyNTS_ScopedConfig_ControlService {
103
107
  */
104
108
  private resolveFromRecords<T = DyNTS_ScopedConfigValue>(
105
109
  key: string,
106
- records: DyNTS_ScopedConfig_DataModel[],
110
+ records: DyNTS_ScopedConfig[],
107
111
  context?: DyNTS_ScopedConfigResolveContext,
108
112
  builtinDefault?: T,
109
113
  ): DyNTS_ScopedConfigResolvedValue<T> {
@@ -114,12 +118,13 @@ export class DyNTS_ScopedConfig_ControlService {
114
118
  if (table && scopePath.length) {
115
119
  for (let i = scopePath.length - 1; i >= 0; i--) {
116
120
  const scopeId: string = scopePath[i].scopeId;
117
- const hit: DyNTS_ScopedConfig_DataModel | undefined = records.find((record) =>
121
+ const hit: DyNTS_ScopedConfig | undefined = records.find((record) =>
118
122
  record.level === DyNTS_ScopedConfig_Level.scope &&
119
123
  record.tableScope === table &&
120
124
  record.scopeId === scopeId &&
121
125
  record.key === key,
122
126
  );
127
+
123
128
  if (hit) {
124
129
  return this.toResolved<T>(hit, 'scope');
125
130
  }
@@ -128,34 +133,36 @@ export class DyNTS_ScopedConfig_ControlService {
128
133
 
129
134
  // 2. TABLE szint.
130
135
  if (table) {
131
- const hit: DyNTS_ScopedConfig_DataModel | undefined = records.find((record) =>
136
+ const hit: DyNTS_ScopedConfig | undefined = records.find((record) =>
132
137
  record.level === DyNTS_ScopedConfig_Level.table &&
133
138
  record.tableScope === table &&
134
139
  record.key === key,
135
140
  );
141
+
136
142
  if (hit) {
137
143
  return this.toResolved<T>(hit, 'table');
138
144
  }
139
145
  }
140
146
 
141
147
  // 3. GLOBAL szint.
142
- const globalHit: DyNTS_ScopedConfig_DataModel | undefined = records.find((record) =>
148
+ const globalHit: DyNTS_ScopedConfig | undefined = records.find((record) =>
143
149
  record.level === DyNTS_ScopedConfig_Level.global && record.key === key,
144
150
  );
151
+
145
152
  if (globalHit) {
146
153
  return this.toResolved<T>(globalHit, 'global');
147
154
  }
148
155
 
149
156
  // 4. builtinDefault (a hívó fallback-je; a bedrock NEM tart katalógust).
150
157
  return {
151
- value: builtinDefault as T,
158
+ value: builtinDefault,
152
159
  resolvedFrom: 'builtin',
153
160
  };
154
161
  }
155
162
 
156
163
  /** Egy DB-rekordot a feloldott-érték shape-re (a forrás-szinttel + audittal). */
157
164
  private toResolved<T = DyNTS_ScopedConfigValue>(
158
- record: DyNTS_ScopedConfig_DataModel,
165
+ record: DyNTS_ScopedConfig,
159
166
  resolvedFrom: DyNTS_ScopedConfigResolvedFrom,
160
167
  ): DyNTS_ScopedConfigResolvedValue<T> {
161
168
  return {
@@ -171,26 +178,30 @@ export class DyNTS_ScopedConfig_ControlService {
171
178
  * A kontextusra releváns aktív rekordok betöltése EGY Mongo-körrel, cache-elve. A filter a global +
172
179
  * (ha van) table + a scopePath összes scopeId-jára szűkít — a merge memóriában fut. `set` invalidál.
173
180
  */
174
- private async loadEffectiveRecords(context?: DyNTS_ScopedConfigResolveContext): Promise<DyNTS_ScopedConfig_DataModel[]> {
181
+ private async loadEffectiveRecords(context?: DyNTS_ScopedConfigResolveContext): Promise<DyNTS_ScopedConfig[]> {
175
182
  const cacheKey: string = this.cacheKey(context);
176
183
  const cached: DyNTS_ScopedConfigCacheEntry | undefined = this.cache.get(cacheKey);
184
+
177
185
  if (cached && cached.expiresAt > Date.now()) {
178
186
  return cached.records;
179
187
  }
180
188
 
181
- const orClauses: DyFM_DBFilterSimple<DyNTS_ScopedConfig_DataModel>[] = [{ level: DyNTS_ScopedConfig_Level.global }];
189
+ const orClauses: DyFM_DBFilterSimple<DyNTS_ScopedConfig>[] = [{ level: DyNTS_ScopedConfig_Level.global }];
190
+
182
191
  if (context?.table) {
183
192
  orClauses.push({ level: DyNTS_ScopedConfig_Level.table, tableScope: context.table });
184
193
  const scopeIds: string[] = (context.scopePath ?? []).map((ref) => ref.scopeId);
194
+
185
195
  if (scopeIds.length) {
186
196
  orClauses.push({ level: DyNTS_ScopedConfig_Level.scope, tableScope: context.table, scopeId: { $in: scopeIds } });
187
197
  }
188
198
  }
189
199
 
190
200
  const dataService: DyNTS_ScopedConfig_DataService = new DyNTS_ScopedConfig_DataService({ issuer: this.issuer });
191
- const records: DyNTS_ScopedConfig_DataModel[] = await dataService.findActiveList({ $or: orClauses });
201
+ const records: DyNTS_ScopedConfig[] = await dataService.findActiveList({ $or: orClauses });
192
202
 
193
203
  this.cache.set(cacheKey, { records: records, expiresAt: Date.now() + this.cacheTtlMs });
204
+
194
205
  return records;
195
206
  }
196
207
 
@@ -198,6 +209,7 @@ export class DyNTS_ScopedConfig_ControlService {
198
209
  private cacheKey(context?: DyNTS_ScopedConfigResolveContext): string {
199
210
  const table: string = context?.table ?? '-';
200
211
  const scopeIds: string = (context?.scopePath ?? []).map((ref) => ref.scopeId).join('>') || '-';
212
+
201
213
  return `${table}|${scopeIds}`;
202
214
  }
203
215
 
@@ -229,22 +241,23 @@ export class DyNTS_ScopedConfig_ControlService {
229
241
  key: string,
230
242
  value: unknown,
231
243
  options: DyNTS_ScopedConfigSetOptions = {},
232
- ): Promise<DyNTS_ScopedConfig_DataModel> {
244
+ ): Promise<DyNTS_ScopedConfig> {
233
245
  this.assertLevelConsistency(level, key, options);
234
246
 
235
247
  const issuer: string = options.issuer ?? this.issuer;
236
- const filter: DyFM_DBFilterSimple<DyNTS_ScopedConfig_DataModel> =
248
+ const filter: DyFM_DBFilterSimple<DyNTS_ScopedConfig> =
237
249
  DyNTS_ScopedConfig_DataService.levelKeyFilter(level, key, options);
238
250
 
239
251
  // Régi aktív rekord (ha van) → soft-delete (archív; history-megőrzés).
240
252
  const findService: DyNTS_ScopedConfig_DataService = new DyNTS_ScopedConfig_DataService({ issuer: issuer });
241
- const existing: DyNTS_ScopedConfig_DataModel = await findService.findActive(filter);
253
+ const existing: DyNTS_ScopedConfig = await findService.findActive(filter);
254
+
242
255
  if (existing && existing._id) {
243
256
  await findService.deleteData(existing._id);
244
257
  }
245
258
 
246
259
  // Új aktív rekord — a `value` Mixed.
247
- const record: DyNTS_ScopedConfig_DataModel = new DyNTS_ScopedConfig_DataModel({
260
+ const record: DyNTS_ScopedConfig = new DyNTS_ScopedConfig({
248
261
  level: level,
249
262
  tableScope: options.tableScope,
250
263
  scopeId: options.scopeId,
@@ -255,9 +268,10 @@ export class DyNTS_ScopedConfig_ControlService {
255
268
  note: options.note,
256
269
  });
257
270
  const writeService: DyNTS_ScopedConfig_DataService = new DyNTS_ScopedConfig_DataService({ data: record, issuer: issuer });
258
- const saved: DyNTS_ScopedConfig_DataModel = await writeService.saveData(record);
271
+ const saved: DyNTS_ScopedConfig = await writeService.saveData(record);
259
272
 
260
273
  this.invalidateCache();
274
+
261
275
  return saved;
262
276
  }
263
277
 
@@ -269,6 +283,7 @@ export class DyNTS_ScopedConfig_ControlService {
269
283
  if ((level === DyNTS_ScopedConfig_Level.table || level === DyNTS_ScopedConfig_Level.scope) && !options.tableScope) {
270
284
  throw new Error(`DyNTS_ScopedConfig: '${key}' '${level}' szintű beállításához kötelező a tableScope.`);
271
285
  }
286
+
272
287
  if (level === DyNTS_ScopedConfig_Level.scope && !options.scopeId) {
273
288
  throw new Error(`DyNTS_ScopedConfig: '${key}' 'scope' szintű beállításához kötelező a scopeId.`);
274
289
  }
@@ -286,10 +301,11 @@ export class DyNTS_ScopedConfig_ControlService {
286
301
  level: DyNTS_ScopedConfig_Level,
287
302
  key: string,
288
303
  options: DyNTS_ScopedConfigSetOptions = {},
289
- ): Promise<DyNTS_ScopedConfig_DataModel[]> {
290
- const filter: DyFM_DBFilterSimple<DyNTS_ScopedConfig_DataModel> =
304
+ ): Promise<DyNTS_ScopedConfig[]> {
305
+ const filter: DyFM_DBFilterSimple<DyNTS_ScopedConfig> =
291
306
  DyNTS_ScopedConfig_DataService.levelKeyFilter(level, key, options);
292
307
  const dataService: DyNTS_ScopedConfig_DataService = new DyNTS_ScopedConfig_DataService({ issuer: options.issuer ?? this.issuer });
308
+
293
309
  return dataService.getArchiveDataService().findDataList(filter, true);
294
310
  }
295
311
  }