@things-factory/headless-twin 10.0.12 โ 10.0.13
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/canonical-ingest.d.ts +57 -2
- package/dist-server/engine/canonical-ingest.js +43 -2
- package/dist-server/engine/canonical-ingest.js.map +1 -1
- package/dist-server/engine/command-routing.js +1 -1
- package/dist-server/engine/command-routing.js.map +1 -1
- package/dist-server/engine/index.d.ts +3 -0
- package/dist-server/engine/index.js +4 -0
- package/dist-server/engine/index.js.map +1 -1
- package/dist-server/engine/ingest-health.d.ts +335 -0
- package/dist-server/engine/ingest-health.js +434 -0
- package/dist-server/engine/ingest-health.js.map +1 -0
- package/dist-server/engine/integration-coverage.d.ts +76 -0
- package/dist-server/engine/integration-coverage.js +73 -0
- package/dist-server/engine/integration-coverage.js.map +1 -0
- package/dist-server/engine/integration-probes.d.ts +65 -0
- package/dist-server/engine/integration-probes.js +100 -0
- package/dist-server/engine/integration-probes.js.map +1 -0
- package/dist-server/engine/integration-runner.d.ts +45 -0
- package/dist-server/engine/integration-runner.js +59 -0
- package/dist-server/engine/integration-runner.js.map +1 -0
- package/dist-server/engine/integration-target-profile.d.ts +57 -0
- package/dist-server/engine/integration-target-profile.js +79 -0
- package/dist-server/engine/integration-target-profile.js.map +1 -0
- package/dist-server/engine/kpi-fold.d.ts +27 -0
- package/dist-server/engine/kpi-fold.js +47 -4
- package/dist-server/engine/kpi-fold.js.map +1 -1
- package/dist-server/engine/kpi-query.js +128 -14
- package/dist-server/engine/kpi-query.js.map +1 -1
- package/dist-server/engine/live-feed-registry.js +2 -16
- package/dist-server/engine/live-feed-registry.js.map +1 -1
- package/dist-server/engine/load-meter.d.ts +1 -1
- package/dist-server/engine/load-meter.js +12 -3
- package/dist-server/engine/load-meter.js.map +1 -1
- package/dist-server/engine/log.d.ts +18 -0
- package/dist-server/engine/log.js +80 -0
- package/dist-server/engine/log.js.map +1 -0
- package/dist-server/engine/loop-lag.d.ts +54 -0
- package/dist-server/engine/loop-lag.js +87 -0
- package/dist-server/engine/loop-lag.js.map +1 -0
- package/dist-server/engine/model-gap.d.ts +108 -0
- package/dist-server/engine/model-gap.js +95 -0
- package/dist-server/engine/model-gap.js.map +1 -0
- package/dist-server/engine/restart-policy.d.ts +3 -3
- package/dist-server/engine/restart-policy.js +4 -4
- package/dist-server/engine/restart-policy.js.map +1 -1
- package/dist-server/engine/runtime-key.js +1 -1
- package/dist-server/engine/runtime-key.js.map +1 -1
- package/dist-server/engine/stage-path.d.ts +83 -0
- package/dist-server/engine/stage-path.js +118 -0
- package/dist-server/engine/stage-path.js.map +1 -0
- package/dist-server/engine/twin-engine.d.ts +352 -16
- package/dist-server/engine/twin-engine.js +1037 -166
- package/dist-server/engine/twin-engine.js.map +1 -1
- package/dist-server/index.js +34 -2
- package/dist-server/index.js.map +1 -1
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.d.ts +5 -0
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js +58 -0
- package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +1 -0
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.d.ts +5 -0
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js +55 -0
- package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +1 -0
- package/dist-server/migrations/index.js +7 -1
- package/dist-server/migrations/index.js.map +1 -1
- package/dist-server/service/index.d.ts +5 -2
- package/dist-server/service/index.js +18 -7
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/reference/discovery-result.d.ts +1 -1
- package/dist-server/service/reference/discovery-result.js +1 -1
- package/dist-server/service/reference/discovery-result.js.map +1 -1
- package/dist-server/service/reference/index.d.ts +4 -1
- package/dist-server/service/reference/index.js +6 -1
- package/dist-server/service/reference/index.js.map +1 -1
- package/dist-server/service/reference/reference-adapter.d.ts +184 -3
- package/dist-server/service/reference/reference-adapter.js +28 -4
- package/dist-server/service/reference/reference-adapter.js.map +1 -1
- package/dist-server/service/reference/reference-assessment.d.ts +68 -0
- package/dist-server/service/reference/reference-assessment.js +136 -0
- package/dist-server/service/reference/reference-assessment.js.map +1 -0
- package/dist-server/service/reference/reference-live.d.ts +12 -1
- package/dist-server/service/reference/reference-live.js +116 -11
- package/dist-server/service/reference/reference-live.js.map +1 -1
- package/dist-server/service/reference/reference-master.d.ts +47 -1
- package/dist-server/service/reference/reference-master.js +34 -4
- package/dist-server/service/reference/reference-master.js.map +1 -1
- package/dist-server/service/reference/reference-probe.d.ts +92 -0
- package/dist-server/service/reference/reference-probe.js +186 -0
- package/dist-server/service/reference/reference-probe.js.map +1 -0
- package/dist-server/service/reference/reference-progress-subscription.d.ts +17 -0
- package/dist-server/service/reference/reference-progress-subscription.js +94 -0
- package/dist-server/service/reference/reference-progress-subscription.js.map +1 -0
- package/dist-server/service/reference/reference-progress.d.ts +38 -0
- package/dist-server/service/reference/reference-progress.js +71 -0
- package/dist-server/service/reference/reference-progress.js.map +1 -0
- package/dist-server/service/reference/reference-resolver.js +210 -43
- package/dist-server/service/reference/reference-resolver.js.map +1 -1
- package/dist-server/service/reference/twin-reference.d.ts +32 -0
- package/dist-server/service/reference/twin-reference.js +10 -0
- package/dist-server/service/reference/twin-reference.js.map +1 -1
- package/dist-server/service/twin-control/twin-control-mutation.js +4 -3
- package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
- package/dist-server/service/twin-event/journal-count.d.ts +21 -0
- package/dist-server/service/twin-event/journal-count.js +26 -0
- package/dist-server/service/twin-event/journal-count.js.map +1 -0
- package/dist-server/service/twin-event/twin-event-keys.d.ts +9 -0
- package/dist-server/service/twin-event/twin-event-keys.js +15 -18
- package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
- package/dist-server/service/twin-event/twin-event-type.d.ts +3 -1
- package/dist-server/service/twin-event/twin-event-type.js +18 -1
- package/dist-server/service/twin-event/twin-event-type.js.map +1 -1
- package/dist-server/service/twin-event/twin-event.d.ts +1 -0
- package/dist-server/service/twin-event/twin-event.js +9 -1
- package/dist-server/service/twin-event/twin-event.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-ingest-window/index.d.ts +5 -0
- package/dist-server/service/twin-ingest-window/index.js +10 -0
- package/dist-server/service/twin-ingest-window/index.js.map +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.d.ts +12 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js +123 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.d.ts +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js +51 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +1 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window.d.ts +16 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window.js +108 -0
- package/dist-server/service/twin-ingest-window/twin-ingest-window.js.map +1 -0
- package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
- package/dist-server/service/twin-journal/twin-journal-query.js +58 -5
- package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +14 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +72 -2
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
- package/dist-server/service/twin-metrics/twin-metrics-query.d.ts +1 -0
- package/dist-server/service/twin-metrics/twin-metrics-query.js +78 -3
- package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
- package/dist-server/service/twin-model/axis-journal-evidence.d.ts +2 -0
- package/dist-server/service/twin-model/axis-journal-evidence.js +89 -0
- package/dist-server/service/twin-model/axis-journal-evidence.js.map +1 -0
- package/dist-server/service/twin-model/epcis-coverage.d.ts +1 -1
- package/dist-server/service/twin-model/epcis-coverage.js +19 -7
- package/dist-server/service/twin-model/epcis-coverage.js.map +1 -1
- package/dist-server/service/twin-model/iec61850-coverage.d.ts +1 -1
- package/dist-server/service/twin-model/iec61850-coverage.js +18 -7
- package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -1
- package/dist-server/service/twin-model/isa95-coverage.d.ts +14 -0
- package/dist-server/service/twin-model/isa95-coverage.js +23 -9
- package/dist-server/service/twin-model/isa95-coverage.js.map +1 -1
- package/dist-server/service/twin-model/item-ref.d.ts +24 -0
- package/dist-server/service/twin-model/item-ref.js +88 -0
- package/dist-server/service/twin-model/item-ref.js.map +1 -0
- package/dist-server/service/twin-model/name-index.d.ts +36 -0
- package/dist-server/service/twin-model/name-index.js +116 -0
- package/dist-server/service/twin-model/name-index.js.map +1 -0
- package/dist-server/service/twin-model/project-structure.js +1 -1
- package/dist-server/service/twin-model/project-structure.js.map +1 -1
- package/dist-server/service/twin-model/status-tally.d.ts +9 -0
- package/dist-server/service/twin-model/status-tally.js +37 -0
- package/dist-server/service/twin-model/status-tally.js.map +1 -0
- package/dist-server/service/twin-model/twin-lineage-query.js +40 -12
- package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-item-query.js +38 -39
- package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-query.js +156 -4
- package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
- package/dist-server/service/twin-model/twin-model-tree-query.js +7 -0
- package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
- package/dist-server/service/twin-readiness/index.d.ts +2 -0
- package/dist-server/service/twin-readiness/index.js +6 -0
- package/dist-server/service/twin-readiness/index.js.map +1 -0
- package/dist-server/service/twin-readiness/twin-readiness-query.d.ts +3 -0
- package/dist-server/service/twin-readiness/twin-readiness-query.js +103 -0
- package/dist-server/service/twin-readiness/twin-readiness-query.js.map +1 -0
- package/dist-server/service/twin-space/twin-space-resolver.d.ts +2 -2
- package/dist-server/service/twin-space/twin-space-resolver.js +5 -4
- package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
- package/dist-shared/entity-delta.d.ts +23 -3
- package/dist-shared/entity-delta.js +12 -8
- package/dist-shared/entity-delta.js.map +1 -1
- package/dist-shared/kpi-broadcast.js +1 -1
- package/dist-shared/kpi-broadcast.js.map +1 -1
- package/dist-shared/touched-items.d.ts +7 -0
- package/dist-shared/touched-items.js +80 -0
- package/dist-shared/touched-items.js.map +1 -0
- package/package.json +7 -7
- package/server/engine/canonical-ingest.ts +92 -7
- package/server/engine/command-routing.ts +1 -1
- package/server/engine/index.ts +4 -0
- package/server/engine/ingest-health.ts +704 -0
- package/server/engine/integration-coverage.ts +147 -0
- package/server/engine/integration-probes.ts +144 -0
- package/server/engine/integration-runner.ts +95 -0
- package/server/engine/integration-target-profile.ts +103 -0
- package/server/engine/kpi-fold.ts +72 -4
- package/server/engine/kpi-query.ts +129 -15
- package/server/engine/live-feed-registry.ts +2 -1
- package/server/engine/load-meter.ts +12 -3
- package/server/engine/log.ts +72 -0
- package/server/engine/loop-lag.ts +120 -0
- package/server/engine/model-gap.ts +168 -0
- package/server/engine/restart-policy.ts +4 -4
- package/server/engine/runtime-key.ts +1 -1
- package/server/engine/stage-path.ts +172 -0
- package/server/engine/twin-engine.ts +1135 -162
- package/server/index.ts +35 -2
- package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +54 -0
- package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +53 -0
- package/server/migrations/index.ts +7 -1
- package/server/service/index.ts +11 -0
- package/server/service/reference/discovery-result.ts +1 -1
- package/server/service/reference/index.ts +6 -1
- package/server/service/reference/reference-adapter.ts +197 -5
- package/server/service/reference/reference-assessment.ts +215 -0
- package/server/service/reference/reference-live.ts +123 -11
- package/server/service/reference/reference-master.ts +64 -4
- package/server/service/reference/reference-probe.ts +264 -0
- package/server/service/reference/reference-progress-subscription.ts +73 -0
- package/server/service/reference/reference-progress.ts +95 -0
- package/server/service/reference/reference-resolver.ts +200 -12
- package/server/service/reference/twin-reference.ts +39 -1
- package/server/service/twin-control/twin-control-mutation.ts +4 -3
- package/server/service/twin-event/journal-count.ts +53 -0
- package/server/service/twin-event/twin-event-keys.ts +16 -1
- package/server/service/twin-event/twin-event-type.ts +26 -2
- package/server/service/twin-event/twin-event.ts +7 -0
- package/server/service/twin-forecast/twin-forecast-query.ts +2 -1
- package/server/service/twin-ingest-window/index.ts +7 -0
- package/server/service/twin-ingest-window/twin-ingest-window-query.ts +125 -0
- package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +57 -0
- package/server/service/twin-ingest-window/twin-ingest-window.ts +113 -0
- package/server/service/twin-instance/twin-instance.ts +1 -1
- package/server/service/twin-journal/twin-journal-query.ts +59 -5
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +77 -3
- package/server/service/twin-metrics/twin-metrics-query.ts +81 -3
- package/server/service/twin-model/axis-journal-evidence.ts +57 -0
- package/server/service/twin-model/epcis-coverage.ts +2 -8
- package/server/service/twin-model/iec61850-coverage.ts +2 -8
- package/server/service/twin-model/isa95-coverage.ts +22 -9
- package/server/service/twin-model/item-ref.ts +80 -0
- package/server/service/twin-model/name-index.ts +94 -0
- package/server/service/twin-model/project-structure.ts +1 -1
- package/server/service/twin-model/status-tally.ts +37 -0
- package/server/service/twin-model/twin-lineage-query.ts +38 -9
- package/server/service/twin-model/twin-model-item-query.ts +26 -27
- package/server/service/twin-model/twin-model-query.ts +155 -4
- package/server/service/twin-model/twin-model-tree-query.ts +7 -0
- package/server/service/twin-readiness/index.ts +3 -0
- package/server/service/twin-readiness/twin-readiness-query.ts +96 -0
- package/server/service/twin-space/twin-space-resolver.ts +5 -4
- package/shared/entity-delta.ts +31 -7
- package/shared/kpi-broadcast.ts +1 -1
- package/shared/touched-items.ts +73 -0
- package/test/axis-journal-evidence.test.ts +71 -0
- package/test/axis-read.test.ts +101 -1
- package/test/boot-resume.test.ts +92 -26
- package/test/broadcast-cost-baseline.test.ts +200 -0
- package/test/broadcast-period.test.ts +58 -0
- package/test/canonical-ingest-vocabularies.test.ts +36 -1
- package/test/canonical-quantity-door.test.ts +61 -0
- package/test/command-routing.test.ts +1 -1
- package/test/declared-location-types.test.ts +89 -0
- package/test/discovery-result.test.ts +1 -1
- package/test/duration-estimators.test.ts +1 -1
- package/test/entity-delta.test.ts +2 -2
- package/test/ingest-bench.test.ts +3 -3
- package/test/ingest-health-engine.test.ts +248 -0
- package/test/ingest-health-wiring.test.ts +119 -0
- package/test/ingest-health.test.ts +306 -0
- package/test/ingest-history.test.ts +247 -0
- package/test/integration-probes.test.ts +103 -0
- package/test/integration-runner.test.ts +95 -0
- package/test/item-ref.test.ts +78 -0
- package/test/journal-read-discipline.test.ts +177 -0
- package/test/journal-retention.test.ts +133 -0
- package/test/journal-sort-axis.test.ts +142 -0
- package/test/journal-write-door.test.ts +110 -0
- package/test/journal-write-trend.test.ts +115 -0
- package/test/kernel-kind-guard.test.ts +4 -4
- package/test/kpi-fold.test.ts +90 -3
- package/test/kpi-query-bench.test.ts +2 -2
- package/test/lineage-survives-restart.test.ts +17 -1
- package/test/live-cursor-wiring.test.ts +87 -0
- package/test/live-feed-registry.test.ts +9 -1
- package/test/live-kernel-facts.test.ts +7 -7
- package/test/live-mirror-parity.test.ts +6 -0
- package/test/load-meter.test.ts +29 -15
- package/test/local-declarations.test.ts +1 -1
- package/test/log-stamp.test.ts +59 -0
- package/test/loop-lag.test.ts +82 -0
- package/test/model-gap.test.ts +153 -0
- package/test/oee-accumulator.test.ts +4 -0
- package/test/operational-vocabulary.test.ts +4 -4
- package/test/read-failure-visible.test.ts +145 -0
- package/test/reference-grounding.test.ts +70 -0
- package/test/resolve-ts-siblings.mjs +52 -0
- package/test/restart-policy.test.ts +7 -7
- package/test/revision-axis.test.ts +93 -0
- package/test/runtime-key.test.ts +2 -2
- package/test/scale-twin-bench.test.ts +2 -2
- package/test/spec-coverage.test.ts +1 -1
- package/test/stage-path.test.ts +95 -0
- package/test/standard-coverage.test.ts +15 -3
- package/test/status-tally.test.ts +55 -0
- package/test/structure-revision-db.test.ts +4 -0
- package/test/tenant-registry-db.test.ts +1 -1
- package/test/time-range.test.ts +152 -0
- package/test/touched-items.test.ts +61 -0
- package/test/twin-event-keys.test.ts +10 -2
- package/test/twin-model-item-db.test.ts +2 -0
- package/test/warm-start-seam.test.ts +4 -0
- package/test/yield-loop.test.ts +57 -2
- package/tsconfig.shared.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -4,6 +4,7 @@ exports.startReferenceLiveFeed = startReferenceLiveFeed;
|
|
|
4
4
|
exports.stopReferenceLiveFeed = stopReferenceLiveFeed;
|
|
5
5
|
exports.listReferenceLiveFeeds = listReferenceLiveFeeds;
|
|
6
6
|
exports.resumeReferenceLiveFeeds = resumeReferenceLiveFeeds;
|
|
7
|
+
const log_js_1 = require("../../engine/log.js");
|
|
7
8
|
const shell_1 = require("@things-factory/shell");
|
|
8
9
|
const reference_adapter_js_1 = require("./reference-adapter.js");
|
|
9
10
|
const index_js_1 = require("../../engine/index.js");
|
|
@@ -22,7 +23,18 @@ const feeds = new Map();
|
|
|
22
23
|
* ์ปค๋ฅํฐ ๋ผ์ด๋ธ ๊ธฐ๋ โ ์ด๋ํฐ openLiveFeed ๋ฅผ ์ธ์คํด์ค์ ๊ฒฐ์ .
|
|
23
24
|
* ๋ฐํ: ๋ผ์ด๋ธ ๊ฒฐ์ ์ฑ๊ณต ์ฌ๋ถ(์ด๋ํฐ๊ฐ openLiveFeed ๋ฏธ์ง์์ด๋ฉด false โ ํธ์ถ์ธก์ด sim ํด๋ฐฑ).
|
|
24
25
|
*/
|
|
25
|
-
async function startReferenceLiveFeed(domainId, adapterType, cfg, site, instanceId
|
|
26
|
+
async function startReferenceLiveFeed(domainId, adapterType, cfg, site, instanceId,
|
|
27
|
+
/**
|
|
28
|
+
* **์ด๋ ๋ ํผ๋ฐ์ค์์ ์ฝ๋ ํผ๋์ธ๊ฐ** โ ์ฝ๊ธฐ ์ปค์๋ฅผ ์ ์ฅํ ์๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํจ๋ค(ยง`loadLiveCursor`).
|
|
29
|
+
*
|
|
30
|
+
* ๋ถ๋ฅด๋ ์ชฝ์ด `TwinReference` ๋ฅผ ์ด๋ฏธ ๋ค๊ณ ์์ผ๋ฏ๋ก ๊ทธ ์ด๋ฆ์ ๋๊ธด๋ค. ์ฒ์์๋ `cfg`ยท`site` ์์
|
|
31
|
+
* ์ฐพ์ผ๋ ค ํ๋๋ฐ **๋ ๋ค ๊ทธ ๊ฐ์ ๊ฐ์ง ์ ์๋ค**: `cfg` ๋ ์ฌ๋์ด ํ๋ฉด์์ ์
๋ ฅํ ์ ์ ์ค์ ์ด๊ณ
|
|
32
|
+
* (`endpoint`ยท`token`โฆ), `site` ๋ ์ปค๋ฅํฐ๊ฐ ์๋ณธ์์ ๋ฐ๊ฒฌํ ๊ฒ์ด๋ค โ **๋ ํผ๋ฐ์ค์ ์ด๋ฆ์ ํธ์คํธ๊ฐ
|
|
33
|
+
* ๋ถ์ด๋ ๊ฒ์ด๊ณ ์๋ณธ์ ๊ทธ๊ฒ์ ๋ชจ๋ฅธ๋ค.** ์ปค๋ฅํฐ๊ฐ ์ฑ์ธ ์ ์๋ ๊ฐ์ ์ปค๋ฅํฐ์์ ์ฝ์ผ๋ ค ํ ๊ฒ์ด ์๋ชป์ด์๋ค.
|
|
34
|
+
*
|
|
35
|
+
* ์ฃผ์ง ์์ผ๋ฉด ์ปค์๋ฅผ ์์ง ์๊ณ **๊ทธ ์ฌ์ค์ ๋งํ๋ค**(์กฐ์ฉํ ์ฐฝ์ด ๋ฏธ๋๋ฌ์ง์ง ์๊ฒ).
|
|
36
|
+
*/
|
|
37
|
+
source) {
|
|
26
38
|
const adapter = (0, reference_adapter_js_1.getAdapter)(adapterType);
|
|
27
39
|
if (!adapter?.openLiveFeed)
|
|
28
40
|
return false;
|
|
@@ -33,29 +45,122 @@ async function startReferenceLiveFeed(domainId, adapterType, cfg, site, instance
|
|
|
33
45
|
// ์๊ฐ ๊ธฐ์ค์ **๊ณต๊ฐ**์ด ๊ฐ๋๋ค(ํ
๋ํธ ์๋) โ ๊ต๋์ HH:MM ์ ์ด๋ ๊ธฐ์ค์ผ๋ก ์ฝ๋.
|
|
34
46
|
index_js_1.TwinEngine.startLive(instanceId, domainId, det.kind, await index_js_1.TwinEngine.withSpaceTimeBase(det.model, domainId));
|
|
35
47
|
stopReferenceLiveFeed(instanceId); // ์ฌ๊ธฐ๋ ์ ์ด์ ํผ๋ ์ ๋ฆฌ
|
|
48
|
+
/*
|
|
49
|
+
* **์ด๋๊น์ง ์ฝ์๋๋ฅผ ์ด ์ธต์ด ๋ค๊ณ ๊ฑด๋จ๋ค**(ยง`LiveFeedContinuity`, 2026-08-23).
|
|
50
|
+
*
|
|
51
|
+
* ์ด๋ํฐ๊ฐ ์ด ๊ฐ์ ์๊ธฐ ์ฌ๋ฌผํจ์ ๋๋ฉด ์๋ณธ์ด ๋ ๋๋ง๋ค ์ ์ฅ ๊ธฐ์ ๊ฐ ๋๊ณ , ๊ทธ์ค ํ๋๊ฐ ์กฐ์ฉํ ๋ค๋ฅด๊ฒ
|
|
52
|
+
* ๋์ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ปค๋์ด ์ด๋ฏธ ๊ฐ๋ผ ๋์๋ค: ใ์์ฒ์ด ์ ์ด์ ๋ค์ ๋งํด ์ฃผ์ง ์๋ ์ถใ์ ์ฌ๊ธฐ๋
|
|
53
|
+
* ์ฐ์์ฑ์ผ๋ก ์ด์ด๋ฐ๋๋ค(ยง`hydrateContinuity`) โ ์ฝ๊ธฐ ์ปค์๊ฐ ์ ํํ ๊ทธ ์ฑ์ง์ด๋ค.
|
|
54
|
+
*
|
|
55
|
+
* ์์ผ๋ฉด `undefined` ๋ฅผ ๊ฑด๋จ๋ค โ ๊ทธ๊ฒ์ด ใ์ฒซ ๋ถ์ใ์ด๋ผ๋ ์ฌ์ค์ด๊ณ , ๊ทธ๋๋ง ์ด๋ํฐ๊ฐ ๋๋์๋ณผ ๋ ์๋ก
|
|
56
|
+
* ์ฒซ ์ฐฝ์ ๋ง๋ ๋ค. ๋น ๊ฐ์ฒด๋ก ๋ฉ์ฐ์ง ์๋๋ค(๊ทธ๋ฌ๋ฉด ์ฒซ ๋ถ์๊ณผ ์ด์ด ๋ถ์์ด ๊ฐ์์ง๋ค).
|
|
57
|
+
*/
|
|
58
|
+
const continuity = await loadLiveCursor(domainId, instanceId, source);
|
|
36
59
|
const unsubscribe = adapter.openLiveFeed(cfg, site, (records) => {
|
|
37
60
|
if (!index_js_1.TwinEngine.owns(domainId, instanceId)) {
|
|
38
61
|
stopReferenceLiveFeed(instanceId); // ์ธ์คํด์ค ์ฌ๋ผ์ง๋ฉด ์๊ฐ ์ ์ง(์์ ๋ง)
|
|
39
62
|
return;
|
|
40
63
|
}
|
|
64
|
+
const offered = Array.isArray(records) ? records.length : records ? 1 : 0;
|
|
41
65
|
const { accepted, rejected } = (0, index_js_1.ingestCanonicalRecords)(records, domainId, new Date().toISOString());
|
|
42
|
-
|
|
43
|
-
|
|
66
|
+
/*
|
|
67
|
+
* ์ปค๋์ด **๋ช ๊ฑด์ ์ค์ ๋ก ๋ฐ์๋**๋ฅผ ํจ๊ป ๋ณธ๋ค. ํธ์์ด ๋ผ์ด๋ธ๋ก ๋์ง ์์ผ๋ฉด `ingestLive` ๊ฐ 0 ์
|
|
68
|
+
* ๋๋ ค์ฃผ๊ณ , ๊ทธ ์ฐจ์ด๊ฐ ๊ณง ใ๋ฐ๋ฅ์ ๋ฒ๋ ค์ง ์ใ๋ค. ์ด๊ฒ์ ํต๊ณผ๋ก ์ธ๋ฉด ๋ฉ์ถ ํธ์์ด 100% ๋ก ๋ณด์ธ๋ค.
|
|
69
|
+
*/
|
|
70
|
+
const applied = accepted.length ? index_js_1.TwinEngine.ingestLive(domainId, instanceId, accepted) : 0;
|
|
71
|
+
const undelivered = accepted.length - applied;
|
|
44
72
|
/*
|
|
45
73
|
* **๊ฑฐ๋ถํ ๊ฒ์ ์กฐ์ฉํ ๋ฒ๋ฆฌ์ง ์๋๋ค.** ์์ ์๋ `rejected` ๋ฅผ ๋ฐ์ง๋ ์์๋ค โ ์ปค๋ฅํฐ์ ๋งคํ์ด
|
|
46
74
|
* ํ๋ฆฌ๋ฉด ํธ์์ ใ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋ใ ๋ชจ์ต์ด ๋๊ณ , ๋ก๊ทธ์๋ ์๋ฌด ํ์ ์ด ์์๋ค.
|
|
47
75
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
76
|
+
* ๊ทธ๋ค์ ์๋ฆฌ์๋ ใํ๋ฉด๊น์ง ๋๋ฅด๊ธฐใ๋ฅผ ์ด์ ์ฑ์ด๋ค. ๊ฑด๋ง๋ค ๋ธ๋ก๋์บ์คํ
ํ์ง ์๊ณ **์ง๊ณ**ํ๋ค โ ํต๊ณผ๋ถ๊น์ง
|
|
77
|
+
* ํจ๊ป ์ธ๋ ์ด์ ๋, ๊ฑฐ๋ถ๋ง ์ธ๋ฉด ใ์ ์
์์ใ๊ณผ ใ์ ์ใ์ด ๋ ๋ค ๊ฑฐ๋ถ 0 ์ผ๋ก ๊ฐ์ ๋ณด์ด๊ธฐ ๋๋ฌธ์ด๋ค.
|
|
78
|
+
* ์กฐํ๋ `twinIngestHealth`.
|
|
79
|
+
*/
|
|
80
|
+
/*
|
|
81
|
+
* **์ฝ์๋ค๋ ๊ฒ ์์ฒด๊ฐ ์ฌ์ค์ด๋ค** โ ๋น ์ฝ๊ธฐ๋ ์ฑ๊ณต์ด๋ฏ๋ก ๋จ์ ๊ธฐ๋ก์ ์ง์ด๋ค(ยง`onReadFailure`).
|
|
82
|
+
* ๊ทธ ๋์ ์์ผ๋ฉด ์กฐ์ฉํ ์๋ณธ์ด ๋๊ธด ์๋ณธ์ผ๋ก ๋ณด์ธ๋ค.
|
|
50
83
|
*/
|
|
84
|
+
index_js_1.TwinEngine.clearIngestReadFailure(domainId, instanceId);
|
|
85
|
+
index_js_1.TwinEngine.recordIngestResult(domainId, instanceId, offered, rejected, Date.now(), undelivered);
|
|
51
86
|
if (rejected.length) {
|
|
52
87
|
const why = rejected[0]?.errors?.join(' ยท ') ?? 'unknown';
|
|
53
|
-
|
|
88
|
+
(0, log_js_1.twinWarn)(`[twin-live] "${instanceId}": ${rejected.length}/${offered} record(s) rejected โ e.g. ${why}`);
|
|
54
89
|
}
|
|
55
|
-
|
|
90
|
+
/* ๋ฒ๋ ค์ง ๊ฒ์ ๋ก๊ทธ์๋ ๋จ๊ธด๋ค โ ํ๋ฉด์ ๋ณด์ง ์๋ ์ฌ๋๋ ์์์ผ ํ๋ค(์ฌ์ค์ด ์ฌ๋ผ์ง๋ ์ค์ด๋ค). */
|
|
91
|
+
if (undelivered > 0) {
|
|
92
|
+
(0, log_js_1.twinWarn)(`[twin-live] "${instanceId}": ${undelivered}/${offered} record(s) NOT delivered โ the twin is not running live; ` +
|
|
93
|
+
`records are being discarded. Start the twin, or disconnect the feed.`);
|
|
94
|
+
}
|
|
95
|
+
}, continuity);
|
|
56
96
|
feeds.set(instanceId, unsubscribe);
|
|
57
97
|
return true;
|
|
58
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* ๊ทธ ์๋ณธ์ ์ฝ๊ธฐ ์ปค์๋ฅผ ๋ถ๋ฌ์ค๊ณ , ์์ง์ด๋ฉด ์ ์ฅํ๋ ํต๋ก๋ฅผ ๋ง๋ ๋ค.
|
|
101
|
+
*
|
|
102
|
+
* ์ปค์๋ **์๋ณธ(`TwinReference`)์ ๊ฒ**์ด์ง ์ธ์คํด์ค์ ๊ฒ์ด ์๋๋ค โ ํ ์๋ณธ์ด ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ๋ณ๊ณ
|
|
103
|
+
* (`scopeSpec.produced`) ์ฝ๋ ๊ฒ์ ํ ๋ฒ์ด๋ค. ์ธ์คํด์ค๋ง๋ค ์ปค์๋ฅผ ๋๋ฉด ๊ฐ์ ํ๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฝ๋๋ค.
|
|
104
|
+
*
|
|
105
|
+
* ์ ์ฅ ์คํจ๋ **์ผํค์ง ์๊ณ ๋งํ๋ค.** ์กฐ์ฉํ ์คํจํ๋ฉด ๋ค์ ์ฌ๊ธฐ๋์์ ์ฐฝ์ด ๋ค์ ๋ฏธ๋๋ฌ์ง๊ณ , ๊ทธ ์์ค์
|
|
106
|
+
* ์ค๋ฅ ์์ด ์ฌ๋ผ์ง๋ค โ ์ด ์ปฌ๋ผ์ ๋ง๋ ์ด์ ๊ฐ ๋ฐ๋ก ๊ทธ๊ฒ์ด๋ค.
|
|
107
|
+
*/
|
|
108
|
+
async function loadLiveCursor(domainId,
|
|
109
|
+
/** ์ฝ๊ธฐ ์คํจ๋ฅผ ์ ์ ํธ์ โ ์ปค์๋ ๋ ํผ๋ฐ์ค์ ๊ฒ์ด์ง๋ง **๊ฑด๊ฐ์ ์ธ์คํด์ค์ ๊ฒ**์ด๋ค(ํ ๋ ํผ๋ฐ์ค๊ฐ ์ฌ๋ฟ์ ๋ณ๋๋ค). */
|
|
110
|
+
instanceId, source) {
|
|
111
|
+
if (!source) {
|
|
112
|
+
/* ์๋ณธ์ ๊ฐ๋ฆฌํฌ ์ ์์ผ๋ฉด ์ ์ฅํ ์๋ฆฌ๋ ์๋ค โ ๊ทธ ์ฌ์ค์ ๋งํ๋ค(์กฐ์ฉํ ์ปค์ ์์ด ๋์ง ์๊ฒ). */
|
|
113
|
+
(0, log_js_1.twinWarn)('[twin-live] live cursor not carried โ the caller did not say which reference this feed reads from');
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
const repo = (0, shell_1.getRepository)(twin_reference_js_1.TwinReference);
|
|
117
|
+
const row = await repo.findOne({ where: { domain: { id: domainId }, source } }).catch(() => null);
|
|
118
|
+
if (!row) {
|
|
119
|
+
(0, log_js_1.twinWarn)(`[twin-live] live cursor not carried โ no reference row for source "${source}"`);
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
const stored = row.liveCursor;
|
|
123
|
+
if (stored?.firstAttachedAt) {
|
|
124
|
+
(0, log_js_1.twinLog)(`[twin-live] "${source}": resuming from stored cursor โ knowledge starts ${stored.firstAttachedAt}`);
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
cursor: stored ?? undefined,
|
|
128
|
+
/*
|
|
129
|
+
* **์๋ณธ์ ๋ฟ์ง ๋ชปํ๋ค** โ ์ด๋ํฐ๊ฐ ์๋ฆฌ๋ฉด ์ํ์ ์ ๋๋ค(ยง`onReadFailure`).
|
|
130
|
+
*
|
|
131
|
+
* ๋ก๊ทธ๋ก๋ ์ด๋ํฐ๊ฐ ์ด๋ฏธ ๋งํ๊ณ ์์๋ค(์ฌ์๋ ๊ฒฝ๊ณ ). ๊ทธ๋ฌ๋ **๋ก๊ทธ๋ ์ฌ๋์ด ๋ณผ ๋๋ง ๊ฐ์ด ์๋ค** โ
|
|
132
|
+
* ํ๋ฉด์ด ๋งํ๋ ค๋ฉด ์กฐํ ๊ฐ๋ฅํ ์ํ์ ์์ด์ผ ํ๋ค.
|
|
133
|
+
*
|
|
134
|
+
* โโ `status` ๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๋๋ค (2026-08-23, ๋๋๋ฆฐ ์๋ฆฌ) โโโโโโโโโโโโโโโโโโโโ
|
|
135
|
+
* ์ฒ์์๋ ๋ ํผ๋ฐ์ค ํ์ `status` ๋ฅผ `'error'` ๋ก๋ ์ ์๋ค โ ใ๋ชฉ๋ก์ด ใ์ฐ๊ฒฐ๋จใ์ด๋ผ ๋งํ๋ฉด์ ์ค์ ๋ก๋
|
|
136
|
+
* ๋ชป ์ฝ๋ ์ํ๋ฅผ ์์ ๋ ค๊ณ ใ. **๊ทธ๊ฒ์ด ํผ๋๋ฅผ ์๊ตฌํ ๊ป๋ค.**
|
|
137
|
+
*
|
|
138
|
+
* ๋ถํ
์ฌ๋ถ์ฐฉ์ `status: 'connected'` ์ธ ๋ ํผ๋ฐ์ค๋ง ๋์ด๋ฆฐ๋ค(ยง`resumeReferenceLiveFeeds`). ๊ทธ๋์
|
|
139
|
+
* ์๋ณธ์ด **์ ๊น** ๋๊ธด ๊ฒ์ด ๊ทธ ํ์ `error` ๋ก ๋ง๋ค๊ณ , ๋ค์ ์ฌ๊ธฐ๋์์ ๊ทธ ํผ๋๋ ์์ ๋ถ์ง ์์๋ค โ
|
|
140
|
+
* ์ค์ธก์ผ๋ก ๊ทธ๋ ๊ฒ ๋ฌ๋ค(09:25 ํ์ `[twin-live]` ์ค์ด ํ ์ค๋ ์์๋ค).
|
|
141
|
+
*
|
|
142
|
+
* ๋ ์ถ์ ํ ์นธ์ ์์ ๊ฒ์ด ์์ธ์ด๋ค:
|
|
143
|
+
* `status` **์ฐ๊ฒฐ ์ค์ ์ด ์ฑ๋ฆฝํ๋** โ ์ ์ ์ํยท๋ง์คํฐ ๋๊ธฐ๊ฐ ์ ํ๋ ์ถ(์ฌ๋ถ์ฐฉ์ ์๊ฒฉ์ด๋ค)
|
|
144
|
+
* ์ฝ๊ธฐ ์คํจ **์ง๊ธ ๋ฟ๋** โ ์ค๊ฐ ์ ์๋ ์ฌ์ค์ด๊ณ , ์ ์
์ฅ๋ถ๊ฐ ๊ทธ ์ถ์ ๊ฐ๋๋ค
|
|
145
|
+
*
|
|
146
|
+
* ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ `lastError` ์๋ง ์ ๋๋ค(์ฌ๋์ด ๋ชฉ๋ก์์ ์ด์ ๋ฅผ ๋ณผ ์ ์๊ฒ). ใ์ง๊ธ ๋ฟ๋ใ๋
|
|
147
|
+
* `ingestHealth().readFailure` ๊ฐ ๋ตํ๊ณ , ์ฑ๊ณตํ ์ฃผ๊ธฐ๊ฐ ๊ทธ๊ฒ์ ์ง์ด๋ค.
|
|
148
|
+
*/
|
|
149
|
+
onReadFailure: ({ reason, stream }) => {
|
|
150
|
+
index_js_1.TwinEngine.recordIngestReadFailure(domainId, instanceId, reason, Date.now(), stream);
|
|
151
|
+
(0, log_js_1.twinWarn)(`[twin-live] "${source}": cannot read from the source${stream ? ` (${stream})` : ''} โ ${reason}`);
|
|
152
|
+
repo
|
|
153
|
+
.update({ id: row.id }, { lastError: `live: ${reason}` })
|
|
154
|
+
.catch(err => (0, log_js_1.twinWarn)(`[twin-live] "${source}": read failure not recorded โ ${err?.message ?? err}`));
|
|
155
|
+
},
|
|
156
|
+
onCursor: next => {
|
|
157
|
+
/* ์ด๋ํฐ๊ฐ ์ค ๋ชจ์์ ๊ทธ๋๋ก ์ ๋๋ค โ ์ด ์ธต์ ํ๋ฆ์ ๋ป์ ๋ชจ๋ฅธ๋ค(์ด์ ๋ ์ด๋ํฐ๊ฐ ์ ํ๋ค). */
|
|
158
|
+
repo
|
|
159
|
+
.update({ id: row.id }, { liveCursor: next })
|
|
160
|
+
.catch(err => (0, log_js_1.twinWarn)(`[twin-live] "${source}": live cursor not saved โ ${err?.message ?? err}`));
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
59
164
|
/** ๋ผ์ด๋ธ ํผ๋ ์ค์ง(unsubscribe). */
|
|
60
165
|
function stopReferenceLiveFeed(instanceId) {
|
|
61
166
|
const unsub = feeds.get(instanceId);
|
|
@@ -147,7 +252,7 @@ async function resumeReferenceLiveFeeds() {
|
|
|
147
252
|
}
|
|
148
253
|
attached.set(p.instanceId, ref.source);
|
|
149
254
|
try {
|
|
150
|
-
const ok = await startReferenceLiveFeed(domainId, ref.adapterType, ref.connectionConfig ?? {}, site, p.instanceId);
|
|
255
|
+
const ok = await startReferenceLiveFeed(domainId, ref.adapterType, ref.connectionConfig ?? {}, site, p.instanceId, ref.source);
|
|
151
256
|
if (ok)
|
|
152
257
|
resumed.push(p.instanceId);
|
|
153
258
|
else
|
|
@@ -160,13 +265,13 @@ async function resumeReferenceLiveFeeds() {
|
|
|
160
265
|
}
|
|
161
266
|
}
|
|
162
267
|
catch (e) {
|
|
163
|
-
|
|
268
|
+
(0, log_js_1.twinError)('[twin-live] feed resume scan failed', e?.message);
|
|
164
269
|
}
|
|
165
270
|
if (resumed.length)
|
|
166
|
-
|
|
271
|
+
(0, log_js_1.twinLog)(`[twin-live] reattached ${resumed.length} feed(s): ${resumed.join(', ')}`);
|
|
167
272
|
/* **์กฐ์ฉํ ๋๊ธฐ์ง ์๋๋ค** โ ๋ถ์ง ์์ ๋ฏธ๋ฌ๋ ใ๋๋๋ฐ ์๋ฌด๊ฒ๋ ์ค์ง ์๋ใ ํธ์์ด๋ค. */
|
|
168
273
|
for (const f of failed)
|
|
169
|
-
|
|
274
|
+
(0, log_js_1.twinWarn)(`[twin-live] "${f.instanceId}" feed NOT reattached โ ${f.error}`);
|
|
170
275
|
return { resumed, failed };
|
|
171
276
|
}
|
|
172
277
|
/*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reference-live.js","sourceRoot":"","sources":["../../../server/service/reference/reference-live.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository } from '@things-factory/shell'\n\nimport { getAdapter, type ConnectionConfig, type SiteDescriptor } from './reference-adapter.js'\nimport { TwinEngine, ingestCanonicalRecords, registerLiveFeedProbe, type CanonicalRecord } from '../../engine/index.js'\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinReference } from './twin-reference.js'\n\n/*\n * ์ปค๋ฅํฐ ๊ธฐ๋ฐ ๋ผ์ด๋ธ ํผ๋ ๊ฒฐ์ (reference โ live, ยง0 ํ๋ ์ โ restartPolicy='resync').\n * ํ๋ฆ: adapter.openLiveFeed(cfg, site, records) โ ingestCanonicalRecords(์ ๊ทโ๋ดํฌ) โ TwinEngine.ingestLive(projector ๋ฏธ๋ฌ).\n * ์ปค๋ฅํฐ๊ฐ \"๋ฒค๋ ์ด๋ฒคํธ โ ์ ๊ท ๋ ์ฝ๋\" ๋งคํ์ ์์ (์ฝ๋)ํ๋ค โ preset ๊ธฐ๋ฐ startLiveFeed(operato-twin, http-get+jsonata)์\n * ๋์นญ์ด๋, ๋งคํ ์์น๋ง ๋ค๋ฅด๋ค. ์ค ์์คํ
์ ํ์ connectionConfig.baseUrl ๊ต์ฒด๋ฟ(์ฝ๋ ๊ฒฝ๋ก ๋์ผ).\n * ์๋ช
์ฃผ๊ธฐ: ์ธ์คํด์ค ์ ์ง(TwinEngine.stop)์ ํ
์ผ๋ก ๋ฌถ์ฌ ํผ๋๋ ํจ๊ป unsubscribe.\n */\n\n/** ํ์ฑ ๋ผ์ด๋ธ ํผ๋ โ instanceId โ unsubscribe(์ด๋ํฐ openLiveFeed ๋ฐํ). */\nconst feeds = new Map<string, () => void>()\n\n/**\n * ์ปค๋ฅํฐ ๋ผ์ด๋ธ ๊ธฐ๋ โ ์ด๋ํฐ openLiveFeed ๋ฅผ ์ธ์คํด์ค์ ๊ฒฐ์ .\n * ๋ฐํ: ๋ผ์ด๋ธ ๊ฒฐ์ ์ฑ๊ณต ์ฌ๋ถ(์ด๋ํฐ๊ฐ openLiveFeed ๋ฏธ์ง์์ด๋ฉด false โ ํธ์ถ์ธก์ด sim ํด๋ฐฑ).\n */\nexport async function startReferenceLiveFeed(\n domainId: string,\n adapterType: string,\n cfg: ConnectionConfig,\n site: SiteDescriptor,\n instanceId: string\n): Promise<boolean> {\n const adapter = getAdapter(adapterType)\n if (!adapter?.openLiveFeed) return false\n\n const det = await TwinEngine.detail(domainId, instanceId)\n if (!det?.model) throw new Error(`instance \"${instanceId}\" not provisioned (no model) โ ingest master before live start`)\n\n // ๊ด์ธก ๊ธฐ๋ โ ์ปค๋ tick ์์ด projector ๊ฐ ์ค ์ด๋ฒคํธ๋ฅผ ๋ฐ์ํ๋ค(startLive ๊ฐ restartPolicy='resync' ๋ก ์ ๋๋ค).\n // ์๊ฐ ๊ธฐ์ค์ **๊ณต๊ฐ**์ด ๊ฐ๋๋ค(ํ
๋ํธ ์๋) โ ๊ต๋์ HH:MM ์ ์ด๋ ๊ธฐ์ค์ผ๋ก ์ฝ๋.\n TwinEngine.startLive(instanceId, domainId, det.kind, await TwinEngine.withSpaceTimeBase(det.model, domainId))\n\n stopReferenceLiveFeed(instanceId) // ์ฌ๊ธฐ๋ ์ ์ด์ ํผ๋ ์ ๋ฆฌ\n const unsubscribe = adapter.openLiveFeed(cfg, site, (records: unknown[]) => {\n if (!TwinEngine.owns(domainId, instanceId)) {\n stopReferenceLiveFeed(instanceId) // ์ธ์คํด์ค ์ฌ๋ผ์ง๋ฉด ์๊ฐ ์ ์ง(์์ ๋ง)\n return\n }\n const { accepted, rejected } = ingestCanonicalRecords(records as CanonicalRecord[], domainId, new Date().toISOString())\n if (accepted.length) TwinEngine.ingestLive(domainId, instanceId, accepted)\n /*\n * **๊ฑฐ๋ถํ ๊ฒ์ ์กฐ์ฉํ ๋ฒ๋ฆฌ์ง ์๋๋ค.** ์์ ์๋ `rejected` ๋ฅผ ๋ฐ์ง๋ ์์๋ค โ ์ปค๋ฅํฐ์ ๋งคํ์ด\n * ํ๋ฆฌ๋ฉด ํธ์์ ใ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋ใ ๋ชจ์ต์ด ๋๊ณ , ๋ก๊ทธ์๋ ์๋ฌด ํ์ ์ด ์์๋ค.\n *\n * ์ง๊ธ์ ์ด์ ์ ํจ๊ป ๋จ๊ธด๋ค. ํ๋ฉด๊น์ง ๋๋ฅด๋ ๊ฒ์ ๋ค์ ์ผ์ด๋ค(๋ผ์ด๋ธ ๊ณ์ธก์ ์ด๋น ์ฌ๋ฌ ๊ฑด์ด๋ผ\n * ๊ฑด๋ง๋ค ๋ฐฉ์กํ๋ฉด ๊ทธ ์์ฒด๊ฐ ๋ถํ๊ฐ ๋๋ค โ ์ง๊ณํด ๋ผ ์๋ฆฌ๊ฐ ํ์ํ๋ค).\n */\n if (rejected.length) {\n const why = rejected[0]?.errors?.join(' ยท ') ?? 'unknown'\n console.warn(`[twin-live] \"${instanceId}\": ${rejected.length} record(s) rejected โ e.g. ${why}`)\n }\n })\n feeds.set(instanceId, unsubscribe)\n return true\n}\n\n/** ๋ผ์ด๋ธ ํผ๋ ์ค์ง(unsubscribe). */\nexport function stopReferenceLiveFeed(instanceId: string): boolean {\n const unsub = feeds.get(instanceId)\n if (!unsub) return false\n try { unsub() } catch { /* noop */ }\n feeds.delete(instanceId)\n return true\n}\n\n/** ํ์ฑ ํผ๋ ๋ชฉ๋ก(๊ด์ธก). */\nexport function listReferenceLiveFeeds(): string[] {\n return [...feeds.keys()]\n}\n\n/**\n * ๋ถํ
๋ **๋์ด์ง ํผ๋๋ฅผ ๋ค์ ๋ถ์ธ๋ค** โ ๋๋ ๋ฏธ๋ฌ ํธ์์ ๊ณ์ธก์ด ๊ณ์ ๋ค์ด์ค๊ฒ.\n *\n * โโ ๋ฌด์์ด ์กฐ์ฉํ ๋๊ฒผ๋ (2026-08-14) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * `startReferenceLiveFeed` ๋ฅผ ๋ถ๋ฅด๋ ๊ณณ์ `importTwinReference` **ํ๋๋ฟ**์ด์๋ค. ๊ทธ๋์ ์๋ฒ๋ฅผ ํ ๋ฒ\n * ์ฌ๊ธฐ๋ํ๋ฉด ๋ฏธ๋ฌ ํธ์์ ใ๋๋ ์คใ์ด๋ผ ๋งํ๋ฉด์ ์๋ฌด ๊ณ์ธก๋ ๋ฐ์ง ์์๋ค โ ์ค๋ฅ๋ ๋ก๊ทธ๋ ์์ด,\n * ์ฌ๋์ ใ๊ฐ์ด ์ ๋ณํ๋คใ๋ก ์๊ฒ ๋๋ค. ์ค ๋ฐฐํฌ์์ ์ฌ๊ธฐ๋ ํ ๋ฒ์ ๊ณ์ธก์ด ๋ฉ์ถ๋ ์
์ด๋ค.\n *\n * โโ ๋์ด๋ฆด ์ฌ๋ฃ๋ ์ด๋ฏธ ์์๋ผ ์๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * `TwinReference` ๊ฐ ์ด๋ํฐ ์ข
๋ฅยท์ ์ ์ค์ ยท๊ทธ ๋ ํผ๋ฐ์ค๊ฐ ๋ง๋ ์ธ์คํด์ค(`scopeSpec.produced`)๋ฅผ ๋ค๊ณ ์๋ค.\n * ์ฌ์ดํธ ์์ ์๋ง ์๋๋ฐ(`hint` ๋ ๋จ๊ธฐ์ง ์์๋ค) **๋ค์ ์ฐพ์์** ์ป๋๋ค(`discoverSites`) โ ์ธ์ ์คํธ๊ฐ\n * ๊ฑท๋ ๊ฒ๊ณผ ๊ฐ์ ๊ธธ์ด๋ฏ๋ก ๊ท์น์ด ๊ฐ๋ผ์ง์ง ์๋๋ค. ๋์ด๋ฆด ์ธ์คํด์ค๊ฐ ์์ผ๋ฉด ๊ทธ ํธ์ถ๋ ํ์ง ์๋๋ค.\n *\n * ์ฌ๊ฐ ๋์์ **๋ฑ๋ก๋ถ๊ฐ ๋๋ ๋ฏธ๋ฌ๋ผ๊ณ ๋งํ๋ ๊ฒ**๋ฟ์ด๋ค: ๋ฉ์ถ ํธ์์ ๋์ด๋ฆฌ๋ฉด ์ฌ๋์ด ๋ฉ์ถ ๊ฒ์\n * ์ฐ๋ฆฌ๊ฐ ๋ค์ ์ผ๋ ๊ฒ์ด๊ณ , ์๋ฎฌ ํธ์์ ์ค ๊ณ์ธก์ ๋ถ์ผ๋ฉด ๋ ํ์ค์ด ์์ธ๋ค.\n */\nexport async function resumeReferenceLiveFeeds(): Promise<{ resumed: string[]; failed: { instanceId: string; error: string }[] }> {\n const resumed: string[] = []\n const failed: { instanceId: string; error: string }[] = []\n /*\n * **ํ ํธ์์ ํผ๋๋ ํ๋๋ค** (2026-08-18).\n *\n * ๊ฐ์ ์ฌ์ดํธ๋ฅผ ๋ ๋ ํผ๋ฐ์ค๊ฐ ๊ฐ๊ฐ ์ธ์ ์คํธํ๋ฉด ๋ ๋ค ๊ทธ ์ธ์คํด์ค๋ฅผ ์๊ธฐ๊ฐ ๋ง๋ ๊ฒ(`produced`)์ผ๋ก\n * ๋ค๊ณ ์๋ค. ๊ธฐ๋ ๋ ๊ทธ ๋ชฉ๋ก์ ๊ทธ๋๋ก ๋๋ฉด ๊ฐ์ ํธ์์ ํผ๋๋ฅผ ๋ ๋ฒ ๋ถ์ด๋๋ฐ, ๋ถ์ด๋ ํจ์๊ฐ ๋ฏธ๋ฌ๋ฅผ\n * ๋ค์ ์ธ์ฐ๋ฏ๋ก(`startLive`) **๋จผ์ ์์ธ ์์ ๊ตฌ๊ฐ์ด ๋ฆฌ์
๋๋ค** โ ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋ฌ๋ค\n * (๋ก๊ทธ: `reattached 2 feed(s): ems-plant-1, ems-plant-1`).\n *\n * ๊ทธ๋ฌ๋ ํ ๋ฒ๋ง ๋ถ์ด๊ณ , **๋ ๋ ํผ๋ฐ์ค๊ฐ ๊ฐ์ ํธ์์ ์ฃผ์ฅํ๋ค๋ ์ฌ์ค์ ๋งํ๋ค** โ ์กฐ์ฉํ ํ๋๋ฅผ\n * ๊ณ ๋ฅด๋ฉด ์ด๋ ์ ์์ด ๊ทธ ํธ์์ ๋จน์ด๊ณ ์๋์ง ์๋ฌด๋ ๋ชจ๋ฅด๊ฒ ๋๋ค.\n */\n const attached = new Map<string, string>() // instanceId โ ๋จผ์ ๋ถ์ธ ๋ ํผ๋ฐ์ค\n try {\n const refs = await getRepository(TwinReference).find({ where: { status: 'connected' }, relations: ['domain'] })\n for (const ref of refs) {\n const domainId = (ref as any).domain?.id ?? (ref as any).domainId\n const adapter = getAdapter(ref.adapterType)\n if (!domainId || !adapter?.openLiveFeed) continue // ๊ด์ธก๋ง ํ๋ ์ด๋ํฐ์๋ ๋์ด๋ฆด ํผ๋๊ฐ ์๋ค\n\n const produced: any[] = ((ref.scopeSpec as any)?.produced ?? []).filter((p: any) => p?.instanceId && p?.siteId)\n if (!produced.length) continue\n\n /* ๋ฑ๋ก๋ถ๊ฐ ใ๋๋ ๋ฏธ๋ฌใ๋ผ๊ณ ๋งํ๋ ๊ฒ๋ง ๊ณ ๋ฅธ๋ค. */\n const rows = await getRepository(TwinInstance).find({\n where: produced.map((p: any) => ({ domain: { id: domainId }, instanceId: p.instanceId })) as any\n })\n const live = produced.filter((p: any) =>\n rows.some(r => r.instanceId === p.instanceId && r.status === 'running' && r.restartPolicy === 'resync')\n )\n if (!live.length) continue\n\n let sites: SiteDescriptor[]\n try {\n sites = await adapter.discoverSites(ref.connectionConfig ?? {})\n } catch (e: any) {\n /* ์ ์์คํ
์ด ์์ง ์ ๋ด์ ์ ์๋ค โ ์ง์ด๋ด์ง ์๊ณ ๊ทธ๋ ๊ฒ ์ ๋๋ค(ํธ์์ ๊ณ์ ใ๋๋ ๋ฏธ๋ฌใ๋ค). */\n for (const p of live) failed.push({ instanceId: p.instanceId, error: `discover failed: ${e?.message ?? 'unknown'}` })\n continue\n }\n\n for (const p of live) {\n const site = sites.find(s => s.siteId === p.siteId)\n if (!site) {\n failed.push({ instanceId: p.instanceId, error: `site \"${p.siteId}\" no longer discoverable` })\n continue\n }\n const owner = attached.get(p.instanceId)\n if (owner) {\n /* ๋ ์ ์์ด ๊ฐ์ ํธ์์ ์ฃผ์ฅํ๋ค โ ๋จผ์ ๋ถ์ ๊ฒ์ ์งํค๊ณ , ๊ทธ ์ฌ์ค์ ๋จ๊ธด๋ค(๋ ๋ค ๋ถ์ด๋ฉด ๋ฏธ๋ฌ๊ฐ ๋ฆฌ์
๋๋ค). */\n failed.push({\n instanceId: p.instanceId,\n error: `also claimed by reference \"${ref.source}\" โ kept the feed from \"${owner}\" (two connections feeding one twin would reset the mirror)`\n })\n continue\n }\n attached.set(p.instanceId, ref.source)\n try {\n const ok = await startReferenceLiveFeed(domainId, ref.adapterType, ref.connectionConfig ?? {}, site, p.instanceId)\n if (ok) resumed.push(p.instanceId)\n else failed.push({ instanceId: p.instanceId, error: 'adapter has no openLiveFeed' })\n } catch (e: any) {\n failed.push({ instanceId: p.instanceId, error: e?.message ?? 'reattach failed' })\n }\n }\n }\n } catch (e: any) {\n console.error('[twin-live] feed resume scan failed', e?.message)\n }\n\n if (resumed.length) console.log(`[twin-live] reattached ${resumed.length} feed(s): ${resumed.join(', ')}`)\n /* **์กฐ์ฉํ ๋๊ธฐ์ง ์๋๋ค** โ ๋ถ์ง ์์ ๋ฏธ๋ฌ๋ ใ๋๋๋ฐ ์๋ฌด๊ฒ๋ ์ค์ง ์๋ใ ํธ์์ด๋ค. */\n for (const f of failed) console.warn(`[twin-live] \"${f.instanceId}\" feed NOT reattached โ ${f.error}`)\n return { resumed, failed }\n}\n\n/*\n * ์ด ๊ณ์ธต์ ํผ๋ ์ฅ๋ถ๋ฅผ ๋ฑ๋กํ๋ค โ ํ๋ฉด์ด ใ๋๊นใ์ ๋งํ ๊ทผ๊ฑฐ๋ **๋ฌป๋ ์๋ฆฌ ํ๋**์ฌ์ผ ํ๋ค.\n * (ํ๋ฆฌ์
๊ธฐ๋ฐ ํผ๋๋ ์ฑ์ด ์๊ธฐ ์ฅ๋ถ๋ฅผ ๋ฐ๋ก ๋ฑ๋กํ๋ค. ํ์ชฝ๋ง ๋ณด๋ฉด ํ๋ฅด๋ ํธ์์ ๋๊ฒผ๋ค๊ณ ๋ถ๋ฅธ๋ค.)\n */\nregisterLiveFeedProbe(() => [...feeds.keys()])\n\n/* ์ธ์คํด์ค ์ ์ง ์ ํผ๋ ์๋ ์ ๋ฆฌ(์๋ช
์ฃผ๊ธฐ ๋์นญ). */\nTwinEngine.onStop(instanceId => stopReferenceLiveFeed(instanceId))\n"]}
|
|
1
|
+
{"version":3,"file":"reference-live.js","sourceRoot":"","sources":["../../../server/service/reference/reference-live.ts"],"names":[],"mappings":";;AAuBA,wDAiFC;AAwED,sDAMC;AAGD,wDAEC;AAkBD,4DA4EC;AAzRD,gDAAkE;AAClE,iDAAqD;AAErD,iEAAwH;AACxH,oDAAuH;AACvH,wEAAgE;AAChE,2DAAmD;AAEnD;;;;;;GAMG;AAEH,iEAAiE;AACjE,MAAM,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAA;AAE3C;;;GAGG;AACI,KAAK,UAAU,sBAAsB,CAC1C,QAAgB,EAChB,WAAmB,EACnB,GAAqB,EACrB,IAAoB,EACpB,UAAkB;AAClB;;;;;;;;;GASG;AACH,MAAe;IAEf,MAAM,OAAO,GAAG,IAAA,iCAAU,EAAC,WAAW,CAAC,CAAA;IACvC,IAAI,CAAC,OAAO,EAAE,YAAY;QAAE,OAAO,KAAK,CAAA;IAExC,MAAM,GAAG,GAAG,MAAM,qBAAU,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;IACzD,IAAI,CAAC,GAAG,EAAE,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,aAAa,UAAU,gEAAgE,CAAC,CAAA;IAEzH,wFAAwF;IACxF,uDAAuD;IACvD,qBAAU,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,qBAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAA;IAE7G,qBAAqB,CAAC,UAAU,CAAC,CAAA,CAAC,iBAAiB;IACnD;;;;;;;;;OASG;IACH,MAAM,UAAU,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,CAAA;IACrE,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,OAAkB,EAAE,EAAE;QACzE,IAAI,CAAC,qBAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,CAAC;YAC3C,qBAAqB,CAAC,UAAU,CAAC,CAAA,CAAC,uBAAuB;YACzD,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACzE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,IAAA,iCAAsB,EAAC,OAA4B,EAAE,QAAQ,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAA;QACvH;;;WAGG;QACH,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAU,CAAC,UAAU,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAC3F,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,GAAG,OAAO,CAAA;QAC7C;;;;;;;WAOG;QACH;;;WAGG;QACH,qBAAU,CAAC,sBAAsB,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QACvD,qBAAU,CAAC,kBAAkB,CAAC,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAA;QAC/F,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,SAAS,CAAA;YACzD,IAAA,iBAAQ,EAAC,gBAAgB,UAAU,MAAM,QAAQ,CAAC,MAAM,IAAI,OAAO,8BAA8B,GAAG,EAAE,CAAC,CAAA;QACzG,CAAC;QACD,2DAA2D;QAC3D,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;YACpB,IAAA,iBAAQ,EACN,gBAAgB,UAAU,MAAM,WAAW,IAAI,OAAO,2DAA2D;gBAC/G,sEAAsE,CACzE,CAAA;QACH,CAAC;IACH,CAAC,EAAE,UAAU,CAAC,CAAA;IACd,KAAK,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAAA;IAClC,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,cAAc,CAC3B,QAAgB;AAChB,wEAAwE;AACxE,UAAkB,EAClB,MAAe;IAEf,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,4DAA4D;QAC5D,IAAA,iBAAQ,EAAC,mGAAmG,CAAC,CAAA;QAC7G,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,IAAI,GAAG,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAA;IACzC,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAS,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IACxG,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,IAAA,iBAAQ,EAAC,sEAAsE,MAAM,GAAG,CAAC,CAAA;QACzF,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAA;IAC7B,IAAI,MAAM,EAAE,eAAe,EAAE,CAAC;QAC5B,IAAA,gBAAO,EAAC,gBAAgB,MAAM,qDAAqD,MAAM,CAAC,eAAe,EAAE,CAAC,CAAA;IAC9G,CAAC;IACD,OAAO;QACL,MAAM,EAAE,MAAM,IAAI,SAAS;QAC3B;;;;;;;;;;;;;;;;;;;;WAoBG;QACH,aAAa,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;YACpC,qBAAU,CAAC,uBAAuB,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAA;YACpF,IAAA,iBAAQ,EAAC,gBAAgB,MAAM,iCAAiC,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC,CAAA;YAC3G,IAAI;iBACD,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,MAAM,EAAE,EAAS,CAAC;iBAC/D,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,gBAAgB,MAAM,kCAAkC,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QAC1G,CAAC;QACD,QAAQ,EAAE,IAAI,CAAC,EAAE;YACf,yDAAyD;YACzD,IAAI;iBACD,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAS,CAAC;iBACnD,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,IAAA,iBAAQ,EAAC,gBAAgB,MAAM,8BAA8B,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAAC,CAAC,CAAA;QACtG,CAAC;KACF,CAAA;AACH,CAAC;AAED,8BAA8B;AAC9B,SAAgB,qBAAqB,CAAC,UAAkB;IACtD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACnC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAA;IACxB,IAAI,CAAC;QAAC,KAAK,EAAE,CAAA;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;IACpC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;IACxB,OAAO,IAAI,CAAA;AACb,CAAC;AAED,oBAAoB;AACpB,SAAgB,sBAAsB;IACpC,OAAO,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAA;AAC1B,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACI,KAAK,UAAU,wBAAwB;IAC5C,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,MAAM,MAAM,GAA4C,EAAE,CAAA;IAC1D;;;;;;;;;;OAUG;IACH,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAA,CAAC,0BAA0B;IACrE,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;QAC/G,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAI,GAAW,CAAC,MAAM,EAAE,EAAE,IAAK,GAAW,CAAC,QAAQ,CAAA;YACjE,MAAM,OAAO,GAAG,IAAA,iCAAU,EAAC,GAAG,CAAC,WAAW,CAAC,CAAA;YAC3C,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,YAAY;gBAAE,SAAQ,CAAC,0BAA0B;YAE5E,MAAM,QAAQ,GAAU,CAAE,GAAG,CAAC,SAAiB,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,IAAI,CAAC,EAAE,MAAM,CAAC,CAAA;YAC/G,IAAI,CAAC,QAAQ,CAAC,MAAM;gBAAE,SAAQ;YAE9B,gCAAgC;YAChC,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,IAAI,CAAC;gBAClD,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAQ;aACjG,CAAC,CAAA;YACF,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CACtC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,aAAa,KAAK,QAAQ,CAAC,CACxG,CAAA;YACD,IAAI,CAAC,IAAI,CAAC,MAAM;gBAAE,SAAQ;YAE1B,IAAI,KAAuB,CAAA;YAC3B,IAAI,CAAC;gBACH,KAAK,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAA;YACjE,CAAC;YAAC,OAAO,CAAM,EAAE,CAAC;gBAChB,6DAA6D;gBAC7D,KAAK,MAAM,CAAC,IAAI,IAAI;oBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,oBAAoB,CAAC,EAAE,OAAO,IAAI,SAAS,EAAE,EAAE,CAAC,CAAA;gBACrH,SAAQ;YACV,CAAC;YAED,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACrB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAC,CAAA;gBACnD,IAAI,CAAC,IAAI,EAAE,CAAC;oBACV,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,MAAM,0BAA0B,EAAE,CAAC,CAAA;oBAC7F,SAAQ;gBACV,CAAC;gBACD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;gBACxC,IAAI,KAAK,EAAE,CAAC;oBACV,oEAAoE;oBACpE,MAAM,CAAC,IAAI,CAAC;wBACV,UAAU,EAAE,CAAC,CAAC,UAAU;wBACxB,KAAK,EAAE,8BAA8B,GAAG,CAAC,MAAM,2BAA2B,KAAK,6DAA6D;qBAC7I,CAAC,CAAA;oBACF,SAAQ;gBACV,CAAC;gBACD,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;gBACtC,IAAI,CAAC;oBACH,MAAM,EAAE,GAAG,MAAM,sBAAsB,CAAC,QAAQ,EAAE,GAAG,CAAC,WAAW,EAAE,GAAG,CAAC,gBAAgB,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAA;oBAC9H,IAAI,EAAE;wBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAA;;wBAC7B,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,6BAA6B,EAAE,CAAC,CAAA;gBACtF,CAAC;gBAAC,OAAO,CAAM,EAAE,CAAC;oBAChB,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,IAAI,iBAAiB,EAAE,CAAC,CAAA;gBACnF,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,IAAA,kBAAS,EAAC,qCAAqC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;IAC9D,CAAC;IAED,IAAI,OAAO,CAAC,MAAM;QAAE,IAAA,gBAAO,EAAC,0BAA0B,OAAO,CAAC,MAAM,aAAa,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;IACtG,wDAAwD;IACxD,KAAK,MAAM,CAAC,IAAI,MAAM;QAAE,IAAA,iBAAQ,EAAC,gBAAgB,CAAC,CAAC,UAAU,2BAA2B,CAAC,CAAC,KAAK,EAAE,CAAC,CAAA;IAClG,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAA;AAC5B,CAAC;AAED;;;GAGG;AACH,IAAA,gCAAqB,EAAC,GAAG,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;AAE9C,kCAAkC;AAClC,qBAAU,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAA","sourcesContent":["import { twinLog, twinWarn, twinError } from '../../engine/log.js'\nimport { getRepository } from '@things-factory/shell'\n\nimport { getAdapter, type ConnectionConfig, type LiveFeedContinuity, type SiteDescriptor } from './reference-adapter.js'\nimport { TwinEngine, ingestCanonicalRecords, registerLiveFeedProbe, type CanonicalRecord } from '../../engine/index.js'\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinReference } from './twin-reference.js'\n\n/*\n * ์ปค๋ฅํฐ ๊ธฐ๋ฐ ๋ผ์ด๋ธ ํผ๋ ๊ฒฐ์ (reference โ live, ยง0 ํ๋ ์ โ restartPolicy='resync').\n * ํ๋ฆ: adapter.openLiveFeed(cfg, site, records) โ ingestCanonicalRecords(์ ๊ทโ๋ดํฌ) โ TwinEngine.ingestLive(projector ๋ฏธ๋ฌ).\n * ์ปค๋ฅํฐ๊ฐ \"๋ฒค๋ ์ด๋ฒคํธ โ ์ ๊ท ๋ ์ฝ๋\" ๋งคํ์ ์์ (์ฝ๋)ํ๋ค โ preset ๊ธฐ๋ฐ startLiveFeed(operato-twin, http-get+jsonata)์\n * ๋์นญ์ด๋, ๋งคํ ์์น๋ง ๋ค๋ฅด๋ค. ์ค ์์คํ
์ ํ์ connectionConfig.baseUrl ๊ต์ฒด๋ฟ(์ฝ๋ ๊ฒฝ๋ก ๋์ผ).\n * ์๋ช
์ฃผ๊ธฐ: ์ธ์คํด์ค ์ ์ง(TwinEngine.stop)์ ํ
์ผ๋ก ๋ฌถ์ฌ ํผ๋๋ ํจ๊ป unsubscribe.\n */\n\n/** ํ์ฑ ๋ผ์ด๋ธ ํผ๋ โ instanceId โ unsubscribe(์ด๋ํฐ openLiveFeed ๋ฐํ). */\nconst feeds = new Map<string, () => void>()\n\n/**\n * ์ปค๋ฅํฐ ๋ผ์ด๋ธ ๊ธฐ๋ โ ์ด๋ํฐ openLiveFeed ๋ฅผ ์ธ์คํด์ค์ ๊ฒฐ์ .\n * ๋ฐํ: ๋ผ์ด๋ธ ๊ฒฐ์ ์ฑ๊ณต ์ฌ๋ถ(์ด๋ํฐ๊ฐ openLiveFeed ๋ฏธ์ง์์ด๋ฉด false โ ํธ์ถ์ธก์ด sim ํด๋ฐฑ).\n */\nexport async function startReferenceLiveFeed(\n domainId: string,\n adapterType: string,\n cfg: ConnectionConfig,\n site: SiteDescriptor,\n instanceId: string,\n /**\n * **์ด๋ ๋ ํผ๋ฐ์ค์์ ์ฝ๋ ํผ๋์ธ๊ฐ** โ ์ฝ๊ธฐ ์ปค์๋ฅผ ์ ์ฅํ ์๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํจ๋ค(ยง`loadLiveCursor`).\n *\n * ๋ถ๋ฅด๋ ์ชฝ์ด `TwinReference` ๋ฅผ ์ด๋ฏธ ๋ค๊ณ ์์ผ๋ฏ๋ก ๊ทธ ์ด๋ฆ์ ๋๊ธด๋ค. ์ฒ์์๋ `cfg`ยท`site` ์์\n * ์ฐพ์ผ๋ ค ํ๋๋ฐ **๋ ๋ค ๊ทธ ๊ฐ์ ๊ฐ์ง ์ ์๋ค**: `cfg` ๋ ์ฌ๋์ด ํ๋ฉด์์ ์
๋ ฅํ ์ ์ ์ค์ ์ด๊ณ \n * (`endpoint`ยท`token`โฆ), `site` ๋ ์ปค๋ฅํฐ๊ฐ ์๋ณธ์์ ๋ฐ๊ฒฌํ ๊ฒ์ด๋ค โ **๋ ํผ๋ฐ์ค์ ์ด๋ฆ์ ํธ์คํธ๊ฐ\n * ๋ถ์ด๋ ๊ฒ์ด๊ณ ์๋ณธ์ ๊ทธ๊ฒ์ ๋ชจ๋ฅธ๋ค.** ์ปค๋ฅํฐ๊ฐ ์ฑ์ธ ์ ์๋ ๊ฐ์ ์ปค๋ฅํฐ์์ ์ฝ์ผ๋ ค ํ ๊ฒ์ด ์๋ชป์ด์๋ค.\n *\n * ์ฃผ์ง ์์ผ๋ฉด ์ปค์๋ฅผ ์์ง ์๊ณ **๊ทธ ์ฌ์ค์ ๋งํ๋ค**(์กฐ์ฉํ ์ฐฝ์ด ๋ฏธ๋๋ฌ์ง์ง ์๊ฒ).\n */\n source?: string\n): Promise<boolean> {\n const adapter = getAdapter(adapterType)\n if (!adapter?.openLiveFeed) return false\n\n const det = await TwinEngine.detail(domainId, instanceId)\n if (!det?.model) throw new Error(`instance \"${instanceId}\" not provisioned (no model) โ ingest master before live start`)\n\n // ๊ด์ธก ๊ธฐ๋ โ ์ปค๋ tick ์์ด projector ๊ฐ ์ค ์ด๋ฒคํธ๋ฅผ ๋ฐ์ํ๋ค(startLive ๊ฐ restartPolicy='resync' ๋ก ์ ๋๋ค).\n // ์๊ฐ ๊ธฐ์ค์ **๊ณต๊ฐ**์ด ๊ฐ๋๋ค(ํ
๋ํธ ์๋) โ ๊ต๋์ HH:MM ์ ์ด๋ ๊ธฐ์ค์ผ๋ก ์ฝ๋.\n TwinEngine.startLive(instanceId, domainId, det.kind, await TwinEngine.withSpaceTimeBase(det.model, domainId))\n\n stopReferenceLiveFeed(instanceId) // ์ฌ๊ธฐ๋ ์ ์ด์ ํผ๋ ์ ๋ฆฌ\n /*\n * **์ด๋๊น์ง ์ฝ์๋๋ฅผ ์ด ์ธต์ด ๋ค๊ณ ๊ฑด๋จ๋ค**(ยง`LiveFeedContinuity`, 2026-08-23).\n *\n * ์ด๋ํฐ๊ฐ ์ด ๊ฐ์ ์๊ธฐ ์ฌ๋ฌผํจ์ ๋๋ฉด ์๋ณธ์ด ๋ ๋๋ง๋ค ์ ์ฅ ๊ธฐ์ ๊ฐ ๋๊ณ , ๊ทธ์ค ํ๋๊ฐ ์กฐ์ฉํ ๋ค๋ฅด๊ฒ\n * ๋์ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ปค๋์ด ์ด๋ฏธ ๊ฐ๋ผ ๋์๋ค: ใ์์ฒ์ด ์ ์ด์ ๋ค์ ๋งํด ์ฃผ์ง ์๋ ์ถใ์ ์ฌ๊ธฐ๋\n * ์ฐ์์ฑ์ผ๋ก ์ด์ด๋ฐ๋๋ค(ยง`hydrateContinuity`) โ ์ฝ๊ธฐ ์ปค์๊ฐ ์ ํํ ๊ทธ ์ฑ์ง์ด๋ค.\n *\n * ์์ผ๋ฉด `undefined` ๋ฅผ ๊ฑด๋จ๋ค โ ๊ทธ๊ฒ์ด ใ์ฒซ ๋ถ์ใ์ด๋ผ๋ ์ฌ์ค์ด๊ณ , ๊ทธ๋๋ง ์ด๋ํฐ๊ฐ ๋๋์๋ณผ ๋ ์๋ก\n * ์ฒซ ์ฐฝ์ ๋ง๋ ๋ค. ๋น ๊ฐ์ฒด๋ก ๋ฉ์ฐ์ง ์๋๋ค(๊ทธ๋ฌ๋ฉด ์ฒซ ๋ถ์๊ณผ ์ด์ด ๋ถ์์ด ๊ฐ์์ง๋ค).\n */\n const continuity = await loadLiveCursor(domainId, instanceId, source)\n const unsubscribe = adapter.openLiveFeed(cfg, site, (records: unknown[]) => {\n if (!TwinEngine.owns(domainId, instanceId)) {\n stopReferenceLiveFeed(instanceId) // ์ธ์คํด์ค ์ฌ๋ผ์ง๋ฉด ์๊ฐ ์ ์ง(์์ ๋ง)\n return\n }\n const offered = Array.isArray(records) ? records.length : records ? 1 : 0\n const { accepted, rejected } = ingestCanonicalRecords(records as CanonicalRecord[], domainId, new Date().toISOString())\n /*\n * ์ปค๋์ด **๋ช ๊ฑด์ ์ค์ ๋ก ๋ฐ์๋**๋ฅผ ํจ๊ป ๋ณธ๋ค. ํธ์์ด ๋ผ์ด๋ธ๋ก ๋์ง ์์ผ๋ฉด `ingestLive` ๊ฐ 0 ์\n * ๋๋ ค์ฃผ๊ณ , ๊ทธ ์ฐจ์ด๊ฐ ๊ณง ใ๋ฐ๋ฅ์ ๋ฒ๋ ค์ง ์ใ๋ค. ์ด๊ฒ์ ํต๊ณผ๋ก ์ธ๋ฉด ๋ฉ์ถ ํธ์์ด 100% ๋ก ๋ณด์ธ๋ค.\n */\n const applied = accepted.length ? TwinEngine.ingestLive(domainId, instanceId, accepted) : 0\n const undelivered = accepted.length - applied\n /*\n * **๊ฑฐ๋ถํ ๊ฒ์ ์กฐ์ฉํ ๋ฒ๋ฆฌ์ง ์๋๋ค.** ์์ ์๋ `rejected` ๋ฅผ ๋ฐ์ง๋ ์์๋ค โ ์ปค๋ฅํฐ์ ๋งคํ์ด\n * ํ๋ฆฌ๋ฉด ํธ์์ ใ์๋ฌด ์ผ๋ ์ผ์ด๋์ง ์๋ใ ๋ชจ์ต์ด ๋๊ณ , ๋ก๊ทธ์๋ ์๋ฌด ํ์ ์ด ์์๋ค.\n *\n * ๊ทธ๋ค์ ์๋ฆฌ์๋ ใํ๋ฉด๊น์ง ๋๋ฅด๊ธฐใ๋ฅผ ์ด์ ์ฑ์ด๋ค. ๊ฑด๋ง๋ค ๋ธ๋ก๋์บ์คํ
ํ์ง ์๊ณ **์ง๊ณ**ํ๋ค โ ํต๊ณผ๋ถ๊น์ง\n * ํจ๊ป ์ธ๋ ์ด์ ๋, ๊ฑฐ๋ถ๋ง ์ธ๋ฉด ใ์ ์
์์ใ๊ณผ ใ์ ์ใ์ด ๋ ๋ค ๊ฑฐ๋ถ 0 ์ผ๋ก ๊ฐ์ ๋ณด์ด๊ธฐ ๋๋ฌธ์ด๋ค.\n * ์กฐํ๋ `twinIngestHealth`.\n */\n /*\n * **์ฝ์๋ค๋ ๊ฒ ์์ฒด๊ฐ ์ฌ์ค์ด๋ค** โ ๋น ์ฝ๊ธฐ๋ ์ฑ๊ณต์ด๋ฏ๋ก ๋จ์ ๊ธฐ๋ก์ ์ง์ด๋ค(ยง`onReadFailure`).\n * ๊ทธ ๋์ ์์ผ๋ฉด ์กฐ์ฉํ ์๋ณธ์ด ๋๊ธด ์๋ณธ์ผ๋ก ๋ณด์ธ๋ค.\n */\n TwinEngine.clearIngestReadFailure(domainId, instanceId)\n TwinEngine.recordIngestResult(domainId, instanceId, offered, rejected, Date.now(), undelivered)\n if (rejected.length) {\n const why = rejected[0]?.errors?.join(' ยท ') ?? 'unknown'\n twinWarn(`[twin-live] \"${instanceId}\": ${rejected.length}/${offered} record(s) rejected โ e.g. ${why}`)\n }\n /* ๋ฒ๋ ค์ง ๊ฒ์ ๋ก๊ทธ์๋ ๋จ๊ธด๋ค โ ํ๋ฉด์ ๋ณด์ง ์๋ ์ฌ๋๋ ์์์ผ ํ๋ค(์ฌ์ค์ด ์ฌ๋ผ์ง๋ ์ค์ด๋ค). */\n if (undelivered > 0) {\n twinWarn(\n `[twin-live] \"${instanceId}\": ${undelivered}/${offered} record(s) NOT delivered โ the twin is not running live; ` +\n `records are being discarded. Start the twin, or disconnect the feed.`\n )\n }\n }, continuity)\n feeds.set(instanceId, unsubscribe)\n return true\n}\n\n/**\n * ๊ทธ ์๋ณธ์ ์ฝ๊ธฐ ์ปค์๋ฅผ ๋ถ๋ฌ์ค๊ณ , ์์ง์ด๋ฉด ์ ์ฅํ๋ ํต๋ก๋ฅผ ๋ง๋ ๋ค.\n *\n * ์ปค์๋ **์๋ณธ(`TwinReference`)์ ๊ฒ**์ด์ง ์ธ์คํด์ค์ ๊ฒ์ด ์๋๋ค โ ํ ์๋ณธ์ด ์ฌ๋ฌ ์ธ์คํด์ค๋ฅผ ๋ณ๊ณ \n * (`scopeSpec.produced`) ์ฝ๋ ๊ฒ์ ํ ๋ฒ์ด๋ค. ์ธ์คํด์ค๋ง๋ค ์ปค์๋ฅผ ๋๋ฉด ๊ฐ์ ํ๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฝ๋๋ค.\n *\n * ์ ์ฅ ์คํจ๋ **์ผํค์ง ์๊ณ ๋งํ๋ค.** ์กฐ์ฉํ ์คํจํ๋ฉด ๋ค์ ์ฌ๊ธฐ๋์์ ์ฐฝ์ด ๋ค์ ๋ฏธ๋๋ฌ์ง๊ณ , ๊ทธ ์์ค์\n * ์ค๋ฅ ์์ด ์ฌ๋ผ์ง๋ค โ ์ด ์ปฌ๋ผ์ ๋ง๋ ์ด์ ๊ฐ ๋ฐ๋ก ๊ทธ๊ฒ์ด๋ค.\n */\nasync function loadLiveCursor(\n domainId: string,\n /** ์ฝ๊ธฐ ์คํจ๋ฅผ ์ ์ ํธ์ โ ์ปค์๋ ๋ ํผ๋ฐ์ค์ ๊ฒ์ด์ง๋ง **๊ฑด๊ฐ์ ์ธ์คํด์ค์ ๊ฒ**์ด๋ค(ํ ๋ ํผ๋ฐ์ค๊ฐ ์ฌ๋ฟ์ ๋ณ๋๋ค). */\n instanceId: string,\n source?: string\n): Promise<LiveFeedContinuity | undefined> {\n if (!source) {\n /* ์๋ณธ์ ๊ฐ๋ฆฌํฌ ์ ์์ผ๋ฉด ์ ์ฅํ ์๋ฆฌ๋ ์๋ค โ ๊ทธ ์ฌ์ค์ ๋งํ๋ค(์กฐ์ฉํ ์ปค์ ์์ด ๋์ง ์๊ฒ). */\n twinWarn('[twin-live] live cursor not carried โ the caller did not say which reference this feed reads from')\n return undefined\n }\n const repo = getRepository(TwinReference)\n const row = await repo.findOne({ where: { domain: { id: domainId } as any, source } }).catch(() => null)\n if (!row) {\n twinWarn(`[twin-live] live cursor not carried โ no reference row for source \"${source}\"`)\n return undefined\n }\n const stored = row.liveCursor\n if (stored?.firstAttachedAt) {\n twinLog(`[twin-live] \"${source}\": resuming from stored cursor โ knowledge starts ${stored.firstAttachedAt}`)\n }\n return {\n cursor: stored ?? undefined,\n /*\n * **์๋ณธ์ ๋ฟ์ง ๋ชปํ๋ค** โ ์ด๋ํฐ๊ฐ ์๋ฆฌ๋ฉด ์ํ์ ์ ๋๋ค(ยง`onReadFailure`).\n *\n * ๋ก๊ทธ๋ก๋ ์ด๋ํฐ๊ฐ ์ด๋ฏธ ๋งํ๊ณ ์์๋ค(์ฌ์๋ ๊ฒฝ๊ณ ). ๊ทธ๋ฌ๋ **๋ก๊ทธ๋ ์ฌ๋์ด ๋ณผ ๋๋ง ๊ฐ์ด ์๋ค** โ\n * ํ๋ฉด์ด ๋งํ๋ ค๋ฉด ์กฐํ ๊ฐ๋ฅํ ์ํ์ ์์ด์ผ ํ๋ค.\n *\n * โโ `status` ๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๋๋ค (2026-08-23, ๋๋๋ฆฐ ์๋ฆฌ) โโโโโโโโโโโโโโโโโโโโ\n * ์ฒ์์๋ ๋ ํผ๋ฐ์ค ํ์ `status` ๋ฅผ `'error'` ๋ก๋ ์ ์๋ค โ ใ๋ชฉ๋ก์ด ใ์ฐ๊ฒฐ๋จใ์ด๋ผ ๋งํ๋ฉด์ ์ค์ ๋ก๋\n * ๋ชป ์ฝ๋ ์ํ๋ฅผ ์์ ๋ ค๊ณ ใ. **๊ทธ๊ฒ์ด ํผ๋๋ฅผ ์๊ตฌํ ๊ป๋ค.**\n *\n * ๋ถํ
์ฌ๋ถ์ฐฉ์ `status: 'connected'` ์ธ ๋ ํผ๋ฐ์ค๋ง ๋์ด๋ฆฐ๋ค(ยง`resumeReferenceLiveFeeds`). ๊ทธ๋์\n * ์๋ณธ์ด **์ ๊น** ๋๊ธด ๊ฒ์ด ๊ทธ ํ์ `error` ๋ก ๋ง๋ค๊ณ , ๋ค์ ์ฌ๊ธฐ๋์์ ๊ทธ ํผ๋๋ ์์ ๋ถ์ง ์์๋ค โ\n * ์ค์ธก์ผ๋ก ๊ทธ๋ ๊ฒ ๋ฌ๋ค(09:25 ํ์ `[twin-live]` ์ค์ด ํ ์ค๋ ์์๋ค).\n *\n * ๋ ์ถ์ ํ ์นธ์ ์์ ๊ฒ์ด ์์ธ์ด๋ค:\n * `status` **์ฐ๊ฒฐ ์ค์ ์ด ์ฑ๋ฆฝํ๋** โ ์ ์ ์ํยท๋ง์คํฐ ๋๊ธฐ๊ฐ ์ ํ๋ ์ถ(์ฌ๋ถ์ฐฉ์ ์๊ฒฉ์ด๋ค)\n * ์ฝ๊ธฐ ์คํจ **์ง๊ธ ๋ฟ๋** โ ์ค๊ฐ ์ ์๋ ์ฌ์ค์ด๊ณ , ์ ์
์ฅ๋ถ๊ฐ ๊ทธ ์ถ์ ๊ฐ๋๋ค\n *\n * ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ `lastError` ์๋ง ์ ๋๋ค(์ฌ๋์ด ๋ชฉ๋ก์์ ์ด์ ๋ฅผ ๋ณผ ์ ์๊ฒ). ใ์ง๊ธ ๋ฟ๋ใ๋\n * `ingestHealth().readFailure` ๊ฐ ๋ตํ๊ณ , ์ฑ๊ณตํ ์ฃผ๊ธฐ๊ฐ ๊ทธ๊ฒ์ ์ง์ด๋ค.\n */\n onReadFailure: ({ reason, stream }) => {\n TwinEngine.recordIngestReadFailure(domainId, instanceId, reason, Date.now(), stream)\n twinWarn(`[twin-live] \"${source}\": cannot read from the source${stream ? ` (${stream})` : ''} โ ${reason}`)\n repo\n .update({ id: row.id }, { lastError: `live: ${reason}` } as any)\n .catch(err => twinWarn(`[twin-live] \"${source}\": read failure not recorded โ ${err?.message ?? err}`))\n },\n onCursor: next => {\n /* ์ด๋ํฐ๊ฐ ์ค ๋ชจ์์ ๊ทธ๋๋ก ์ ๋๋ค โ ์ด ์ธต์ ํ๋ฆ์ ๋ป์ ๋ชจ๋ฅธ๋ค(์ด์ ๋ ์ด๋ํฐ๊ฐ ์ ํ๋ค). */\n repo\n .update({ id: row.id }, { liveCursor: next } as any)\n .catch(err => twinWarn(`[twin-live] \"${source}\": live cursor not saved โ ${err?.message ?? err}`))\n }\n }\n}\n\n/** ๋ผ์ด๋ธ ํผ๋ ์ค์ง(unsubscribe). */\nexport function stopReferenceLiveFeed(instanceId: string): boolean {\n const unsub = feeds.get(instanceId)\n if (!unsub) return false\n try { unsub() } catch { /* noop */ }\n feeds.delete(instanceId)\n return true\n}\n\n/** ํ์ฑ ํผ๋ ๋ชฉ๋ก(๊ด์ธก). */\nexport function listReferenceLiveFeeds(): string[] {\n return [...feeds.keys()]\n}\n\n/**\n * ๋ถํ
๋ **๋์ด์ง ํผ๋๋ฅผ ๋ค์ ๋ถ์ธ๋ค** โ ๋๋ ๋ฏธ๋ฌ ํธ์์ ๊ณ์ธก์ด ๊ณ์ ๋ค์ด์ค๊ฒ.\n *\n * โโ ๋ฌด์์ด ์กฐ์ฉํ ๋๊ฒผ๋ (2026-08-14) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * `startReferenceLiveFeed` ๋ฅผ ๋ถ๋ฅด๋ ๊ณณ์ `importTwinReference` **ํ๋๋ฟ**์ด์๋ค. ๊ทธ๋์ ์๋ฒ๋ฅผ ํ ๋ฒ\n * ์ฌ๊ธฐ๋ํ๋ฉด ๋ฏธ๋ฌ ํธ์์ ใ๋๋ ์คใ์ด๋ผ ๋งํ๋ฉด์ ์๋ฌด ๊ณ์ธก๋ ๋ฐ์ง ์์๋ค โ ์ค๋ฅ๋ ๋ก๊ทธ๋ ์์ด,\n * ์ฌ๋์ ใ๊ฐ์ด ์ ๋ณํ๋คใ๋ก ์๊ฒ ๋๋ค. ์ค ๋ฐฐํฌ์์ ์ฌ๊ธฐ๋ ํ ๋ฒ์ ๊ณ์ธก์ด ๋ฉ์ถ๋ ์
์ด๋ค.\n *\n * โโ ๋์ด๋ฆด ์ฌ๋ฃ๋ ์ด๋ฏธ ์์๋ผ ์๋ค โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n * `TwinReference` ๊ฐ ์ด๋ํฐ ์ข
๋ฅยท์ ์ ์ค์ ยท๊ทธ ๋ ํผ๋ฐ์ค๊ฐ ๋ง๋ ์ธ์คํด์ค(`scopeSpec.produced`)๋ฅผ ๋ค๊ณ ์๋ค.\n * ์ฌ์ดํธ ์์ ์๋ง ์๋๋ฐ(`hint` ๋ ๋จ๊ธฐ์ง ์์๋ค) **๋ค์ ์ฐพ์์** ์ป๋๋ค(`discoverSites`) โ ์ธ์ ์คํธ๊ฐ\n * ๊ฑท๋ ๊ฒ๊ณผ ๊ฐ์ ๊ธธ์ด๋ฏ๋ก ๊ท์น์ด ๊ฐ๋ผ์ง์ง ์๋๋ค. ๋์ด๋ฆด ์ธ์คํด์ค๊ฐ ์์ผ๋ฉด ๊ทธ ํธ์ถ๋ ํ์ง ์๋๋ค.\n *\n * ์ฌ๊ฐ ๋์์ **๋ฑ๋ก๋ถ๊ฐ ๋๋ ๋ฏธ๋ฌ๋ผ๊ณ ๋งํ๋ ๊ฒ**๋ฟ์ด๋ค: ๋ฉ์ถ ํธ์์ ๋์ด๋ฆฌ๋ฉด ์ฌ๋์ด ๋ฉ์ถ ๊ฒ์\n * ์ฐ๋ฆฌ๊ฐ ๋ค์ ์ผ๋ ๊ฒ์ด๊ณ , ์๋ฎฌ ํธ์์ ์ค ๊ณ์ธก์ ๋ถ์ผ๋ฉด ๋ ํ์ค์ด ์์ธ๋ค.\n */\nexport async function resumeReferenceLiveFeeds(): Promise<{ resumed: string[]; failed: { instanceId: string; error: string }[] }> {\n const resumed: string[] = []\n const failed: { instanceId: string; error: string }[] = []\n /*\n * **ํ ํธ์์ ํผ๋๋ ํ๋๋ค** (2026-08-18).\n *\n * ๊ฐ์ ์ฌ์ดํธ๋ฅผ ๋ ๋ ํผ๋ฐ์ค๊ฐ ๊ฐ๊ฐ ์ธ์ ์คํธํ๋ฉด ๋ ๋ค ๊ทธ ์ธ์คํด์ค๋ฅผ ์๊ธฐ๊ฐ ๋ง๋ ๊ฒ(`produced`)์ผ๋ก\n * ๋ค๊ณ ์๋ค. ๊ธฐ๋ ๋ ๊ทธ ๋ชฉ๋ก์ ๊ทธ๋๋ก ๋๋ฉด ๊ฐ์ ํธ์์ ํผ๋๋ฅผ ๋ ๋ฒ ๋ถ์ด๋๋ฐ, ๋ถ์ด๋ ํจ์๊ฐ ๋ฏธ๋ฌ๋ฅผ\n * ๋ค์ ์ธ์ฐ๋ฏ๋ก(`startLive`) **๋จผ์ ์์ธ ์์ ๊ตฌ๊ฐ์ด ๋ฆฌ์
๋๋ค** โ ์ค์ ๋ก ๊ทธ๋ ๊ฒ ๋ฌ๋ค\n * (๋ก๊ทธ: `reattached 2 feed(s): ems-plant-1, ems-plant-1`).\n *\n * ๊ทธ๋ฌ๋ ํ ๋ฒ๋ง ๋ถ์ด๊ณ , **๋ ๋ ํผ๋ฐ์ค๊ฐ ๊ฐ์ ํธ์์ ์ฃผ์ฅํ๋ค๋ ์ฌ์ค์ ๋งํ๋ค** โ ์กฐ์ฉํ ํ๋๋ฅผ\n * ๊ณ ๋ฅด๋ฉด ์ด๋ ์ ์์ด ๊ทธ ํธ์์ ๋จน์ด๊ณ ์๋์ง ์๋ฌด๋ ๋ชจ๋ฅด๊ฒ ๋๋ค.\n */\n const attached = new Map<string, string>() // instanceId โ ๋จผ์ ๋ถ์ธ ๋ ํผ๋ฐ์ค\n try {\n const refs = await getRepository(TwinReference).find({ where: { status: 'connected' }, relations: ['domain'] })\n for (const ref of refs) {\n const domainId = (ref as any).domain?.id ?? (ref as any).domainId\n const adapter = getAdapter(ref.adapterType)\n if (!domainId || !adapter?.openLiveFeed) continue // ๊ด์ธก๋ง ํ๋ ์ด๋ํฐ์๋ ๋์ด๋ฆด ํผ๋๊ฐ ์๋ค\n\n const produced: any[] = ((ref.scopeSpec as any)?.produced ?? []).filter((p: any) => p?.instanceId && p?.siteId)\n if (!produced.length) continue\n\n /* ๋ฑ๋ก๋ถ๊ฐ ใ๋๋ ๋ฏธ๋ฌใ๋ผ๊ณ ๋งํ๋ ๊ฒ๋ง ๊ณ ๋ฅธ๋ค. */\n const rows = await getRepository(TwinInstance).find({\n where: produced.map((p: any) => ({ domain: { id: domainId }, instanceId: p.instanceId })) as any\n })\n const live = produced.filter((p: any) =>\n rows.some(r => r.instanceId === p.instanceId && r.status === 'running' && r.restartPolicy === 'resync')\n )\n if (!live.length) continue\n\n let sites: SiteDescriptor[]\n try {\n sites = await adapter.discoverSites(ref.connectionConfig ?? {})\n } catch (e: any) {\n /* ์ ์์คํ
์ด ์์ง ์ ๋ด์ ์ ์๋ค โ ์ง์ด๋ด์ง ์๊ณ ๊ทธ๋ ๊ฒ ์ ๋๋ค(ํธ์์ ๊ณ์ ใ๋๋ ๋ฏธ๋ฌใ๋ค). */\n for (const p of live) failed.push({ instanceId: p.instanceId, error: `discover failed: ${e?.message ?? 'unknown'}` })\n continue\n }\n\n for (const p of live) {\n const site = sites.find(s => s.siteId === p.siteId)\n if (!site) {\n failed.push({ instanceId: p.instanceId, error: `site \"${p.siteId}\" no longer discoverable` })\n continue\n }\n const owner = attached.get(p.instanceId)\n if (owner) {\n /* ๋ ์ ์์ด ๊ฐ์ ํธ์์ ์ฃผ์ฅํ๋ค โ ๋จผ์ ๋ถ์ ๊ฒ์ ์งํค๊ณ , ๊ทธ ์ฌ์ค์ ๋จ๊ธด๋ค(๋ ๋ค ๋ถ์ด๋ฉด ๋ฏธ๋ฌ๊ฐ ๋ฆฌ์
๋๋ค). */\n failed.push({\n instanceId: p.instanceId,\n error: `also claimed by reference \"${ref.source}\" โ kept the feed from \"${owner}\" (two connections feeding one twin would reset the mirror)`\n })\n continue\n }\n attached.set(p.instanceId, ref.source)\n try {\n const ok = await startReferenceLiveFeed(domainId, ref.adapterType, ref.connectionConfig ?? {}, site, p.instanceId, ref.source)\n if (ok) resumed.push(p.instanceId)\n else failed.push({ instanceId: p.instanceId, error: 'adapter has no openLiveFeed' })\n } catch (e: any) {\n failed.push({ instanceId: p.instanceId, error: e?.message ?? 'reattach failed' })\n }\n }\n }\n } catch (e: any) {\n twinError('[twin-live] feed resume scan failed', e?.message)\n }\n\n if (resumed.length) twinLog(`[twin-live] reattached ${resumed.length} feed(s): ${resumed.join(', ')}`)\n /* **์กฐ์ฉํ ๋๊ธฐ์ง ์๋๋ค** โ ๋ถ์ง ์์ ๋ฏธ๋ฌ๋ ใ๋๋๋ฐ ์๋ฌด๊ฒ๋ ์ค์ง ์๋ใ ํธ์์ด๋ค. */\n for (const f of failed) twinWarn(`[twin-live] \"${f.instanceId}\" feed NOT reattached โ ${f.error}`)\n return { resumed, failed }\n}\n\n/*\n * ์ด ๊ณ์ธต์ ํผ๋ ์ฅ๋ถ๋ฅผ ๋ฑ๋กํ๋ค โ ํ๋ฉด์ด ใ๋๊นใ์ ๋งํ ๊ทผ๊ฑฐ๋ **๋ฌป๋ ์๋ฆฌ ํ๋**์ฌ์ผ ํ๋ค.\n * (ํ๋ฆฌ์
๊ธฐ๋ฐ ํผ๋๋ ์ฑ์ด ์๊ธฐ ์ฅ๋ถ๋ฅผ ๋ฐ๋ก ๋ฑ๋กํ๋ค. ํ์ชฝ๋ง ๋ณด๋ฉด ํ๋ฅด๋ ํธ์์ ๋๊ฒผ๋ค๊ณ ๋ถ๋ฅธ๋ค.)\n */\nregisterLiveFeedProbe(() => [...feeds.keys()])\n\n/* ์ธ์คํด์ค ์ ์ง ์ ํผ๋ ์๋ ์ ๋ฆฌ(์๋ช
์ฃผ๊ธฐ ๋์นญ). */\nTwinEngine.onStop(instanceId => stopReferenceLiveFeed(instanceId))\n"]}
|
|
@@ -421,6 +421,21 @@ export interface ReferenceMaster {
|
|
|
421
421
|
* BOM ์ ์ค๋ช
๋ฌธ์์๋ง ์ ์ด ๋ ์ฑ ํคํธ๋ฅผ ๋ชป ๋ง๋๋ ํธ์์ ๋ง๋ ์์ธ). ๊ทผ๊ฑฐ๋ ์ปค๋ ๊ณ์ฝ ์ฃผ์์.
|
|
422
422
|
*/
|
|
423
423
|
productionSpec?: unknown;
|
|
424
|
+
/**
|
|
425
|
+
* **์ด ์๋ณธ์ด ์๋ณ์๋ฅผ ๋ง๋๋ ์ด๋ฆ๊ณต๊ฐ** โ `TwinModelDef.identity` ๋ก ํต๊ณผํ๋ค.
|
|
426
|
+
*
|
|
427
|
+
* **์ ์ธ์ด ์์ผ๋ฉด ์ปค๋์ด ๊ฑฐ์ ํ๋ค** (0.7.45~). ์์ ์๋ ์์ ํ๋ฆฌํฝ์ค๋ก ํ๋ ํธยทํธ๋ ์ผ๋ฌยท๋ฌธ์๋ฅผ
|
|
428
|
+
* ๋ง๋ค์๋๋ฐ(`0614141` โ GS1 ์ด ๊ท๊ฒฉ ์์ ๋ก ์ฐ๋ค ๋ฒ๋ฆฐ ๊ฐ์ด๊ณ `06โฆ` ์ ์ค ๋ฐฐ์ ๋์ญ์ด๋ค), ๊ทธ ๊ฐ์
|
|
429
|
+
* ์ ๋์ ์์ํ ๋จ์ผ๋ฉด์ ์ง์ด๋ธ ๊ฒ์ด๋ผ๊ณ ๋งํด ์ฃผ๋ ๋ฐ๊ฐ ์์๋ค. ๊ทธ๋์ ์ปค๋์ด ๋ง๋ค์ง ์๋๋ค.
|
|
430
|
+
*
|
|
431
|
+
* ์๋ณธ์ด ์๊ธฐ ๋๋ฉ์ธ์ ๋งํ๋ฉด ๊ทธ ์๋์์ ๋ง๋ ๋ค โ ๊ทธ๊ฒ์ด ํ์ค ์ ํฉ์ด๋ค(CBV 2.0 ยง8.2.4ยทยง8.5.5,
|
|
432
|
+
* ใ๊ทธ ์ธํฐ๋ท ๋๋ฉ์ธ ์์ ์๊ฐ ๋ฐฐ์ ํ๋คใ). GS1 ํค๋ฅผ ์ฐ๋ ค๋ฉด `documentTypes` + `companyPrefix` ์ด๊ณ ,
|
|
433
|
+
* ๊ทธ๋ **์๋ฆฌ ์๊ฐ ๋ง์์ผ ํ๋ค**(SGTIN ์ ํ๋ฆฌํฝ์ค + ํ๋ชฉ์ฐธ์กฐ = 13์๋ฆฌ, GS1 TDS).
|
|
434
|
+
*
|
|
435
|
+
* ์ ์ฒด์ฑ์ ์์ฐ๊ณผ ๋ฌด๊ดํ๋ฏ๋ก `productionSpec` ์ด ์๋๋ผ **๋ชจ๋ธ**์ด ๊ฐ๋๋ค โ ์ฐฝ๊ณ ยท์ผ๋๋ ์๋ฌด๊ฒ๋
|
|
436
|
+
* ์์ฐํ์ง ์์ผ๋ฉด์ ํ๋ ํธยทํธ๋ ์ผ๋ฌ๋ฅผ ์๋ณํ๋ค.
|
|
437
|
+
*/
|
|
438
|
+
identity?: unknown;
|
|
424
439
|
/**
|
|
425
440
|
* ์ฌ๋ โ ์ ์ธํ์ง ์์ผ๋ฉด **์ธ์ ์ ์ฝ์ด ์๋ ํธ์**์ด ๋๋ค(์ค๋น๋ง ์์ผ๋ฉด ์ธ์ ๋ ๊ฐ๋๋๋ ๊ณต์ฅ).
|
|
426
441
|
* ๊ณต์ ์ด ์ธ์์ ์๊ตฌํ๋๋ฐ ์ฌ๋์ด ์์ผ๋ฉด ๊ทธ ์์
์ ์์๋์ง ์๋๋ค โ ๊ทธ๊ฒ์ด ์ฌ์ค์ด๋ฏ๋ก ๊ทธ๋๋ก ๋๋ค.
|
|
@@ -449,6 +464,21 @@ export interface ReferenceMaster {
|
|
|
449
464
|
* ๋๊ณ ๋ ์กฐ์ฉํ ์ฑ๊ณตํ๋ค. ์ฎ๊ธฐ๋ ์ฌ๋๋ง ์๋ ์ฌ์ค์ ์ฎ๊ธฐ๋ ์๋ฆฌ์์ ์ค์ด์ผ ํ๋ค.
|
|
450
465
|
*/
|
|
451
466
|
warnings?: IngestWarning[];
|
|
467
|
+
/**
|
|
468
|
+
* **์๋ณธ์ด ๊ฐ์ง ์** โ ์ฎ๊ธด ์์ ๋ถ๋ชจ๋ค.
|
|
469
|
+
*
|
|
470
|
+
* ์ดํ์ ๋์ฐฉํ ๋ชจ๋ธ๋ง ๋ณผ ์ ์์ด์ ใ๋ ์ํผ 1,261ใ๊น์ง๋ง ๋งํ ์ ์์๋ค. ๊ทธ๋ฐ๋ฐ ์ฌ๋์ด ๋ฌป๋ ๊ฒ์
|
|
471
|
+
* ใ๊ทธ๊ฒ ์ ๋ถ์ธ๊ฐใ๋ค โ ์๋ณธ์ 1,408๊ฐ๊ฐ ์์๊ณ 147๊ฐ๋ฅผ ์ฎ๊ธฐ์ง ๋ชปํ๋ค๋ฉด ๊ทธ ์ฌ์ค์ด ์ดํ์ ์ฒซ ์ค์
|
|
472
|
+
* ์์ด์ผ ํ๋ค. ์ค์ ๋ก ์ฌ์ฉ์๊ฐ ํ๋ชฉ 2,789 ์ ์์ฌ 1,789 ์ ์ฐจ์ด๋ฅผ ํ๋ฉด์์ ์ฝ์ด ๋ด์ง ๋ชปํด ์ง์
|
|
473
|
+
* ๋ฌผ์๋ค(2026-08-22).
|
|
474
|
+
*
|
|
475
|
+
* ๋ถ๋ชจ๋ฅผ ์๋ ๊ฒ์ **์ปค๋ฅํฐ๋ฟ์ด๋ค.** ๊ทธ๋์ ์ปค๋ฅํฐ๊ฐ ์ค์ด ๋ณด๋ธ๋ค. ๋ณด๋ด์ง ์์ผ๋ฉด ์ดํ์ ๋ถ๋ชจ ์์ด
|
|
476
|
+
* ์ฎ๊ธด ์๋ง ๋งํ๋ค โ **์ง์ด๋ด์ง ์๋๋ค.**
|
|
477
|
+
*
|
|
478
|
+
* ์ด์ ๋ ์ดํ์ด ์ธ๋ ์ด๋ฆ๊ณผ ๊ฐ๋ค(`recipes`ยท`materials`ยท`totalInputs`ยทโฆ). ๊ฐ์ **์๋ณธ์ ๋๊น์ง ์ฝ์ด์
|
|
479
|
+
* ์ผ ๊ฒ**์ด์ด์ผ ํ๋ค. ์๋ฆฐ ์ฝ๊ธฐ์ ์๋ฅผ ์ฌ๊ธฐ ๋ด์ผ๋ฉด ใ์ ๋ถ ์ฎ๊ฒผ๋คใ๋ ๊ฑฐ์ง์ด ๋๋ค.
|
|
480
|
+
*/
|
|
481
|
+
originCounts?: Record<string, number>;
|
|
452
482
|
}
|
|
453
483
|
export interface IngestedTwin {
|
|
454
484
|
model: any;
|
|
@@ -495,8 +525,24 @@ export interface IngestWarning {
|
|
|
495
525
|
* ๊ทธ ๊ฐ์ ์์ ์ ๋ค) ๋์ **๊ทธ ์กฐํฉ์ ๋งํ๋ค** โ ๊ณต๊ฐ์ ์๊ฐ๋๋ฅผ ์ ์ธํ๋ฉด ์ฌ๋ผ์ง๋ ๊ฒฝ๊ณ ๋ค.
|
|
496
526
|
*/
|
|
497
527
|
export declare const generationWithoutTimeZone: (spaceId: string, equipmentId: string) => IngestWarning;
|
|
498
|
-
/**
|
|
528
|
+
/**
|
|
529
|
+
* ์๋ฌด๋ ์ ์ธํ์ง ์์ ์๋ฆฌ ํ์
โ ๊ทธ ์๋ฆฌ๋ ํ๋ฆ์ ์ฐธ์ฌํ์ง ๋ชปํ ์ ์๋ค.
|
|
530
|
+
*
|
|
531
|
+
* **๋ฌป๋ ์๋๋ฅผ ๊ณ ์ณค๋ค (2026-08-20).** ์์ ์๋ ๋ด์ฅ ์นดํ๋ก๊ทธ์๊ฒ๋ง ๋ฌผ์๋ค. ๊ทธ๋ฐ๋ฐ ์๋ณธ์ด ์๊ธฐ
|
|
532
|
+
* `DomainDefinition.locationTypes` ๋ฅผ ํจ๊ป ๋ณด๋ด๋ฉด **๊ทธ ์ ์ธ์ด ์ ๋ณธ**์ด๋ค โ ์นดํ๋ก๊ทธ๋ ์ฐ๋ฆฌ๊ฐ ์๋
|
|
533
|
+
* ๋๋ฉ์ธ๋ค์ ๊ธฐ๋ณธ ์ดํ์ผ ๋ฟ์ด๋ค. ๋ฌผ์ ์๋๊ฐ ํ๋ ธ์ผ๋, ์๊ธฐ ์ดํ๋ฅผ ์ ์ธํ ์๋ณธ์ ์ ์์ ์ธ ํ์
๋ง๋ค
|
|
534
|
+
* ๊ฒฝ๊ณ ๋ฅผ ๋ฐ์๋ค(F&B ๋ผ์ธ์ ๋ถ์ด๋ฉด ์๋ฆฌ๋ง๋ค ํ๋์ฉ). ์์์ด ๋๋ฉด ์ฌ๋์ ๊ฒฝ๊ณ ๋ฅผ ์ฝ์ง ์๊ฒ ๋๊ณ , ๊ทธ๋
|
|
535
|
+
* ์ง์ง ๊ฒฝ๊ณ ๋ ํจ๊ป ์ฃฝ๋๋ค.
|
|
536
|
+
*/
|
|
499
537
|
export declare const unknownLocationType: (system: string, type: string, id: string) => IngestWarning;
|
|
538
|
+
/**
|
|
539
|
+
* ์๋ณธ์ด ํจ๊ป ๋ณด๋ธ ์๋ฆฌ ํ์
์ ์ธ โ ์์ผ๋ฉด **์ด๊ฒ์ด ์ ๋ณธ**์ด๋ค.
|
|
540
|
+
*
|
|
541
|
+
* ์ปค๋ ๊ณ์ฝ์ `DomainDefinition.locationTypes` ๋ `{ key, label, โฆ }` ๋ชฉ๋ก์ด๋ค. ์ฝ์ ์ ์๋ ๋ชจ์์ด๋ฉด
|
|
542
|
+
* `undefined` ๋ฅผ ๋๋ ค **์นดํ๋ก๊ทธ๋ก ๋จ์ด์ง๋ค** โ ๋น ๋ฐฐ์ด์ ๋๋ ค์ฃผ๋ฉด ใ์๋ฌด ํ์
๋ ์ ์ธ๋์ง ์์๋คใ๊ฐ
|
|
543
|
+
* ๋์ด ๋ชจ๋ ์๋ฆฌ๊ฐ ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋๋ค(์๋ ๊ฒ๊ณผ ๋ชป ์ฝ์ ๊ฒ์ ๋ค๋ฅด๋ค).
|
|
544
|
+
*/
|
|
545
|
+
export declare function declaredLocationTypes(productionSpec: unknown): string[] | undefined;
|
|
500
546
|
/** ์๊ฐ๋ ๋ฌธ์์ด์ ๋ชป ์ฝ์๋ค โ ์๊ฐ ํด์์ด UTC ๋ก ๋จ์ด์ง๋ค(์กฐ์ฉํ ํ์ง ์๊ฐ์ผ๋ก ๊ฐ์ ํ์ง ์๋๋ค). */
|
|
501
547
|
export declare const unknownTimezone: (timezone: string) => IngestWarning;
|
|
502
548
|
/** ์์
์ ์์ ์์์๊ฐยทํ๋ผ๋ฏธํฐ๊ฐ ์๋ค โ ์ปค๋ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ๋์ํ๋ค. */
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
11
|
exports.siteEquipmentAdopted = exports.knobDefaultsFilled = exports.describeWarnings = exports.connectorMappingFallback = exports.structureAdopted = exports.projectionFailed = exports.unresolvedReference = exports.noViewableRepresentation = exports.operationWithoutDuration = exports.unknownTimezone = exports.unknownLocationType = exports.generationWithoutTimeZone = void 0;
|
|
12
12
|
exports.utcOffsetOf = utcOffsetOf;
|
|
13
|
+
exports.declaredLocationTypes = declaredLocationTypes;
|
|
13
14
|
exports.masterToTwin = masterToTwin;
|
|
14
15
|
exports.pickOriginSite = pickOriginSite;
|
|
15
16
|
/**
|
|
@@ -44,7 +45,7 @@ function utcOffsetOf(timezone, at = new Date()) {
|
|
|
44
45
|
return sign * (Number(m[2]) * 60 + Number(m[3] ?? 0));
|
|
45
46
|
}
|
|
46
47
|
catch {
|
|
47
|
-
return undefined; // ์ ์ ์๋ ์ด๋ฆ โ Intl ์ด
|
|
48
|
+
return undefined; // ์ ์ ์๋ ์ด๋ฆ โ Intl ์ด ์ค๋ฅ๋ฅผ ๋ธ๋ค
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
@@ -66,13 +67,36 @@ const generationWithoutTimeZone = (spaceId, equipmentId) => ({
|
|
|
66
67
|
'so the generation peak will not land at local noon. Declare the space time zone (we do not guess one).'
|
|
67
68
|
});
|
|
68
69
|
exports.generationWithoutTimeZone = generationWithoutTimeZone;
|
|
69
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* ์๋ฌด๋ ์ ์ธํ์ง ์์ ์๋ฆฌ ํ์
โ ๊ทธ ์๋ฆฌ๋ ํ๋ฆ์ ์ฐธ์ฌํ์ง ๋ชปํ ์ ์๋ค.
|
|
72
|
+
*
|
|
73
|
+
* **๋ฌป๋ ์๋๋ฅผ ๊ณ ์ณค๋ค (2026-08-20).** ์์ ์๋ ๋ด์ฅ ์นดํ๋ก๊ทธ์๊ฒ๋ง ๋ฌผ์๋ค. ๊ทธ๋ฐ๋ฐ ์๋ณธ์ด ์๊ธฐ
|
|
74
|
+
* `DomainDefinition.locationTypes` ๋ฅผ ํจ๊ป ๋ณด๋ด๋ฉด **๊ทธ ์ ์ธ์ด ์ ๋ณธ**์ด๋ค โ ์นดํ๋ก๊ทธ๋ ์ฐ๋ฆฌ๊ฐ ์๋
|
|
75
|
+
* ๋๋ฉ์ธ๋ค์ ๊ธฐ๋ณธ ์ดํ์ผ ๋ฟ์ด๋ค. ๋ฌผ์ ์๋๊ฐ ํ๋ ธ์ผ๋, ์๊ธฐ ์ดํ๋ฅผ ์ ์ธํ ์๋ณธ์ ์ ์์ ์ธ ํ์
๋ง๋ค
|
|
76
|
+
* ๊ฒฝ๊ณ ๋ฅผ ๋ฐ์๋ค(F&B ๋ผ์ธ์ ๋ถ์ด๋ฉด ์๋ฆฌ๋ง๋ค ํ๋์ฉ). ์์์ด ๋๋ฉด ์ฌ๋์ ๊ฒฝ๊ณ ๋ฅผ ์ฝ์ง ์๊ฒ ๋๊ณ , ๊ทธ๋
|
|
77
|
+
* ์ง์ง ๊ฒฝ๊ณ ๋ ํจ๊ป ์ฃฝ๋๋ค.
|
|
78
|
+
*/
|
|
70
79
|
const unknownLocationType = (system, type, id) => ({
|
|
71
80
|
code: 'unknown-location-type',
|
|
72
81
|
params: { system, type, id },
|
|
73
|
-
message: `"${type}" is
|
|
82
|
+
message: `"${type}" is declared nowhere for ${system} (${id}) โ neither in the master's own locationTypes nor in the built-in ` +
|
|
83
|
+
`catalog, so the kernel may not include this location in the flow`
|
|
74
84
|
});
|
|
75
85
|
exports.unknownLocationType = unknownLocationType;
|
|
86
|
+
/**
|
|
87
|
+
* ์๋ณธ์ด ํจ๊ป ๋ณด๋ธ ์๋ฆฌ ํ์
์ ์ธ โ ์์ผ๋ฉด **์ด๊ฒ์ด ์ ๋ณธ**์ด๋ค.
|
|
88
|
+
*
|
|
89
|
+
* ์ปค๋ ๊ณ์ฝ์ `DomainDefinition.locationTypes` ๋ `{ key, label, โฆ }` ๋ชฉ๋ก์ด๋ค. ์ฝ์ ์ ์๋ ๋ชจ์์ด๋ฉด
|
|
90
|
+
* `undefined` ๋ฅผ ๋๋ ค **์นดํ๋ก๊ทธ๋ก ๋จ์ด์ง๋ค** โ ๋น ๋ฐฐ์ด์ ๋๋ ค์ฃผ๋ฉด ใ์๋ฌด ํ์
๋ ์ ์ธ๋์ง ์์๋คใ๊ฐ
|
|
91
|
+
* ๋์ด ๋ชจ๋ ์๋ฆฌ๊ฐ ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋๋ค(์๋ ๊ฒ๊ณผ ๋ชป ์ฝ์ ๊ฒ์ ๋ค๋ฅด๋ค).
|
|
92
|
+
*/
|
|
93
|
+
function declaredLocationTypes(productionSpec) {
|
|
94
|
+
const list = productionSpec?.definition?.locationTypes;
|
|
95
|
+
if (!Array.isArray(list) || !list.length)
|
|
96
|
+
return undefined;
|
|
97
|
+
const keys = list.map((t) => (typeof t === 'string' ? t : t?.key)).filter((k) => typeof k === 'string' && k);
|
|
98
|
+
return keys.length ? keys : undefined;
|
|
99
|
+
}
|
|
76
100
|
/** ์๊ฐ๋ ๋ฌธ์์ด์ ๋ชป ์ฝ์๋ค โ ์๊ฐ ํด์์ด UTC ๋ก ๋จ์ด์ง๋ค(์กฐ์ฉํ ํ์ง ์๊ฐ์ผ๋ก ๊ฐ์ ํ์ง ์๋๋ค). */
|
|
77
101
|
const unknownTimezone = (timezone) => ({
|
|
78
102
|
code: 'unknown-timezone',
|
|
@@ -177,7 +201,11 @@ exports.siteEquipmentAdopted = siteEquipmentAdopted;
|
|
|
177
201
|
function masterToTwin(master, catalog) {
|
|
178
202
|
/* ์ปค๋ฅํฐ๊ฐ ์ฎ๊ธฐ๋ฉฐ ์๊ฒ ๋ ๊ฒ์ ๋จผ์ ์ฃ๋๋ค โ ์์ธ์ด ์์ ์ค๋ ํธ์ด ์ฝ๊ธฐ ์ฝ๋ค(๋์ฒด๊ฐ ๋จผ์ , ๊ทธ ๊ฒฐ๊ณผ๊ฐ ๋ค). */
|
|
179
203
|
const warnings = [...(master.warnings ?? [])];
|
|
180
|
-
|
|
204
|
+
/*
|
|
205
|
+
* ์๋ณธ์ด ์๊ธฐ ์ดํ๋ฅผ ์ ์ธํ์ผ๋ฉด **๊ทธ๊ฒ์ ๋์กฐํ๋ค.** ๋ด์ฅ ์นดํ๋ก๊ทธ๋ ๊ทธ ์ ์ธ์ด ์์ ๋์ ๊ธฐ๋ณธ์ด๋ค โ
|
|
206
|
+
* ์๋๋ฅผ ๋ฐ๊พธ์ง ์์ผ๋ฉด, ์๊ธฐ ์ดํ๋ฅผ ์ ์ธํ ์๋ณธ์ด ์ ์์ ์ธ ์๋ฆฌ๋ง๋ค ๊ฒฝ๊ณ ๋ฅผ ๋ฐ๋๋ค.
|
|
207
|
+
*/
|
|
208
|
+
const known = declaredLocationTypes(master.productionSpec) ?? catalog?.[master.system]?.locationTypes ?? [];
|
|
181
209
|
const locationEntries = master.locations.filter(l => l.role === 'location' || l.role === 'both');
|
|
182
210
|
const areaLocs = master.locations.filter(l => l.role === 'area' || l.role === 'both');
|
|
183
211
|
const locations = locationEntries.map(l => {
|
|
@@ -276,6 +304,8 @@ function masterToTwin(master, catalog) {
|
|
|
276
304
|
locations, equipment, layout, spaceId,
|
|
277
305
|
/* ์์ฐ ์ ์๋ ์๋์ง ์๊ณ ํต๊ณผ โ ๊ฒฝ๊ณ์์ ์ดํ๋ฅผ ๊ฐ์ง ์๋๋ค(์ปค๋์ด ๊ทธ๋๋ก ์๋นํ๋ค). */
|
|
278
306
|
...(master.productionSpec ? { productionSpec: master.productionSpec } : {}),
|
|
307
|
+
/* ์ ์ฒด์ฑ ์ ์ธ๋ ๊ทธ๋๋ก ํต๊ณผํ๋ค โ ์์ผ๋ฉด ๋ง๋ค์ง ์๋๋ค(์ปค๋์ด ๋ ๊ฑฐ์ ์์๋ก ๋จ์ด์ง๋ค). */
|
|
308
|
+
...(master.identity ? { identity: master.identity } : {}),
|
|
279
309
|
...(materialDefinitions?.length ? { materialDefinitions } : {}),
|
|
280
310
|
...(materialClasses?.length ? { materialClasses } : {}),
|
|
281
311
|
...(utcOffsetMinutes !== undefined ? { utcOffsetMinutes } : {}),
|