@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
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ๋ก๊ทธ์ **์๊ฐ์ด ์๋ค** โ ๊ทธ๋ฆฌ๊ณ ์ด๋ค ์ธ์๋ ๋ฒ๋ฆฌ์ง ์๋๋ค (2026-08-22).
|
|
3
|
+
*
|
|
4
|
+
* ๋ฃจํ๊ฐ 55์ด ๋งํ ๊ฒ์ ๊ณ๊ธฐ๋ก ์์๋๋๋ฐ ๊ทธ ์๊ฐ์ ๋ฌด์จ ์ผ์ด ์์๋์ง ๋ก๊ทธ์์ ์ฐพ์ ์ ์์๋ค.
|
|
5
|
+
* ํธ์์ ์ค์ด `console.log` ๋ก ๋๊ฐ ์๊ฐ์ด ์์๊ธฐ ๋๋ฌธ์ด๋ค. ์ด ์ํ์ด ์งํค๋ ๊ฒ:
|
|
6
|
+
* โ ํ์ โ ํ๋ ์์ํฌ ์ค๊ณผ ๊ฐ์ ๋ชจ์, **๋ฐ๋ฆฌ์ด๊น์ง**(๊ณ๊ธฐ์ ๊ฐ์ด epoch ms ๋ค)
|
|
7
|
+
* โก ์ง์ญ ์๊ฐ โ ํ๋ ์์ํฌ์ ๋ค๋ฅธ ์ค๊ณผ ๊ฐ์ ๊ธฐ์ค(UTC ๋ก ์ฐ์ผ๋ฉด ๋๋ํ ์ฝ์ ์ ์๋ค)
|
|
8
|
+
* โข ์ธ์๋ฅผ ๋ฒ๋ฆฌ์ง ์๋๋ค โ ์ค๋ฅ๋ ์คํ๊น์ง(`console.error(msg, err)` ๋ก ์ฐ๋ ์๋ฆฌ๊ฐ ๋ง๋ค)
|
|
9
|
+
* โฃ ํธ์ ์์ค์ `console.` ์ง์ ํธ์ถ์ด ๋จ์ง ์๋๋ค โ ํ๋๋ผ๋ ๋จ์ผ๋ฉด ๊ทธ ์ค๋ง ์๊ฐ์ด ์๋ค
|
|
10
|
+
*/
|
|
11
|
+
import { test } from 'node:test'
|
|
12
|
+
import assert from 'node:assert/strict'
|
|
13
|
+
import { readFileSync, readdirSync } from 'node:fs'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
|
|
16
|
+
import { line, stamp } from '../server/engine/log.ts'
|
|
17
|
+
|
|
18
|
+
test('์๊ฐ์ ๋ฐ๋ฆฌ์ด์ ์คํ์
๊น์ง ์ ๋๋ค โ ๊ฐ์ ์ด ์์ ์์๋ฅผ ๊ฐ๋ฆด ์ ์๊ฒ', () => {
|
|
19
|
+
const s = stamp(new Date(2026, 7, 22, 5, 54, 12, 345))
|
|
20
|
+
assert.match(s, /^2026-08-22T05:54:12\.345[+-]\d\d:\d\d$/, `ํ์์ด ๋ค๋ฅด๋ค: ${s}`)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('์ง์ญ ์๊ฐ์ผ๋ก ์ ๋๋ค โ ํ๋ ์์ํฌ์ ๋ค๋ฅธ ์ค๊ณผ ๊ฐ์ ๊ธฐ์ค', () => {
|
|
24
|
+
const at = new Date(2026, 0, 2, 3, 4, 5, 6)
|
|
25
|
+
const s = stamp(at)
|
|
26
|
+
assert.ok(s.startsWith('2026-01-02T03:04:05.006'), `์ง์ญ ์๊ฐ์ด ์๋๋ค: ${s}`)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('์ค๋ฅ๋ ์คํ๊น์ง ๋จ๋๋ค โ ใ์ด๋์ ๋ฌ๋ใ๋ฅผ ์์ง ์๊ฒ', () => {
|
|
30
|
+
const err = new Error('๋ถ์ด ๋ฌ๋ค')
|
|
31
|
+
const out = line(['[twin-engine] ์ ์ฅ ์คํจ', err])
|
|
32
|
+
assert.ok(out.includes('[twin-engine] ์ ์ฅ ์คํจ'))
|
|
33
|
+
assert.ok(out.includes('๋ถ์ด ๋ฌ๋ค'))
|
|
34
|
+
assert.ok(out.includes('log-stamp.test'), '์คํ์ด ์์ด์ผ ์ด๋ ์๋ฆฌ์์ ๋ฌ๋์ง ์ ์ ์๋ค')
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
test('๊ฐ์ด ์์ด๋ ์์๋ค๋ ์ฌ์ค์ ๋จ๊ธด๋ค โ ์กฐ์ฉํ ์ง์ฐ์ง ์๋๋ค', () => {
|
|
38
|
+
assert.equal(line(['a', undefined, null, 0]), 'a undefined null 0')
|
|
39
|
+
const circular: any = { name: 'ใฑ' }
|
|
40
|
+
circular.self = circular
|
|
41
|
+
assert.ok(line(['๋ณด๊ณ ', circular]).startsWith('๋ณด๊ณ '), '์ํ ์ฐธ์กฐ์๋ ์ค์ด ๋จ์์ผ ํ๋ค')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('ํธ์ ์์ค์ console ์ง์ ํธ์ถ์ด ๋จ์ ์์ง ์๋ค โ ํ ์ค์ด๋ผ๋ ๋จ์ผ๋ฉด ๊ทธ ์ค๋ง ์๊ฐ์ด ์๋ค', () => {
|
|
45
|
+
const root = fileURLToPath(new URL('../server/', import.meta.url))
|
|
46
|
+
const offenders: string[] = []
|
|
47
|
+
const walk = (dir: string) => {
|
|
48
|
+
for (const e of readdirSync(dir, { withFileTypes: true })) {
|
|
49
|
+
const p = dir + e.name
|
|
50
|
+
if (e.isDirectory()) walk(p + '/')
|
|
51
|
+
else if (e.name.endsWith('.ts') && e.name !== 'log.ts') {
|
|
52
|
+
const src = readFileSync(p, 'utf-8')
|
|
53
|
+
for (const m of src.matchAll(/console\.(log|warn|error)\(/g)) offenders.push(`${p.slice(root.length)} console.${m[1]}`)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
walk(root)
|
|
58
|
+
assert.deepEqual(offenders, [], `์๊ฐ ์๋ ๋ก๊ทธ๊ฐ ๋จ์ ์๋ค โ twinLogยทtwinWarnยทtwinError ๋ฅผ ์ด๋ค:\n ${offenders.join('\n ')}`)
|
|
59
|
+
})
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ๋ฃจํ ์ง์ฒด ๊ณ๊ธฐ โ **์์ธ์ ์ง์ด๋ด์ง ์๊ธฐ ์ํ ๊ฐ**์ด ์ ํํ์ง ๋ณธ๋ค (2026-08-21).
|
|
3
|
+
*
|
|
4
|
+
* ์งํค๋ ๊ฒ:
|
|
5
|
+
* โ ๋ฆ๊ฒ ๊นจ์ด๋ ๋งํผ๋ง ์ง์ฒด๋ค โ ์ ๋ ๊นจ์ด๋ ํ๋ณธ์ 0 ์ด๊ณ , 0 ์ ์ ์ฒด๋ก ์ธ์ง ์๋๋ค.
|
|
6
|
+
* โก ์ฐฝ์ด ๋ซํ๊ธฐ ์ ์๋ `recent` ๊ฐ **null** ์ด๋ค(์ฑ์ฐ๋ ์ค์ธ ์ฐฝ์ ใ์ง๊ธใ์ผ๋ก ์ฝ์ผ๋ฉด ๊ณผ์ ์ง๊ณ๋ค).
|
|
7
|
+
* โข ๊ฐ์ฅ ๊ธธ๊ฒ ๋งํ **์๊ฐ**์ ๋ ๋ค โ ์ธ์ ์๋์ง๊ฐ ์์ธ์ ๊ฐ๋ฆฌ๋ ๊ทผ๊ฑฐ๋ค.
|
|
8
|
+
* โฃ ๋ฌธํฑ ์ดํ์ ํ๋ค๋ฆผ์ ์ ์ฒด๋ก ์ธ์ง ์๋๋ค.
|
|
9
|
+
*/
|
|
10
|
+
import { test } from 'node:test'
|
|
11
|
+
import assert from 'node:assert/strict'
|
|
12
|
+
|
|
13
|
+
import { LoopLagSampler } from '../server/engine/loop-lag.ts'
|
|
14
|
+
|
|
15
|
+
/** ์๊ณ๋ฅผ ์์ผ๋ก ๋ฐ์ด ๋ฃ๋๋ค โ ์ค์ ํ์ด๋จธ๋ก ์ฌ๋ฉด ๊ธฐ๊ณ ์ํ๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ํ๋ค. */
|
|
16
|
+
function sampler(sampleMs = 500, stallMs = 200, windowMs = 10_000) {
|
|
17
|
+
let now = 1_000_000
|
|
18
|
+
const s = new LoopLagSampler(sampleMs, stallMs, windowMs, () => now)
|
|
19
|
+
return { s, advance: (ms: number) => (now += ms), at: () => now }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test('์ ๋ ๊นจ์ด๋ ํ๋ณธ์ ์ง์ฒด๊ฐ 0 ์ด๊ณ ์ ์ฒด๋ก ์ธ์ง ์๋๋ค', () => {
|
|
23
|
+
const { s, advance, at } = sampler()
|
|
24
|
+
for (let i = 0; i < 4; i++) {
|
|
25
|
+
advance(500)
|
|
26
|
+
assert.equal(s.sample(at()), 0)
|
|
27
|
+
}
|
|
28
|
+
assert.equal(s.view().total.stalls, 0)
|
|
29
|
+
assert.equal(s.view().total.maxMs, 0)
|
|
30
|
+
assert.equal(s.view().total.samples, 4)
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
test('๋ฆ๊ฒ ๊นจ์ด๋ ๋งํผ์ด ์ง์ฒด๋ค โ ๊ทธ ์ด๊ณผ๋ถ๋ง', () => {
|
|
34
|
+
const { s, advance, at } = sampler()
|
|
35
|
+
advance(500)
|
|
36
|
+
s.sample(at())
|
|
37
|
+
advance(4_600) // ์์ ๋ณด๋ค 4,100ms ๋ฆ๊ฒ
|
|
38
|
+
assert.equal(s.sample(at()), 4_100)
|
|
39
|
+
assert.equal(s.view().total.maxMs, 4_100)
|
|
40
|
+
assert.equal(s.view().total.stalls, 1)
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('๋ฌธํฑ ์ดํ์ ํ๋ค๋ฆผ์ ์ ์ฒด๊ฐ ์๋๋ค โ ๊ฐ์ ๋จ๊ธฐ๊ณ ์ธ์ง๋ ์๋๋ค', () => {
|
|
44
|
+
const { s, advance, at } = sampler(500, 200)
|
|
45
|
+
advance(650) // 150ms ์ง์ฒด โ ๋ฌธํฑ 200 ๋ฏธ๋ง
|
|
46
|
+
s.sample(at())
|
|
47
|
+
const v = s.view()
|
|
48
|
+
assert.equal(v.total.maxMs, 150)
|
|
49
|
+
assert.equal(v.total.stalls, 0, '๋ฌธํฑ ์ดํ๋ฅผ ์ธ๋ฉด ์ ์ ์ํ๊ฐ ์ ์ฒด๋ก ๋ณด์ธ๋ค')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('์ฐฝ์ด ๋ซํ๊ธฐ ์ ์๋ recent ๊ฐ null ์ด๋ค โ ์ฑ์ฐ๋ ์ค์ธ ์ฐฝ์ ใ์ง๊ธใ์ผ๋ก ์ฝ์ง ์๋๋ค', () => {
|
|
53
|
+
const { s, advance, at } = sampler(500, 200, 2_000)
|
|
54
|
+
advance(500)
|
|
55
|
+
s.sample(at())
|
|
56
|
+
assert.equal(s.view().recent, null)
|
|
57
|
+
|
|
58
|
+
/* ์ฐฝ ๊ธธ์ด๋ฅผ ๋๊ธฐ๋ฉด ๊ทธ ์ฐฝ์ด ๋ซํ `recent` ๊ฐ ๋๋ค. */
|
|
59
|
+
advance(2_000)
|
|
60
|
+
s.sample(at())
|
|
61
|
+
const v = s.view()
|
|
62
|
+
assert.ok(v.recent, '์ฐฝ ๊ธธ์ด๋ฅผ ๋๊ฒผ์ผ๋ฉด ๋ซํ ์ฐฝ์ด ์์ด์ผ ํ๋ค')
|
|
63
|
+
assert.equal(v.recent!.stalls, 1, '1,500ms ์ง์ฒด๋ ์ ์ฒด ํ ๋ฒ์ด๋ค')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
test('๊ฐ์ฅ ๊ธธ๊ฒ ๋งํ ์๊ฐ์ ๋ ๋ค โ ์ธ์ ์๋์ง๊ฐ ์์ธ์ ๊ฐ๋ฆฐ๋ค', () => {
|
|
67
|
+
const { s, advance, at } = sampler()
|
|
68
|
+
advance(500)
|
|
69
|
+
s.sample(at())
|
|
70
|
+
advance(3_000)
|
|
71
|
+
const worst = at()
|
|
72
|
+
s.sample(worst)
|
|
73
|
+
advance(500)
|
|
74
|
+
s.sample(at())
|
|
75
|
+
assert.equal(s.view().worstAtMs, worst)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('ํ ๋ฒ๋ ์ฌ์ง ์์์ผ๋ฉด ์ ์ฒด ์๊ฐ์ null ์ด๋ค โ 0 ์ผ๋ก ์ ์ง ์๋๋ค', () => {
|
|
79
|
+
const { s } = sampler()
|
|
80
|
+
assert.equal(s.view().worstAtMs, null)
|
|
81
|
+
assert.equal(s.view().recent, null)
|
|
82
|
+
})
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* โ
ใ์๋ณธ์ด ๋งํ ์ ์๋ ๊ฒใ์ ์ธ๋ ๊ท์จ.
|
|
3
|
+
*
|
|
4
|
+
* โโ ์ ์ด๊ฒ์ด ํ์ํ๊ฐ (2026-08-20 ์ค์ธก) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
5
|
+
* ๋๊ธฐํ ๊ฑด๊ฐ ๊ธฐ๋ฅ์ ๋ง๋ค ๋ ์ ๊ฐ ์ ์ ๋ฅผ ์ด๋ ๊ฒ ์ ์๋ค: *ใ์ปค๋ฅํฐ์ ๋งคํ์ด ํ ๊ธ์ ํ๋ฆฌ๋ฉด ํธ์์
|
|
6
|
+
* ๋น ๊ณต์ฅ์ด ๋๋คใ*. ์ฌ์ฉ์๊ฐ ๊ทธ ์ ์ ๋ฅผ ๊ฒ์ฆํ๊ฒ ํด์ ์ฌ ๋ดค๋๋, ์ ์
๋ฌธ์ ์ฐธ์กฐ ์ค๋ฅ๋ฅผ **๊ฑฐ๋ถํ์ง
|
|
7
|
+
* ์์๋ค**:
|
|
8
|
+
*
|
|
9
|
+
* ๋ชจ๋ฅด๋ ๋ก์ผ์ด์
ใ์คํ-99ใ โ ํต๊ณผ
|
|
10
|
+
* ๋ชจ๋ฅด๋ bizStep ใPUTAWAY_X17ใ โ ํต๊ณผ
|
|
11
|
+
* ๋ชจ๋ฅด๋ ๊ณ๋๊ธฐ ใMMXU-์คํ-99ใ โ ํต๊ณผ
|
|
12
|
+
*
|
|
13
|
+
* ์ฆ ๊ทธ ๊ธฐ๋ฅ์ด ์ก๊ฒ ๋ค๊ณ ๋ด์ธ์ด ๋ํ ์ฌ๋ก๊ฐ `mapping-blocked` ๋ก๋ **๋ฐ ์ ์์๋ค.** ๊ฑฐ๋ถ๋๋ ๊ฒ์
|
|
14
|
+
* ํํ ์ค๋ฅ๋ฟ์ด๋ค(์๊ฐ ํ์ยท์ซ์ ์๋ ๊ฐยทepc ์์).
|
|
15
|
+
*
|
|
16
|
+
* ๊ฑฐ๋ถํ์ง ์๋ ๊ฒ์ด ์ณ๋ค โ ์์ฒ์ด ๋ชจ๋ธ๋ณด๋ค ๋จผ์ ์ ๋ก์ผ์ด์
์ ๋งํ๋ ๊ฒ์ ์ ์์ด๊ณ , ๊ฑฐ๋ถํ๋ฉด ๊ทธ ์ ํ
|
|
17
|
+
* ๊ณ์ธก์ ์๋๋ค. ์ปค๋์ ํก์ํ๊ณ **ํ์ํ๋ค**(`origin: 'observed'`). ๋น ์ ธ ์๋ ๊ฒ์ ๊ทธ ํ์๋ฅผ
|
|
18
|
+
* ใ๋ง์ถฐ์ง๊ณ ์๋ใ๋ฅผ ๋ณด๋ ์ฌ๋์๊ฒ ์๋ ์ผ์ด์๋ค.
|
|
19
|
+
*
|
|
20
|
+
* โโ ์งํค๋ ๊ฒ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
21
|
+
* โ ๋ง์คํฐ๊ฐ ๋งํ ๊ฒ๊ณผ ๊ด์ธก์ผ๋ก ์๊ฒ ๋ ๊ฒ์ ์์ง ์๋๋ค
|
|
22
|
+
* โก ํธ์์ด ์ ๋๋ฉด `null` โ ใ์๋คใ์ ใ์ธ์ด ๋ณด์ง ๋ชปํ๋คใ๋ ๋ค๋ฅด๋ค
|
|
23
|
+
* โข ์กฐ์ฉํ ์๋ฅด์ง ์๋๋ค โ ์ํ์์ ๋ฐ๋ ค๋ ์๋ฅผ ํจ๊ป ๋ธ๋ค
|
|
24
|
+
* โฃ ๋ฎ์ง ๋ชปํ๋ ์ถ์ ๋ฐํ๋ค โ ๊ณ๋๊ธฐ๋ ์ปค๋์ด ํ์๋ฅผ ๋ฌ์ง ์์ ์ด ํ๋ฉด์ด ๋ชป ์ฐพ์ ์ค๋ค
|
|
25
|
+
*/
|
|
26
|
+
import { test } from 'node:test'
|
|
27
|
+
import assert from 'node:assert/strict'
|
|
28
|
+
|
|
29
|
+
import { GAP_ID_LIMIT, modelGapOf } from '../server/engine/model-gap.ts'
|
|
30
|
+
|
|
31
|
+
const loc = (id: string, origin: string) => ({ id, origin })
|
|
32
|
+
|
|
33
|
+
test('๋ง์คํฐ๊ฐ ๋งํ ๋ก์ผ์ด์
์ ๊ฐญ์ด ์๋๋ค โ ์ ์ธ๋ ๊ฒ์ ๋ฌธ์ ๋ก ์ธ์ง ์๋๋ค', () => {
|
|
34
|
+
const g = modelGapOf({
|
|
35
|
+
locations: [loc('dock-recv', 'master'), loc('bin-1', 'master')],
|
|
36
|
+
equipment: [loc('fk-1', 'master')]
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
assert.equal(g!.total, 0)
|
|
40
|
+
assert.deepEqual(g!.locations.ids, [])
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('๊ด์ธก์ผ๋ก๋ง ์๊ฒ ๋ ๊ฒ์ ์ถ๋ง๋ค ์ผ๋ค โ ์์ฒ์ด ์ฐ๋ฆฌ๊ฐ ๋ชจ๋ฅด๋ id ๋ฅผ ๋ณด๋ด๊ณ ์๋ค', () => {
|
|
44
|
+
const g = modelGapOf({
|
|
45
|
+
locations: [loc('dock-recv', 'master'), loc('์คํ-99', 'observed'), loc('A-77', 'observed')],
|
|
46
|
+
equipment: [loc('fk-1', 'master'), loc('์๋-์ง๊ฒ์ฐจ', 'observed')],
|
|
47
|
+
persons: [loc('unknown-op', 'observed')]
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
assert.equal(g!.locations.count, 2)
|
|
51
|
+
assert.equal(g!.locations.unknown, 0, 'ํ์๊ฐ ๋ค ์์ผ๋ฉด ๋ชจ๋ฆ์ 0')
|
|
52
|
+
assert.deepEqual(g!.locations.ids, ['์คํ-99', 'A-77'], 'id ๋ฅผ ๋ณด์ฌ ์ค๋ค โ ์คํ๋ ๋์ผ๋ก ์ฐพ๋๋ค')
|
|
53
|
+
assert.equal(g!.equipment.count, 1)
|
|
54
|
+
assert.equal(g!.persons.count, 1)
|
|
55
|
+
assert.equal(g!.total, 4, '์ธ ์ถ์ ํฉ')
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('ํธ์์ด ์ ๋๋ฉด ใ์์ใ์ด๋ค โ 0 ์ด ์๋๋ค', () => {
|
|
59
|
+
/* ๋น๊ตํ ์๋๊ฐ ์๋ค. 0 ์ผ๋ก ๋ตํ๋ฉด ใ์์ฒ์ด ์ฐ๋ฆฌ๊ฐ ์๋ ๊ฒ๋ง ๋ณด๋ธ๋คใ๋ ์๋ ์ฌ์ค์ด ์๊ธด๋ค. */
|
|
60
|
+
assert.equal(modelGapOf(null), null)
|
|
61
|
+
assert.equal(modelGapOf(undefined), null)
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('๋์ง๋ง ๊ด์ธก ๊ฐญ์ด ์์ผ๋ฉด 0 ์ด๋ค โ ์ด๊ฑด ใ์์ใ๊ณผ ๋ค๋ฅด๋ค', () => {
|
|
65
|
+
const g = modelGapOf({ locations: [] })
|
|
66
|
+
|
|
67
|
+
assert.notEqual(g, null, '์ธ์ด ๋ดค๋ค')
|
|
68
|
+
assert.equal(g!.total, 0, '์ธ์ด ๋ณด๋ ์์๋ค')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('id ๋ฅผ ์กฐ์ฉํ ์๋ฅด์ง ์๋๋ค โ ๋ฐ๋ ค๋ ์๋ฅผ ํจ๊ป ๋ธ๋ค', () => {
|
|
72
|
+
const many = Array.from({ length: GAP_ID_LIMIT + 7 }, (_, i) => loc(`ghost-${i}`, 'observed'))
|
|
73
|
+
const g = modelGapOf({ locations: many })
|
|
74
|
+
|
|
75
|
+
assert.equal(g!.locations.count, GAP_ID_LIMIT + 7, '์ ๋ถ ์ผ๋ค')
|
|
76
|
+
assert.equal(g!.locations.ids.length, GAP_ID_LIMIT, '๋ณด์ด๋ ๊ฒ์ ์ํ๊น์ง')
|
|
77
|
+
assert.equal(g!.locations.more, 7, '๋ฐ๋ ค๋ ์๋ฅผ ๋งํ๋ค')
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
test('์ปค๋์ด ๋ด์ ์ค ๋ชจ๋ฅธ ์ฌ๊ฑด์ ํจ๊ป ๋ธ๋ค โ ์ฐธ์กฐ ๋ฌธ์ ์ ๋ค๋ฅธ ์ฌ์ค์ด๋ค', () => {
|
|
81
|
+
const at = Date.parse('2026-08-20T01:02:03.000Z')
|
|
82
|
+
const g = modelGapOf({
|
|
83
|
+
unhandled: [
|
|
84
|
+
{ eventType: 'epcis.TransformationEvent', count: 12, lastAtMs: at },
|
|
85
|
+
{ eventType: 'aggregation-mixed-classes', count: 3 }
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
assert.equal(g!.unhandled.length, 2)
|
|
90
|
+
assert.equal(g!.unhandled[0].lastAt, '2026-08-20T01:02:03.000Z', '์ธ์ ๊น์ง ๋ฌ๋์ง โ ๋ฉ์ถ ์ข
๋ฅ๋ ๊ณ ์ณ์ง ๊ฒ์ด๋ค')
|
|
91
|
+
assert.equal(g!.unhandled[1].lastAt, null, '์๊ฐ์ด ์์ผ๋ฉด ์ง์ด๋ด์ง ์๋๋ค')
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
test('๋ชจ๋ฅด๋ ์ค๋น์ ์๋์ง ๋ณด๊ณ ๋ ใ์์ใ๊ณผ 0 ์ ๊ฐ๋ฅธ๋ค โ ๊ฒฝ๋ก๊ฐ `energy` ์์ด๋ค', () => {
|
|
95
|
+
/*
|
|
96
|
+
* ์ด ๊ฐ์ **๋ฃจํธ์์ ์ฝ๊ณ ์์๋ค**(2026-08-20์ ์ก์). ์ปค๋์ `EnergyState` ์์ ๋ด์ผ๋ฏ๋ก ๋ฃจํธ์์
|
|
97
|
+
* ์ฝ์ผ๋ฉด ์์ํ `null` ์ด๊ณ , ์ค๋ฅ ์์ด ใ์๋์ง ํธ์์ด ์๋๋คใ๋ก ์ฝํ๋ค. ๋๋ง ์ฝ๋ ํ๋๋ฅผ ์๋ชป๋
|
|
98
|
+
* ๊ฒฝ๋ก์์ ์ฝ์ผ๋ฉด ์ด๋ ๊ฒ ์กฐ์ฉํ ์ฌ๋ผ์ง๋ค.
|
|
99
|
+
*
|
|
100
|
+
* ๊ทธ๋ฆฌ๊ณ ์ปค๋์ 0 ์ด๋ฉด ๊ทธ ์นธ์ ๋ง๋ค์ง ์๋๋ค. ๊ทธ๋์ `energy` ์์ฒด๊ฐ ์๋์ง๋ก ใ์ธ์๊ณ 0ใ๊ณผ
|
|
101
|
+
* ใ์๋์ง ํธ์์ด ์๋ใ์ ๊ฐ๋ฅธ๋ค.
|
|
102
|
+
*/
|
|
103
|
+
assert.equal(modelGapOf({})!.unknownEquipmentReports, null, '์๋์ง ํธ์์ด ์๋๋ฉด ์ด ์๊ฐ ์๋ค')
|
|
104
|
+
assert.equal(modelGapOf({ energy: { points: [] } })!.unknownEquipmentReports, 0, '์๋์ง ํธ์์ด๋ฉด ์ธ์๊ณ 0 ์ด๋ค')
|
|
105
|
+
assert.equal(modelGapOf({ energy: { unknownEquipment: 41 } })!.unknownEquipmentReports, 41)
|
|
106
|
+
assert.equal(
|
|
107
|
+
modelGapOf({ unknownEquipment: 41 } as any)!.unknownEquipmentReports,
|
|
108
|
+
null,
|
|
109
|
+
'๋ฃจํธ์ ์๋ ๊ฐ์ ์ง์ง ์๋๋ค โ ๊ทธ ๊ฒฝ๋ก๋ ์ปค๋์ ๊ฒ์ด ์๋๋ค'
|
|
110
|
+
)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
test('๊ณ๋๊ธฐ๋ ๋ฎ๋๋ค โ ์ด ์ถ์ด ๊ฐ์ฅ ๋ฌด๊ฒ๋ค', () => {
|
|
114
|
+
/*
|
|
115
|
+
* ๋ชจ๋ฅด๋ `meterId` ๋ ์กฐ์ฉํ ์ ๊ณ๋๊ธฐ๊ฐ ๋๊ณ ๊ทธ kW ๊ฐ ๊ทธ ํ์ฅ์ ์์ยทํผํฌยท์๊ธ ํ์ ์ ๋ํด์ง๋ค.
|
|
116
|
+
* ๋ก์ผ์ด์
์คํ๋ ์คํค๋งคํฑ์ด ๋น๋ ๊ฒ์ผ๋ก ๋๋ฌ๋์ง๋ง, ์ด๊ฑด **๊ทธ๋ด๋ฏํ ์ซ์**๋ก ๋์จ๋ค.
|
|
117
|
+
* ์ปค๋ 0.7.39 ๊ฐ `MeterPointState.origin` ์ ๋ด๋ฉด์ ๋ฎ์ ์ ์๊ฒ ๋๋ค.
|
|
118
|
+
*/
|
|
119
|
+
const g = modelGapOf({
|
|
120
|
+
energy: { points: [loc('main-incoming', 'master'), loc('MMXU-์คํ-99', 'observed')] }
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
assert.equal(g!.meters.count, 1)
|
|
124
|
+
assert.deepEqual(g!.meters.ids, ['MMXU-์คํ-99'])
|
|
125
|
+
assert.equal(g!.total, 1, '๊ณ๋๊ธฐ๋ ํฉ์ ๋ ๋ค')
|
|
126
|
+
assert.deepEqual(g!.notCovered, [], '๋ฎ์ง ๋ชปํ๋ ์ถ์ด ์๋ค')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('ํ์๊ฐ ์๋ ํญ๋ชฉ์ ใ์ ์ธ๋จใ์ด ์๋๋ผ ใ๋ชจ๋ฆใ์ผ๋ก ์ผ๋ค', () => {
|
|
130
|
+
/*
|
|
131
|
+
* ๊ณ๋๊ธฐ์ `origin` ์ ๋ฆ๊ฒ ์๊ธด ์นธ์ด๋ผ, ์ ์ค๋
์ท์์ ์ด์ด๋ฐ์ ์ง์ ์๋ ์๋ค(`undefined`).
|
|
132
|
+
* ๋ง์คํฐ๋ก ์ธ๋ฉด ์คํ๋ฅผ ๋์น๊ณ , ๊ด์ธก์ผ๋ก ์ธ๋ฉด ์ ์์ ๋ฌธ์ ๋ก ๋ง๋ ๋ค. ๋ ๋ค ํ๋ฆฌ๋ค.
|
|
133
|
+
*/
|
|
134
|
+
const g = modelGapOf({
|
|
135
|
+
energy: { points: [{ id: 'carried-over' }, loc('main', 'master'), loc('ghost', 'observed')] }
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
assert.equal(g!.meters.unknown, 1, 'ํ์ ์๋ ๊ฒ์ ๋ชจ๋ฆ')
|
|
139
|
+
assert.equal(g!.meters.count, 1, '๊ด์ธก ๊ฐญ์ ์์ด์ง ์๋๋ค')
|
|
140
|
+
assert.ok(!g!.meters.ids.includes('carried-over'), '๋ชจ๋ฅด๋ ๊ฒ์ ์คํ๋ก ์ง๋ชฉํ์ง ์๋๋ค')
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
test('`origin` ์ ใ์ง๊ธ ๋ชจ๋ธ์ ์๋๊ฐใ์ ๋ต์ด๋ค โ ์ฑํ๋๋ฉด ๊ฐญ์์ ๋น ์ง๋ค', () => {
|
|
144
|
+
/*
|
|
145
|
+
* ์ปค๋์ด ํ๋ณธ๋ง๋ค ๋ค์ ๋ง์ถ๋ค. ํ ๋ฒ ์ฐ๊ณ ๋๋ฉด ๋์ค์ ์ ์ธ๋ ๊ณ๋๊ธฐ๊ฐ ์์ํ `observed` ๋ก ๋จ๋๋ค.
|
|
146
|
+
* ๊ทธ๋์ ์ฑํ ๋ค ์ค๋
์ท์์๋ ๊ฐ์ id ๊ฐ `master` ๋ก ์ค๊ณ , ์ด ๋์ถ์ ๊ทธ๊ฒ์ ๊ทธ๋๋ก ๋ฐ๋ฅธ๋ค.
|
|
147
|
+
*/
|
|
148
|
+
const before = modelGapOf({ energy: { points: [loc('new-meter', 'observed')] } })
|
|
149
|
+
const after = modelGapOf({ energy: { points: [loc('new-meter', 'master')] } })
|
|
150
|
+
|
|
151
|
+
assert.equal(before!.meters.count, 1)
|
|
152
|
+
assert.equal(after!.meters.count, 0, '๋ชจ๋ธ์ ๋ค์ด์ค๋ฉด ๊ฐญ์ด ์๋๋ค')
|
|
153
|
+
})
|
|
@@ -18,6 +18,10 @@ const TICK = 1000
|
|
|
18
18
|
function runSimCollect() {
|
|
19
19
|
const m = {
|
|
20
20
|
source: 'oee', system: 'wms' as const, siteName: 'O',
|
|
21
|
+
/* ์ด ํฝ์ค์ฒ๊ฐ ์๋ณ์๋ฅผ ๋ง๋๋ ์ด๋ฆ๊ณต๊ฐ โ **ํฝ์ค์ฒ๋ง๋ค ๋ค๋ฅด๊ฒ** ๋๋ค(๊ฐ์ ์ ๋ ์๋์์ ์๋ก ๋ค๋ฅธ
|
|
22
|
+
์ํ์ ๋ฒํธ๊ฐ ๋ถ๋ช์น๋ฉด ํ์ค์ ์ ์ผ์ฑ ์๊ตฌ๋ฅผ ๊นฌ๋ค, CBV 2.0 ยง8.2.4). ์ปค๋์ ์ ์ธ ์์ด ํ๋ ํธยท๋ฌธ์๋ฅผ
|
|
23
|
+
๋ง๋ค์ง ์๋๋ค(0.7.45 ์์ ๋ ์กฐ ํ๋ฆฌํฝ์ค๋ฅผ ์ง์ ๋ค). */
|
|
24
|
+
identity: { namespaces: ['https://twin.test/oee-accumulator'] },
|
|
21
25
|
space: { width: 90, depth: 40, unit: 'm' },
|
|
22
26
|
locations: [
|
|
23
27
|
{ id: 'a', type: 'warehouse', role: 'area' as const },
|
|
@@ -37,7 +37,7 @@ test('์ด์ ์ฌ์ค์ด ์๊ธฐ ๋ดํฌ๋ก ๋์จ๋ค โ EPCIS ๋ก ๊ฐ์ธ์ง์ง ์
|
|
|
37
37
|
test('๋ค ์ดํ๊ฐ ํ ๋ฐฐ์น์์ ๊ฐ๋ฆฐ๋ค โ ์ค ํผ๋๋ ์์ฌ ์จ๋ค', () => {
|
|
38
38
|
const { accepted, rejected } = ingestCanonicalRecords(
|
|
39
39
|
[
|
|
40
|
-
{ epc: 'urn:epc:id:sgtin:
|
|
40
|
+
{ epc: 'urn:epc:id:sgtin:9521321.012345.1', action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:receiving', readPoint: 'dock-1' },
|
|
41
41
|
{ meterId: 'm-1', kW: 120 },
|
|
42
42
|
{ equipmentId: 'pv-1', generatedKW: 40 },
|
|
43
43
|
{ moverId: 'fk-1', kind: 'forklift', status: 'busy' }, // vocabulary-guard: allow ์ ๋ ์์ด์ด ํ๋
|
|
@@ -80,8 +80,8 @@ test('ํผ๋ ๊ฒฐ์ ์ด ๊ฑฐ๋ถ๋ฅผ ์กฐ์ฉํ ๋ฒ๋ฆฌ์ง ์๋๋ค โ ์ด์ ๋ฅผ ์ฌ
|
|
|
80
80
|
test('๋ด๊น ๋ ์ฝ๋๊ฐ ์๊ธฐ ๋ดํฌ๋ก ๋์จ๋ค โ ๊ฐ์ฒด ๊ด์ธก๊ณผ ํ ๋ฐฐ์น์ ์์ฌ ์๋ ๊ฐ๋ฆฐ๋ค', () => {
|
|
81
81
|
const { accepted, rejected } = ingestCanonicalRecords(
|
|
82
82
|
[
|
|
83
|
-
{ epc: 'urn:epc:id:sgtin:
|
|
84
|
-
{ parentID: 'urn:epc:id:sscc:0614141.0000000001', childEPCs: ['urn:epc:id:sgtin:
|
|
83
|
+
{ epc: 'urn:epc:id:sgtin:9521321.012345.1', action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:receiving', readPoint: 'dock-1' },
|
|
84
|
+
{ parentID: 'urn:epc:id:sscc:0614141.0000000001', childEPCs: ['urn:epc:id:sgtin:9521321.012345.1'], action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:packing', readPoint: 'packing' }
|
|
85
85
|
] as any,
|
|
86
86
|
'domain-1',
|
|
87
87
|
AT
|
|
@@ -93,7 +93,7 @@ test('๋ด๊น ๋ ์ฝ๋๊ฐ ์๊ธฐ ๋ดํฌ๋ก ๋์จ๋ค โ ๊ฐ์ฒด ๊ด์ธก๊ณผ ํ
|
|
|
93
93
|
|
|
94
94
|
test('์๋ฆฌ๋ฅผ ๊ตฌ์กฐ์งธ ์ค์ผ๋ฉด ๊ฑฐ๋ถํ๋ค โ ์์ ์๋ "[object Object]" ๋ก ๊ตณ์ด ์ ๋์ ์์๋ค', () => {
|
|
95
95
|
const { accepted, rejected } = ingestCanonicalRecords(
|
|
96
|
-
[{ epc: 'urn:epc:id:sgtin:
|
|
96
|
+
[{ epc: 'urn:epc:id:sgtin:9521321.012345.1', action: 'ADD', bizStep: 'urn:epcglobal:cbv:bizstep:receiving', readPoint: { id: 'dock-1' } }] as any,
|
|
97
97
|
'domain-1',
|
|
98
98
|
AT
|
|
99
99
|
)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* โ
ใ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋คใ์ ใ์๋ณธ์ด ์กฐ์ฉํ๋คใ๋ **๋ค๋ฅธ ์ฌ์ค**์ด๋ค โ ์ํ๊ฐ ๊ทธ๊ฒ์ ๊ฐ๋ ค์ผ ํ๋ค.
|
|
3
|
+
*
|
|
4
|
+
* โโ ๋ฌด์์ด ์กฐ์ฉํ๋ (2026-08-23 ์ค์ธก) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
5
|
+
* ์ค ์๋ณธ์ด ๋๊ฒผ๋ค(`jejoup.hatiolab.com:4000` ์ ์ ์๊ฐ ์ด๊ณผ, HTTP 000 / 8์ด). ๊ทธ๋ฐ๋ฐ ํธ์์
|
|
6
|
+
* **์กฐํ ๊ฐ๋ฅํ ์ํ ์ด๋์๋ ๊ทธ ์ฌ์ค์ด ์์๋ค.**
|
|
7
|
+
*
|
|
8
|
+
* recordIngest `onRecords` ๊ฐ ๋ถ๋ฆด ๋๋ง ๋๋ฌํ๋ค โ ์ฝ๊ธฐ ์คํจ๋ ๊ทธ ๋ฌธ์ ์ค์ง ์๋๋ค
|
|
9
|
+
* TwinReference.lastError ๋ง์คํฐ ๋๊ธฐยท์ ์ ์ํ์๋ง ์ ํ๋ค โ ๋ผ์ด๋ธ ํผ๋๋ ์ ์ง ์์๋ค
|
|
10
|
+
* ๊ณ์ฝ `openLiveFeed` ์ ใ์ฝ์ง ๋ชปํ๋คใ๋ฅผ ๋งํ ํต๋ก๊ฐ ์์๋ค
|
|
11
|
+
*
|
|
12
|
+
* ์ด๋ํฐ๋ **๋ก๊ทธ๋ก๋ ๋งํ๊ณ ์์๋ค**(์ฌ์๋ ๊ฒฝ๊ณ ). ๊ทธ๋ฌ๋ ๋ก๊ทธ๋ ์ฌ๋์ด ๋ณผ ๋๋ง ๊ฐ์ด ์๋ค โ ํ๋ฉด์ด
|
|
13
|
+
* ๋งํ๋ ค๋ฉด ์ํ์ ์์ด์ผ ํ๋ค. ์ค์ฆ ๋ฐ๋ชจ ์ค์ ์๋ณธ์ด ๋๊ธฐ๋ฉด ์ฌ์ฉ์๊ฐ ์์ธ์ ์ฐพ์ ์ ์๋ค.
|
|
14
|
+
*
|
|
15
|
+
* โโ ์ด ์ํ์ด ์งํค๋ ๊ฒ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
16
|
+
* โ ์คํจ๊ฐ ์ํ์ ๋จ๋๋ค โก ใ๋ช ๋ฒใ๊ณผ ใ์ธ์ ๋ถํฐใ๋ฅผ ํจ๊ป ๋ ๋ค(ํ ๋ฒ์ ํ๋ค๋ฆผ๊ณผ 20๋ถ์งธ ๋จ์ ์ ๋ค๋ฅด๋ค)
|
|
17
|
+
* โข **๋น ์ฝ๊ธฐ๋ ์ฑ๊ณต์ด๋ค** โ ์กฐ์ฉํ ์๋ณธ์ ๋๊ธด ์๋ณธ์ผ๋ก ๋ง๋ค์ง ์๋๋ค
|
|
18
|
+
* โฃ ์กฐํ ๋ทฐ๋ก ๋๊ฐ๋ค โ ์ํ์๋ง ์๊ณ ์ ๋๊ฐ๋ฉด ํ๋ฉด์ด ๋ชป ๋ณธ๋ค
|
|
19
|
+
*/
|
|
20
|
+
import { test } from 'node:test'
|
|
21
|
+
import assert from 'node:assert/strict'
|
|
22
|
+
import { readFileSync } from 'node:fs'
|
|
23
|
+
import { join } from 'node:path'
|
|
24
|
+
import {
|
|
25
|
+
clearReadFailure,
|
|
26
|
+
ingestHealth,
|
|
27
|
+
newIngestLedger,
|
|
28
|
+
recordIngest,
|
|
29
|
+
recordReadFailure
|
|
30
|
+
} from '../server/engine/ingest-health.ts'
|
|
31
|
+
|
|
32
|
+
const T0 = Date.parse('2026-08-23T06:00:00.000Z')
|
|
33
|
+
|
|
34
|
+
test('์คํจ๊ฐ ์ํ์ ๋จ๋๋ค โ ์ฌ์ ์ ํ๋ฆ๊น์ง', () => {
|
|
35
|
+
const l = newIngestLedger()
|
|
36
|
+
assert.equal(l.readFailure, undefined, '์ฒ์์๋ ์๋ค(์์์ด ใ๋ฟ๋๋คใ๋ ๋ป์ด๋ค)')
|
|
37
|
+
recordReadFailure(l, 'connect ETIMEDOUT', T0, 'lot')
|
|
38
|
+
assert.equal(l.readFailure?.consecutive, 1)
|
|
39
|
+
assert.equal(l.readFailure?.reason, 'connect ETIMEDOUT')
|
|
40
|
+
assert.equal(l.readFailure?.stream, 'lot', '์ด๋ ํ๊ฐ ๋งํ๋๊ฐ ์์ธ ์ฐพ๊ธฐ์ ์ ๋ฐ์ด๋ค')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('ํ ๋ฒ์ ํ๋ค๋ฆผ๊ณผ 20๋ถ์งธ ๋จ์ ์ ๊ฐ๋ฅธ๋ค โ ์์ ์๊ฐ์ ์งํจ๋ค', () => {
|
|
44
|
+
/*
|
|
45
|
+
* ๋งค๋ฒ ์๋ก ์ ์ผ๋ฉด ํ๋ฉด์ด ๋ ใ๋ฐฉ๊ธ ์คํจํ๋คใ๋ง ๋ณด๊ฒ ๋๊ณ , ๊ณ์๋ ๋จ์ ์ ๋์๋กญ์ง ์๊ฒ ๋งํ๋ค.
|
|
46
|
+
*/
|
|
47
|
+
const l = newIngestLedger()
|
|
48
|
+
recordReadFailure(l, 'ETIMEDOUT', T0)
|
|
49
|
+
recordReadFailure(l, 'ETIMEDOUT', T0 + 600_000)
|
|
50
|
+
recordReadFailure(l, 'ETIMEDOUT', T0 + 1_200_000)
|
|
51
|
+
assert.equal(l.readFailure?.consecutive, 3)
|
|
52
|
+
assert.equal(l.readFailure?.sinceMs, T0, '์ฒ์ ์คํจํ ์๊ฐ์ ์งํจ๋ค')
|
|
53
|
+
assert.equal(l.readFailure?.lastAtMs, T0 + 1_200_000, '๋ง์ง๋ง ์คํจ๋ ๊ฐฑ์ ๋๋ค')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('๋น ์ฝ๊ธฐ๋ ์ฑ๊ณต์ด๋ค โ ์กฐ์ฉํ ์๋ณธ์ ๋๊ธด ์๋ณธ์ผ๋ก ๋ง๋ค์ง ์๋๋ค', () => {
|
|
57
|
+
/*
|
|
58
|
+
* โ
์ด ๋จ์ ์ด ๊ณ ์น๋ ค๋ ๊ฒ์ **๋ฐ๋ ๋ฐฉํฅ์ผ๋ก ํ๋ฆฌ๋ ๊ฒ**์ ๋ง๋๋ค. ์๋ณธ์ด ใ์ ๊ฒ์ด ์๋คใ๊ณ ๋ตํ ๊ฒ์
|
|
59
|
+
* ๋ฟ์๋ค๋ ๋ป์ด๋ค.
|
|
60
|
+
*/
|
|
61
|
+
const l = newIngestLedger()
|
|
62
|
+
recordReadFailure(l, 'ETIMEDOUT', T0)
|
|
63
|
+
clearReadFailure(l)
|
|
64
|
+
assert.equal(l.readFailure, undefined, '์ฝ์์ผ๋ฉด ๋จ์ ๊ธฐ๋ก์ด ์ฌ๋ผ์ง๋ค')
|
|
65
|
+
/* ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ค ๋ค์ ์คํจํ๋ฉด **์ ๋จ์ **์ด๋ค โ ์ ์์ ์๊ฐ์ ๋ฌผ๋ ค๋ฐ์ง ์๋๋ค. */
|
|
66
|
+
recordReadFailure(l, 'ETIMEDOUT', T0 + 3_600_000)
|
|
67
|
+
assert.equal(l.readFailure?.consecutive, 1, '์ฐ์์ด ๋๊ฒผ์ผ๋ฏ๋ก 1 ๋ถํฐ')
|
|
68
|
+
assert.equal(l.readFailure?.sinceMs, T0 + 3_600_000, '์ ๋จ์ ์ ์์์ด๋ค')
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('์กฐํ ๋ทฐ๋ก ๋๊ฐ๋ค โ ์ํ์๋ง ์์ผ๋ฉด ํ๋ฉด์ด ๋ชป ๋ณธ๋ค', () => {
|
|
72
|
+
const l = newIngestLedger()
|
|
73
|
+
recordReadFailure(l, 'connect ETIMEDOUT', T0, 'inventory')
|
|
74
|
+
const v = ingestHealth(l, 'attached', undefined, T0 + 60_000)
|
|
75
|
+
assert.ok(v.readFailure, '๋ทฐ์ ์ค๋ ค์ผ ํ๋ค')
|
|
76
|
+
assert.equal(v.readFailure?.consecutive, 1)
|
|
77
|
+
assert.equal(v.readFailure?.since, new Date(T0).toISOString())
|
|
78
|
+
assert.equal(v.readFailure?.reason, 'connect ETIMEDOUT')
|
|
79
|
+
assert.equal(v.readFailure?.stream, 'inventory')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('๋ฟ๊ณ ์์ผ๋ฉด ๊ทธ ํ๋๋ฅผ ๋ง๋ค์ง ์๋๋ค โ ๋น ๊ฐ์ด ใ๋ฟ๋๋คใ๋ก ์ฝํ์ง ์๊ฒ', () => {
|
|
83
|
+
const l = newIngestLedger()
|
|
84
|
+
recordIngest(l, 3, [], T0)
|
|
85
|
+
const v = ingestHealth(l, 'attached', undefined, T0 + 1000)
|
|
86
|
+
assert.equal(v.readFailure, undefined)
|
|
87
|
+
/* ๊ฐ๋๊ฐ ์ค์ค๋ก๋ฅผ ์ฆ๋ช
ํ๋ค โ ์ด ์ฅ๋ถ๊ฐ ์ค์ ๋ก ๋ฌด์์ ๋ฐ์๋ค. */
|
|
88
|
+
assert.equal(v.total.offered, 3, '๋น ๋น๊ต๋ก ํต๊ณผํ์ง ์๋๋ค')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
test('ใ์ ์
์์ใ๊ณผ ใ๋ฟ์ง ๋ชปํจใ์ ๋ค๋ฅธ ํ์ ์ด๋ค', () => {
|
|
92
|
+
/*
|
|
93
|
+
* ์ ์
์์์ ์๋ณธ์ด ์กฐ์ฉํ ๊ฒ์ผ ์ ์๊ณ , ๋ฟ์ง ๋ชปํจ์ ์ฐ๋ฆฌ๊ฐ ๋ฌป์ง๋ ๋ชปํ ๊ฒ์ด๋ค. ๋ ์ํ๊ฐ ๊ฐ์
|
|
94
|
+
* ๊ฐ์ผ๋ก ๋ญ๊ฐ์ง๋ฉด ํ๋ฉด์ด ๋ ๋ฌธ์ฅ์ ๋ค๋ฅด๊ฒ ๋งํ ์ ์๋ค.
|
|
95
|
+
*/
|
|
96
|
+
const quiet = newIngestLedger()
|
|
97
|
+
const dark = newIngestLedger()
|
|
98
|
+
recordReadFailure(dark, 'ETIMEDOUT', T0)
|
|
99
|
+
|
|
100
|
+
const vq = ingestHealth(quiet, 'attached', undefined, T0)
|
|
101
|
+
const vd = ingestHealth(dark, 'attached', undefined, T0)
|
|
102
|
+
assert.equal(vq.lastAt, null, '์กฐ์ฉํ ์ชฝ๋ ๋ฐ์ ๊ฒ์ด ์๋ค')
|
|
103
|
+
assert.equal(vd.lastAt, null, '๋๊ธด ์ชฝ๋ ๋ฐ์ ๊ฒ์ด ์๋ค โ ๊ทธ ๊ฐ๋ง์ผ๋ก๋ ๊ฐ๋ฆฌ์ง ์๋๋ค')
|
|
104
|
+
assert.notEqual(Boolean(vq.readFailure), Boolean(vd.readFailure), '์ด ์ถ์ด ๊ทธ ๋์ ๊ฐ๋ฅธ๋ค')
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
/*
|
|
108
|
+
* โโ ์ฝ๊ธฐ ์คํจ๊ฐ **ํผ๋๋ฅผ ๋๋ฉด ์ ๋๋ค** (2026-08-23, ๋๋๋ฆฐ ์๋ฆฌ) โโโโโโโโโโโโ
|
|
109
|
+
*
|
|
110
|
+
* ์ฒ์ ๊ตฌํ์์ ์ฝ๊ธฐ ์คํจ๊ฐ ๋ ํผ๋ฐ์ค ํ์ `status` ๋ฅผ `'error'` ๋ก ์ ์๋ค. ๊ทธ๊ฒ์ด **ํผ๋๋ฅผ ์๊ตฌํ
|
|
111
|
+
* ๊ป๋ค**: ๋ถํ
์ฌ๋ถ์ฐฉ์ `status: 'connected'` ์ธ ๋ ํผ๋ฐ์ค๋ง ๋์ด๋ฆฌ๋ฏ๋ก, ์๋ณธ์ด **์ ๊น** ๋๊ธด ๊ฒ์ด
|
|
112
|
+
* ๋ค์ ์ฌ๊ธฐ๋์์ ๊ทธ ํธ์์ ์์ ๊ตถ๊ฒผ๋ค. ์ค์ธก์ผ๋ก ๊ทธ๋ ๊ฒ ๋ฌ๋ค โ ๊ทธ ํ์ ๋ก๊ทธ์ `[twin-live]` ์ค์ด
|
|
113
|
+
* ํ ์ค๋ ์์๋ค.
|
|
114
|
+
*
|
|
115
|
+
* ๋ ์ถ์ ํ ์นธ์ ์์ ๊ฒ์ด ์์ธ์ด๋ค.
|
|
116
|
+
*
|
|
117
|
+
* status **์ฐ๊ฒฐ ์ค์ ์ด ์ฑ๋ฆฝํ๋** โ ์ ์ ์ํยท๋ง์คํฐ ๋๊ธฐ๊ฐ ์ ํ๋ค. ์ฌ๋ถ์ฐฉ์ **์๊ฒฉ**์ด๋ค
|
|
118
|
+
* ์ฝ๊ธฐ ์คํจ **์ง๊ธ ๋ฟ๋** โ ์ค๊ฐ ์ ์๋ ์ฌ์ค์ด๊ณ ์ ์
์ฅ๋ถ๊ฐ ๊ทธ ์ถ์ ๊ฐ๋๋ค
|
|
119
|
+
*
|
|
120
|
+
* ใ์ฌ์ค์ ๋งํ๊ฒใ ํ๋ ค๋ ๊ฒ์ด ใ์ฌ์ค์ ๋ชป ๋ฃ๊ฒใ ๋ง๋ค์๋ค. ๊ทธ ๋ฐฉํฅ์ ์คํจ๋ ์กฐ์ฉํ๋ค โ ํ๋ฉด์
|
|
121
|
+
* ใ์๋ณธ์ ๋ฟ์ง ๋ชปํ๋คใ๋ฅผ ์ ์งํ๊ฒ ๋งํ๋ฉด์, ์ ์ ๋ค์ ๋ฟ์ ๊ธฐํ๋ฅผ ์๋๋ค.
|
|
122
|
+
*/
|
|
123
|
+
test('์ฝ๊ธฐ ์คํจ๊ฐ ๋ ํผ๋ฐ์ค์ status ๋ฅผ ๊ฑด๋๋ฆฌ์ง ์๋๋ค โ ๊ทธ๊ฒ์ด ์ฌ๋ถ์ฐฉ์ ์๊ฒฉ์ด๋ค', () => {
|
|
124
|
+
const src = readFileSync(join(import.meta.dirname, '..', 'server', 'service', 'reference', 'reference-live.ts'), 'utf8')
|
|
125
|
+
const code = src.replace(/\/\*[\s\S]*?\*\//g, ' ').replace(/(^|[^:])\/\/.*$/gm, '$1')
|
|
126
|
+
|
|
127
|
+
const at = code.indexOf('onReadFailure:')
|
|
128
|
+
assert.ok(at > 0, 'onReadFailure ๋ฐฐ์ ์ด ์์ด์ผ ํ๋ค')
|
|
129
|
+
const body = code.slice(at, at + 600)
|
|
130
|
+
|
|
131
|
+
assert.doesNotMatch(body, /status:/, '์ฝ๊ธฐ ์คํจ๋ status ๋ฅผ ์ ์ง ์๋๋ค โ ์ ์ผ๋ฉด ๋ค์ ๋ถํ
์ด ๊ทธ ํผ๋๋ฅผ ๋์ด๋ฆฌ์ง ์๋๋ค')
|
|
132
|
+
/* ๋์ ์ด์ ๋ ๋จ๊ธด๋ค โ ์ฌ๋์ด ๋ชฉ๋ก์์ ๋ณผ ์ ์๊ฒ. */
|
|
133
|
+
assert.match(body, /lastError/, '์ด์ ๋ ๋ ํผ๋ฐ์ค ํ์ ๋จ๊ธด๋ค')
|
|
134
|
+
/* ๊ทธ๋ฆฌ๊ณ ใ์ง๊ธ ๋ฟ๋ใ๋ ์ฅ๋ถ๊ฐ ๋ตํ๋ค. */
|
|
135
|
+
assert.match(body, /recordIngestReadFailure/, '์ ์
์ฅ๋ถ๊ฐ ๊ทธ ์ถ์ ๋ ๋ค')
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('์ฌ๋ถ์ฐฉ์ ์๊ฒฉ์ connected ๋ฟ์ด๋ค โ ๊ทธ๋์ ๊ทธ ๊ฐ์ ํจ๋ถ๋ก ๋ฐ๊พธ๋ฉด ์ ๋๋ค', () => {
|
|
139
|
+
/*
|
|
140
|
+
* ์ด ๋จ์ ์ด ์ ๊ฐ๋์ **์ด์ **๋ฅผ ๋ชป๋ฐ๋๋ค. ์ฌ๋ถ์ฐฉ ์กฐ๊ฑด์ด ๋์ด์ง๋ฉด ์ ๊ท์จ์ ๊ทผ๊ฑฐ๊ฐ ์ฝํด์ง๋ฏ๋ก,
|
|
141
|
+
* ๋์ด ํจ๊ป ์์ง์ฌ์ผ ํ๋ค.
|
|
142
|
+
*/
|
|
143
|
+
const src = readFileSync(join(import.meta.dirname, '..', 'server', 'service', 'reference', 'reference-live.ts'), 'utf8')
|
|
144
|
+
assert.match(src, /find\(\{ where: \{ status: 'connected' \}/, '๋ถํ
์ฌ๋ถ์ฐฉ์ connected ๋ง ๋์ด๋ฆฐ๋ค')
|
|
145
|
+
})
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* โ
์ปค๋ฅํฐ์ **๊ทผ๊ฑฐ ์์ค** โ ๋ชฉ์ผ๋ก ํ์ธํ ๊ฒ์ ํ์ธ์ผ๋ก ๋ถ๋ฅด์ง ์๋๋ค.
|
|
3
|
+
*
|
|
4
|
+
* โโ ์ ์ด ์ถ์ด ์๊ฒผ๋ (2026-08-23, ํ ๋ ๋ฆด๋ฆฌ์ฆ ์ค๋น) โโโโโโโโโโโโโโโโโโโโโโโโ
|
|
5
|
+
* ๋ฑ๋ก๋ ์ปค๋ฅํฐ ์ด๋ท ์ค ์ค ์์คํ
์ ๋ถ์ด ๋ณธ ๊ฒ์ **ํ๋**๋ค(์ฒซ ์ค ์ฐ๋). ๋๋จธ์ง๋ ๋ชฉ์ ๋๊ณ ๋ง๋ค์๋ค.
|
|
6
|
+
* ๊ทธ๋ฐ๋ฐ ํ๋ฉด์ ์ปค๋ฅํฐ ๋ชฉ๋ก์ ๊ทธ ๊ตฌ๋ถ์ด ์์ด์ **๋ชฉ์ผ๋ก ํ์ธํ ๊ฒ์ด ํ์ธ์ผ๋ก ๋ณด์ธ๋ค.**
|
|
7
|
+
*
|
|
8
|
+
* ์ด ์ ์ฅ์๋ ๊ฐ์ ๋ชจ์์ ๋ฅ๋ ฅ ์ถ์์ ์ด๋ฏธ ๊ฑฐ์ ํ๋ค โ ใ์ ์ธ๋ง ์๋ ๋ฅ๋ ฅ์ ์ฌ์ฉ์์๊ฒ ๊ฑฐ์ง๋ง์ด ๋๋คใ
|
|
9
|
+
* (ยง`capabilitiesOf`). ๊ทธ ๊ท์จ์ ๊ทผ๊ฑฐ์๋ ์ธ์ด๋ค.
|
|
10
|
+
*
|
|
11
|
+
* โโ ๋ฌด์์ ๊ฒ์ฆํ ์ ์๊ณ ๋ฌด์์ ๋ชป ํ๋ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
12
|
+
* ๋ฅ๋ ฅ์ ๊ตฌํ์ด ์๋์ง ๋ณด์ ์ ์ธ์ ๊ฒ์ฆํ ์ ์๋ค. **๊ทผ๊ฑฐ๋ ๋ณผ ์ ์๋ค** โ ์ฌ๋์ด ์๋ ์ฌ์ค์ด๋ค.
|
|
13
|
+
* ๊ทธ๋์ ๊ฒ์ฆํ ์ ์๋ ํ๋๋ง ๊ฒ์ฆํ๋ค: **์ค ์์คํ
์ ์ฃผ์ฅํ๋ฉด ๋ฌด์์ ๋๊ณ ์ธ์ง ๋งํด์ผ ํ๋ค.**
|
|
14
|
+
* ๊ฐ๋ฆฌํค๋ ๋์์ด ์๋ ์ฃผ์ฅ์ ์ฃผ์ฅ์ด ์๋๊ณ , ๊ทธ๋ฐ ์ฃผ์ฅ์ ๋ก์๋ ์๋ฌด๋ ์ ์ ์๋ค.
|
|
15
|
+
*/
|
|
16
|
+
import { test } from 'node:test'
|
|
17
|
+
import assert from 'node:assert/strict'
|
|
18
|
+
import { groundingOf, type ReferenceAdapter } from '../server/service/reference/reference-adapter.ts'
|
|
19
|
+
|
|
20
|
+
const adapter = (grounding?: any) => ({ type: 't', grounding } as unknown as ReferenceAdapter)
|
|
21
|
+
|
|
22
|
+
test('์ ์ธ์ด ์์ผ๋ฉด ใ๋ชจ๋ฅธ๋คใ๋ค โ ใ๋ชฉ์ด๋คใ๊ฐ ์๋๋ค', () => {
|
|
23
|
+
/*
|
|
24
|
+
* ๋์ ๊ฐ๊ฒ ๋๋ฉด ์์ง ์ ์ธํ์ง ์์ ์ ์ปค๋ฅํฐ๊ฐ ๋ชฉ์ผ๋ก ๋์ธ์ฐํ๋ค โ ๊ทธ๊ฒ๋ ์๋ ์ฌ์ค์ด๋ค.
|
|
25
|
+
* ํ๋ฉด์ `unknown` ์ ใ์์ง ๋ฐํ์ง ์์๋คใ๋ก ๋งํด์ผ ํ๋ค.
|
|
26
|
+
*/
|
|
27
|
+
assert.deepEqual(groundingOf(adapter()), { level: 'unknown' })
|
|
28
|
+
assert.deepEqual(groundingOf(undefined), { level: 'unknown' })
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('์ค ์์คํ
์ ์ฃผ์ฅํ๋ฉด ๋ฌด์์ ๋๊ณ ์ธ์ง ๋งํด์ผ ํ๋ค โ ์๋๋ฉด ์ฃผ์ฅ์ด ๋ด๋ ค๊ฐ๋ค', () => {
|
|
32
|
+
/* โ
์ด ๊ฐ๋์ ํต์ฌ. ๋์ ์๋ ์ฃผ์ฅ์ ๋ก์๋ ์๋ฌด๋ ๋ชจ๋ฅธ๋ค. */
|
|
33
|
+
for (const level of ['instance', 'product'] as const) {
|
|
34
|
+
const g = groundingOf(adapter({ level }))
|
|
35
|
+
assert.equal(g.level, 'unknown', `${level} ์ฃผ์ฅ์ด ๋์ ์์ด ํต๊ณผํ๋ฉด ์ ๋๋ค`)
|
|
36
|
+
assert.match(g.downgraded ?? '', /does not say what it was verified against/)
|
|
37
|
+
assert.match(g.downgraded ?? '', new RegExp(level), '๋ฌด์์ ์ฃผ์ฅํ๋์ง ํจ๊ป ๋งํ๋ค')
|
|
38
|
+
}
|
|
39
|
+
/* ์ฌ๋ฐฑ๋ง ์๋ ๊ฒ๋ ๋น์ด ์๋ ๊ฒ์ด๋ค โ ํ์์ ์ฑ์ ํต๊ณผํ์ง ๋ชปํ๊ฒ. */
|
|
40
|
+
assert.equal(groundingOf(adapter({ level: 'instance', verifiedAgainst: ' ' })).level, 'unknown')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('๋์์ ๋งํ๋ฉด ๊ทธ ์ฃผ์ฅ์ด ์ ๋ค', () => {
|
|
44
|
+
const g = groundingOf(adapter({ level: 'instance', verifiedAgainst: 'chef v1 ยท jejoup / pocheon' }))
|
|
45
|
+
assert.equal(g.level, 'instance')
|
|
46
|
+
assert.equal(g.verifiedAgainst, 'chef v1 ยท jejoup / pocheon')
|
|
47
|
+
assert.equal(g.downgraded, undefined)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('๋ชฉ๊ณผ ๊ฐ์์ ๋์ ์์ด๋ ์ ๋ค โ ๊ทธ ์์ฒด๊ฐ ์ฌ์ค์ด๋ค', () => {
|
|
51
|
+
/*
|
|
52
|
+
* `mock` ์ ใ์ค ์์คํ
์ ๋ถ์ด ๋ณธ ์ ์ด ์๋คใ๋ ์ฌ์ค์ด๊ณ ๊ทธ๊ฒ์ ๋งํ๋ ๋ฐ ๋์์ด ํ์ํ์ง ์๋ค.
|
|
53
|
+
* `synthetic` ์ ํ๊ณ๊ฐ ์๋๋ผ **์ฑ์ง**์ด๋ค โ ๊ฐ์ ์๋ณธ์ ์ค์ค๋ก ๋ง๋ค์ด ๋ธ๋ค.
|
|
54
|
+
*/
|
|
55
|
+
assert.equal(groundingOf(adapter({ level: 'mock' })).level, 'mock')
|
|
56
|
+
assert.equal(groundingOf(adapter({ level: 'synthetic' })).level, 'synthetic')
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('instance ์ product ๋ฅผ ๊ฐ๋ฅธ๋ค โ ๊ทธ ๊ตฌ๋ถ์ด ์ด ์ดํ์ ์์ ์ด๋ค', () => {
|
|
60
|
+
/*
|
|
61
|
+
* ์ฒซ ์ค ์ฐ๋์์ ๊ทธ ๋ฐฐํฌ๋ง์ ์ฑ์ง์ด ๋ท ๋๋ฌ๋ฌ๋๋ฐ(๊ด๊ณ ๋ฆฌ์๋ฒ๊ฐ ๋ค๋ฅธ ํ
๋ํธ์ ํ์ ๋ตํ๋ค ยท ๋ชจ๋ฅด๋
|
|
62
|
+
* ํํฐ๋ฅผ ์กฐ์ฉํ ๋ฌด์ํ๋ค ยท ์ง์์ง ํ๋ชฉ์ BOM ์ด ๋จ์ ์๋ค ยท ์ฌ์ค์ ๋ฌดํ์ ๋ปํ๋ ํ์) **๊ทธ๊ฒ์ด
|
|
63
|
+
* ์ ํ์ ์ฑ์ง์ธ์ง ๊ทธ ์ธ์คํด์ค์ ์ฑ์ง์ธ์ง ์๋ฌด๋ ๋ชจ๋ฅธ๋ค.** ๋ ๋ฒ์งธ ๋ฐฐํฌ๊ฐ ๋ถ๋ ๋ ๊ฐ๋ฆฐ๋ค.
|
|
64
|
+
*
|
|
65
|
+
* ๊ทธ๋์ ํ๋๋ก ํ์ธํ ๊ฒ์ `product` ๋ผ ๋ถ๋ฅด๋ฉด ์ ๋๊ณ , ์ดํ๊ฐ ๊ทธ ๊ตฌ๋ถ์ ๋ด๋๋ค.
|
|
66
|
+
*/
|
|
67
|
+
const one = groundingOf(adapter({ level: 'instance', verifiedAgainst: 'ํ ๋ฐฐํฌ' }))
|
|
68
|
+
const many = groundingOf(adapter({ level: 'product', verifiedAgainst: '์ธ ๋ฐฐํฌ' }))
|
|
69
|
+
assert.notEqual(one.level, many.level, '๋ ์์ค์ด ๊ฐ์ ๊ฐ์ผ๋ก ๋ญ๊ฐ์ง์ง ์๋๋ค')
|
|
70
|
+
})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* โ
์์ค ์ํ์ด ํ์ ๋ชจ๋์ ๋ถ๋ฅผ ์ ์๊ฒ ํ๋ค โ **`operato-twin` ์ ๊ฐ์ ๊ท์น์ ์ด ํจํค์ง์๋ ๋๋ค** โ **`.js` ๋ก ์ ํ ์๋ ๊ฒฝ๋ก๋ฅผ `.ts` ๋ก ๋์ง๋๋ค.**
|
|
3
|
+
*
|
|
4
|
+
* โโ ๋ฌด์์ด ์๊ณ ์์๋ (2026-08-22) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
5
|
+
* ์ด ํจํค์ง์ `npm test` ๋ `node --test test/*.test.ts` ๋ก **์์ค๋ฅผ ๊ทธ๋๋ก ์คํ**ํ๋ค. ๊ทธ๋ฐ๋ฐ ์๋ฒ
|
|
6
|
+
* ์์ค๋ tsc ๋ก ๋น๋๋๋ ์ฝ๋์ด๋ฏ๋ก ์๋ import ๋ฅผ `'./x.js'` ๋ก ์ ๋๋ค(๊ทธ๊ฒ์ด ๋น๋ ์ฐ์ถ๋ฌผ์์ ๋ง๋
|
|
7
|
+
* ๊ฒฝ๋ก๋ค). ํ์
๋ง ์ง์ฐ๋ ์คํ์ ๊ทธ `.js` ๋ฅผ `.ts` ๋ก ๋ฐ๊ฟ ์ฃผ์ง ์๋๋ค.
|
|
8
|
+
*
|
|
9
|
+
* ๊ทธ๋์ **์์ค ๋ชจ๋์ด ํ์ ๋ชจ๋์ ๊ฐ์ผ๋ก ์ฐธ์กฐํ๋ ์๊ฐ** ๊ทธ ๋ชจ๋ ๊ทธ๋ํ๋ฅผ ๋ถ๋ฅด๋ ์ํ์ด ์ ๋ถ ์ ๋ค.
|
|
10
|
+
* ์ค์ธก์ผ๋ก ํ๋ฃจ์ ๋ค ์ข
๋ฅ๊ฐ ์ด ๋ฒฝ์ ๊ฑธ๋ ธ๋ค: `identity/namespace.js`(์ ์ฒด์ฑ ์ด๋ฆ๊ณต๊ฐ) ยท
|
|
11
|
+
* `engine/log.js`(๋ก๊ทธ ๋ฌธ) ยท `isa95-coverage.js`(์ ํฉ์ฑ ํ์ ) ยท `journal-count.js`(์ ๋ ์ธ๊ธฐ). ๋ ๊ฐ์ ์ค๋ฅ๋ค.
|
|
12
|
+
*
|
|
13
|
+
* Cannot find module 'โฆ/server/identity/namespace.js' imported from 'โฆ/templates/wms-unit-load.ts'
|
|
14
|
+
*
|
|
15
|
+
* โโ ์ ์ด ๋ฐฉ์์ธ๊ฐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
16
|
+
* ๊ณ ๋ฅด๋ ๊ธธ์ด ๋ ์์๋ค.
|
|
17
|
+
*
|
|
18
|
+
* โ ๊ทธ ์ํ๋ค์ **๋น๋ ์ฐ์ถ๋ฌผ**(`dist-server`)๋ก ๋๋ฆฐ๋ค โ ์ด ํจํค์ง์ ์ ๋ก๊ฐ ์๋ค. ๊ทธ๋ฌ๋ ์ํ๋ง๋ค
|
|
19
|
+
* ๊ทธ ๋ฐฐ์ ์ ์ ์ด์ผ ํ๊ณ , ๊ฑธ๋ฆฌ๋ ์ํ์ด ๋ ๋๋ง๋ค ๊ฐ์ ์ผ์ ๋ค์ ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์ฐ์ถ๋ฌผ์ด ๋ก์ผ๋ฉด
|
|
20
|
+
* **๊ณ ์น ์ฝ๋๊ฐ ์๋ ๊ฒ์ด ๋๋ฉด์ ์ด๋ก์ผ๋ก ๋ณด์ธ๋ค.**
|
|
21
|
+
* โก ์์๋ฅผ ์ฐ๋ ํ์ผ ์์ผ๋ก ์ฎ๊ธด๋ค โ ๊ฐ ์ฐธ์กฐ๊ฐ ์ฌ๋ผ์ง์ง๋ง **์ ๋ณธ์ด ํฉ์ด์ง๋ค.** ๊ทธ๊ฒ์ด ์ด ์์๋ฅผ ํ
|
|
22
|
+
* ์๋ฆฌ์ ๋ชจ์ ์ด์ ์ ์ ๋ฉด์ผ๋ก ์ด๊ธ๋๋ค.
|
|
23
|
+
*
|
|
24
|
+
* ๋ ๋ค ์ฆ์์ ํผํ๋ ๊ฒ์ด๊ณ , ์์ธ์ **ํด์ ๊ท์น ํ๋**๋ค. ๊ทธ๋์ ๊ท์น์ ๊ณ ์น๋ค: ์๋ ๊ฒฝ๋ก `.js` ๊ฐ
|
|
25
|
+
* ์๊ณ ๊ฐ์ ์ด๋ฆ์ `.ts` ๊ฐ ์์ผ๋ฉด ๊ทธ๊ฒ์ ์ด๋ค. ํ ์๋ฆฌ์ ๋๋ฏ๋ก ๊ฑธ๋ฆฌ๋ ์ํ์ด ๋์ด๋ ํ ์ผ์ด ์๋ค.
|
|
26
|
+
*
|
|
27
|
+
* โโ ๋ฌด์์ ํ์ง ์๋๊ฐ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
28
|
+
* **ํจํค์ง ์ด๋ฆ(`@things-factory/โฆ`)์ ์๋์ง ์๋๋ค.** ๊ทธ๊ฒ์ ์์กด ํจํค์ง์ ์ฐ์ถ๋ฌผ์ ๊ฐ๋ฆฌํค๋
|
|
29
|
+
* ๊ฒ์ด๊ณ ์ค์ ๋ก `.js` ๊ฐ ์๋ค. ๋์ง๋ ๊ฒ์ **์๋ ๊ฒฝ๋ก**๋ฟ์ด๊ณ , ๊ทธ๊ฒ๋ `.ts` ๊ฐ ์ค์ ๋ก ์์ ๋๋ง์ด๋ค โ
|
|
30
|
+
* ์์ผ๋ฉด ์๋ ์ค๋ฅ๊ฐ ๊ทธ๋๋ก ๋๋ค(์๋ ๊ฒ์ ์ง์ด๋ด์ง ์๋๋ค).
|
|
31
|
+
*/
|
|
32
|
+
import { registerHooks } from 'node:module'
|
|
33
|
+
import { existsSync } from 'node:fs'
|
|
34
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
35
|
+
|
|
36
|
+
registerHooks({
|
|
37
|
+
resolve(specifier, context, nextResolve) {
|
|
38
|
+
/* ์๋ ๊ฒฝ๋ก์ `.js` ๋ง ๋ณธ๋ค โ ํจํค์ง ์ด๋ฆ๊ณผ ๊ทธ ๋ฐ์ ํ์ฅ์๋ ๊ทธ๋๋ก ๋๋ค. */
|
|
39
|
+
if (!specifier.startsWith('.') || !specifier.endsWith('.js')) return nextResolve(specifier, context)
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
return nextResolve(specifier, context)
|
|
43
|
+
} catch (err) {
|
|
44
|
+
/* ํด์์ด ์คํจํ ๊ทธ๋๋ง `.ts` ๋ฅผ ๋ณธ๋ค โ ์ฑ๊ณตํ๋ ๊ฒฝ๋ก์ ๋ป์ ๋ฐ๊พธ์ง ์๋๋ค. */
|
|
45
|
+
const parent = context?.parentURL
|
|
46
|
+
if (!parent) throw err
|
|
47
|
+
const asTs = new URL(specifier.slice(0, -3) + '.ts', parent)
|
|
48
|
+
if (!existsSync(fileURLToPath(asTs))) throw err
|
|
49
|
+
return { url: pathToFileURL(fileURLToPath(asTs)).href, shortCircuit: true, format: 'module-typescript' }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})
|