@futdevpro/nts-dynamo 1.15.58 → 1.15.60
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.
- package/.dynamo/logs/cicd-pipeline/output.log +1622 -1705
- package/.dynamo/logs/cicd-pipeline/status.json +30 -30
- package/build/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.d.ts.map +1 -1
- package/build/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.js +2 -2
- package/build/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.js.map +1 -1
- package/build/_modules/ai/_services/ai-embedding-mock.service.d.ts +1 -1
- package/build/_modules/ai/_services/ai-embedding-mock.service.d.ts.map +1 -1
- package/build/_modules/ai/_services/ai-embedding-mock.service.js.map +1 -1
- package/build/_modules/ai/_services/ai-embedding-provider.registry.d.ts.map +1 -1
- package/build/_modules/ai/_services/ai-embedding-provider.registry.js.map +1 -1
- package/build/_modules/ai/_services/lmstudio-embedding.control-service.d.ts +1 -1
- package/build/_modules/ai/_services/lmstudio-embedding.control-service.d.ts.map +1 -1
- package/build/_modules/ai/_services/lmstudio-embedding.control-service.js +3 -3
- package/build/_modules/ai/_services/lmstudio-embedding.control-service.js.map +1 -1
- package/build/_modules/ai/index.d.ts +2 -0
- package/build/_modules/ai/index.d.ts.map +1 -1
- package/build/_modules/ai/index.js +4 -0
- package/build/_modules/ai/index.js.map +1 -1
- package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.d.ts +17 -17
- package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.d.ts.map +1 -1
- package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.js +21 -21
- package/build/_modules/data-readers/_collections/dynts-sqlite-reader.util.js.map +1 -1
- package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.d.ts +4 -4
- package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.d.ts.map +1 -1
- package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.js +5 -5
- package/build/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.js.map +1 -1
- package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.d.ts +4 -4
- package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.d.ts.map +1 -1
- package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.js +4 -4
- package/build/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.js.map +1 -1
- package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.d.ts +6 -6
- package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.d.ts.map +1 -1
- package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.js +5 -5
- package/build/_modules/local-vector-search/_services/lvs-vector-persist.data-service.js.map +1 -1
- package/build/_modules/mcp/_models/interfaces/dynts-mcp.interface.d.ts +1 -1
- package/build/_modules/mcp/_models/interfaces/dynts-mcp.interface.js +1 -1
- package/build/_modules/mcp/_services/dynts-mcp-server.service-base.d.ts +4 -4
- package/build/_modules/mcp/_services/dynts-mcp-server.service-base.d.ts.map +1 -1
- package/build/_modules/mcp/_services/dynts-mcp-server.service-base.js +6 -6
- package/build/_modules/mcp/_services/dynts-mcp-server.service-base.js.map +1 -1
- package/build/_modules/mcp/_services/dynts-mcp.adapter.d.ts +11 -11
- package/build/_modules/mcp/_services/dynts-mcp.adapter.d.ts.map +1 -1
- package/build/_modules/mcp/_services/dynts-mcp.adapter.js +16 -11
- package/build/_modules/mcp/_services/dynts-mcp.adapter.js.map +1 -1
- package/build/_modules/mcp/index.js +1 -1
- package/build/_modules/mcp/index.js.map +1 -1
- package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.d.ts +3 -3
- package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.d.ts.map +1 -1
- package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.js +4 -4
- package/build/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.js.map +1 -1
- package/build/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.d.ts.map +1 -1
- package/build/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.js +9 -0
- package/build/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.js.map +1 -1
- package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.d.ts +3 -3
- package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.d.ts.map +1 -1
- package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.js +1 -1
- package/build/_modules/scoped-config/_services/dynts-scoped-config.control-service.js.map +1 -1
- package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.d.ts +7 -7
- package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.d.ts.map +1 -1
- package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.js +2 -2
- package/build/_modules/scoped-config/_services/dynts-scoped-config.data-service.js.map +1 -1
- package/package.json +1 -1
- package/src/_modules/ai/_modules/document-ai/_collections/dai-code-chunking.util.ts +39 -7
- package/src/_modules/ai/_services/ai-embedding-mock.service.ts +18 -4
- package/src/_modules/ai/_services/ai-embedding-provider.registry.ts +4 -0
- package/src/_modules/ai/_services/lmstudio-embedding.control-service.ts +26 -5
- package/src/_modules/ai/index.ts +5 -0
- package/src/_modules/data-readers/_collections/dynts-sqlite-reader.util.spec.ts +145 -130
- package/src/_modules/data-readers/_collections/dynts-sqlite-reader.util.ts +131 -120
- package/src/_modules/local-vector-search/_models/data-models/lvs-vector-persist.data-model.ts +6 -5
- package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.spec.ts +35 -35
- package/src/_modules/local-vector-search/_services/lvs-persistent-vector-pool.control-service.ts +9 -5
- package/src/_modules/local-vector-search/_services/lvs-vector-persist.data-service.spec.ts +11 -11
- package/src/_modules/local-vector-search/_services/lvs-vector-persist.data-service.ts +19 -17
- package/src/_modules/mcp/_models/interfaces/dynts-mcp.interface.ts +1 -1
- package/src/_modules/mcp/_services/dynts-mcp-server.service-base.spec.ts +123 -114
- package/src/_modules/mcp/_services/dynts-mcp-server.service-base.ts +44 -39
- package/src/_modules/mcp/_services/dynts-mcp.adapter.ts +114 -103
- package/src/_modules/mcp/index.ts +1 -1
- package/src/_modules/scoped-config/_models/data-models/dynts-scoped-config.data-model.ts +5 -4
- package/src/_modules/scoped-config/_models/interfaces/dynts-scoped-config.interface.ts +0 -2
- package/src/_modules/scoped-config/_services/dynts-scoped-config.control-service.spec.ts +19 -13
- package/src/_modules/scoped-config/_services/dynts-scoped-config.control-service.ts +37 -21
- package/src/_modules/scoped-config/_services/dynts-scoped-config.data-service.spec.ts +11 -6
- package/src/_modules/scoped-config/_services/dynts-scoped-config.data-service.ts +17 -14
|
@@ -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
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
* `
|
|
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
|
-
|
|
32
|
-
|
|
36
|
+
/** A SDK MCP-szerver (a transport-agnosztikus protocol-réteg). */
|
|
37
|
+
private readonly server: Server;
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
public registerTool(definition: DyNTS_Mcp_ToolDefinition): void {
|
|
56
|
+
this.tools.set(definition.name, definition);
|
|
57
|
+
}
|
|
53
58
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
await this.server.connect(transport);
|
|
66
|
-
}
|
|
68
|
+
public async startStdio(): Promise<void> {
|
|
69
|
+
const transport: StdioServerTransport = new StdioServerTransport();
|
|
67
70
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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
|
-
|
|
139
|
-
|
|
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
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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 `
|
|
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
|
|
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<
|
|
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
|
|
68
|
-
new DyFM_DataModel_Params<
|
|
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 {
|
|
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<
|
|
31
|
-
new
|
|
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:
|
|
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:
|
|
253
|
+
const existing: DyNTS_ScopedConfig =
|
|
250
254
|
makeRecord({ _id: 'old-id', level: DyNTS_ScopedConfig_Level.global, key: 'read.topK', value: 10 });
|
|
251
|
-
const savedNew:
|
|
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:
|
|
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:
|
|
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?:
|
|
285
|
+
.and.callFake((data?: DyNTS_ScopedConfig) => Promise.resolve(data));
|
|
280
286
|
|
|
281
|
-
const result:
|
|
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 {
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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:
|
|
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<
|
|
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<
|
|
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:
|
|
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<
|
|
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<
|
|
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:
|
|
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:
|
|
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:
|
|
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<
|
|
290
|
-
const filter: DyFM_DBFilterSimple<
|
|
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
|
}
|