@things-factory/headless-twin 10.0.7 → 10.0.9
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/dist-server/engine/attention-digest.d.ts +52 -0
- package/dist-server/engine/attention-digest.js +76 -0
- package/dist-server/engine/attention-digest.js.map +1 -0
- package/dist-server/engine/board-vocabulary.d.ts +17 -0
- package/dist-server/engine/board-vocabulary.js +63 -0
- package/dist-server/engine/board-vocabulary.js.map +1 -0
- package/dist-server/engine/command-routing.d.ts +33 -0
- package/dist-server/engine/command-routing.js +53 -0
- package/dist-server/engine/command-routing.js.map +1 -0
- package/dist-server/engine/entity-delta.d.ts +13 -6
- package/dist-server/engine/entity-delta.js +38 -12
- package/dist-server/engine/entity-delta.js.map +1 -1
- package/dist-server/engine/index.d.ts +6 -0
- package/dist-server/engine/index.js +10 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/kpi-baseline.d.ts +78 -0
- package/dist-server/engine/kpi-baseline.js +123 -0
- package/dist-server/engine/kpi-baseline.js.map +1 -0
- package/dist-server/engine/kpi-broadcast.d.ts +4 -0
- package/dist-server/engine/kpi-broadcast.js +16 -0
- package/dist-server/engine/kpi-broadcast.js.map +1 -0
- package/dist-server/engine/kpi-query.d.ts +31 -0
- package/dist-server/engine/kpi-query.js +50 -2
- package/dist-server/engine/kpi-query.js.map +1 -1
- package/dist-server/engine/live-attentions.d.ts +1 -0
- package/dist-server/engine/live-attentions.js +7 -1
- package/dist-server/engine/live-attentions.js.map +1 -1
- package/dist-server/engine/runtime-key.d.ts +15 -0
- package/dist-server/engine/runtime-key.js +64 -0
- package/dist-server/engine/runtime-key.js.map +1 -0
- package/dist-server/engine/state-axes.d.ts +16 -0
- package/dist-server/engine/state-axes.js +54 -0
- package/dist-server/engine/state-axes.js.map +1 -0
- package/dist-server/engine/twin-engine.d.ts +92 -16
- package/dist-server/engine/twin-engine.js +335 -77
- package/dist-server/engine/twin-engine.js.map +1 -1
- package/dist-server/engine/twin-level.d.ts +23 -0
- package/dist-server/engine/twin-level.js +52 -0
- package/dist-server/engine/twin-level.js.map +1 -0
- package/dist-server/engine/warm-start.d.ts +58 -12
- package/dist-server/engine/warm-start.js +80 -9
- package/dist-server/engine/warm-start.js.map +1 -1
- package/dist-server/service/reference/discovery-result.d.ts +34 -0
- package/dist-server/service/reference/discovery-result.js +84 -0
- package/dist-server/service/reference/discovery-result.js.map +1 -0
- package/dist-server/service/reference/ingest-space.d.ts +30 -0
- package/dist-server/service/reference/ingest-space.js +63 -0
- package/dist-server/service/reference/ingest-space.js.map +1 -0
- package/dist-server/service/reference/knob-defaults.d.ts +20 -0
- package/dist-server/service/reference/knob-defaults.js +59 -0
- package/dist-server/service/reference/knob-defaults.js.map +1 -0
- package/dist-server/service/reference/reference-live.js +2 -2
- package/dist-server/service/reference/reference-live.js.map +1 -1
- package/dist-server/service/reference/reference-master.d.ts +37 -2
- package/dist-server/service/reference/reference-master.js +55 -5
- package/dist-server/service/reference/reference-master.js.map +1 -1
- package/dist-server/service/reference/reference-resolver.d.ts +2 -2
- package/dist-server/service/reference/reference-resolver.js +71 -15
- package/dist-server/service/reference/reference-resolver.js.map +1 -1
- package/dist-server/service/twin-attention/twin-attention-query.d.ts +8 -1
- package/dist-server/service/twin-attention/twin-attention-query.js +39 -8
- package/dist-server/service/twin-attention/twin-attention-query.js.map +1 -1
- package/dist-server/service/twin-control/twin-control-mutation.d.ts +2 -0
- package/dist-server/service/twin-control/twin-control-mutation.js +29 -10
- package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
- package/dist-server/service/twin-forecast/twin-forecast-query.js +2 -1
- package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
- package/dist-server/service/twin-instance/twin-instance.js +4 -2
- package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
- package/dist-server/service/twin-journal/twin-journal-query.d.ts +6 -2
- package/dist-server/service/twin-journal/twin-journal-query.js +25 -7
- package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +8 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +23 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.js +1 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
- package/dist-server/service/twin-space/twin-space-resolver.js +9 -0
- package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
- package/dist-server/service/twin-state/twin-state-subscription.js +1 -1
- package/dist-server/service/twin-state/twin-state-subscription.js.map +1 -1
- package/dist-server/service/twin-structure/twin-structure.js +2 -1
- package/dist-server/service/twin-structure/twin-structure.js.map +1 -1
- package/dist-server/service/twin-target/twin-target-resolver.js +21 -4
- package/dist-server/service/twin-target/twin-target-resolver.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/server/engine/attention-digest.ts +102 -0
- package/server/engine/board-vocabulary.ts +61 -0
- package/server/engine/command-routing.ts +67 -0
- package/server/engine/entity-delta.ts +33 -11
- package/server/engine/index.ts +10 -0
- package/server/engine/kpi-baseline.ts +202 -0
- package/server/engine/kpi-broadcast.ts +13 -0
- package/server/engine/kpi-query.ts +81 -3
- package/server/engine/live-attentions.ts +7 -2
- package/server/engine/runtime-key.ts +58 -0
- package/server/engine/state-axes.ts +55 -0
- package/server/engine/twin-engine.ts +350 -77
- package/server/engine/twin-level.ts +48 -0
- package/server/engine/warm-start.ts +130 -16
- package/server/service/reference/discovery-result.ts +95 -0
- package/server/service/reference/ingest-space.ts +70 -0
- package/server/service/reference/knob-defaults.ts +59 -0
- package/server/service/reference/reference-live.ts +2 -2
- package/server/service/reference/reference-master.ts +94 -8
- package/server/service/reference/reference-resolver.ts +80 -16
- package/server/service/twin-attention/twin-attention-query.ts +43 -6
- package/server/service/twin-control/twin-control-mutation.ts +31 -12
- package/server/service/twin-forecast/twin-forecast-query.ts +3 -2
- package/server/service/twin-instance/twin-instance.ts +6 -2
- package/server/service/twin-journal/twin-journal-query.ts +35 -5
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +18 -2
- package/server/service/twin-metrics/twin-metrics-query.ts +1 -1
- package/server/service/twin-space/twin-space-resolver.ts +10 -1
- package/server/service/twin-state/twin-state-subscription.ts +1 -1
- package/server/service/twin-structure/twin-structure.ts +4 -1
- package/server/service/twin-target/twin-target-resolver.ts +22 -4
- package/test/attention-digest.test.ts +135 -0
- package/test/board-vocabulary.test.ts +114 -0
- package/test/capability-mapping.test.ts +4 -4
- package/test/command-routing.test.ts +61 -0
- package/test/discovery-result.test.ts +75 -0
- package/test/entity-delta.test.ts +25 -25
- package/test/ingest-bench.test.ts +3 -3
- package/test/ingest-space.test.ts +50 -0
- package/test/knob-defaults.test.ts +72 -0
- package/test/kpi-baseline-db.test.ts +214 -0
- package/test/kpi-baseline.test.ts +196 -0
- package/test/kpi-query-bench.test.ts +128 -0
- package/test/live-mirror-parity.test.ts +35 -2
- package/test/master-to-twin.test.ts +7 -3
- package/test/mutation-gate.test.ts +108 -0
- package/test/oee-accumulator.test.ts +65 -1
- package/test/registry-key-guard.test.ts +80 -0
- package/test/runtime-key.test.ts +66 -0
- package/test/scale-twin-bench.test.ts +2 -2
- package/test/state-axes.test.ts +74 -0
- package/test/streamline-e2e.test.ts +2 -2
- package/test/structure-revision-db.test.ts +5 -4
- package/test/tenant-registry-db.test.ts +149 -0
- package/test/warm-start-seam.test.ts +140 -0
- package/test/warm-start.test.ts +138 -4
|
@@ -5,16 +5,34 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const shell_1 = require("@things-factory/shell");
|
|
7
7
|
const index_js_1 = require("../../engine/index.js");
|
|
8
|
+
const knob_defaults_js_1 = require("./knob-defaults.js");
|
|
9
|
+
const reference_master_js_1 = require("./reference-master.js");
|
|
8
10
|
const twin_instance_js_1 = require("../twin-instance/twin-instance.js");
|
|
9
11
|
const twin_reference_js_1 = require("./twin-reference.js");
|
|
10
12
|
const reference_registry_js_1 = require("./reference-registry.js");
|
|
11
13
|
const reference_adapter_js_1 = require("./reference-adapter.js");
|
|
14
|
+
const discovery_result_js_1 = require("./discovery-result.js");
|
|
12
15
|
const reference_live_js_1 = require("./reference-live.js");
|
|
13
16
|
const template_registry_js_1 = require("./template-registry.js");
|
|
14
17
|
/*
|
|
15
18
|
* Face2 레퍼런스 인제스트 채널(ADR-0018) — 등록된 레퍼런스 소스를 열거하고, 골라서 트윈으로 인제스트.
|
|
16
19
|
* "연결하고 내 것을 불러온다" — 엔티티는 레퍼런스에서 오지 손배선/발명이 아니다.
|
|
17
20
|
*/
|
|
21
|
+
/**
|
|
22
|
+
* 발견 조회의 시간 상한 — 15초.
|
|
23
|
+
*
|
|
24
|
+
* 어댑터 계약에 시간 제한이 없다. 주소가 틀린 엔드포인트는 답하지 않고, 그러면 화면이 무한히 돈다 —
|
|
25
|
+
* 사용자에게는 "실패" 보다 못한 상태다(무엇을 기다리는지 모른 채 기다린다). 실 시스템 조회가 몇 초
|
|
26
|
+
* 걸리는 것은 정상이므로 넉넉히 두되, 끝은 있어야 한다.
|
|
27
|
+
*/
|
|
28
|
+
const DISCOVER_TIMEOUT_MS = 15_000;
|
|
29
|
+
const TIMEOUT = 'discover-timeout';
|
|
30
|
+
function withTimeout(work, ms) {
|
|
31
|
+
return new Promise((resolve, reject) => {
|
|
32
|
+
const timer = setTimeout(() => reject(Object.assign(new Error('timeout'), { code: TIMEOUT })), ms);
|
|
33
|
+
work.then(v => { clearTimeout(timer); resolve(v); }, e => { clearTimeout(timer); reject(e); });
|
|
34
|
+
});
|
|
35
|
+
}
|
|
18
36
|
let TwinReferenceResolver = class TwinReferenceResolver {
|
|
19
37
|
/** 등록된 레퍼런스 소스 목록(요약 + 이미 인제스트됐는지). */
|
|
20
38
|
async referenceSources(context) {
|
|
@@ -30,7 +48,7 @@ let TwinReferenceResolver = class TwinReferenceResolver {
|
|
|
30
48
|
areaCount: m.locations.filter(l => l.role === 'area' || l.role === 'both').length,
|
|
31
49
|
equipmentCount: (m.equipment ?? []).length,
|
|
32
50
|
imported: !!reg,
|
|
33
|
-
running:
|
|
51
|
+
running: index_js_1.TwinEngine.owns(domainId, m.source)
|
|
34
52
|
});
|
|
35
53
|
}
|
|
36
54
|
return out;
|
|
@@ -56,25 +74,36 @@ let TwinReferenceResolver = class TwinReferenceResolver {
|
|
|
56
74
|
return (0, template_registry_js_1.listTemplates)().map(t => ({ id: t.id, label: t.label, system: t.system, description: t.description, detail: t.detail, knobs: t.knobs }));
|
|
57
75
|
}
|
|
58
76
|
/** 템플릿 + 노브 → 합성 마스터 → 인제스트(+기동+시나리오). 레퍼런스 import 와 같은 경로, 원천만 합성. */
|
|
59
|
-
async createFromTemplate(templateId, params, context, start) {
|
|
77
|
+
async createFromTemplate(templateId, params, context, start, spaceId) {
|
|
60
78
|
const tpl = (0, template_registry_js_1.getTemplate)(templateId);
|
|
61
79
|
if (!tpl)
|
|
62
80
|
return { ok: false, error: `unknown template: ${templateId}` };
|
|
63
81
|
const domainId = context.state.domain.id;
|
|
64
82
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
83
|
+
/*
|
|
84
|
+
* **빠진 노브를 서버가 채운다.** 기본값을 아는 곳은 노브 스키마(계약)인데 그것을 적용하는 곳이
|
|
85
|
+
* 위자드뿐이었다 — 그래서 화면을 거치지 않는 호출자(AI·스크립트·API)가 파라미터를 일부만 주면
|
|
86
|
+
* 템플릿 안에서 발생률이 0 이 되고 **아무것도 하지 않는 트윈**이 조용히 만들어졌다.
|
|
87
|
+
* 채운 노브 이름은 경고로 함께 돌려준다 — 조용히 채우는 것도 조용히 비우는 것만큼 위험하다.
|
|
88
|
+
*/
|
|
89
|
+
const filled = (0, knob_defaults_js_1.filledKnobKeys)(tpl.knobs, params);
|
|
90
|
+
const effective = (0, knob_defaults_js_1.applyKnobDefaults)(tpl.knobs, params);
|
|
91
|
+
const { master, scenario } = tpl.build(effective);
|
|
92
|
+
/* 공간 선택은 템플릿을 거치지 않는다 — 템플릿마다 이 노브를 알고 있어야 한다면 새 템플릿이
|
|
93
|
+
조용히 무시하게 된다. 합성된 마스터에 한 곳에서 얹는다(레퍼런스 인제스트와 같은 경로). */
|
|
94
|
+
const res = await index_js_1.TwinEngine.ingestMaster(domainId, master, { spaceId });
|
|
67
95
|
if (start !== false) {
|
|
68
96
|
await index_js_1.TwinEngine.startFromRegistry(domainId, res.instanceId);
|
|
69
97
|
if (scenario) {
|
|
70
|
-
const runtime = index_js_1.TwinEngine.runtime(res.instanceId);
|
|
98
|
+
const runtime = index_js_1.TwinEngine.runtime(domainId, res.instanceId);
|
|
71
99
|
if (runtime) {
|
|
72
100
|
runtime.scenario.load(scenario);
|
|
73
101
|
runtime.scenario.start();
|
|
74
102
|
}
|
|
75
103
|
}
|
|
76
104
|
}
|
|
77
|
-
|
|
105
|
+
const warnings = filled.length ? [(0, reference_master_js_1.knobDefaultsFilled)(filled), ...res.warnings] : res.warnings;
|
|
106
|
+
return { ok: true, instanceId: res.instanceId, spaceId: res.spaceId, warnings };
|
|
78
107
|
}
|
|
79
108
|
catch (e) {
|
|
80
109
|
return { ok: false, error: e?.message || 'template instantiation failed' };
|
|
@@ -137,7 +166,7 @@ let TwinReferenceResolver = class TwinReferenceResolver {
|
|
|
137
166
|
.filter(p => instMap.has(p.instanceId))
|
|
138
167
|
.map(p => {
|
|
139
168
|
const inst = instMap.get(p.instanceId);
|
|
140
|
-
return { instanceId: p.instanceId, spaceId: p.spaceId, siteId: p.siteId, kind: inst.kind, status: inst.status, running:
|
|
169
|
+
return { instanceId: p.instanceId, spaceId: p.spaceId, siteId: p.siteId, kind: inst.kind, status: inst.status, running: index_js_1.TwinEngine.owns(domainId, p.instanceId) };
|
|
141
170
|
});
|
|
142
171
|
return {
|
|
143
172
|
source: r.source,
|
|
@@ -230,17 +259,31 @@ let TwinReferenceResolver = class TwinReferenceResolver {
|
|
|
230
259
|
*/
|
|
231
260
|
/** 레퍼런스가 노출하는 사이트/공장 발견 — 트윈 생성 시 "어느 공장" 선택용(§2.2). */
|
|
232
261
|
async discoverReferenceSites(source, context) {
|
|
262
|
+
/*
|
|
263
|
+
* **"못 찾았다" 와 "없다" 를 가른다.** 예전에는 넷을 빈 배열 하나로 접었고(레퍼런스 없음·어댑터
|
|
264
|
+
* 미상·조회 실패·정말 0건), 화면은 그 모두를 "사이트를 찾지 못했습니다" 라고만 말했다. 실 시스템
|
|
265
|
+
* 연결에서 가장 자주 막히는 자리인데 자격이 틀렸는지 주소가 틀렸는지 알 수 없었다.
|
|
266
|
+
* 판정과 문장 형태는 `discovery-result`(순수)가 갖는다.
|
|
267
|
+
*/
|
|
233
268
|
const ref = await (0, shell_1.getRepository)(twin_reference_js_1.TwinReference).findOne({ where: { domain: { id: context.state.domain.id }, source } });
|
|
234
269
|
if (!ref)
|
|
235
|
-
return
|
|
270
|
+
return (0, discovery_result_js_1.failed)((0, discovery_result_js_1.referenceNotFound)(source));
|
|
236
271
|
const adapter = (0, reference_adapter_js_1.getAdapter)(ref.adapterType);
|
|
237
272
|
if (!adapter)
|
|
238
|
-
return
|
|
273
|
+
return (0, discovery_result_js_1.failed)((0, discovery_result_js_1.adapterUnknown)(ref.adapterType, source));
|
|
239
274
|
try {
|
|
240
|
-
|
|
275
|
+
/*
|
|
276
|
+
* **기다려도 답이 없으면 사유를 준다.** 어댑터 계약에 시간 제한이 없어서, 주소가 틀린 엔드포인트는
|
|
277
|
+
* 화면을 무한히 돌게 만들었다 — 무한히 도는 화면은 조용한 실패의 다른 얼굴이다.
|
|
278
|
+
* 상한은 여기서 정한다(어댑터마다 다르게 두면 사용자가 어느 것을 기다리는지 알 수 없다).
|
|
279
|
+
*/
|
|
280
|
+
const sites = await withTimeout(adapter.discoverSites(ref.connectionConfig ?? {}), DISCOVER_TIMEOUT_MS);
|
|
281
|
+
return (0, discovery_result_js_1.discovered)(sites);
|
|
241
282
|
}
|
|
242
|
-
catch {
|
|
243
|
-
|
|
283
|
+
catch (e) {
|
|
284
|
+
if (e?.code === TIMEOUT)
|
|
285
|
+
return (0, discovery_result_js_1.failed)((0, discovery_result_js_1.discoveryTimedOut)(source, DISCOVER_TIMEOUT_MS / 1000));
|
|
286
|
+
return (0, discovery_result_js_1.failed)((0, discovery_result_js_1.discoveryFailed)(source, (0, discovery_result_js_1.detailOf)(e)));
|
|
244
287
|
}
|
|
245
288
|
}
|
|
246
289
|
/**
|
|
@@ -288,7 +331,13 @@ let TwinReferenceResolver = class TwinReferenceResolver {
|
|
|
288
331
|
await repo.update({ id: ref.id }, {
|
|
289
332
|
status: 'connected',
|
|
290
333
|
lastSyncedAt: new Date().toISOString(),
|
|
291
|
-
|
|
334
|
+
/*
|
|
335
|
+
* **영어 canonical 로 남긴다.** 이 값은 DB 에 저장되고 연결 화면이 그대로 뿌린다 — 예전에는
|
|
336
|
+
* 한글 산문(`N개 사이트 실패`)이라 다섯 언어 화면에 한글이 새어 나갔다. 어댑터가 주는 사유도
|
|
337
|
+
* 같은 필드에 들어오므로(그것은 원 시스템의 말이다) 키가 아니라 영어 문장으로 통일한다.
|
|
338
|
+
* 어느 사이트가 왜 실패했는지는 `failed[]` 가 답한다 — 화면이 그것을 보여 준다.
|
|
339
|
+
*/
|
|
340
|
+
lastError: failed.length ? `${failed.length} of ${sites.length} site(s) failed: ${failed.map((f) => f.siteId).join(', ')}` : null,
|
|
292
341
|
scopeSpec: { ...(ref.scopeSpec ?? {}), produced: [...prev, ...producedNew] }
|
|
293
342
|
});
|
|
294
343
|
return { ok: instances.length > 0, instances, failed };
|
|
@@ -308,6 +357,7 @@ tslib_1.__decorate([
|
|
|
308
357
|
tslib_1.__metadata("design:returntype", Promise)
|
|
309
358
|
], TwinReferenceResolver.prototype, "referenceSources", null);
|
|
310
359
|
tslib_1.__decorate([
|
|
360
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
311
361
|
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Ingest a registered reference source into a twin (space + instance). Optionally start it.' }),
|
|
312
362
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('source')),
|
|
313
363
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
@@ -324,13 +374,15 @@ tslib_1.__decorate([
|
|
|
324
374
|
tslib_1.__metadata("design:returntype", Promise)
|
|
325
375
|
], TwinReferenceResolver.prototype, "twinTemplates", null);
|
|
326
376
|
tslib_1.__decorate([
|
|
377
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
327
378
|
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Instantiate a twin template with params → synthetic master → ingest (+start+scenario). Returns {ok, instanceId, spaceId}.' }),
|
|
328
379
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('templateId')),
|
|
329
380
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('params', type => shell_1.ScalarObject)),
|
|
330
381
|
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
331
382
|
tslib_1.__param(3, (0, type_graphql_1.Arg)('start', { nullable: true })),
|
|
383
|
+
tslib_1.__param(4, (0, type_graphql_1.Arg)('spaceId', { nullable: true, description: 'Existing space to co-locate this twin into (add a lens to a site). Omit to create its own space.' })),
|
|
332
384
|
tslib_1.__metadata("design:type", Function),
|
|
333
|
-
tslib_1.__metadata("design:paramtypes", [String, Object, Object, Boolean]),
|
|
385
|
+
tslib_1.__metadata("design:paramtypes", [String, Object, Object, Boolean, String]),
|
|
334
386
|
tslib_1.__metadata("design:returntype", Promise)
|
|
335
387
|
], TwinReferenceResolver.prototype, "createFromTemplate", null);
|
|
336
388
|
tslib_1.__decorate([
|
|
@@ -376,6 +428,7 @@ tslib_1.__decorate([
|
|
|
376
428
|
tslib_1.__metadata("design:returntype", Array)
|
|
377
429
|
], TwinReferenceResolver.prototype, "referenceAdapters", null);
|
|
378
430
|
tslib_1.__decorate([
|
|
431
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
379
432
|
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Create or update a tenant-scoped twin reference (persisted).' }),
|
|
380
433
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('source')),
|
|
381
434
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('patch', type => shell_1.ScalarObject)),
|
|
@@ -385,6 +438,7 @@ tslib_1.__decorate([
|
|
|
385
438
|
tslib_1.__metadata("design:returntype", Promise)
|
|
386
439
|
], TwinReferenceResolver.prototype, "saveTwinReference", null);
|
|
387
440
|
tslib_1.__decorate([
|
|
441
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
388
442
|
(0, type_graphql_1.Mutation)(returns => Boolean, { description: 'Delete a tenant-scoped reference. If removeTwins, also remove the twin instances it produced (provenance cascade); otherwise twins are kept (detached).' }),
|
|
389
443
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('source')),
|
|
390
444
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
@@ -394,6 +448,7 @@ tslib_1.__decorate([
|
|
|
394
448
|
tslib_1.__metadata("design:returntype", Promise)
|
|
395
449
|
], TwinReferenceResolver.prototype, "deleteTwinReference", null);
|
|
396
450
|
tslib_1.__decorate([
|
|
451
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
397
452
|
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Test a reference connection via its adapter; updates status.' }),
|
|
398
453
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('source')),
|
|
399
454
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
@@ -402,7 +457,7 @@ tslib_1.__decorate([
|
|
|
402
457
|
tslib_1.__metadata("design:returntype", Promise)
|
|
403
458
|
], TwinReferenceResolver.prototype, "testReferenceConnection", null);
|
|
404
459
|
tslib_1.__decorate([
|
|
405
|
-
(0, type_graphql_1.Query)(returns =>
|
|
460
|
+
(0, type_graphql_1.Query)(returns => shell_1.ScalarObject, { description: 'Discover sites/factories exposed by a reference. Returns { sites, error? } — an empty list with no error means the system genuinely has none, which is different from a failure.' }),
|
|
406
461
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('source')),
|
|
407
462
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
408
463
|
tslib_1.__metadata("design:type", Function),
|
|
@@ -410,6 +465,7 @@ tslib_1.__decorate([
|
|
|
410
465
|
tslib_1.__metadata("design:returntype", Promise)
|
|
411
466
|
], TwinReferenceResolver.prototype, "discoverReferenceSites", null);
|
|
412
467
|
tslib_1.__decorate([
|
|
468
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
413
469
|
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'Create twins from a reference: discover sites → filter by siteIds (if given) → fetch master(s) → provision. start=false to only provision; live=true to run as a mirror (adapter openLiveFeed → live projector) instead of sim.' }),
|
|
414
470
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('source')),
|
|
415
471
|
tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference-resolver.js","sourceRoot":"","sources":["../../../server/service/reference/reference-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Mutation, Query, Resolver } from 'type-graphql'\n\nimport { ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinReference } from './twin-reference.js'\nimport { listReferences, getReference } from './reference-registry.js'\nimport { getAdapter, listAdapterTypes, listAdapters } from './reference-adapter.js'\nimport { startReferenceLiveFeed } from './reference-live.js'\nimport { listTemplates, getTemplate } from './template-registry.js'\n\n/*\n * Face2 레퍼런스 인제스트 채널(ADR-0018) — 등록된 레퍼런스 소스를 열거하고, 골라서 트윈으로 인제스트.\n * \"연결하고 내 것을 불러온다\" — 엔티티는 레퍼런스에서 오지 손배선/발명이 아니다.\n */\n@Resolver()\nexport class TwinReferenceResolver {\n /** 등록된 레퍼런스 소스 목록(요약 + 이미 인제스트됐는지). */\n @Query(returns => [ScalarObject], { description: 'List registered reference sources (virtual or real adapters) available to ingest.' })\n async referenceSources(@Ctx() context: ResolverContext): Promise<any[]> {\n const domainId = context.state.domain.id\n const out: any[] = []\n for (const m of listReferences()) {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId: m.source } })\n out.push({\n source: m.source,\n system: m.system,\n siteName: m.siteName,\n locationCount: m.locations.filter(l => l.role === 'location' || l.role === 'both').length,\n areaCount: m.locations.filter(l => l.role === 'area' || l.role === 'both').length,\n equipmentCount: (m.equipment ?? []).length,\n imported: !!reg,\n running: !!TwinEngine.instances[m.source]\n })\n }\n return out\n }\n\n /** 소스를 인제스트 → 공간 + 인스턴스 생성(provision). start 면 기동까지. */\n @Mutation(returns => ScalarObject, { description: 'Ingest a registered reference source into a twin (space + instance). Optionally start it.' })\n async importFromReference(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('start', { nullable: true }) start?: boolean\n ): Promise<any> {\n const master = getReference(source)\n if (!master) return { ok: false, error: `unknown reference source: ${source}` }\n const domainId = context.state.domain.id\n try {\n const res = await TwinEngine.ingestMaster(domainId, master)\n if (start) await TwinEngine.startFromRegistry(domainId, res.instanceId)\n return { ok: true, instanceId: res.instanceId, spaceId: res.spaceId, warnings: res.warnings }\n } catch (e: any) {\n return { ok: false, error: e?.message || 'ingest failed' }\n }\n }\n\n /** 등록된 트윈 템플릿(파라미터화 아키타입) 목록 — 노브 스키마 포함(클라이언트 폼용). */\n @Query(returns => [ScalarObject], { description: 'List registered twin templates (parameterized archetypes) with their knob schema.' })\n async twinTemplates(@Ctx() _context: ResolverContext): Promise<any[]> {\n return listTemplates().map(t => ({ id: t.id, label: t.label, system: t.system, description: t.description, detail: t.detail, knobs: t.knobs }))\n }\n\n /** 템플릿 + 노브 → 합성 마스터 → 인제스트(+기동+시나리오). 레퍼런스 import 와 같은 경로, 원천만 합성. */\n @Mutation(returns => ScalarObject, { description: 'Instantiate a twin template with params → synthetic master → ingest (+start+scenario). Returns {ok, instanceId, spaceId}.' })\n async createFromTemplate(\n @Arg('templateId') templateId: string,\n @Arg('params', type => ScalarObject) params: any,\n @Ctx() context: ResolverContext,\n @Arg('start', { nullable: true }) start?: boolean\n ): Promise<any> {\n const tpl = getTemplate(templateId)\n if (!tpl) return { ok: false, error: `unknown template: ${templateId}` }\n const domainId = context.state.domain.id\n try {\n const { master, scenario } = tpl.build(params || {})\n const res = await TwinEngine.ingestMaster(domainId, master)\n if (start !== false) {\n await TwinEngine.startFromRegistry(domainId, res.instanceId)\n if (scenario) {\n const runtime = TwinEngine.runtime(res.instanceId)\n if (runtime) {\n runtime.scenario.load(scenario)\n runtime.scenario.start()\n }\n }\n }\n return { ok: true, instanceId: res.instanceId, spaceId: res.spaceId, warnings: res.warnings }\n } catch (e: any) {\n return { ok: false, error: e?.message || 'template instantiation failed' }\n }\n }\n\n /* ── 레퍼런스 관리(엔티티 기반·테넌트 스코프) — reference-management P1 ────────\n * 전역 인메모리(referenceSources/importFromReference)와 공존. 이쪽은 TwinReference 행 + 어댑터 레지스트리.\n */\n\n @Query(returns => [ScalarObject], { description: 'List tenant-scoped persisted twin references (adapter-backed).' })\n async twinReferences(@Ctx() context: ResolverContext): Promise<any[]> {\n const domainId = context.state.domain.id\n const rows = await getRepository(TwinReference).find({ where: { domain: { id: domainId } } })\n // provenance 라이브 대조 — 지워진 트윈은 producedCount 에서 자동 제외(상태 동기의 lazy 방식).\n const liveIds = new Set((await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })).map(i => i.instanceId))\n return rows.map(r => {\n const produced = (((r.scopeSpec as any)?.produced ?? []) as any[]).filter(p => liveIds.has(p.instanceId))\n return {\n source: r.source, system: r.system, siteName: r.siteName, description: r.description,\n adapterType: r.adapterType, status: r.status, lastSyncedAt: r.lastSyncedAt, lastError: r.lastError,\n producedCount: produced.length, produced\n }\n })\n }\n\n @Query(returns => [String], { description: 'List registered reference adapter type keys.' })\n referenceAdapterTypes(): string[] {\n return listAdapterTypes()\n }\n\n /**\n * 인티그레이션 그룹핑 (reference-management §2.3·D11) — 산출물을 커넥터 타입 ▸ Connection ▸ 인스턴스 2단으로.\n * 트윈-네이티브 온톨로지(integration 무의존): TwinReference 가 그룹핑 노드(source=connectionName),\n * scopeSpec.connectorType 로 상위 분류. producedCount 는 라이브 인스턴스로 대조(지워진 트윈 제외).\n */\n @Query(returns => [ScalarObject], { description: 'Group integration items 2-tier: connector type ▸ connection ▸ produced twins. (reference-management §2.3)' })\n async twinConnections(@Ctx() context: ResolverContext): Promise<any[]> {\n const domainId = context.state.domain.id\n const rows = await getRepository(TwinReference).find({ where: { domain: { id: domainId } } })\n const liveIds = new Set((await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })).map(i => i.instanceId))\n const groups = new Map<string, any[]>()\n for (const r of rows) {\n const connectorType = (r.scopeSpec as any)?.connectorType ?? r.adapterType\n const producedCount = (((r.scopeSpec as any)?.produced ?? []) as any[]).filter(p => liveIds.has(p.instanceId)).length\n const conn = { source: r.source, name: r.siteName, status: r.status, adapterType: r.adapterType, producedCount, lastSyncedAt: r.lastSyncedAt }\n if (!groups.has(connectorType)) groups.set(connectorType, [])\n groups.get(connectorType)!.push(conn)\n }\n return [...groups.entries()].map(([connectorType, connections]) => ({\n connectorType,\n connectionCount: connections.length,\n instanceCount: connections.reduce((s, c) => s + c.producedCount, 0),\n connections\n }))\n }\n\n /** 한 Connection 그룹 노드 상세 — 그 아래 생성된 트윈 인스턴스(라이브 대조·상태·기동여부). */\n @Query(returns => ScalarObject, { nullable: true, description: 'One connection grouping location with its produced twin instances (live-checked). (reference-management §2.3)' })\n async twinConnection(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any | null> {\n const domainId = context.state.domain.id\n const r = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source } })\n if (!r) return null\n const produced = ((r.scopeSpec as any)?.produced ?? []) as any[]\n const instMap = new Map((await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })).map(i => [i.instanceId, i]))\n const instances = produced\n .filter(p => instMap.has(p.instanceId))\n .map(p => {\n const inst = instMap.get(p.instanceId) as any\n return { instanceId: p.instanceId, spaceId: p.spaceId, siteId: p.siteId, kind: inst.kind, status: inst.status, running: !!(TwinEngine as any).instances?.[p.instanceId] }\n })\n return {\n source: r.source,\n connectorType: (r.scopeSpec as any)?.connectorType ?? r.adapterType,\n name: r.siteName,\n status: r.status,\n system: r.system,\n lastSyncedAt: r.lastSyncedAt,\n instanceCount: instances.length,\n instances\n }\n }\n\n /** 단건 상세(뷰/편집) — connectionConfig 포함, 어댑터 스키마의 secret 필드는 마스킹(있으면 '••••••'). */\n @Query(returns => ScalarObject, { nullable: true, description: 'Get one tenant-scoped reference with its connection config (secret fields masked) for view/edit.' })\n async twinReference(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any | null> {\n const r = await getRepository(TwinReference).findOne({ where: { domain: { id: context.state.domain.id }, source } })\n if (!r) return null\n const secretKeys = new Set((getAdapter(r.adapterType)?.meta?.configSchema ?? []).filter(f => f.secret).map(f => f.key))\n const cfg: any = {}\n for (const [k, v] of Object.entries((r.connectionConfig as any) ?? {})) cfg[k] = secretKeys.has(k) ? (v ? '••••••' : '') : v\n return {\n source: r.source, system: r.system, siteName: r.siteName, description: r.description,\n adapterType: r.adapterType, connectionConfig: cfg, status: r.status, lastSyncedAt: r.lastSyncedAt, lastError: r.lastError\n }\n }\n\n @Query(returns => [ScalarObject], { description: 'List reference connector metadata (label, domain, config schema, availability) for the connect UI.' })\n referenceAdapters(): any[] {\n return listAdapters().map(a => ({ type: a.type, ...(a.meta ?? {}) }))\n }\n\n @Mutation(returns => ScalarObject, { description: 'Create or update a tenant-scoped twin reference (persisted).' })\n async saveTwinReference(\n @Arg('source') source: string,\n @Arg('patch', type => ScalarObject) patch: any,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinReference)\n const existing = await repo.findOne({ where: { domain: { id: domainId }, source } })\n const saved = await repo.save(\n repo.create({\n ...(existing ?? {}),\n domain: { id: domainId } as any,\n source,\n system: patch.system ?? existing?.system,\n siteName: patch.siteName ?? existing?.siteName,\n description: patch.description ?? existing?.description,\n adapterType: patch.adapterType ?? existing?.adapterType,\n // 필드 단위 병합 — 편집 시 생략된 키(예: 마스킹된 secret)는 기존 값 유지.\n connectionConfig: patch.connectionConfig\n ? { ...((existing?.connectionConfig as any) ?? {}), ...patch.connectionConfig }\n : existing?.connectionConfig,\n mappingSpec: patch.mappingSpec ?? existing?.mappingSpec,\n scopeSpec: patch.scopeSpec ?? existing?.scopeSpec,\n status: patch.status ?? existing?.status ?? 'draft'\n })\n )\n return { ok: true, source: saved.source }\n }\n\n /** 연결 해제 — removeTwins=true 면 이 레퍼런스가 만든 트윈(provenance)도 함께 제거(라이프사이클 연쇄). 기본은 트윈 보존(분리). */\n @Mutation(returns => Boolean, { description: 'Delete a tenant-scoped reference. If removeTwins, also remove the twin instances it produced (provenance cascade); otherwise twins are kept (detached).' })\n async deleteTwinReference(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('removeTwins', { nullable: true }) removeTwins?: boolean\n ): Promise<boolean> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: domainId }, source } })\n if (removeTwins && ref) {\n for (const p of (((ref.scopeSpec as any)?.produced ?? []) as any[])) {\n try {\n await TwinEngine.remove(domainId, p.instanceId)\n } catch {\n /* 이미 없거나 실패 — 연쇄는 best-effort. */\n }\n }\n }\n await repo.delete({ domain: { id: domainId } as any, source })\n return true\n }\n\n @Mutation(returns => ScalarObject, { description: 'Test a reference connection via its adapter; updates status.' })\n async testReferenceConnection(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any> {\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: context.state.domain.id }, source } })\n if (!ref) return { ok: false, error: `unknown reference: ${source}` }\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return { ok: false, error: `no adapter for type: ${ref.adapterType}` }\n try {\n const res = await adapter.testConnection(ref.connectionConfig ?? {})\n await repo.update({ id: ref.id }, { status: res.ok ? 'connected' : 'error', lastError: res.error ?? null } as any)\n return res\n } catch (e: any) {\n return { ok: false, error: e?.message ?? 'test failed' }\n }\n }\n\n /**\n * 어댑터 기반 인제스트 — discoverSites → 사이트별 fetchMaster → ingestMaster (fan-out, §2.2·§4.2).\n * P1 은 대개 N=1(virtual/단일). start 면 각 인스턴스 기동. 라이브 피드·mode 는 face2-inbound-live 소유.\n */\n /** 레퍼런스가 노출하는 사이트/공장 발견 — 트윈 생성 시 \"어느 공장\" 선택용(§2.2). */\n @Query(returns => [ScalarObject], { description: 'Discover sites/factories exposed by a reference (adapter.discoverSites) — for twin-creation site selection.' })\n async discoverReferenceSites(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any[]> {\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: context.state.domain.id }, source } })\n if (!ref) return []\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return []\n try {\n return await adapter.discoverSites(ref.connectionConfig ?? {})\n } catch {\n return []\n }\n }\n\n /**\n * 트윈 생성 — 레퍼런스에서 사이트 발견 → (siteIds 있으면 그 공장만) → fetchMaster → provision. 사이트별 resilient.\n * 여러 공장을 관할하는 소스는 siteIds 로 \"어느 공장\"을 골라 생성(1:N, §2.1·§2.2).\n */\n @Mutation(returns => ScalarObject, { description: 'Create twins from a reference: discover sites → filter by siteIds (if given) → fetch master(s) → provision. start=false to only provision; live=true to run as a mirror (adapter openLiveFeed → live projector) instead of sim.' })\n async importTwinReference(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('siteIds', type => [String], { nullable: true }) siteIds?: string[],\n @Arg('start', { nullable: true }) start?: boolean,\n @Arg('live', { nullable: true }) live?: boolean\n ): Promise<any> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: domainId }, source } })\n if (!ref) return { ok: false, error: `unknown reference: ${source}` }\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return { ok: false, error: `no adapter for type: ${ref.adapterType}` }\n const cfg = ref.connectionConfig ?? {}\n try {\n let sites = await adapter.discoverSites(cfg)\n if (siteIds?.length) sites = sites.filter(s => siteIds.includes(s.siteId))\n const instances: any[] = []\n const failed: any[] = []\n for (const site of sites) {\n try {\n const master = await adapter.fetchMaster(cfg, site)\n const res = await TwinEngine.ingestMaster(domainId, master)\n if (start !== false) {\n // live=true + 어댑터가 openLiveFeed 지원 → mirror(실 이벤트 미러). 아니면 sim 기동(fallback).\n const wentLive = live ? await startReferenceLiveFeed(domainId, ref.adapterType, cfg, site, res.instanceId) : false\n if (!wentLive) await TwinEngine.startFromRegistry(domainId, res.instanceId)\n instances.push({ siteId: site.siteId, instanceId: res.instanceId, spaceId: res.spaceId, mode: wentLive ? 'live' : 'sim', warnings: res.warnings })\n } else {\n instances.push({ siteId: site.siteId, instanceId: res.instanceId, spaceId: res.spaceId, mode: 'provisioned', warnings: res.warnings })\n }\n } catch (e: any) {\n failed.push({ siteId: site.siteId, error: e?.message ?? 'failed' })\n }\n }\n // provenance — 이 레퍼런스가 만든 인스턴스 추적(scopeSpec.produced). 삭제 연쇄·상태 동기·네비게이션 근거.\n const producedNew = instances.map(i => ({ siteId: i.siteId, instanceId: i.instanceId, spaceId: i.spaceId }))\n const prev: any[] = ((ref.scopeSpec as any)?.produced ?? []).filter((p: any) => !producedNew.some(n => n.instanceId === p.instanceId))\n await repo.update(\n { id: ref.id },\n {\n status: 'connected',\n lastSyncedAt: new Date().toISOString(),\n lastError: failed.length ? `${failed.length}개 사이트 실패` : null,\n scopeSpec: { ...((ref.scopeSpec as any) ?? {}), produced: [...prev, ...producedNew] }\n } as any\n )\n return { ok: instances.length > 0, instances, failed }\n } catch (e: any) {\n await repo.update({ id: ref.id }, { status: 'error', lastError: e?.message ?? 'ingest failed' } as any)\n return { ok: false, error: e?.message ?? 'ingest failed' }\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"reference-resolver.js","sourceRoot":"","sources":["../../../server/service/reference/reference-resolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Mutation, Query, Resolver, Directive} from 'type-graphql'\n\nimport { ScalarObject, getRepository } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { applyKnobDefaults, filledKnobKeys } from './knob-defaults.js'\nimport { knobDefaultsFilled } from './reference-master.js'\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinReference } from './twin-reference.js'\nimport { listReferences, getReference } from './reference-registry.js'\nimport { getAdapter, listAdapterTypes, listAdapters } from './reference-adapter.js'\nimport {\n discovered, failed, detailOf,\n referenceNotFound, adapterUnknown, discoveryFailed, discoveryTimedOut\n} from './discovery-result.js'\nimport { startReferenceLiveFeed } from './reference-live.js'\nimport { listTemplates, getTemplate } from './template-registry.js'\n\n/*\n * Face2 레퍼런스 인제스트 채널(ADR-0018) — 등록된 레퍼런스 소스를 열거하고, 골라서 트윈으로 인제스트.\n * \"연결하고 내 것을 불러온다\" — 엔티티는 레퍼런스에서 오지 손배선/발명이 아니다.\n */\n\n/**\n * 발견 조회의 시간 상한 — 15초.\n *\n * 어댑터 계약에 시간 제한이 없다. 주소가 틀린 엔드포인트는 답하지 않고, 그러면 화면이 무한히 돈다 —\n * 사용자에게는 \"실패\" 보다 못한 상태다(무엇을 기다리는지 모른 채 기다린다). 실 시스템 조회가 몇 초\n * 걸리는 것은 정상이므로 넉넉히 두되, 끝은 있어야 한다.\n */\nconst DISCOVER_TIMEOUT_MS = 15_000\nconst TIMEOUT = 'discover-timeout'\n\nfunction withTimeout<T>(work: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(Object.assign(new Error('timeout'), { code: TIMEOUT })), ms)\n work.then(\n v => { clearTimeout(timer); resolve(v) },\n e => { clearTimeout(timer); reject(e) }\n )\n })\n}\n\n@Resolver()\nexport class TwinReferenceResolver {\n /** 등록된 레퍼런스 소스 목록(요약 + 이미 인제스트됐는지). */\n @Query(returns => [ScalarObject], { description: 'List registered reference sources (virtual or real adapters) available to ingest.' })\n async referenceSources(@Ctx() context: ResolverContext): Promise<any[]> {\n const domainId = context.state.domain.id\n const out: any[] = []\n for (const m of listReferences()) {\n const reg = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId: m.source } })\n out.push({\n source: m.source,\n system: m.system,\n siteName: m.siteName,\n locationCount: m.locations.filter(l => l.role === 'location' || l.role === 'both').length,\n areaCount: m.locations.filter(l => l.role === 'area' || l.role === 'both').length,\n equipmentCount: (m.equipment ?? []).length,\n imported: !!reg,\n running: TwinEngine.owns(domainId, m.source)\n })\n }\n return out\n }\n\n /** 소스를 인제스트 → 공간 + 인스턴스 생성(provision). start 면 기동까지. */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Ingest a registered reference source into a twin (space + instance). Optionally start it.' })\n async importFromReference(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('start', { nullable: true }) start?: boolean\n ): Promise<any> {\n const master = getReference(source)\n if (!master) return { ok: false, error: `unknown reference source: ${source}` }\n const domainId = context.state.domain.id\n try {\n const res = await TwinEngine.ingestMaster(domainId, master)\n if (start) await TwinEngine.startFromRegistry(domainId, res.instanceId)\n return { ok: true, instanceId: res.instanceId, spaceId: res.spaceId, warnings: res.warnings }\n } catch (e: any) {\n return { ok: false, error: e?.message || 'ingest failed' }\n }\n }\n\n /** 등록된 트윈 템플릿(파라미터화 아키타입) 목록 — 노브 스키마 포함(클라이언트 폼용). */\n @Query(returns => [ScalarObject], { description: 'List registered twin templates (parameterized archetypes) with their knob schema.' })\n async twinTemplates(@Ctx() _context: ResolverContext): Promise<any[]> {\n return listTemplates().map(t => ({ id: t.id, label: t.label, system: t.system, description: t.description, detail: t.detail, knobs: t.knobs }))\n }\n\n /** 템플릿 + 노브 → 합성 마스터 → 인제스트(+기동+시나리오). 레퍼런스 import 와 같은 경로, 원천만 합성. */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Instantiate a twin template with params → synthetic master → ingest (+start+scenario). Returns {ok, instanceId, spaceId}.' })\n async createFromTemplate(\n @Arg('templateId') templateId: string,\n @Arg('params', type => ScalarObject) params: any,\n @Ctx() context: ResolverContext,\n @Arg('start', { nullable: true }) start?: boolean,\n @Arg('spaceId', { nullable: true, description: 'Existing space to co-locate this twin into (add a lens to a site). Omit to create its own space.' }) spaceId?: string\n ): Promise<any> {\n const tpl = getTemplate(templateId)\n if (!tpl) return { ok: false, error: `unknown template: ${templateId}` }\n const domainId = context.state.domain.id\n try {\n /*\n * **빠진 노브를 서버가 채운다.** 기본값을 아는 곳은 노브 스키마(계약)인데 그것을 적용하는 곳이\n * 위자드뿐이었다 — 그래서 화면을 거치지 않는 호출자(AI·스크립트·API)가 파라미터를 일부만 주면\n * 템플릿 안에서 발생률이 0 이 되고 **아무것도 하지 않는 트윈**이 조용히 만들어졌다.\n * 채운 노브 이름은 경고로 함께 돌려준다 — 조용히 채우는 것도 조용히 비우는 것만큼 위험하다.\n */\n const filled = filledKnobKeys(tpl.knobs, params)\n const effective = applyKnobDefaults(tpl.knobs, params)\n const { master, scenario } = tpl.build(effective)\n /* 공간 선택은 템플릿을 거치지 않는다 — 템플릿마다 이 노브를 알고 있어야 한다면 새 템플릿이\n 조용히 무시하게 된다. 합성된 마스터에 한 곳에서 얹는다(레퍼런스 인제스트와 같은 경로). */\n const res = await TwinEngine.ingestMaster(domainId, master, { spaceId })\n if (start !== false) {\n await TwinEngine.startFromRegistry(domainId, res.instanceId)\n if (scenario) {\n const runtime = TwinEngine.runtime(domainId, res.instanceId)\n if (runtime) {\n runtime.scenario.load(scenario)\n runtime.scenario.start()\n }\n }\n }\n const warnings = filled.length ? [knobDefaultsFilled(filled), ...res.warnings] : res.warnings\n return { ok: true, instanceId: res.instanceId, spaceId: res.spaceId, warnings }\n } catch (e: any) {\n return { ok: false, error: e?.message || 'template instantiation failed' }\n }\n }\n\n /* ── 레퍼런스 관리(엔티티 기반·테넌트 스코프) — reference-management P1 ────────\n * 전역 인메모리(referenceSources/importFromReference)와 공존. 이쪽은 TwinReference 행 + 어댑터 레지스트리.\n */\n\n @Query(returns => [ScalarObject], { description: 'List tenant-scoped persisted twin references (adapter-backed).' })\n async twinReferences(@Ctx() context: ResolverContext): Promise<any[]> {\n const domainId = context.state.domain.id\n const rows = await getRepository(TwinReference).find({ where: { domain: { id: domainId } } })\n // provenance 라이브 대조 — 지워진 트윈은 producedCount 에서 자동 제외(상태 동기의 lazy 방식).\n const liveIds = new Set((await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })).map(i => i.instanceId))\n return rows.map(r => {\n const produced = (((r.scopeSpec as any)?.produced ?? []) as any[]).filter(p => liveIds.has(p.instanceId))\n return {\n source: r.source, system: r.system, siteName: r.siteName, description: r.description,\n adapterType: r.adapterType, status: r.status, lastSyncedAt: r.lastSyncedAt, lastError: r.lastError,\n producedCount: produced.length, produced\n }\n })\n }\n\n @Query(returns => [String], { description: 'List registered reference adapter type keys.' })\n referenceAdapterTypes(): string[] {\n return listAdapterTypes()\n }\n\n /**\n * 인티그레이션 그룹핑 (reference-management §2.3·D11) — 산출물을 커넥터 타입 ▸ Connection ▸ 인스턴스 2단으로.\n * 트윈-네이티브 온톨로지(integration 무의존): TwinReference 가 그룹핑 노드(source=connectionName),\n * scopeSpec.connectorType 로 상위 분류. producedCount 는 라이브 인스턴스로 대조(지워진 트윈 제외).\n */\n @Query(returns => [ScalarObject], { description: 'Group integration items 2-tier: connector type ▸ connection ▸ produced twins. (reference-management §2.3)' })\n async twinConnections(@Ctx() context: ResolverContext): Promise<any[]> {\n const domainId = context.state.domain.id\n const rows = await getRepository(TwinReference).find({ where: { domain: { id: domainId } } })\n const liveIds = new Set((await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })).map(i => i.instanceId))\n const groups = new Map<string, any[]>()\n for (const r of rows) {\n const connectorType = (r.scopeSpec as any)?.connectorType ?? r.adapterType\n const producedCount = (((r.scopeSpec as any)?.produced ?? []) as any[]).filter(p => liveIds.has(p.instanceId)).length\n const conn = { source: r.source, name: r.siteName, status: r.status, adapterType: r.adapterType, producedCount, lastSyncedAt: r.lastSyncedAt }\n if (!groups.has(connectorType)) groups.set(connectorType, [])\n groups.get(connectorType)!.push(conn)\n }\n return [...groups.entries()].map(([connectorType, connections]) => ({\n connectorType,\n connectionCount: connections.length,\n instanceCount: connections.reduce((s, c) => s + c.producedCount, 0),\n connections\n }))\n }\n\n /** 한 Connection 그룹 노드 상세 — 그 아래 생성된 트윈 인스턴스(라이브 대조·상태·기동여부). */\n @Query(returns => ScalarObject, { nullable: true, description: 'One connection grouping location with its produced twin instances (live-checked). (reference-management §2.3)' })\n async twinConnection(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any | null> {\n const domainId = context.state.domain.id\n const r = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source } })\n if (!r) return null\n const produced = ((r.scopeSpec as any)?.produced ?? []) as any[]\n const instMap = new Map((await getRepository(TwinInstance).find({ where: { domain: { id: domainId } } })).map(i => [i.instanceId, i]))\n const instances = produced\n .filter(p => instMap.has(p.instanceId))\n .map(p => {\n const inst = instMap.get(p.instanceId) as any\n return { instanceId: p.instanceId, spaceId: p.spaceId, siteId: p.siteId, kind: inst.kind, status: inst.status, running: TwinEngine.owns(domainId, p.instanceId) }\n })\n return {\n source: r.source,\n connectorType: (r.scopeSpec as any)?.connectorType ?? r.adapterType,\n name: r.siteName,\n status: r.status,\n system: r.system,\n lastSyncedAt: r.lastSyncedAt,\n instanceCount: instances.length,\n instances\n }\n }\n\n /** 단건 상세(뷰/편집) — connectionConfig 포함, 어댑터 스키마의 secret 필드는 마스킹(있으면 '••••••'). */\n @Query(returns => ScalarObject, { nullable: true, description: 'Get one tenant-scoped reference with its connection config (secret fields masked) for view/edit.' })\n async twinReference(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any | null> {\n const r = await getRepository(TwinReference).findOne({ where: { domain: { id: context.state.domain.id }, source } })\n if (!r) return null\n const secretKeys = new Set((getAdapter(r.adapterType)?.meta?.configSchema ?? []).filter(f => f.secret).map(f => f.key))\n const cfg: any = {}\n for (const [k, v] of Object.entries((r.connectionConfig as any) ?? {})) cfg[k] = secretKeys.has(k) ? (v ? '••••••' : '') : v\n return {\n source: r.source, system: r.system, siteName: r.siteName, description: r.description,\n adapterType: r.adapterType, connectionConfig: cfg, status: r.status, lastSyncedAt: r.lastSyncedAt, lastError: r.lastError\n }\n }\n\n @Query(returns => [ScalarObject], { description: 'List reference connector metadata (label, domain, config schema, availability) for the connect UI.' })\n referenceAdapters(): any[] {\n return listAdapters().map(a => ({ type: a.type, ...(a.meta ?? {}) }))\n }\n\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Create or update a tenant-scoped twin reference (persisted).' })\n async saveTwinReference(\n @Arg('source') source: string,\n @Arg('patch', type => ScalarObject) patch: any,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinReference)\n const existing = await repo.findOne({ where: { domain: { id: domainId }, source } })\n const saved = await repo.save(\n repo.create({\n ...(existing ?? {}),\n domain: { id: domainId } as any,\n source,\n system: patch.system ?? existing?.system,\n siteName: patch.siteName ?? existing?.siteName,\n description: patch.description ?? existing?.description,\n adapterType: patch.adapterType ?? existing?.adapterType,\n // 필드 단위 병합 — 편집 시 생략된 키(예: 마스킹된 secret)는 기존 값 유지.\n connectionConfig: patch.connectionConfig\n ? { ...((existing?.connectionConfig as any) ?? {}), ...patch.connectionConfig }\n : existing?.connectionConfig,\n mappingSpec: patch.mappingSpec ?? existing?.mappingSpec,\n scopeSpec: patch.scopeSpec ?? existing?.scopeSpec,\n status: patch.status ?? existing?.status ?? 'draft'\n })\n )\n return { ok: true, source: saved.source }\n }\n\n /** 연결 해제 — removeTwins=true 면 이 레퍼런스가 만든 트윈(provenance)도 함께 제거(라이프사이클 연쇄). 기본은 트윈 보존(분리). */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => Boolean, { description: 'Delete a tenant-scoped reference. If removeTwins, also remove the twin instances it produced (provenance cascade); otherwise twins are kept (detached).' })\n async deleteTwinReference(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('removeTwins', { nullable: true }) removeTwins?: boolean\n ): Promise<boolean> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: domainId }, source } })\n if (removeTwins && ref) {\n for (const p of (((ref.scopeSpec as any)?.produced ?? []) as any[])) {\n try {\n await TwinEngine.remove(domainId, p.instanceId)\n } catch {\n /* 이미 없거나 실패 — 연쇄는 best-effort. */\n }\n }\n }\n await repo.delete({ domain: { id: domainId } as any, source })\n return true\n }\n\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Test a reference connection via its adapter; updates status.' })\n async testReferenceConnection(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any> {\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: context.state.domain.id }, source } })\n if (!ref) return { ok: false, error: `unknown reference: ${source}` }\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return { ok: false, error: `no adapter for type: ${ref.adapterType}` }\n try {\n const res = await adapter.testConnection(ref.connectionConfig ?? {})\n await repo.update({ id: ref.id }, { status: res.ok ? 'connected' : 'error', lastError: res.error ?? null } as any)\n return res\n } catch (e: any) {\n return { ok: false, error: e?.message ?? 'test failed' }\n }\n }\n\n /**\n * 어댑터 기반 인제스트 — discoverSites → 사이트별 fetchMaster → ingestMaster (fan-out, §2.2·§4.2).\n * P1 은 대개 N=1(virtual/단일). start 면 각 인스턴스 기동. 라이브 피드·mode 는 face2-inbound-live 소유.\n */\n /** 레퍼런스가 노출하는 사이트/공장 발견 — 트윈 생성 시 \"어느 공장\" 선택용(§2.2). */\n @Query(returns => ScalarObject, { description: 'Discover sites/factories exposed by a reference. Returns { sites, error? } — an empty list with no error means the system genuinely has none, which is different from a failure.' })\n async discoverReferenceSites(@Arg('source') source: string, @Ctx() context: ResolverContext): Promise<any> {\n /*\n * **\"못 찾았다\" 와 \"없다\" 를 가른다.** 예전에는 넷을 빈 배열 하나로 접었고(레퍼런스 없음·어댑터\n * 미상·조회 실패·정말 0건), 화면은 그 모두를 \"사이트를 찾지 못했습니다\" 라고만 말했다. 실 시스템\n * 연결에서 가장 자주 막히는 자리인데 자격이 틀렸는지 주소가 틀렸는지 알 수 없었다.\n * 판정과 문장 형태는 `discovery-result`(순수)가 갖는다.\n */\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: context.state.domain.id }, source } })\n if (!ref) return failed(referenceNotFound(source))\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return failed(adapterUnknown(ref.adapterType, source))\n try {\n /*\n * **기다려도 답이 없으면 사유를 준다.** 어댑터 계약에 시간 제한이 없어서, 주소가 틀린 엔드포인트는\n * 화면을 무한히 돌게 만들었다 — 무한히 도는 화면은 조용한 실패의 다른 얼굴이다.\n * 상한은 여기서 정한다(어댑터마다 다르게 두면 사용자가 어느 것을 기다리는지 알 수 없다).\n */\n const sites = await withTimeout(adapter.discoverSites(ref.connectionConfig ?? {}), DISCOVER_TIMEOUT_MS)\n return discovered(sites)\n } catch (e: any) {\n if (e?.code === TIMEOUT) return failed(discoveryTimedOut(source, DISCOVER_TIMEOUT_MS / 1000))\n return failed(discoveryFailed(source, detailOf(e)))\n }\n }\n\n /**\n * 트윈 생성 — 레퍼런스에서 사이트 발견 → (siteIds 있으면 그 공장만) → fetchMaster → provision. 사이트별 resilient.\n * 여러 공장을 관할하는 소스는 siteIds 로 \"어느 공장\"을 골라 생성(1:N, §2.1·§2.2).\n */\n @Directive('@privilege(category: \"twin\", privilege: \"mutation\", domainOwnerGranted: true, superUserGranted: true)')\n @Mutation(returns => ScalarObject, { description: 'Create twins from a reference: discover sites → filter by siteIds (if given) → fetch master(s) → provision. start=false to only provision; live=true to run as a mirror (adapter openLiveFeed → live projector) instead of sim.' })\n async importTwinReference(\n @Arg('source') source: string,\n @Ctx() context: ResolverContext,\n @Arg('siteIds', type => [String], { nullable: true }) siteIds?: string[],\n @Arg('start', { nullable: true }) start?: boolean,\n @Arg('live', { nullable: true }) live?: boolean\n ): Promise<any> {\n const domainId = context.state.domain.id\n const repo = getRepository(TwinReference)\n const ref = await repo.findOne({ where: { domain: { id: domainId }, source } })\n if (!ref) return { ok: false, error: `unknown reference: ${source}` }\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return { ok: false, error: `no adapter for type: ${ref.adapterType}` }\n const cfg = ref.connectionConfig ?? {}\n try {\n let sites = await adapter.discoverSites(cfg)\n if (siteIds?.length) sites = sites.filter(s => siteIds.includes(s.siteId))\n const instances: any[] = []\n const failed: any[] = []\n for (const site of sites) {\n try {\n const master = await adapter.fetchMaster(cfg, site)\n const res = await TwinEngine.ingestMaster(domainId, master)\n if (start !== false) {\n // live=true + 어댑터가 openLiveFeed 지원 → mirror(실 이벤트 미러). 아니면 sim 기동(fallback).\n const wentLive = live ? await startReferenceLiveFeed(domainId, ref.adapterType, cfg, site, res.instanceId) : false\n if (!wentLive) await TwinEngine.startFromRegistry(domainId, res.instanceId)\n instances.push({ siteId: site.siteId, instanceId: res.instanceId, spaceId: res.spaceId, mode: wentLive ? 'live' : 'sim', warnings: res.warnings })\n } else {\n instances.push({ siteId: site.siteId, instanceId: res.instanceId, spaceId: res.spaceId, mode: 'provisioned', warnings: res.warnings })\n }\n } catch (e: any) {\n failed.push({ siteId: site.siteId, error: e?.message ?? 'failed' })\n }\n }\n // provenance — 이 레퍼런스가 만든 인스턴스 추적(scopeSpec.produced). 삭제 연쇄·상태 동기·네비게이션 근거.\n const producedNew = instances.map(i => ({ siteId: i.siteId, instanceId: i.instanceId, spaceId: i.spaceId }))\n const prev: any[] = ((ref.scopeSpec as any)?.produced ?? []).filter((p: any) => !producedNew.some(n => n.instanceId === p.instanceId))\n await repo.update(\n { id: ref.id },\n {\n status: 'connected',\n lastSyncedAt: new Date().toISOString(),\n /*\n * **영어 canonical 로 남긴다.** 이 값은 DB 에 저장되고 연결 화면이 그대로 뿌린다 — 예전에는\n * 한글 산문(`N개 사이트 실패`)이라 다섯 언어 화면에 한글이 새어 나갔다. 어댑터가 주는 사유도\n * 같은 필드에 들어오므로(그것은 원 시스템의 말이다) 키가 아니라 영어 문장으로 통일한다.\n * 어느 사이트가 왜 실패했는지는 `failed[]` 가 답한다 — 화면이 그것을 보여 준다.\n */\n lastError: failed.length ? `${failed.length} of ${sites.length} site(s) failed: ${failed.map((f: any) => f.siteId).join(', ')}` : null,\n scopeSpec: { ...((ref.scopeSpec as any) ?? {}), produced: [...prev, ...producedNew] }\n } as any\n )\n return { ok: instances.length > 0, instances, failed }\n } catch (e: any) {\n await repo.update({ id: ref.id }, { status: 'error', lastError: e?.message ?? 'ingest failed' } as any)\n return { ok: false, error: e?.message ?? 'ingest failed' }\n }\n }\n}\n"]}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
1
|
export declare class TwinAttentionQuery {
|
|
2
|
-
twinAttentions(
|
|
2
|
+
twinAttentions(context: ResolverContext, instanceId?: string, spaceId?: string,
|
|
3
|
+
/** 상위 몇 건만 — 말하지 않으면 자르지 않는다. 전체 개수는 `twinAttentionDigest` 가 함께 답한다. */
|
|
4
|
+
limit?: number): Promise<any[]>;
|
|
5
|
+
/**
|
|
6
|
+
* 잘랐다면 **몇 건을 잘랐는지**와 자리 색 요약까지 — 목록만 주면 화면이 "N건 더" 를 말할 수 없다.
|
|
7
|
+
* 자리별 최고 심각도는 **전량을 근거로** 접는다(상위 N 으로 접으면 20위 밖 신호를 가진 자리가 색을 잃는다).
|
|
8
|
+
*/
|
|
9
|
+
twinAttentionDigest(context: ResolverContext, spaceId?: string, instanceId?: string, limit?: number): Promise<any>;
|
|
3
10
|
}
|
|
@@ -5,6 +5,7 @@ const tslib_1 = require("tslib");
|
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
6
|
const shell_1 = require("@things-factory/shell");
|
|
7
7
|
const index_js_1 = require("../../engine/index.js");
|
|
8
|
+
const attention_digest_js_1 = require("../../engine/attention-digest.js");
|
|
8
9
|
/*
|
|
9
10
|
* 주목 신호(Attention) 질의 — 현재 스냅샷의 요약된 "봐야 할 것".
|
|
10
11
|
* 커널 computeAttentions() 파생: severity(ISA-18.2/IEC 62682) · state(OPC UA A&C) ·
|
|
@@ -13,13 +14,29 @@ const index_js_1 = require("../../engine/index.js");
|
|
|
13
14
|
* (실시간 스트림은 twinState subscription 이 attentions 를 포함. 이건 one-shot '질의' 표면.)
|
|
14
15
|
*/
|
|
15
16
|
let TwinAttentionQuery = class TwinAttentionQuery {
|
|
16
|
-
async twinAttentions(instanceId,
|
|
17
|
-
if (
|
|
17
|
+
async twinAttentions(context, instanceId, spaceId, limit) {
|
|
18
|
+
if (spaceId)
|
|
19
|
+
return (await index_js_1.TwinEngine.attentionsOfSpace(context.state.domain.id, spaceId, limit ?? undefined)).attentions;
|
|
20
|
+
if (!instanceId || !index_js_1.TwinEngine.owns(context.state.domain.id, instanceId))
|
|
18
21
|
return []; // 테넌트 격리
|
|
19
22
|
// 라이브 커널 스냅샷(fresh) 우선 — snapshot()=resync() 는 캐시라 커맨드 델타 지연(recover 와 동일 원천 사용).
|
|
20
|
-
const kernel = index_js_1.TwinEngine.kernel(instanceId);
|
|
21
|
-
const snap = kernel?.getSnapshot?.() ?? index_js_1.TwinEngine.snapshot(instanceId);
|
|
22
|
-
|
|
23
|
+
const kernel = index_js_1.TwinEngine.kernel(context.state.domain.id, instanceId);
|
|
24
|
+
const snap = kernel?.getSnapshot?.() ?? index_js_1.TwinEngine.snapshot(context.state.domain.id, instanceId);
|
|
25
|
+
const list = snap?.attentions ?? [];
|
|
26
|
+
return limit && limit > 0 ? (0, attention_digest_js_1.digestAttentions)(list, limit).attentions : list;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 잘랐다면 **몇 건을 잘랐는지**와 자리 색 요약까지 — 목록만 주면 화면이 "N건 더" 를 말할 수 없다.
|
|
30
|
+
* 자리별 최고 심각도는 **전량을 근거로** 접는다(상위 N 으로 접으면 20위 밖 신호를 가진 자리가 색을 잃는다).
|
|
31
|
+
*/
|
|
32
|
+
async twinAttentionDigest(context, spaceId, instanceId, limit) {
|
|
33
|
+
if (spaceId)
|
|
34
|
+
return index_js_1.TwinEngine.attentionsOfSpace(context.state.domain.id, spaceId, limit ?? undefined);
|
|
35
|
+
if (!instanceId || !index_js_1.TwinEngine.owns(context.state.domain.id, instanceId))
|
|
36
|
+
return { attentions: [], attentionTotal: 0, severityByLocation: {} };
|
|
37
|
+
const kernel = index_js_1.TwinEngine.kernel(context.state.domain.id, instanceId);
|
|
38
|
+
const snap = kernel?.getSnapshot?.() ?? index_js_1.TwinEngine.snapshot(context.state.domain.id, instanceId);
|
|
39
|
+
return (0, attention_digest_js_1.digestAttentions)((snap?.attentions ?? []).map((a) => ({ ...a, instanceId })), limit ?? undefined);
|
|
23
40
|
}
|
|
24
41
|
};
|
|
25
42
|
exports.TwinAttentionQuery = TwinAttentionQuery;
|
|
@@ -27,12 +44,26 @@ tslib_1.__decorate([
|
|
|
27
44
|
(0, type_graphql_1.Query)(returns => [shell_1.ScalarObject], {
|
|
28
45
|
description: 'Active attention signals (things to look at) derived from the current twin snapshot — severity (ISA-18.2), lifecycle state (OPC UA A&C), space anchor, and suggested action.'
|
|
29
46
|
}),
|
|
30
|
-
tslib_1.__param(0, (0, type_graphql_1.
|
|
31
|
-
tslib_1.__param(1, (0, type_graphql_1.
|
|
47
|
+
tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
|
|
48
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('instanceId', { nullable: true })),
|
|
49
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('spaceId', { nullable: true })),
|
|
50
|
+
tslib_1.__param(3, (0, type_graphql_1.Arg)('limit', type => type_graphql_1.Int, { nullable: true })),
|
|
32
51
|
tslib_1.__metadata("design:type", Function),
|
|
33
|
-
tslib_1.__metadata("design:paramtypes", [String,
|
|
52
|
+
tslib_1.__metadata("design:paramtypes", [Object, String, String, Number]),
|
|
34
53
|
tslib_1.__metadata("design:returntype", Promise)
|
|
35
54
|
], TwinAttentionQuery.prototype, "twinAttentions", null);
|
|
55
|
+
tslib_1.__decorate([
|
|
56
|
+
(0, type_graphql_1.Query)(returns => shell_1.ScalarObject, {
|
|
57
|
+
description: 'Attention signals for a space (all its lenses) or one twin, with the total count and the per-location highest severity folded from all of them.'
|
|
58
|
+
}),
|
|
59
|
+
tslib_1.__param(0, (0, type_graphql_1.Ctx)()),
|
|
60
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('spaceId', { nullable: true })),
|
|
61
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('instanceId', { nullable: true })),
|
|
62
|
+
tslib_1.__param(3, (0, type_graphql_1.Arg)('limit', type => type_graphql_1.Int, { nullable: true })),
|
|
63
|
+
tslib_1.__metadata("design:type", Function),
|
|
64
|
+
tslib_1.__metadata("design:paramtypes", [Object, String, String, Number]),
|
|
65
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
66
|
+
], TwinAttentionQuery.prototype, "twinAttentionDigest", null);
|
|
36
67
|
exports.TwinAttentionQuery = TwinAttentionQuery = tslib_1.__decorate([
|
|
37
68
|
(0, type_graphql_1.Resolver)()
|
|
38
69
|
], TwinAttentionQuery);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"twin-attention-query.js","sourceRoot":"","sources":["../../../server/service/twin-attention/twin-attention-query.ts"],"names":[],"mappings":";;;;AAAA,+
|
|
1
|
+
{"version":3,"file":"twin-attention-query.js","sourceRoot":"","sources":["../../../server/service/twin-attention/twin-attention-query.ts"],"names":[],"mappings":"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","sourcesContent":["import { Arg, Ctx, Int, Query, Resolver } from 'type-graphql'\n\nimport { ScalarObject } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\nimport { digestAttentions } from '../../engine/attention-digest.js'\n\n/*\n * 주목 신호(Attention) 질의 — 현재 스냅샷의 요약된 \"봐야 할 것\".\n * 커널 computeAttentions() 파생: severity(ISA-18.2/IEC 62682) · state(OPC UA A&C) ·\n * anchor(locationId/moverId/orderId = 공간 위치) · suggestedAction(조치 제안). kind 는 도메인 소유(무방언).\n * full StateSnapshot 대신 이 경량 목록을 AI read 도구·insight UI 가 소싱(대용량 덤프 회피).\n * (실시간 스트림은 twinState subscription 이 attentions 를 포함. 이건 one-shot '질의' 표면.)\n */\n@Resolver()\nexport class TwinAttentionQuery {\n @Query(returns => [ScalarObject], {\n description: 'Active attention signals (things to look at) derived from the current twin snapshot — severity (ISA-18.2), lifecycle state (OPC UA A&C), space anchor, and suggested action.'\n })\n async twinAttentions(\n @Ctx() context: ResolverContext,\n @Arg('instanceId', { nullable: true }) instanceId?: string,\n /*\n * **공간으로 물으면 그 현장의 모든 렌즈에서 모아 답한다** — 한 현실을 WMS·MES·YMS 가 함께 비추므로\n * \"이 현장에서 봐야 할 것\" 은 렌즈 하나로 답할 수 없다. 예전에는 화면이 인스턴스마다 물어 손으로\n * 합쳤고, 그러면 정렬 규칙이 화면마다 갈린다.\n *\n * 경고는 **합집합이 그대로 뜻이 있는 유일한 렌즈**다. 예측은 합칠 수 없다(P50 두 개를 더할 수 없다) —\n * 그래서 예측은 여전히 인스턴스별로 답하고 화면이 나란히 놓는다.\n */\n @Arg('spaceId', { nullable: true }) spaceId?: string,\n /** 상위 몇 건만 — 말하지 않으면 자르지 않는다. 전체 개수는 `twinAttentionDigest` 가 함께 답한다. */\n @Arg('limit', type => Int, { nullable: true }) limit?: number\n ): Promise<any[]> {\n if (spaceId) return (await TwinEngine.attentionsOfSpace(context.state.domain.id, spaceId, limit ?? undefined)).attentions\n if (!instanceId || !TwinEngine.owns(context.state.domain.id, instanceId)) return [] // 테넌트 격리\n // 라이브 커널 스냅샷(fresh) 우선 — snapshot()=resync() 는 캐시라 커맨드 델타 지연(recover 와 동일 원천 사용).\n const kernel = TwinEngine.kernel(context.state.domain.id, instanceId)\n const snap = kernel?.getSnapshot?.() ?? TwinEngine.snapshot(context.state.domain.id, instanceId)\n const list = snap?.attentions ?? []\n return limit && limit > 0 ? digestAttentions(list, limit).attentions : list\n }\n\n /**\n * 잘랐다면 **몇 건을 잘랐는지**와 자리 색 요약까지 — 목록만 주면 화면이 \"N건 더\" 를 말할 수 없다.\n * 자리별 최고 심각도는 **전량을 근거로** 접는다(상위 N 으로 접으면 20위 밖 신호를 가진 자리가 색을 잃는다).\n */\n @Query(returns => ScalarObject, {\n description: 'Attention signals for a space (all its lenses) or one twin, with the total count and the per-location highest severity folded from all of them.'\n })\n async twinAttentionDigest(\n @Ctx() context: ResolverContext,\n @Arg('spaceId', { nullable: true }) spaceId?: string,\n @Arg('instanceId', { nullable: true }) instanceId?: string,\n @Arg('limit', type => Int, { nullable: true }) limit?: number\n ): Promise<any> {\n if (spaceId) return TwinEngine.attentionsOfSpace(context.state.domain.id, spaceId, limit ?? undefined)\n if (!instanceId || !TwinEngine.owns(context.state.domain.id, instanceId)) return { attentions: [], attentionTotal: 0, severityByLocation: {} }\n const kernel = TwinEngine.kernel(context.state.domain.id, instanceId)\n const snap = kernel?.getSnapshot?.() ?? TwinEngine.snapshot(context.state.domain.id, instanceId)\n return digestAttentions((snap?.attentions ?? []).map((a: any) => ({ ...a, instanceId })), limit ?? undefined)\n }\n}\n"]}
|
|
@@ -3,6 +3,8 @@ export declare class TwinControlMutation {
|
|
|
3
3
|
dispatchTwinCommand(instanceId: string, command: any, context: ResolverContext): Promise<{
|
|
4
4
|
accepted: boolean;
|
|
5
5
|
error?: string;
|
|
6
|
+
errorCode?: string;
|
|
7
|
+
errorParams?: Record<string, string | number>;
|
|
6
8
|
}>;
|
|
7
9
|
/** Scenario 채널 — 생성기 시나리오 제어(load/start/pause/setSpeed). */
|
|
8
10
|
controlTwinScenario(instanceId: string, action: string, context: ResolverContext, scenario?: any): Promise<boolean>;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.TwinControlMutation = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const twin_kernel_1 = require("@operato/twin-kernel");
|
|
6
7
|
const shell_1 = require("@things-factory/shell");
|
|
7
8
|
const index_js_1 = require("../../engine/index.js");
|
|
8
9
|
/*
|
|
@@ -17,31 +18,47 @@ let TwinControlMutation = class TwinControlMutation {
|
|
|
17
18
|
/** Command 채널 — 오더 hold/resume/release 등. 커널 dispatch 로 위임, ack{accepted,error} 반환. */
|
|
18
19
|
async dispatchTwinCommand(instanceId, command, context) {
|
|
19
20
|
const domainId = context.state.domain?.id;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
if (!domainId)
|
|
22
|
+
return { accepted: false, error: 'no-domain', errorCode: 'no-domain' };
|
|
23
|
+
/*
|
|
24
|
+
* 라우팅은 엔진이 한다 — 예전에는 여기서 `inst.runtime.dispatch` 를 곧바로 불렀고, `runtime` 이
|
|
25
|
+
* 시뮬에만 있어서 미러 트윈에서는 이 한 줄이 TypeError 로 터졌다(깔끔한 거절이 아니라 실패).
|
|
26
|
+
* 권위(모드) × 성격(주석/액추에이션) 판정은 한 곳에만 둔다.
|
|
27
|
+
*/
|
|
28
|
+
const ack = await index_js_1.TwinEngine.dispatchCommand(domainId, instanceId, command);
|
|
26
29
|
/* 라이브 구조 변이(resource.add)는 저장 board 에도 반영 — 프로비저닝 편집기·재기동이 추가분을 잃지 않게. */
|
|
27
30
|
if (ack?.accepted && command?.type === 'resource.add') {
|
|
28
31
|
await index_js_1.TwinEngine.syncBoardEquipment(domainId, instanceId).catch(err => console.error('twin syncBoardEquipment fail', err));
|
|
29
32
|
}
|
|
30
|
-
|
|
33
|
+
/* 거절 사유는 **언어 중립 코드**로 함께 돌려준다 — 화면이 `twin.cmderr.<code>` 로 사람 말을 만든다. */
|
|
34
|
+
return { accepted: !!ack?.accepted, error: ack?.error, errorCode: ack?.errorCode, errorParams: ack?.errorParams };
|
|
31
35
|
}
|
|
32
36
|
/** Scenario 채널 — 생성기 시나리오 제어(load/start/pause/setSpeed). */
|
|
33
37
|
async controlTwinScenario(instanceId, action, context, scenario) {
|
|
34
38
|
const domainId = context.state.domain?.id;
|
|
35
|
-
|
|
36
|
-
if (!
|
|
39
|
+
/* 테넌트 격리 — 레지스트리를 직접 색인하지 않는다(키에 도메인이 들어 있다). */
|
|
40
|
+
if (!index_js_1.TwinEngine.owns(domainId, instanceId))
|
|
37
41
|
return false;
|
|
38
|
-
const runtime =
|
|
42
|
+
const runtime = index_js_1.TwinEngine.runtime(domainId, instanceId);
|
|
39
43
|
/*
|
|
40
44
|
* 자극 주입 가드 — mirror 트윈(외부 실물이 진실)은 커널 시나리오 엔진이 없다(startLive=projector, runtime 없음).
|
|
41
45
|
* what-if 를 여기에 주입하면 현실을 오염시키므로 거부한다(sim-experiment/sim-world 만 자극 가능). silent throw 방지.
|
|
42
46
|
*/
|
|
43
47
|
if (!runtime?.scenario)
|
|
44
48
|
return false;
|
|
49
|
+
/*
|
|
50
|
+
* **잘못된 선언은 문 앞에서 막는다.** 예전에는 검증 없이 실었고, 다음 tick 에서 `rate.meanPerHour`
|
|
51
|
+
* 를 읽다 터져 **서버 프로세스가 내려갔다**(클라이언트가 보낸 값 하나로 앱 전체가 죽었다).
|
|
52
|
+
* 규칙은 커널이 들고 있다(계약의 주인) — 호스트가 따로 만들면 방언이 생긴다.
|
|
53
|
+
*/
|
|
54
|
+
if (action === 'load') {
|
|
55
|
+
const v = (0, twin_kernel_1.validateScenario)(scenario);
|
|
56
|
+
if (v.ok === false) {
|
|
57
|
+
/* 사유를 로그로 남긴다 — 이 뮤테이션의 반환은 Boolean 계약이라 사유를 실어 보낼 자리가 없다. */
|
|
58
|
+
console.warn(`[twin] scenario rejected for "${instanceId}": ${v.errorCode} ${JSON.stringify(v.errorParams ?? {})}`);
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
45
62
|
if (action === 'load' && scenario)
|
|
46
63
|
runtime.scenario.load(scenario);
|
|
47
64
|
else if (action === 'start')
|
|
@@ -57,6 +74,7 @@ let TwinControlMutation = class TwinControlMutation {
|
|
|
57
74
|
};
|
|
58
75
|
exports.TwinControlMutation = TwinControlMutation;
|
|
59
76
|
tslib_1.__decorate([
|
|
77
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
60
78
|
(0, type_graphql_1.Mutation)(returns => shell_1.ScalarObject, { description: 'dispatch a twin command (order.hold/resume/release …). Returns {accepted, error?}.' }),
|
|
61
79
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
|
|
62
80
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('command', type => shell_1.ScalarObject)),
|
|
@@ -66,6 +84,7 @@ tslib_1.__decorate([
|
|
|
66
84
|
tslib_1.__metadata("design:returntype", Promise)
|
|
67
85
|
], TwinControlMutation.prototype, "dispatchTwinCommand", null);
|
|
68
86
|
tslib_1.__decorate([
|
|
87
|
+
(0, type_graphql_1.Directive)('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)'),
|
|
69
88
|
(0, type_graphql_1.Mutation)(returns => Boolean, { description: 'control twin scenario (load|start|pause|setSpeed)' }),
|
|
70
89
|
tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
|
|
71
90
|
tslib_1.__param(1, (0, type_graphql_1.Arg)('action')),
|