@things-factory/headless-twin 10.0.14 → 10.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (478) hide show
  1. package/dist-server/engine/attention-digest.d.ts +4 -4
  2. package/dist-server/engine/attention-digest.js +7 -7
  3. package/dist-server/engine/attention-digest.js.map +1 -1
  4. package/dist-server/engine/canonical-ingest.d.ts +11 -2
  5. package/dist-server/engine/canonical-ingest.js +137 -8
  6. package/dist-server/engine/canonical-ingest.js.map +1 -1
  7. package/dist-server/engine/command-routing.js +1 -1
  8. package/dist-server/engine/command-routing.js.map +1 -1
  9. package/dist-server/engine/declared-stimulus.js +1 -1
  10. package/dist-server/engine/declared-stimulus.js.map +1 -1
  11. package/dist-server/engine/energy-topology.js +1 -1
  12. package/dist-server/engine/energy-topology.js.map +1 -1
  13. package/dist-server/engine/ingest-dedupe.d.ts +38 -0
  14. package/dist-server/engine/ingest-dedupe.js +145 -0
  15. package/dist-server/engine/ingest-dedupe.js.map +1 -0
  16. package/dist-server/engine/ingest-health.d.ts +124 -9
  17. package/dist-server/engine/ingest-health.js +169 -15
  18. package/dist-server/engine/ingest-health.js.map +1 -1
  19. package/dist-server/engine/integration-probes.d.ts +3 -3
  20. package/dist-server/engine/integration-probes.js +6 -6
  21. package/dist-server/engine/integration-probes.js.map +1 -1
  22. package/dist-server/engine/kpi-baseline.js +4 -4
  23. package/dist-server/engine/kpi-baseline.js.map +1 -1
  24. package/dist-server/engine/kpi-fold.d.ts +122 -12
  25. package/dist-server/engine/kpi-fold.js +247 -18
  26. package/dist-server/engine/kpi-fold.js.map +1 -1
  27. package/dist-server/engine/kpi-query.d.ts +11 -11
  28. package/dist-server/engine/kpi-query.js +185 -28
  29. package/dist-server/engine/kpi-query.js.map +1 -1
  30. package/dist-server/engine/live-feed-registry.d.ts +1 -1
  31. package/dist-server/engine/live-feed-registry.js +1 -1
  32. package/dist-server/engine/live-feed-registry.js.map +1 -1
  33. package/dist-server/engine/load-meter.d.ts +1 -1
  34. package/dist-server/engine/load-meter.js.map +1 -1
  35. package/dist-server/engine/local-declarations.d.ts +7 -7
  36. package/dist-server/engine/local-declarations.js +9 -9
  37. package/dist-server/engine/local-declarations.js.map +1 -1
  38. package/dist-server/engine/log.d.ts +1 -1
  39. package/dist-server/engine/log.js +1 -1
  40. package/dist-server/engine/log.js.map +1 -1
  41. package/dist-server/engine/measured-estimator.js +1 -1
  42. package/dist-server/engine/measured-estimator.js.map +1 -1
  43. package/dist-server/engine/measured-yield.js +1 -1
  44. package/dist-server/engine/measured-yield.js.map +1 -1
  45. package/dist-server/engine/model-basis.d.ts +1 -1
  46. package/dist-server/engine/model-basis.js +1 -1
  47. package/dist-server/engine/model-basis.js.map +1 -1
  48. package/dist-server/engine/model-gap.d.ts +3 -3
  49. package/dist-server/engine/model-gap.js +1 -1
  50. package/dist-server/engine/model-gap.js.map +1 -1
  51. package/dist-server/engine/model-vocabulary.js +1 -1
  52. package/dist-server/engine/model-vocabulary.js.map +1 -1
  53. package/dist-server/engine/oee-accumulator.d.ts +4 -4
  54. package/dist-server/engine/oee-accumulator.js +3 -3
  55. package/dist-server/engine/oee-accumulator.js.map +1 -1
  56. package/dist-server/engine/property-effects.js +2 -2
  57. package/dist-server/engine/property-effects.js.map +1 -1
  58. package/dist-server/engine/read-time.d.ts +22 -0
  59. package/dist-server/engine/read-time.js +81 -0
  60. package/dist-server/engine/read-time.js.map +1 -0
  61. package/dist-server/engine/restart-policy.js +1 -1
  62. package/dist-server/engine/restart-policy.js.map +1 -1
  63. package/dist-server/engine/runtime-key.js +1 -1
  64. package/dist-server/engine/runtime-key.js.map +1 -1
  65. package/dist-server/engine/spec-coverage.d.ts +2 -2
  66. package/dist-server/engine/spec-coverage.js +1 -1
  67. package/dist-server/engine/spec-coverage.js.map +1 -1
  68. package/dist-server/engine/stage-path.d.ts +4 -4
  69. package/dist-server/engine/stage-path.js +1 -1
  70. package/dist-server/engine/stage-path.js.map +1 -1
  71. package/dist-server/engine/state-axes.d.ts +1 -1
  72. package/dist-server/engine/state-axes.js +2 -2
  73. package/dist-server/engine/state-axes.js.map +1 -1
  74. package/dist-server/engine/travel-estimator.d.ts +2 -2
  75. package/dist-server/engine/travel-estimator.js +1 -1
  76. package/dist-server/engine/travel-estimator.js.map +1 -1
  77. package/dist-server/engine/twin-engine.d.ts +243 -53
  78. package/dist-server/engine/twin-engine.js +690 -191
  79. package/dist-server/engine/twin-engine.js.map +1 -1
  80. package/dist-server/engine/warm-start.d.ts +2 -2
  81. package/dist-server/engine/warm-start.js +5 -5
  82. package/dist-server/engine/warm-start.js.map +1 -1
  83. package/dist-server/index.js +1 -1
  84. package/dist-server/index.js.map +1 -1
  85. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js +1 -1
  86. package/dist-server/migrations/1786000000000-RenameTwinInstanceBoardToModel.js.map +1 -1
  87. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js +3 -3
  88. package/dist-server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.js.map +1 -1
  89. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js +2 -2
  90. package/dist-server/migrations/1786200000000-CarryLiveFeedCursor.js.map +1 -1
  91. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.d.ts +5 -0
  92. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js +54 -0
  93. package/dist-server/migrations/1786300000000-IndexEventTypeByTime.js.map +1 -0
  94. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.d.ts +5 -0
  95. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js +44 -0
  96. package/dist-server/migrations/1786400000000-IndexEventCreatedAt.js.map +1 -0
  97. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.d.ts +6 -0
  98. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js +84 -0
  99. package/dist-server/migrations/1786500000000-CreateTwinSubjectEvents.js.map +1 -0
  100. package/dist-server/migrations/index.js +7 -1
  101. package/dist-server/migrations/index.js.map +1 -1
  102. package/dist-server/routes.d.ts +1 -0
  103. package/dist-server/routes.js +69 -5
  104. package/dist-server/routes.js.map +1 -1
  105. package/dist-server/service/index.d.ts +2 -2
  106. package/dist-server/service/index.js +27 -24
  107. package/dist-server/service/index.js.map +1 -1
  108. package/dist-server/service/reference/control-routing.d.ts +1 -1
  109. package/dist-server/service/reference/control-routing.js +1 -1
  110. package/dist-server/service/reference/control-routing.js.map +1 -1
  111. package/dist-server/service/reference/discovery-result.d.ts +2 -2
  112. package/dist-server/service/reference/discovery-result.js +3 -3
  113. package/dist-server/service/reference/discovery-result.js.map +1 -1
  114. package/dist-server/service/reference/hook-contract.d.ts +43 -0
  115. package/dist-server/service/reference/hook-contract.js +59 -0
  116. package/dist-server/service/reference/hook-contract.js.map +1 -0
  117. package/dist-server/service/reference/ingest-space.d.ts +1 -1
  118. package/dist-server/service/reference/ingest-space.js +4 -4
  119. package/dist-server/service/reference/ingest-space.js.map +1 -1
  120. package/dist-server/service/reference/knob-defaults.d.ts +1 -1
  121. package/dist-server/service/reference/knob-defaults.js +4 -4
  122. package/dist-server/service/reference/knob-defaults.js.map +1 -1
  123. package/dist-server/service/reference/reference-adapter.d.ts +140 -8
  124. package/dist-server/service/reference/reference-adapter.js +27 -0
  125. package/dist-server/service/reference/reference-adapter.js.map +1 -1
  126. package/dist-server/service/reference/reference-hook.d.ts +20 -0
  127. package/dist-server/service/reference/reference-hook.js +133 -0
  128. package/dist-server/service/reference/reference-hook.js.map +1 -0
  129. package/dist-server/service/reference/reference-live.d.ts +2 -2
  130. package/dist-server/service/reference/reference-live.js +88 -13
  131. package/dist-server/service/reference/reference-live.js.map +1 -1
  132. package/dist-server/service/reference/reference-master.d.ts +14 -14
  133. package/dist-server/service/reference/reference-master.js +34 -12
  134. package/dist-server/service/reference/reference-master.js.map +1 -1
  135. package/dist-server/service/reference/reference-resolver.d.ts +1 -1
  136. package/dist-server/service/reference/reference-resolver.js +10 -10
  137. package/dist-server/service/reference/reference-resolver.js.map +1 -1
  138. package/dist-server/service/reference/twin-reference.d.ts +3 -3
  139. package/dist-server/service/reference/twin-reference.js.map +1 -1
  140. package/dist-server/service/twin-attention/twin-attention-query.d.ts +1 -1
  141. package/dist-server/service/twin-attention/twin-attention-query.js +1 -1
  142. package/dist-server/service/twin-attention/twin-attention-query.js.map +1 -1
  143. package/dist-server/service/twin-audit/command-audit.d.ts +1 -1
  144. package/dist-server/service/twin-audit/command-audit.js.map +1 -1
  145. package/dist-server/service/twin-audit/twin-audit-event.d.ts +1 -1
  146. package/dist-server/service/twin-audit/twin-audit-event.js.map +1 -1
  147. package/dist-server/service/twin-audit/twin-audit-query.js +1 -1
  148. package/dist-server/service/twin-audit/twin-audit-query.js.map +1 -1
  149. package/dist-server/service/twin-control/twin-control-mutation.js +1 -1
  150. package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -1
  151. package/dist-server/service/twin-event/twin-event-keys.d.ts +22 -2
  152. package/dist-server/service/twin-event/twin-event-keys.js +37 -5
  153. package/dist-server/service/twin-event/twin-event-keys.js.map +1 -1
  154. package/dist-server/service/twin-event/twin-event-type.d.ts +1 -0
  155. package/dist-server/service/twin-event/twin-event-type.js +8 -1
  156. package/dist-server/service/twin-event/twin-event-type.js.map +1 -1
  157. package/dist-server/service/twin-event/twin-event.d.ts +2 -2
  158. package/dist-server/service/twin-event/twin-event.js +32 -4
  159. package/dist-server/service/twin-event/twin-event.js.map +1 -1
  160. package/dist-server/service/twin-forecast/forecast-metrics.js +1 -1
  161. package/dist-server/service/twin-forecast/forecast-metrics.js.map +1 -1
  162. package/dist-server/service/twin-forecast/gap-analytics.d.ts +1 -1
  163. package/dist-server/service/twin-forecast/gap-analytics.js.map +1 -1
  164. package/dist-server/service/twin-forecast/twin-forecast-query.js +29 -11
  165. package/dist-server/service/twin-forecast/twin-forecast-query.js.map +1 -1
  166. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.d.ts +1 -1
  167. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js +1 -1
  168. package/dist-server/service/twin-ingest-window/twin-ingest-window-query.js.map +1 -1
  169. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js +1 -1
  170. package/dist-server/service/twin-ingest-window/twin-ingest-window-writer.js.map +1 -1
  171. package/dist-server/service/twin-instance/twin-instance.js.map +1 -1
  172. package/dist-server/service/twin-journal/event-type-split-shape.d.ts +50 -0
  173. package/dist-server/service/twin-journal/event-type-split-shape.js +111 -0
  174. package/dist-server/service/twin-journal/event-type-split-shape.js.map +1 -0
  175. package/dist-server/service/twin-journal/event-type-split.d.ts +15 -0
  176. package/dist-server/service/twin-journal/event-type-split.js +102 -0
  177. package/dist-server/service/twin-journal/event-type-split.js.map +1 -0
  178. package/dist-server/service/twin-journal/journal-order.d.ts +15 -0
  179. package/dist-server/service/twin-journal/journal-order.js +17 -0
  180. package/dist-server/service/twin-journal/journal-order.js.map +1 -0
  181. package/dist-server/service/twin-journal/twin-journal-query.d.ts +5 -5
  182. package/dist-server/service/twin-journal/twin-journal-query.js +232 -21
  183. package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -1
  184. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +27 -1
  185. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +59 -3
  186. package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
  187. package/dist-server/service/twin-metrics/twin-metrics-query.js +14 -1
  188. package/dist-server/service/twin-metrics/twin-metrics-query.js.map +1 -1
  189. package/dist-server/service/twin-model/axis-journal-evidence.js +1 -1
  190. package/dist-server/service/twin-model/axis-journal-evidence.js.map +1 -1
  191. package/dist-server/service/twin-model/epcis-coverage.js +36 -1
  192. package/dist-server/service/twin-model/epcis-coverage.js.map +1 -1
  193. package/dist-server/service/twin-model/iec61850-coverage.js +1 -1
  194. package/dist-server/service/twin-model/iec61850-coverage.js.map +1 -1
  195. package/dist-server/service/twin-model/isa95-coverage.d.ts +15 -2
  196. package/dist-server/service/twin-model/isa95-coverage.js +32 -8
  197. package/dist-server/service/twin-model/isa95-coverage.js.map +1 -1
  198. package/dist-server/service/twin-model/item-ref.js +2 -2
  199. package/dist-server/service/twin-model/item-ref.js.map +1 -1
  200. package/dist-server/service/twin-model/name-index.d.ts +1 -1
  201. package/dist-server/service/twin-model/name-index.js +1 -1
  202. package/dist-server/service/twin-model/name-index.js.map +1 -1
  203. package/dist-server/service/twin-model/project-structure.d.ts +1 -1
  204. package/dist-server/service/twin-model/project-structure.js +3 -3
  205. package/dist-server/service/twin-model/project-structure.js.map +1 -1
  206. package/dist-server/service/twin-model/twin-equipment.d.ts +1 -1
  207. package/dist-server/service/twin-model/twin-equipment.js +1 -1
  208. package/dist-server/service/twin-model/twin-equipment.js.map +1 -1
  209. package/dist-server/service/twin-model/twin-lineage-query.js +16 -5
  210. package/dist-server/service/twin-model/twin-lineage-query.js.map +1 -1
  211. package/dist-server/service/twin-model/twin-location.d.ts +1 -1
  212. package/dist-server/service/twin-model/twin-location.js.map +1 -1
  213. package/dist-server/service/twin-model/twin-model-item-query.d.ts +3 -3
  214. package/dist-server/service/twin-model/twin-model-item-query.js +14 -14
  215. package/dist-server/service/twin-model/twin-model-item-query.js.map +1 -1
  216. package/dist-server/service/twin-model/twin-model-mutation.d.ts +2 -2
  217. package/dist-server/service/twin-model/twin-model-mutation.js +4 -4
  218. package/dist-server/service/twin-model/twin-model-mutation.js.map +1 -1
  219. package/dist-server/service/twin-model/twin-model-query.js +117 -28
  220. package/dist-server/service/twin-model/twin-model-query.js.map +1 -1
  221. package/dist-server/service/twin-model/twin-model-tree-query.js +22 -0
  222. package/dist-server/service/twin-model/twin-model-tree-query.js.map +1 -1
  223. package/dist-server/service/twin-model/twin-operation.d.ts +1 -1
  224. package/dist-server/service/twin-model/twin-operation.js +1 -1
  225. package/dist-server/service/twin-model/twin-operation.js.map +1 -1
  226. package/dist-server/service/twin-space/move-space.js +2 -2
  227. package/dist-server/service/twin-space/move-space.js.map +1 -1
  228. package/dist-server/service/twin-space/representation-role.d.ts +2 -0
  229. package/dist-server/service/twin-space/representation-role.js +18 -0
  230. package/dist-server/service/twin-space/representation-role.js.map +1 -0
  231. package/dist-server/service/twin-space/space-integrity.d.ts +1 -1
  232. package/dist-server/service/twin-space/space-integrity.js.map +1 -1
  233. package/dist-server/service/twin-space/twin-space-representation.d.ts +2 -0
  234. package/dist-server/service/twin-space/twin-space-representation.js +16 -0
  235. package/dist-server/service/twin-space/twin-space-representation.js.map +1 -1
  236. package/dist-server/service/twin-space/twin-space-resolver.d.ts +2 -2
  237. package/dist-server/service/twin-space/twin-space-resolver.js +36 -7
  238. package/dist-server/service/twin-space/twin-space-resolver.js.map +1 -1
  239. package/dist-server/service/twin-structure/twin-structure.js +3 -3
  240. package/dist-server/service/twin-structure/twin-structure.js.map +1 -1
  241. package/dist-server/service/twin-subject/event-subjects.d.ts +43 -0
  242. package/dist-server/service/twin-subject/event-subjects.js +137 -0
  243. package/dist-server/service/twin-subject/event-subjects.js.map +1 -0
  244. package/dist-server/service/twin-subject/index.d.ts +9 -0
  245. package/dist-server/service/twin-subject/index.js +16 -0
  246. package/dist-server/service/twin-subject/index.js.map +1 -0
  247. package/dist-server/service/twin-subject/item-resolver.d.ts +10 -0
  248. package/dist-server/service/twin-subject/item-resolver.js +93 -0
  249. package/dist-server/service/twin-subject/item-resolver.js.map +1 -0
  250. package/dist-server/service/twin-subject/subject-query-shape.d.ts +22 -0
  251. package/dist-server/service/twin-subject/subject-query-shape.js +88 -0
  252. package/dist-server/service/twin-subject/subject-query-shape.js.map +1 -0
  253. package/dist-server/service/twin-subject/twin-subject-backfill.d.ts +23 -0
  254. package/dist-server/service/twin-subject/twin-subject-backfill.js +159 -0
  255. package/dist-server/service/twin-subject/twin-subject-backfill.js.map +1 -0
  256. package/dist-server/service/twin-subject/twin-subject-event.d.ts +14 -0
  257. package/dist-server/service/twin-subject/twin-subject-event.js +111 -0
  258. package/dist-server/service/twin-subject/twin-subject-event.js.map +1 -0
  259. package/dist-server/service/twin-subject/twin-subject-fast-path.d.ts +39 -0
  260. package/dist-server/service/twin-subject/twin-subject-fast-path.js +295 -0
  261. package/dist-server/service/twin-subject/twin-subject-fast-path.js.map +1 -0
  262. package/dist-server/service/twin-subject/twin-subject-query.d.ts +27 -0
  263. package/dist-server/service/twin-subject/twin-subject-query.js +232 -0
  264. package/dist-server/service/twin-subject/twin-subject-query.js.map +1 -0
  265. package/dist-server/service/twin-subject/twin-subject-writer.d.ts +27 -0
  266. package/dist-server/service/twin-subject/twin-subject-writer.js +166 -0
  267. package/dist-server/service/twin-subject/twin-subject-writer.js.map +1 -0
  268. package/dist-server/service/twin-target/twin-target-resolver.js +1 -1
  269. package/dist-server/service/twin-target/twin-target-resolver.js.map +1 -1
  270. package/dist-shared/entity-delta.d.ts +1 -1
  271. package/dist-shared/entity-delta.js +3 -3
  272. package/dist-shared/entity-delta.js.map +1 -1
  273. package/dist-shared/touched-items.js +2 -2
  274. package/dist-shared/touched-items.js.map +1 -1
  275. package/dist-shared/twin-level.js +1 -1
  276. package/dist-shared/twin-level.js.map +1 -1
  277. package/package.json +3 -3
  278. package/server/engine/attention-digest.ts +9 -9
  279. package/server/engine/canonical-ingest.ts +170 -13
  280. package/server/engine/command-routing.ts +1 -1
  281. package/server/engine/declared-stimulus.ts +1 -1
  282. package/server/engine/energy-topology.ts +1 -1
  283. package/server/engine/ingest-dedupe.ts +149 -0
  284. package/server/engine/ingest-health.ts +234 -20
  285. package/server/engine/integration-probes.ts +7 -7
  286. package/server/engine/kpi-baseline.ts +4 -4
  287. package/server/engine/kpi-fold.ts +395 -27
  288. package/server/engine/kpi-query.ts +212 -46
  289. package/server/engine/live-feed-registry.ts +1 -1
  290. package/server/engine/load-meter.ts +1 -1
  291. package/server/engine/local-declarations.ts +13 -13
  292. package/server/engine/log.ts +1 -1
  293. package/server/engine/measured-estimator.ts +1 -1
  294. package/server/engine/measured-yield.ts +1 -1
  295. package/server/engine/model-basis.ts +2 -2
  296. package/server/engine/model-gap.ts +3 -3
  297. package/server/engine/model-vocabulary.ts +1 -1
  298. package/server/engine/oee-accumulator.ts +4 -4
  299. package/server/engine/property-effects.ts +2 -2
  300. package/server/engine/read-time.ts +77 -0
  301. package/server/engine/restart-policy.ts +1 -1
  302. package/server/engine/runtime-key.ts +1 -1
  303. package/server/engine/spec-coverage.ts +3 -3
  304. package/server/engine/stage-path.ts +5 -5
  305. package/server/engine/state-axes.ts +2 -2
  306. package/server/engine/travel-estimator.ts +2 -2
  307. package/server/engine/twin-engine.ts +764 -201
  308. package/server/engine/warm-start.ts +6 -6
  309. package/server/index.ts +1 -1
  310. package/server/migrations/1786000000000-RenameTwinInstanceBoardToModel.ts +1 -1
  311. package/server/migrations/1786100000000-PromoteEventActionAndSyncWarnings.ts +3 -3
  312. package/server/migrations/1786200000000-CarryLiveFeedCursor.ts +2 -2
  313. package/server/migrations/1786300000000-IndexEventTypeByTime.ts +48 -0
  314. package/server/migrations/1786400000000-IndexEventCreatedAt.ts +38 -0
  315. package/server/migrations/1786500000000-CreateTwinSubjectEvents.ts +93 -0
  316. package/server/migrations/index.ts +7 -1
  317. package/server/routes.ts +68 -5
  318. package/server/service/index.ts +4 -1
  319. package/server/service/reference/control-routing.ts +1 -1
  320. package/server/service/reference/discovery-result.ts +3 -3
  321. package/server/service/reference/hook-contract.ts +103 -0
  322. package/server/service/reference/ingest-space.ts +4 -4
  323. package/server/service/reference/knob-defaults.ts +4 -4
  324. package/server/service/reference/reference-adapter.ts +166 -9
  325. package/server/service/reference/reference-hook.ts +145 -0
  326. package/server/service/reference/reference-live.ts +92 -14
  327. package/server/service/reference/reference-master.ts +39 -17
  328. package/server/service/reference/reference-resolver.ts +10 -10
  329. package/server/service/reference/twin-reference.ts +3 -3
  330. package/server/service/twin-attention/twin-attention-query.ts +1 -1
  331. package/server/service/twin-audit/command-audit.ts +1 -1
  332. package/server/service/twin-audit/twin-audit-event.ts +2 -2
  333. package/server/service/twin-audit/twin-audit-query.ts +1 -1
  334. package/server/service/twin-control/twin-control-mutation.ts +1 -1
  335. package/server/service/twin-event/twin-event-keys.ts +37 -5
  336. package/server/service/twin-event/twin-event-type.ts +18 -1
  337. package/server/service/twin-event/twin-event.ts +32 -6
  338. package/server/service/twin-forecast/forecast-metrics.ts +1 -1
  339. package/server/service/twin-forecast/gap-analytics.ts +1 -1
  340. package/server/service/twin-forecast/twin-forecast-query.ts +30 -11
  341. package/server/service/twin-ingest-window/twin-ingest-window-query.ts +1 -1
  342. package/server/service/twin-ingest-window/twin-ingest-window-writer.ts +1 -1
  343. package/server/service/twin-instance/twin-instance.ts +4 -4
  344. package/server/service/twin-journal/event-type-split-shape.ts +112 -0
  345. package/server/service/twin-journal/event-type-split.ts +144 -0
  346. package/server/service/twin-journal/journal-order.ts +20 -0
  347. package/server/service/twin-journal/twin-journal-query.ts +224 -20
  348. package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +57 -3
  349. package/server/service/twin-metrics/twin-metrics-query.ts +14 -1
  350. package/server/service/twin-model/axis-journal-evidence.ts +1 -1
  351. package/server/service/twin-model/epcis-coverage.ts +36 -1
  352. package/server/service/twin-model/iec61850-coverage.ts +1 -1
  353. package/server/service/twin-model/isa95-coverage.ts +45 -8
  354. package/server/service/twin-model/item-ref.ts +2 -2
  355. package/server/service/twin-model/name-index.ts +1 -1
  356. package/server/service/twin-model/project-structure.ts +4 -4
  357. package/server/service/twin-model/twin-equipment.ts +2 -2
  358. package/server/service/twin-model/twin-lineage-query.ts +16 -5
  359. package/server/service/twin-model/twin-location.ts +1 -1
  360. package/server/service/twin-model/twin-model-item-query.ts +14 -14
  361. package/server/service/twin-model/twin-model-mutation.ts +4 -4
  362. package/server/service/twin-model/twin-model-query.ts +117 -28
  363. package/server/service/twin-model/twin-model-tree-query.ts +25 -1
  364. package/server/service/twin-model/twin-operation.ts +2 -2
  365. package/server/service/twin-space/move-space.ts +3 -3
  366. package/server/service/twin-space/representation-role.ts +15 -0
  367. package/server/service/twin-space/space-integrity.ts +1 -1
  368. package/server/service/twin-space/twin-space-representation.ts +37 -0
  369. package/server/service/twin-space/twin-space-resolver.ts +39 -7
  370. package/server/service/twin-structure/twin-structure.ts +3 -3
  371. package/server/service/twin-subject/event-subjects.ts +155 -0
  372. package/server/service/twin-subject/index.ts +10 -0
  373. package/server/service/twin-subject/item-resolver.ts +92 -0
  374. package/server/service/twin-subject/subject-query-shape.ts +84 -0
  375. package/server/service/twin-subject/twin-subject-backfill.ts +196 -0
  376. package/server/service/twin-subject/twin-subject-event.ts +101 -0
  377. package/server/service/twin-subject/twin-subject-fast-path.ts +346 -0
  378. package/server/service/twin-subject/twin-subject-query.ts +210 -0
  379. package/server/service/twin-subject/twin-subject-writer.ts +189 -0
  380. package/server/service/twin-target/twin-target-resolver.ts +1 -1
  381. package/shared/entity-delta.ts +3 -3
  382. package/shared/touched-items.ts +2 -2
  383. package/shared/twin-level.ts +1 -1
  384. package/test/adopt-structure-live.test.ts +3 -3
  385. package/test/aggregate-not-findone.test.ts +112 -0
  386. package/test/attention-digest.test.ts +6 -6
  387. package/test/axis-read.test.ts +2 -2
  388. package/test/boot-resume.test.ts +20 -7
  389. package/test/broadcast-period.test.ts +2 -2
  390. package/test/broadcast-queue-overflow.test.ts +244 -0
  391. package/test/canonical-ingest-vocabularies.test.ts +179 -7
  392. package/test/canonical-quantity-door.test.ts +2 -2
  393. package/test/checkpoint-refuses-empty.test.ts +2 -2
  394. package/test/connector-capability-declaration.test.ts +88 -0
  395. package/test/control-capability.test.ts +1 -1
  396. package/test/cursor-stall-not-read-failure.test.ts +2 -2
  397. package/test/declaration-reaches-model.test.ts +5 -5
  398. package/test/declared-stimulus.test.ts +4 -4
  399. package/test/discovery-result.test.ts +2 -2
  400. package/test/entity-delta.test.ts +4 -4
  401. package/test/event-subjects.test.ts +147 -0
  402. package/test/event-time-column.test.ts +3 -3
  403. package/test/event-type-split.test.ts +155 -0
  404. package/test/fold-gap-speaks.test.ts +53 -0
  405. package/test/forecast-metrics.test.ts +1 -1
  406. package/test/forecast-tuning.test.ts +1 -1
  407. package/test/ingest-health-engine.test.ts +2 -2
  408. package/test/ingest-health-wiring.test.ts +7 -5
  409. package/test/ingest-health.test.ts +6 -6
  410. package/test/ingest-history.test.ts +2 -2
  411. package/test/ingest-idempotent.test.ts +132 -0
  412. package/test/ingest-space.test.ts +3 -3
  413. package/test/integration-probes.test.ts +3 -3
  414. package/test/integration-runner.test.ts +1 -1
  415. package/test/item-ref.test.ts +1 -1
  416. package/test/journal-order-axis.test.ts +80 -0
  417. package/test/journal-read-discipline.test.ts +16 -6
  418. package/test/journal-retention.test.ts +171 -29
  419. package/test/journal-sort-axis.test.ts +1 -1
  420. package/test/journal-write-door.test.ts +3 -3
  421. package/test/journal-write-trend.test.ts +1 -1
  422. package/test/kernel-kind-guard.test.ts +3 -3
  423. package/test/knob-defaults.test.ts +1 -1
  424. package/test/kpi-baseline-db.test.ts +2 -2
  425. package/test/kpi-fold.test.ts +185 -14
  426. package/test/kpi-query-bench.test.ts +3 -3
  427. package/test/live-cursor-wiring.test.ts +6 -6
  428. package/test/live-kernel-facts.test.ts +11 -11
  429. package/test/live-mirror-parity.test.ts +3 -3
  430. package/test/load-meter.test.ts +1 -1
  431. package/test/local-declarations.test.ts +10 -10
  432. package/test/log-stamp.test.ts +1 -1
  433. package/test/measured-yield.test.ts +2 -2
  434. package/test/merge-streams.test.ts +70 -0
  435. package/test/mirror-resumes-from-checkpoint.test.ts +13 -13
  436. package/test/model-basis.test.ts +2 -2
  437. package/test/model-gap.test.ts +4 -4
  438. package/test/model-vocabulary.test.ts +2 -2
  439. package/test/move-space.test.ts +1 -1
  440. package/test/oee-accumulator.test.ts +2 -2
  441. package/test/operational-vocabulary.test.ts +2 -2
  442. package/test/project-structure-db.test.ts +2 -2
  443. package/test/projection-reaches-screen.test.ts +2 -2
  444. package/test/property-effects.test.ts +3 -3
  445. package/test/read-failure-ledger.test.ts +106 -0
  446. package/test/read-failure-visible.test.ts +7 -7
  447. package/test/read-time.test.ts +118 -0
  448. package/test/reference-grounding.test.ts +1 -1
  449. package/test/reference-hook.test.ts +86 -0
  450. package/test/registry-key-guard.test.ts +1 -1
  451. package/test/rename-twin.test.ts +81 -0
  452. package/test/restart-policy.test.ts +3 -3
  453. package/test/resync-origin-site.test.ts +3 -3
  454. package/test/revision-axis.test.ts +14 -8
  455. package/test/runtime-key.test.ts +3 -3
  456. package/test/snapshot-freshness.test.ts +4 -4
  457. package/test/source-outcome-audit.test.ts +1 -1
  458. package/test/space-integrity.test.ts +1 -1
  459. package/test/space-representation.test.ts +66 -0
  460. package/test/space-scope-includes-stopped.test.ts +55 -0
  461. package/test/spec-coverage.test.ts +1 -1
  462. package/test/standard-coverage.test.ts +43 -1
  463. package/test/status-tally.test.ts +1 -1
  464. package/test/structure-revision-db.test.ts +7 -7
  465. package/test/subject-fast-path.test.ts +148 -0
  466. package/test/subject-read-model.test.ts +175 -0
  467. package/test/touched-items.test.ts +2 -2
  468. package/test/twin-audit.test.ts +1 -1
  469. package/test/twin-event-keys.test.ts +49 -3
  470. package/test/twin-model-item-db.test.ts +5 -5
  471. package/test/twin-model-tree-db.test.ts +35 -2
  472. package/test/twin-origin-resync.test.ts +1 -1
  473. package/test/warm-start-seam.test.ts +1 -1
  474. package/test/warm-start.test.ts +6 -6
  475. package/test/withheld-door.test.ts +95 -0
  476. package/test/yield-loop.test.ts +4 -4
  477. package/tsconfig.shared.tsbuildinfo +1 -1
  478. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,70 @@
1
- /* 헤드리스 트윈은 GraphQL(subscription/mutation)로 동작 — REST 라우터는 미사용(빈 부트스트랩). */
2
- process.on('bootstrap-module-global-public-route', (app, globalPublicRouter) => { });
3
- process.on('bootstrap-module-global-private-route', (app, globalPrivateRouter) => { });
4
- process.on('bootstrap-module-domain-public-route', (app, domainPublicRouter) => { });
5
- process.on('bootstrap-module-domain-private-route', (app, domainPrivateRouter) => { });
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /*
4
+ * 이 패키지가 여는 HTTP 자리 — 지금은 웹훅 하나다.
5
+ *
6
+ * ── 왜 여기인가 ─────────────────────────────────────────────────────────────
7
+ * 커넥터는 주소를 만들 수 없다. 어댑터 계약에 주소를 등록하는 자리가 없고, 있어서도 안 된다 — 주소는
8
+ * 앱의 것이고 커넥터마다 제각기 열면 인증도 제각기가 된다.
9
+ *
10
+ * 그래서 입구는 **하나**다. 어느 연결의 것인지는 주소의 이름으로 가려내고, 본문을 우리 어휘로 옮기는
11
+ * 것은 그 연결의 커넥터가 한다(§`reference-hook`).
12
+ *
13
+ * ── 왜 도메인 공개 라우터인가 ───────────────────────────────────────────────
14
+ * 밀어 주는 쪽은 사람이 아니다. 사람 인증(JWT)을 요구하면 연결된 시스템이 우리 토큰을 발급받아
15
+ * 갱신하며 관리해야 하고, 대부분의 현장에서 그것 때문에 연동이 서지 않는다.
16
+ *
17
+ * 대신 **연결마다 비밀값**을 두고 그것으로 확인한다. 비밀값을 선언하지 않은 연결은 훅을 받지 않는다 —
18
+ * 인증 없는 입구를 열어 두는 것보다 훅을 못 쓰는 것이 낫다.
19
+ */
20
+ const canonical_ingest_js_1 = require("./engine/canonical-ingest.js");
21
+ const twin_engine_js_1 = require("./engine/twin-engine.js");
22
+ const reference_hook_js_1 = require("./service/reference/reference-hook.js");
23
+ process.on('bootstrap-module-domain-public-route', (_app, router) => {
24
+ /*
25
+ * 주소에 트윈까지 적는다 — 어느 트윈에 넣을지 짐작하지 않는다.
26
+ *
27
+ * 한 연결이 여러 사이트를 만들면 트윈도 여럿이다. 본문을 보고 고르게 하면 그 판단이 커넥터마다
28
+ * 달라지고, 틀리면 다른 공장의 사실이 이 공장에 들어간다. 주소가 말하게 하면 그 일이 없다.
29
+ */
30
+ router.post('/twin/hook/:source/:instanceId', async (ctx) => {
31
+ const domain = ctx.state?.domain;
32
+ if (!domain) {
33
+ ctx.status = 400;
34
+ ctx.body = { ok: false, error: 'no domain context' };
35
+ return;
36
+ }
37
+ const outcome = await (0, reference_hook_js_1.handleHook)({
38
+ domainId: domain.id,
39
+ source: String(ctx.params.source ?? ''),
40
+ instanceId: String(ctx.params.instanceId ?? ''),
41
+ headers: (ctx.request?.headers ?? {}),
42
+ body: ctx.request?.body,
43
+ /*
44
+ * 폴링이 쓰는 길을 그대로 쓴다 — 검증도 유입도 같은 자리다. 그래서 트윈 쪽에서는 물어서 받은
45
+ * 것과 밀어 받은 것이 구별되지 않는다. 구별되는 것은 유입 장부의 `sources` 한 줄뿐이다.
46
+ */
47
+ ingest: (instanceId, records) => {
48
+ const { accepted, rejected, masterData } = (0, canonical_ingest_js_1.ingestCanonicalRecords)(records, domain.id, new Date().toISOString());
49
+ /* 사건이 아닌 것은 상태만 세운다 — 밀어 받는 길도 같은 규율이다(§`applyMasterData`). */
50
+ if (masterData.length)
51
+ twin_engine_js_1.TwinEngine.applyMasterData(domain.id, instanceId, masterData);
52
+ const { applied, duplicates } = twin_engine_js_1.TwinEngine.ingestLiveResult(domain.id, instanceId, accepted, 'hook');
53
+ /*
54
+ * 커널이 받지 못한 수를 이름으로 남긴다 — 트윈이 멈춘 사이 버려진 레코드를 「통과」로 세면
55
+ * 화면이 100% 라고 말한다. 중복으로 걸러진 것은 버려진 것이 아니므로 빼고 센다.
56
+ */
57
+ const undelivered = Math.max(0, accepted.length - applied - duplicates);
58
+ twin_engine_js_1.TwinEngine.recordIngestResult(domain.id, instanceId, records.length, rejected, Date.now(), undelivered);
59
+ return { applied, duplicates, rejected: rejected.length };
60
+ }
61
+ });
62
+ ctx.status = outcome.status;
63
+ ctx.body = outcome.body;
64
+ });
65
+ });
66
+ /* 나머지 셋은 이 패키지가 쓰지 않는다 — 자리는 남겨 둔다(다른 모듈이 같은 신호를 기다린다). */
67
+ process.on('bootstrap-module-global-public-route', (_app, _router) => { });
68
+ process.on('bootstrap-module-global-private-route', (_app, _router) => { });
69
+ process.on('bootstrap-module-domain-private-route', (_app, _router) => { });
6
70
  //# sourceMappingURL=routes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes.js","sourceRoot":"","sources":["../server/routes.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,OAAO,CAAC,EAAE,CAAC,sCAA6C,EAAE,CAAC,GAAG,EAAE,kBAAkB,EAAE,EAAE,GAAE,CAAC,CAAC,CAAA;AAC1F,OAAO,CAAC,EAAE,CAAC,uCAA8C,EAAE,CAAC,GAAG,EAAE,mBAAmB,EAAE,EAAE,GAAE,CAAC,CAAC,CAAA;AAC5F,OAAO,CAAC,EAAE,CAAC,sCAA6C,EAAE,CAAC,GAAG,EAAE,kBAAkB,EAAE,EAAE,GAAE,CAAC,CAAC,CAAA;AAC1F,OAAO,CAAC,EAAE,CAAC,uCAA8C,EAAE,CAAC,GAAG,EAAE,mBAAmB,EAAE,EAAE,GAAE,CAAC,CAAC,CAAA","sourcesContent":["/* 헤드리스 트윈은 GraphQL(subscription/mutation)로 동작 — REST 라우터는 미사용(빈 부트스트랩). */\nprocess.on('bootstrap-module-global-public-route' as any, (app, globalPublicRouter) => {})\nprocess.on('bootstrap-module-global-private-route' as any, (app, globalPrivateRouter) => {})\nprocess.on('bootstrap-module-domain-public-route' as any, (app, domainPublicRouter) => {})\nprocess.on('bootstrap-module-domain-private-route' as any, (app, domainPrivateRouter) => {})\n"]}
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../server/routes.ts"],"names":[],"mappings":";;AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,sEAAqE;AACrE,4DAAoD;AACpD,6EAAkE;AAElE,OAAO,CAAC,EAAE,CAAC,sCAA6C,EAAE,CAAC,IAAS,EAAE,MAAW,EAAE,EAAE;IACnF;;;;;OAKG;IACH,MAAM,CAAC,IAAI,CAAC,gCAAgC,EAAE,KAAK,EAAE,GAAQ,EAAE,EAAE;QAC/D,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,EAAE,MAAM,CAAA;QAChC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,GAAG,CAAC,MAAM,GAAG,GAAG,CAAA;YAChB,GAAG,CAAC,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAA;YACpD,OAAM;QACR,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAA,8BAAU,EAAC;YAC/B,QAAQ,EAAE,MAAM,CAAC,EAAE;YACnB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;YACvC,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;YAC/C,OAAO,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,IAAI,EAAE,CAA4B;YAChE,IAAI,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI;YACvB;;;eAGG;YACH,MAAM,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,EAAE;gBAC9B,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAA,4CAAsB,EAAC,OAAc,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,CAAA;gBACtH,+DAA+D;gBAC/D,IAAI,UAAU,CAAC,MAAM;oBAAE,2BAAU,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAA;gBACpF,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,2BAAU,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA;gBACpG;;;mBAGG;gBACH,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC,CAAA;gBACvE,2BAAU,CAAC,kBAAkB,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAA;gBACvG,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAA;YAC3D,CAAC;SACF,CAAC,CAAA;QACF,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAA;QAC3B,GAAG,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IACzB,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,2DAA2D;AAC3D,OAAO,CAAC,EAAE,CAAC,sCAA6C,EAAE,CAAC,IAAS,EAAE,OAAY,EAAE,EAAE,GAAE,CAAC,CAAC,CAAA;AAC1F,OAAO,CAAC,EAAE,CAAC,uCAA8C,EAAE,CAAC,IAAS,EAAE,OAAY,EAAE,EAAE,GAAE,CAAC,CAAC,CAAA;AAC3F,OAAO,CAAC,EAAE,CAAC,uCAA8C,EAAE,CAAC,IAAS,EAAE,OAAY,EAAE,EAAE,GAAE,CAAC,CAAC,CAAA","sourcesContent":["/*\n * 이 패키지가 여는 HTTP 자리 — 지금은 웹훅 하나다.\n *\n * ── 왜 여기인가 ─────────────────────────────────────────────────────────────\n * 커넥터는 주소를 만들 수 없다. 어댑터 계약에 주소를 등록하는 자리가 없고, 있어서도 안 된다 — 주소는\n * 앱의 것이고 커넥터마다 제각기 열면 인증도 제각기가 된다.\n *\n * 그래서 입구는 **하나**다. 어느 연결의 것인지는 주소의 이름으로 가려내고, 본문을 우리 어휘로 옮기는\n * 것은 그 연결의 커넥터가 한다(§`reference-hook`).\n *\n * ── 왜 도메인 공개 라우터인가 ───────────────────────────────────────────────\n * 밀어 주는 쪽은 사람이 아니다. 사람 인증(JWT)을 요구하면 연결된 시스템이 우리 토큰을 발급받아\n * 갱신하며 관리해야 하고, 대부분의 현장에서 그것 때문에 연동이 서지 않는다.\n *\n * 대신 **연결마다 비밀값**을 두고 그것으로 확인한다. 비밀값을 선언하지 않은 연결은 훅을 받지 않는다 —\n * 인증 없는 입구를 열어 두는 것보다 훅을 못 쓰는 것이 낫다.\n */\nimport { ingestCanonicalRecords } from './engine/canonical-ingest.js'\nimport { TwinEngine } from './engine/twin-engine.js'\nimport { handleHook } from './service/reference/reference-hook.js'\n\nprocess.on('bootstrap-module-domain-public-route' as any, (_app: any, router: any) => {\n /*\n * 주소에 트윈까지 적는다 — 어느 트윈에 넣을지 짐작하지 않는다.\n *\n * 한 연결이 여러 사이트를 만들면 트윈도 여럿이다. 본문을 보고 고르게 하면 그 판단이 커넥터마다\n * 달라지고, 틀리면 다른 공장의 사실이 이 공장에 들어간다. 주소가 말하게 하면 그 일이 없다.\n */\n router.post('/twin/hook/:source/:instanceId', async (ctx: any) => {\n const domain = ctx.state?.domain\n if (!domain) {\n ctx.status = 400\n ctx.body = { ok: false, error: 'no domain context' }\n return\n }\n const outcome = await handleHook({\n domainId: domain.id,\n source: String(ctx.params.source ?? ''),\n instanceId: String(ctx.params.instanceId ?? ''),\n headers: (ctx.request?.headers ?? {}) as Record<string, unknown>,\n body: ctx.request?.body,\n /*\n * 폴링이 쓰는 길을 그대로 쓴다 — 검증도 유입도 같은 자리다. 그래서 트윈 쪽에서는 물어서 받은\n * 것과 밀어 받은 것이 구별되지 않는다. 구별되는 것은 유입 장부의 `sources` 한 줄뿐이다.\n */\n ingest: (instanceId, records) => {\n const { accepted, rejected, masterData } = ingestCanonicalRecords(records as any, domain.id, new Date().toISOString())\n /* 사건이 아닌 것은 상태만 세운다 — 밀어 받는 길도 같은 규율이다(§`applyMasterData`). */\n if (masterData.length) TwinEngine.applyMasterData(domain.id, instanceId, masterData)\n const { applied, duplicates } = TwinEngine.ingestLiveResult(domain.id, instanceId, accepted, 'hook')\n /*\n * 커널이 받지 못한 수를 이름으로 남긴다 — 트윈이 멈춘 사이 버려진 레코드를 「통과」로 세면\n * 화면이 100% 라고 말한다. 중복으로 걸러진 것은 버려진 것이 아니므로 빼고 센다.\n */\n const undelivered = Math.max(0, accepted.length - applied - duplicates)\n TwinEngine.recordIngestResult(domain.id, instanceId, records.length, rejected, Date.now(), undelivered)\n return { applied, duplicates, rejected: rejected.length }\n }\n })\n ctx.status = outcome.status\n ctx.body = outcome.body\n })\n})\n\n/* 나머지 셋은 이 패키지가 쓰지 않는다 — 자리는 남겨 둔다(다른 모듈이 같은 신호를 기다린다). */\nprocess.on('bootstrap-module-global-public-route' as any, (_app: any, _router: any) => {})\nprocess.on('bootstrap-module-global-private-route' as any, (_app: any, _router: any) => {})\nprocess.on('bootstrap-module-domain-private-route' as any, (_app: any, _router: any) => {})\n"]}
@@ -17,10 +17,10 @@ export * from './reference/template-registry.js';
17
17
  export * from './reference/reference-probe.js';
18
18
  export * from './reference/reference-assessment.js';
19
19
  export * from './twin-lifecycle/domain-catalog.js';
20
- export declare const entities: (typeof import("./twin-event/twin-event.js").TwinEvent | typeof import("./twin-instance/twin-instance.js").TwinInstance | typeof import("./reference/twin-reference.js").TwinReference | typeof import("./twin-structure/twin-structure.js").TwinStructure | typeof import("./twin-space/twin-space.js").TwinSpace | typeof import("./twin-space/twin-space-representation.js").TwinSpaceRepresentation | typeof import("./twin-space/twin-space-area.js").TwinSpaceArea | typeof import("./twin-space/twin-area.js").TwinArea | typeof import("./twin-model/twin-location.js").TwinLocation | typeof import("./twin-model/twin-equipment.js").TwinEquipment | typeof import("./twin-model/twin-operation.js").TwinOperation | typeof import("./twin-target/twin-target.js").TwinTarget | typeof import("./twin-audit/twin-audit-event.js").TwinAuditEvent | typeof import("./twin-ingest-window/twin-ingest-window.js").TwinIngestWindow)[];
20
+ export declare const entities: (typeof import("./twin-event/twin-event.js").TwinEvent | typeof import("./twin-subject/twin-subject-event.js").TwinSubjectEvent | typeof import("./twin-instance/twin-instance.js").TwinInstance | typeof import("./reference/twin-reference.js").TwinReference | typeof import("./twin-structure/twin-structure.js").TwinStructure | typeof import("./twin-space/twin-space.js").TwinSpace | typeof import("./twin-space/twin-space-representation.js").TwinSpaceRepresentation | typeof import("./twin-space/twin-space-area.js").TwinSpaceArea | typeof import("./twin-space/twin-area.js").TwinArea | typeof import("./twin-model/twin-location.js").TwinLocation | typeof import("./twin-model/twin-equipment.js").TwinEquipment | typeof import("./twin-model/twin-operation.js").TwinOperation | typeof import("./twin-target/twin-target.js").TwinTarget | typeof import("./twin-audit/twin-audit-event.js").TwinAuditEvent | typeof import("./twin-ingest-window/twin-ingest-window.js").TwinIngestWindow)[];
21
21
  export declare const subscribers: any[];
22
22
  export declare const schema: {
23
23
  typeDefs: {};
24
- resolverClasses: (typeof import("./twin-state/twin-state-subscription.js").TwinStateSubscription | typeof import("./twin-audit/twin-audit-query.js").TwinAuditQuery | typeof import("./twin-space/twin-space-resolver.js").TwinSpaceResolver | typeof import("./twin-target/twin-target-resolver.js").TwinTargetResolver | typeof import("./reference/reference-resolver.js").TwinReferenceResolver | typeof import("./reference/reference-progress-subscription.js").TwinReferenceProgressSubscription | typeof import("./twin-control/twin-control-mutation.js").TwinControlMutation | typeof import("./twin-model/twin-model-query.js").TwinModelQuery | typeof import("./twin-model/twin-model-item-query.js").TwinModelItemQuery | typeof import("./twin-model/twin-model-tree-query.js").TwinModelTreeQuery | typeof import("./twin-model/twin-model-mutation.js").TwinModelMutation | typeof import("./twin-model/twin-lineage-query.js").TwinLineageQuery | typeof import("./twin-ingest-window/twin-ingest-window-query.js").TwinIngestWindowQuery | typeof import("./twin-lifecycle/twin-lifecycle-mutation.js").TwinLifecycleMutation | typeof import("./twin-journal/twin-journal-query.js").TwinJournalQuery | typeof import("./twin-forecast/twin-forecast-query.js").TwinForecastQuery | typeof import("./twin-attention/twin-attention-query.js").TwinAttentionQuery | typeof import("./twin-metrics/twin-metrics-query.js").TwinMetricsQuery | typeof import("./twin-readiness/twin-readiness-query.js").TwinReadinessQuery)[];
24
+ resolverClasses: (typeof import("./twin-state/twin-state-subscription.js").TwinStateSubscription | typeof import("./twin-subject/twin-subject-query.js").TwinSubjectQuery | typeof import("./twin-subject/twin-subject-query.js").TwinSubjectMutation | typeof import("./twin-audit/twin-audit-query.js").TwinAuditQuery | typeof import("./twin-space/twin-space-resolver.js").TwinSpaceResolver | typeof import("./twin-target/twin-target-resolver.js").TwinTargetResolver | typeof import("./reference/reference-resolver.js").TwinReferenceResolver | typeof import("./reference/reference-progress-subscription.js").TwinReferenceProgressSubscription | typeof import("./twin-control/twin-control-mutation.js").TwinControlMutation | typeof import("./twin-model/twin-model-query.js").TwinModelQuery | typeof import("./twin-model/twin-model-item-query.js").TwinModelItemQuery | typeof import("./twin-model/twin-model-tree-query.js").TwinModelTreeQuery | typeof import("./twin-model/twin-model-mutation.js").TwinModelMutation | typeof import("./twin-model/twin-lineage-query.js").TwinLineageQuery | typeof import("./twin-ingest-window/twin-ingest-window-query.js").TwinIngestWindowQuery | typeof import("./twin-lifecycle/twin-lifecycle-mutation.js").TwinLifecycleMutation | typeof import("./twin-journal/twin-journal-query.js").TwinJournalQuery | typeof import("./twin-forecast/twin-forecast-query.js").TwinForecastQuery | typeof import("./twin-attention/twin-attention-query.js").TwinAttentionQuery | typeof import("./twin-metrics/twin-metrics-query.js").TwinMetricsQuery | typeof import("./twin-readiness/twin-readiness-query.js").TwinReadinessQuery)[];
25
25
  directives: {};
26
26
  };
@@ -27,55 +27,58 @@ tslib_1.__exportStar(require("./reference/reference-assessment.js"), exports);
27
27
  tslib_1.__exportStar(require("./twin-lifecycle/domain-catalog.js"), exports);
28
28
  /* IMPORT ENTITIES AND RESOLVERS */
29
29
  const index_js_1 = require("./twin-event/index.js");
30
- const index_js_2 = require("./twin-audit/index.js");
31
- const index_js_3 = require("./twin-instance/index.js");
32
- const index_js_4 = require("./twin-structure/index.js");
33
- const index_js_5 = require("./twin-space/index.js");
34
- const index_js_6 = require("./twin-target/index.js");
35
- const index_js_7 = require("./reference/index.js");
36
- const index_js_8 = require("./twin-state/index.js");
37
- const index_js_9 = require("./twin-control/index.js");
38
- const index_js_10 = require("./twin-model/index.js");
30
+ const index_js_2 = require("./twin-subject/index.js");
31
+ const index_js_3 = require("./twin-audit/index.js");
32
+ const index_js_4 = require("./twin-instance/index.js");
33
+ const index_js_5 = require("./twin-structure/index.js");
34
+ const index_js_6 = require("./twin-space/index.js");
35
+ const index_js_7 = require("./twin-target/index.js");
36
+ const index_js_8 = require("./reference/index.js");
37
+ const index_js_9 = require("./twin-state/index.js");
38
+ const index_js_10 = require("./twin-control/index.js");
39
+ const index_js_11 = require("./twin-model/index.js");
39
40
  /* 인제스트 창 — 동기화 추이를 재기동 뒤에도 이어 보기 위한 행(리졸버 없음: 메모리 장부가 조회를 답한다). */
40
- const index_js_11 = require("./twin-ingest-window/index.js");
41
- const index_js_12 = require("./twin-lifecycle/index.js");
42
- const index_js_13 = require("./twin-journal/index.js");
43
- const index_js_14 = require("./twin-forecast/index.js");
44
- const index_js_15 = require("./twin-attention/index.js");
45
- const index_js_16 = require("./twin-metrics/index.js");
46
- const index_js_17 = require("./twin-readiness/index.js");
41
+ const index_js_12 = require("./twin-ingest-window/index.js");
42
+ const index_js_13 = require("./twin-lifecycle/index.js");
43
+ const index_js_14 = require("./twin-journal/index.js");
44
+ const index_js_15 = require("./twin-forecast/index.js");
45
+ const index_js_16 = require("./twin-attention/index.js");
46
+ const index_js_17 = require("./twin-metrics/index.js");
47
+ const index_js_18 = require("./twin-readiness/index.js");
47
48
  exports.entities = [
48
49
  /* ENTITIES */
49
50
  ...index_js_1.entities,
50
- ...index_js_11.entities,
51
51
  ...index_js_2.entities,
52
+ ...index_js_12.entities,
52
53
  ...index_js_3.entities,
53
54
  ...index_js_4.entities,
54
55
  ...index_js_5.entities,
55
56
  ...index_js_6.entities,
56
57
  ...index_js_7.entities,
58
+ ...index_js_8.entities,
57
59
  /* 구조 투영 — model JSON 에서 풀어낸 표준 엔티티(ADR-0032). 원본에서 온 캐시. */
58
- ...index_js_10.entities
60
+ ...index_js_11.entities
59
61
  ];
60
62
  exports.subscribers = [];
61
63
  exports.schema = {
62
64
  typeDefs: {},
63
65
  resolverClasses: [
64
66
  /* RESOLVER CLASSES */
65
- ...index_js_8.resolvers,
66
67
  ...index_js_9.resolvers,
67
- ...index_js_12.resolvers,
68
+ ...index_js_10.resolvers,
68
69
  ...index_js_13.resolvers,
69
- ...index_js_2.resolvers,
70
70
  ...index_js_14.resolvers,
71
+ ...index_js_3.resolvers,
71
72
  ...index_js_15.resolvers,
72
73
  ...index_js_16.resolvers,
73
74
  ...index_js_17.resolvers,
75
+ ...index_js_18.resolvers,
76
+ ...index_js_12.resolvers,
74
77
  ...index_js_11.resolvers,
75
- ...index_js_10.resolvers,
76
- ...index_js_5.resolvers,
77
78
  ...index_js_6.resolvers,
78
- ...index_js_7.resolvers
79
+ ...index_js_7.resolvers,
80
+ ...index_js_8.resolvers,
81
+ ...index_js_2.resolvers
79
82
  ],
80
83
  directives: {}
81
84
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,qEAA0C;AAC1C,2EAAgD;AAChD,qFAA0D;AAC1D,2EAAgD;AAChD,qEAA0C;AAC1C,oFAAyD;AACzD,0EAA+C;AAC/C,uEAA4C;AAC5C,6EAAkD;AAClD,kFAAuD;AACvD,0EAA+C;AAC/C,4EAAiD;AACjD,2EAAgD;AAChD,wEAA6C;AAC7C,wEAA6C;AAC7C,2EAAgD;AAChD,4DAA4D;AAC5D,yEAA8C;AAC9C,iEAAiE;AACjE,8EAAmD;AACnD,sEAAsE;AACtE,6EAAkD;AAElD,mCAAmC;AACnC,oDAAqE;AACrE,oDAAsG;AACtG,uDAA2E;AAC3E,wDAA6E;AAC7E,oDAAsG;AACtG,qDAAyG;AACzG,mDAA6G;AAC7G,oDAAuE;AACvE,sDAA2E;AAC3E,qDAAsG;AACtG,mEAAmE;AACnE,6DAA4H;AAC5H,yDAA+E;AAC/E,uDAA2E;AAC3E,wDAA6E;AAC7E,yDAA+E;AAC/E,uDAA2E;AAC3E,yDAA+E;AAElE,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,mBAAiB;IACpB,GAAG,oBAAwB;IAC3B,GAAG,mBAAiB;IACpB,GAAG,mBAAoB;IACvB,GAAG,mBAAqB;IACxB,GAAG,mBAAiB;IACpB,GAAG,mBAAkB;IACrB,GAAG,mBAAqB;IACxB,4DAA4D;IAC5D,GAAG,oBAAiB;CACrB,CAAA;AAEY,QAAA,WAAW,GAAG,EAAE,CAAA;AAEhB,QAAA,MAAM,GAAG;IACpB,QAAQ,EAAE,EAAE;IACZ,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,oBAAkB;QACrB,GAAG,oBAAoB;QACvB,GAAG,qBAAsB;QACzB,GAAG,qBAAoB;QACvB,GAAG,oBAAkB;QACrB,GAAG,qBAAqB;QACxB,GAAG,qBAAsB;QACzB,GAAG,qBAAoB;QACvB,GAAG,qBAAsB;QACzB,GAAG,qBAAyB;QAC5B,GAAG,qBAAkB;QACrB,GAAG,oBAAkB;QACrB,GAAG,oBAAmB;QACtB,GAAG,oBAAsB;KAC1B;IACD,UAAU,EAAE,EAAE;CACf,CAAA","sourcesContent":["/* EXPORT ENTITY TYPES */\nexport * from './twin-event/twin-event.js'\nexport * from './twin-audit/twin-audit-event.js'\nexport * from './twin-ingest-window/twin-ingest-window.js'\nexport * from './twin-instance/twin-instance.js'\nexport * from './twin-space/twin-space.js'\nexport * from './twin-space/twin-space-representation.js'\nexport * from './twin-space/twin-space-area.js'\nexport * from './twin-target/twin-target.js'\nexport * from './twin-structure/twin-structure.js'\nexport * from './twin-state/twin-state-subscription.js'\nexport * from './reference/reference-master.js'\nexport * from './reference/reference-registry.js'\nexport * from './reference/reference-adapter.js'\nexport * from './reference/reference-live.js'\nexport * from './reference/twin-reference.js'\nexport * from './reference/template-registry.js'\n/* 커넥터 점검 하네스 — 실 원본에 붙여 무엇이 채워지고 무엇이 비는지 센다(앱을 띄우지 않는다). */\nexport * from './reference/reference-probe.js'\n/* 읽은 뒤의 총평(사실 층) — 화면이 표로 그리고, 더 알고 싶을 때 AI 가 이 사실만 근거로 서술한다. */\nexport * from './reference/reference-assessment.js'\n/* 도메인 어휘 카탈로그 조합(커널 SSOT 노출) — 서버측 소비자(board-ai 도구 등)가 같은 형태를 쓰도록. */\nexport * from './twin-lifecycle/domain-catalog.js'\n\n/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as TwinEventEntities } from './twin-event/index.js'\nimport { entities as TwinAuditEntities, resolvers as TwinAuditResolvers } from './twin-audit/index.js'\nimport { entities as TwinInstanceEntities } from './twin-instance/index.js'\nimport { entities as TwinStructureEntities } from './twin-structure/index.js'\nimport { entities as TwinSpaceEntities, resolvers as TwinSpaceResolvers } from './twin-space/index.js'\nimport { entities as TwinTargetEntities, resolvers as TwinTargetResolvers } from './twin-target/index.js'\nimport { entities as TwinReferenceEntities, resolvers as TwinReferenceResolvers } from './reference/index.js'\nimport { resolvers as TwinStateResolvers } from './twin-state/index.js'\nimport { resolvers as TwinControlResolvers } from './twin-control/index.js'\nimport { entities as TwinModelEntities, resolvers as TwinModelResolvers } from './twin-model/index.js'\n/* 인제스트 창 — 동기화 추이를 재기동 뒤에도 이어 보기 위한 행(리졸버 없음: 메모리 장부가 조회를 답한다). */\nimport { entities as TwinIngestWindowEntities, resolvers as TwinIngestWindowResolvers } from './twin-ingest-window/index.js'\nimport { resolvers as TwinLifecycleResolvers } from './twin-lifecycle/index.js'\nimport { resolvers as TwinJournalResolvers } from './twin-journal/index.js'\nimport { resolvers as TwinForecastResolvers } from './twin-forecast/index.js'\nimport { resolvers as TwinAttentionResolvers } from './twin-attention/index.js'\nimport { resolvers as TwinMetricsResolvers } from './twin-metrics/index.js'\nimport { resolvers as TwinReadinessResolvers } from './twin-readiness/index.js'\n\nexport const entities = [\n /* ENTITIES */\n ...TwinEventEntities,\n ...TwinIngestWindowEntities,\n ...TwinAuditEntities,\n ...TwinInstanceEntities,\n ...TwinStructureEntities,\n ...TwinSpaceEntities,\n ...TwinTargetEntities,\n ...TwinReferenceEntities,\n /* 구조 투영 — model JSON 에서 풀어낸 표준 엔티티(ADR-0032). 원본에서 온 캐시. */\n ...TwinModelEntities\n]\n\nexport const subscribers = []\n\nexport const schema = {\n typeDefs: {},\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...TwinStateResolvers,\n ...TwinControlResolvers,\n ...TwinLifecycleResolvers,\n ...TwinJournalResolvers,\n ...TwinAuditResolvers,\n ...TwinForecastResolvers,\n ...TwinAttentionResolvers,\n ...TwinMetricsResolvers,\n ...TwinReadinessResolvers,\n ...TwinIngestWindowResolvers,\n ...TwinModelResolvers,\n ...TwinSpaceResolvers,\n ...TwinTargetResolvers,\n ...TwinReferenceResolvers\n ],\n directives: {}\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yBAAyB;AACzB,qEAA0C;AAC1C,2EAAgD;AAChD,qFAA0D;AAC1D,2EAAgD;AAChD,qEAA0C;AAC1C,oFAAyD;AACzD,0EAA+C;AAC/C,uEAA4C;AAC5C,6EAAkD;AAClD,kFAAuD;AACvD,0EAA+C;AAC/C,4EAAiD;AACjD,2EAAgD;AAChD,wEAA6C;AAC7C,wEAA6C;AAC7C,2EAAgD;AAChD,4DAA4D;AAC5D,yEAA8C;AAC9C,iEAAiE;AACjE,8EAAmD;AACnD,sEAAsE;AACtE,6EAAkD;AAElD,mCAAmC;AACnC,oDAAqE;AACrE,sDAA4G;AAC5G,oDAAsG;AACtG,uDAA2E;AAC3E,wDAA6E;AAC7E,oDAAsG;AACtG,qDAAyG;AACzG,mDAA6G;AAC7G,oDAAuE;AACvE,uDAA2E;AAC3E,qDAAsG;AACtG,mEAAmE;AACnE,6DAA4H;AAC5H,yDAA+E;AAC/E,uDAA2E;AAC3E,wDAA6E;AAC7E,yDAA+E;AAC/E,uDAA2E;AAC3E,yDAA+E;AAElE,QAAA,QAAQ,GAAG;IACtB,cAAc;IACd,GAAG,mBAAiB;IACpB,GAAG,mBAAmB;IACtB,GAAG,oBAAwB;IAC3B,GAAG,mBAAiB;IACpB,GAAG,mBAAoB;IACvB,GAAG,mBAAqB;IACxB,GAAG,mBAAiB;IACpB,GAAG,mBAAkB;IACrB,GAAG,mBAAqB;IACxB,4DAA4D;IAC5D,GAAG,oBAAiB;CACrB,CAAA;AAEY,QAAA,WAAW,GAAG,EAAE,CAAA;AAEhB,QAAA,MAAM,GAAG;IACpB,QAAQ,EAAE,EAAE;IACZ,eAAe,EAAE;QACf,sBAAsB;QACtB,GAAG,oBAAkB;QACrB,GAAG,qBAAoB;QACvB,GAAG,qBAAsB;QACzB,GAAG,qBAAoB;QACvB,GAAG,oBAAkB;QACrB,GAAG,qBAAqB;QACxB,GAAG,qBAAsB;QACzB,GAAG,qBAAoB;QACvB,GAAG,qBAAsB;QACzB,GAAG,qBAAyB;QAC5B,GAAG,qBAAkB;QACrB,GAAG,oBAAkB;QACrB,GAAG,oBAAmB;QACtB,GAAG,oBAAsB;QACzB,GAAG,oBAAoB;KACxB;IACD,UAAU,EAAE,EAAE;CACf,CAAA","sourcesContent":["/* EXPORT ENTITY TYPES */\nexport * from './twin-event/twin-event.js'\nexport * from './twin-audit/twin-audit-event.js'\nexport * from './twin-ingest-window/twin-ingest-window.js'\nexport * from './twin-instance/twin-instance.js'\nexport * from './twin-space/twin-space.js'\nexport * from './twin-space/twin-space-representation.js'\nexport * from './twin-space/twin-space-area.js'\nexport * from './twin-target/twin-target.js'\nexport * from './twin-structure/twin-structure.js'\nexport * from './twin-state/twin-state-subscription.js'\nexport * from './reference/reference-master.js'\nexport * from './reference/reference-registry.js'\nexport * from './reference/reference-adapter.js'\nexport * from './reference/reference-live.js'\nexport * from './reference/twin-reference.js'\nexport * from './reference/template-registry.js'\n/* 커넥터 점검 하네스 — 실 원본에 붙여 무엇이 채워지고 무엇이 비는지 센다(앱을 띄우지 않는다). */\nexport * from './reference/reference-probe.js'\n/* 읽은 뒤의 총평(사실 층) — 화면이 표로 그리고, 더 알고 싶을 때 AI 가 이 사실만 근거로 서술한다. */\nexport * from './reference/reference-assessment.js'\n/* 도메인 어휘 카탈로그 조합(커널 SSOT 노출) — 서버측 소비자(board-ai 도구 등)가 같은 형태를 쓰도록. */\nexport * from './twin-lifecycle/domain-catalog.js'\n\n/* IMPORT ENTITIES AND RESOLVERS */\nimport { entities as TwinEventEntities } from './twin-event/index.js'\nimport { entities as TwinSubjectEntities, resolvers as TwinSubjectResolvers } from './twin-subject/index.js'\nimport { entities as TwinAuditEntities, resolvers as TwinAuditResolvers } from './twin-audit/index.js'\nimport { entities as TwinInstanceEntities } from './twin-instance/index.js'\nimport { entities as TwinStructureEntities } from './twin-structure/index.js'\nimport { entities as TwinSpaceEntities, resolvers as TwinSpaceResolvers } from './twin-space/index.js'\nimport { entities as TwinTargetEntities, resolvers as TwinTargetResolvers } from './twin-target/index.js'\nimport { entities as TwinReferenceEntities, resolvers as TwinReferenceResolvers } from './reference/index.js'\nimport { resolvers as TwinStateResolvers } from './twin-state/index.js'\nimport { resolvers as TwinControlResolvers } from './twin-control/index.js'\nimport { entities as TwinModelEntities, resolvers as TwinModelResolvers } from './twin-model/index.js'\n/* 인제스트 창 — 동기화 추이를 재기동 뒤에도 이어 보기 위한 행(리졸버 없음: 메모리 장부가 조회를 답한다). */\nimport { entities as TwinIngestWindowEntities, resolvers as TwinIngestWindowResolvers } from './twin-ingest-window/index.js'\nimport { resolvers as TwinLifecycleResolvers } from './twin-lifecycle/index.js'\nimport { resolvers as TwinJournalResolvers } from './twin-journal/index.js'\nimport { resolvers as TwinForecastResolvers } from './twin-forecast/index.js'\nimport { resolvers as TwinAttentionResolvers } from './twin-attention/index.js'\nimport { resolvers as TwinMetricsResolvers } from './twin-metrics/index.js'\nimport { resolvers as TwinReadinessResolvers } from './twin-readiness/index.js'\n\nexport const entities = [\n /* ENTITIES */\n ...TwinEventEntities,\n ...TwinSubjectEntities,\n ...TwinIngestWindowEntities,\n ...TwinAuditEntities,\n ...TwinInstanceEntities,\n ...TwinStructureEntities,\n ...TwinSpaceEntities,\n ...TwinTargetEntities,\n ...TwinReferenceEntities,\n /* 구조 투영 — model JSON 에서 풀어낸 표준 엔티티(ADR-0032). 원본에서 온 캐시. */\n ...TwinModelEntities\n]\n\nexport const subscribers = []\n\nexport const schema = {\n typeDefs: {},\n resolverClasses: [\n /* RESOLVER CLASSES */\n ...TwinStateResolvers,\n ...TwinControlResolvers,\n ...TwinLifecycleResolvers,\n ...TwinJournalResolvers,\n ...TwinAuditResolvers,\n ...TwinForecastResolvers,\n ...TwinAttentionResolvers,\n ...TwinMetricsResolvers,\n ...TwinReadinessResolvers,\n ...TwinIngestWindowResolvers,\n ...TwinModelResolvers,\n ...TwinSpaceResolvers,\n ...TwinTargetResolvers,\n ...TwinReferenceResolvers,\n ...TwinSubjectResolvers\n ],\n directives: {}\n}\n"]}
@@ -2,7 +2,7 @@ import { type ControlCommand, type ControlResult } from './reference-adapter.js'
2
2
  /**
3
3
  * 이 트윈의 원본에 구동 명령을 보낸다 — **원본이 없거나 능력을 선언하지 않으면 거절한다.**
4
4
  *
5
- * 거절을 조용히 하지 않는다: 사유 코드를 돌려주고 화면이 그것을 사람 말로 옮긴다. 「아무 일도 일어나지
5
+ * 거절을 알리지 않고 하지 않는다: 사유 코드를 돌려주고 화면이 그것을 사람 말로 옮긴다. 「아무 일도 일어나지
6
6
  * 않았다」가 가장 비싼 답이다.
7
7
  */
8
8
  export declare function routeControl(domainId: string, instanceId: string, command: ControlCommand): Promise<ControlResult>;
@@ -24,7 +24,7 @@ const reference_adapter_js_1 = require("./reference-adapter.js");
24
24
  /**
25
25
  * 이 트윈의 원본에 구동 명령을 보낸다 — **원본이 없거나 능력을 선언하지 않으면 거절한다.**
26
26
  *
27
- * 거절을 조용히 하지 않는다: 사유 코드를 돌려주고 화면이 그것을 사람 말로 옮긴다. 「아무 일도 일어나지
27
+ * 거절을 알리지 않고 하지 않는다: 사유 코드를 돌려주고 화면이 그것을 사람 말로 옮긴다. 「아무 일도 일어나지
28
28
  * 않았다」가 가장 비싼 답이다.
29
29
  */
30
30
  async function routeControl(domainId, instanceId, command) {
@@ -1 +1 @@
1
- {"version":3,"file":"control-routing.js","sourceRoot":"","sources":["../../../server/service/reference/control-routing.ts"],"names":[],"mappings":";;AA2BA,oCA2BC;AAGD,kDAIC;AA7DD;;;;;;;;;;;;;;GAcG;AACH,iDAAqD;AAErD,wEAAgE;AAChE,2DAAmD;AACnD,iEAAiI;AAEjI;;;;;GAKG;AACI,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,UAAkB,EAAE,OAAuB;IAC9F,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;IAC3G,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;IAEzE,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;IACnH,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,gEAAgE;QAChE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,UAAU,uCAAuC,EAAE,CAAA;IAC7G,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,iCAAU,EAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,CAAC,WAAW,EAAE,CAAA;IAC/E,IAAI,CAAC,IAAA,qCAAc,EAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACjD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,cAAc;YACpB,MAAM,EAAE,WAAW,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,WAAW,yHAAyH;SAC5K,CAAA;IACH,CAAC;IAED;;;OAGG;IACH,MAAM,MAAM,GAAI,IAAI,CAAC,MAAc,EAAE,MAAM,CAAA;IAC3C,MAAM,IAAI,GAA+B,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IACxE,OAAO,OAAO,CAAC,OAAQ,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAA;AACjG,CAAC;AAED,sDAAsD;AAC/C,KAAK,UAAU,mBAAmB,CAAC,QAAgB,EAAE,UAAkB;IAC5E,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;IACnH,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,CAAA;IACrC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,YAAY,EAAE,IAAA,qCAAc,EAAC,IAAA,iCAAU,EAAC,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,CAAA;AACxH,CAAC","sourcesContent":["/*\n * **구동은 원본을 지난다** — 트윈을 우회하지 않는다 (ADR-0029 §8, 2026-08-19).\n *\n * ── 무엇이 뚫려 있었나 ──────────────────────────────────────────────────────\n * `controlTwinScenario` 가 `TwinEngine.runtime(...).scenario` 를 **직접** 잡았다. 그래서 시뮬만 할 수 있는\n * 일(자극·배속·정지)이 계약 밖의 지름길로 들어왔고, 실 시스템에는 그 자리가 아예 없었다 — ADR-0029 의\n * 판정 문장에 걸리는 상태였다.\n *\n * 이제 길은 하나다: **트윈 → 그 트윈의 원본 → 어댑터가 선언한 `control` 능력.** 선언하지 않은 원본에는\n * 문이 열리지 않고, 그 사실을 코드로 말한다(`not-declared`). 실 WMS 가 정지되지 않는 것은 결손이 아니다.\n *\n * ── 전송은 여기서 묻지 않는다 (§7) ──────────────────────────────────────────\n * 인프로세스 시뮬레이터는 같은 계약을 인프로세스로 이행한다. 나중에 그것이 다른 프로세스로 나가도 이 경로는\n * 바뀌지 않는다 — 「계약을 지나는가」만 보고 「네트워크를 타는가」는 묻지 않는다.\n */\nimport { getRepository } from '@things-factory/shell'\n\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinReference } from './twin-reference.js'\nimport { capabilitiesOf, getAdapter, type ControlCommand, type ControlResult, type SiteDescriptor } from './reference-adapter.js'\n\n/**\n * 이 트윈의 원본에 구동 명령을 보낸다 — **원본이 없거나 능력을 선언하지 않으면 거절한다.**\n *\n * 거절을 조용히 하지 않는다: 사유 코드를 돌려주고 화면이 그것을 사람 말로 옮긴다. 「아무 일도 일어나지\n * 않았다」가 가장 비싼 답이다.\n */\nexport async function routeControl(domainId: string, instanceId: string, command: ControlCommand): Promise<ControlResult> {\n const inst = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return { ok: false, code: 'unknown-twin', detail: instanceId }\n\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source: instanceId } })\n if (!ref) {\n /* 원본을 모르는 트윈 — 구동할 대상이 없다. 트윈을 직접 흔드는 길은 두지 않는다(그것이 지름길이었다). */\n return { ok: false, code: 'no-source', detail: `twin \"${instanceId}\" does not remember a source to drive` }\n }\n\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return { ok: false, code: 'no-adapter', detail: ref.adapterType }\n if (!capabilitiesOf(adapter).includes('control')) {\n return {\n ok: false,\n code: 'not-declared',\n detail: `source \"${ref.source}\" (${ref.adapterType}) does not declare the control capability — a real system is not paused or seeded, and that is a fact rather than a gap`\n }\n }\n\n /*\n * 사이트를 함께 넘긴다 — 원본 하나가 여러 사이트를 낼 수 있다(`discoverSites`). 우리가 아는 것은\n * 이 트윈이 어느 사이트에서 왔는지이고(`origin.siteId`), 모르면 넘기지 않는다(지어내지 않는다).\n */\n const siteId = (inst.origin as any)?.siteId\n const site: SiteDescriptor | undefined = siteId ? { siteId } : undefined\n return adapter.control!(ref.connectionConfig ?? {}, site, { ...command, instanceId, domainId })\n}\n\n/** 이 트윈의 원본이 선언한 능력 — 화면이 「무엇을 할 수 있나」를 먼저 알 수 있게. */\nexport async function controlCapabilityOf(domainId: string, instanceId: string): Promise<{ source?: string; adapterType?: string; capabilities: string[] }> {\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source: instanceId } })\n if (!ref) return { capabilities: [] }\n return { source: ref.source, adapterType: ref.adapterType, capabilities: capabilitiesOf(getAdapter(ref.adapterType)) }\n}\n"]}
1
+ {"version":3,"file":"control-routing.js","sourceRoot":"","sources":["../../../server/service/reference/control-routing.ts"],"names":[],"mappings":";;AA2BA,oCA2BC;AAGD,kDAIC;AA7DD;;;;;;;;;;;;;;GAcG;AACH,iDAAqD;AAErD,wEAAgE;AAChE,2DAAmD;AACnD,iEAAiI;AAEjI;;;;;GAKG;AACI,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,UAAkB,EAAE,OAAuB;IAC9F,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAa,EAAC,+BAAY,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;IAC3G,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,CAAA;IAEzE,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;IACnH,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,gEAAgE;QAChE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,SAAS,UAAU,uCAAuC,EAAE,CAAA;IAC7G,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,iCAAU,EAAC,GAAG,CAAC,WAAW,CAAC,CAAA;IAC3C,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,CAAC,WAAW,EAAE,CAAA;IAC/E,IAAI,CAAC,IAAA,qCAAc,EAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACjD,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,cAAc;YACpB,MAAM,EAAE,WAAW,GAAG,CAAC,MAAM,MAAM,GAAG,CAAC,WAAW,yHAAyH;SAC5K,CAAA;IACH,CAAC;IAED;;;OAGG;IACH,MAAM,MAAM,GAAI,IAAI,CAAC,MAAc,EAAE,MAAM,CAAA;IAC3C,MAAM,IAAI,GAA+B,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;IACxE,OAAO,OAAO,CAAC,OAAQ,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAA;AACjG,CAAC;AAED,sDAAsD;AAC/C,KAAK,UAAU,mBAAmB,CAAC,QAAgB,EAAE,UAAkB;IAC5E,MAAM,GAAG,GAAG,MAAM,IAAA,qBAAa,EAAC,iCAAa,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,CAAC,CAAA;IACnH,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,YAAY,EAAE,EAAE,EAAE,CAAA;IACrC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE,YAAY,EAAE,IAAA,qCAAc,EAAC,IAAA,iCAAU,EAAC,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,CAAA;AACxH,CAAC","sourcesContent":["/*\n * **구동은 원본을 지난다** — 트윈을 우회하지 않는다 (ADR-0029 §8, 2026-08-19).\n *\n * ── 무엇이 뚫려 있었나 ──────────────────────────────────────────────────────\n * `controlTwinScenario` 가 `TwinEngine.runtime(...).scenario` 를 **직접** 잡았다. 그래서 시뮬만 할 수 있는\n * 일(자극·배속·정지)이 계약 밖의 지름길로 들어왔고, 실 시스템에는 그 자리가 아예 없었다 — ADR-0029 의\n * 판정 문장에 걸리는 상태였다.\n *\n * 이제 길은 하나다: **트윈 → 그 트윈의 원본 → 어댑터가 선언한 `control` 능력.** 선언하지 않은 원본에는\n * 문이 열리지 않고, 그 사실을 코드로 말한다(`not-declared`). 실 WMS 가 정지되지 않는 것은 결손이 아니다.\n *\n * ── 전송은 여기서 묻지 않는다 (§7) ──────────────────────────────────────────\n * 인프로세스 시뮬레이터는 같은 계약을 인프로세스로 이행한다. 나중에 그것이 다른 프로세스로 나가도 이 경로는\n * 바뀌지 않는다 — 「계약을 지나는가」만 보고 「네트워크를 타는가」는 묻지 않는다.\n */\nimport { getRepository } from '@things-factory/shell'\n\nimport { TwinInstance } from '../twin-instance/twin-instance.js'\nimport { TwinReference } from './twin-reference.js'\nimport { capabilitiesOf, getAdapter, type ControlCommand, type ControlResult, type SiteDescriptor } from './reference-adapter.js'\n\n/**\n * 이 트윈의 원본에 구동 명령을 보낸다 — **원본이 없거나 능력을 선언하지 않으면 거절한다.**\n *\n * 거절을 알리지 않고 하지 않는다: 사유 코드를 돌려주고 화면이 그것을 사람 말로 옮긴다. 「아무 일도 일어나지\n * 않았다」가 가장 비싼 답이다.\n */\nexport async function routeControl(domainId: string, instanceId: string, command: ControlCommand): Promise<ControlResult> {\n const inst = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })\n if (!inst) return { ok: false, code: 'unknown-twin', detail: instanceId }\n\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source: instanceId } })\n if (!ref) {\n /* 원본을 모르는 트윈 — 구동할 대상이 없다. 트윈을 직접 흔드는 길은 두지 않는다(그것이 지름길이었다). */\n return { ok: false, code: 'no-source', detail: `twin \"${instanceId}\" does not remember a source to drive` }\n }\n\n const adapter = getAdapter(ref.adapterType)\n if (!adapter) return { ok: false, code: 'no-adapter', detail: ref.adapterType }\n if (!capabilitiesOf(adapter).includes('control')) {\n return {\n ok: false,\n code: 'not-declared',\n detail: `source \"${ref.source}\" (${ref.adapterType}) does not declare the control capability — a real system is not paused or seeded, and that is a fact rather than a gap`\n }\n }\n\n /*\n * 사이트를 함께 넘긴다 — 원본 하나가 여러 사이트를 낼 수 있다(`discoverSites`). 우리가 아는 것은\n * 이 트윈이 어느 사이트에서 왔는지이고(`origin.siteId`), 모르면 넘기지 않는다(지어내지 않는다).\n */\n const siteId = (inst.origin as any)?.siteId\n const site: SiteDescriptor | undefined = siteId ? { siteId } : undefined\n return adapter.control!(ref.connectionConfig ?? {}, site, { ...command, instanceId, domainId })\n}\n\n/** 이 트윈의 원본이 선언한 능력 — 화면이 「무엇을 할 수 있나」를 먼저 알 수 있게. */\nexport async function controlCapabilityOf(domainId: string, instanceId: string): Promise<{ source?: string; adapterType?: string; capabilities: string[] }> {\n const ref = await getRepository(TwinReference).findOne({ where: { domain: { id: domainId }, source: instanceId } })\n if (!ref) return { capabilities: [] }\n return { source: ref.source, adapterType: ref.adapterType, capabilities: capabilitiesOf(getAdapter(ref.adapterType)) }\n}\n"]}
@@ -21,14 +21,14 @@ export declare const discoveryFailed: (source: string, detail: string) => Discov
21
21
  /** 기다려도 답이 없었다 — 무한히 도는 화면보다 사유가 낫다. */
22
22
  export declare const discoveryTimedOut: (source: string, seconds: number) => DiscoveryError;
23
23
  /**
24
- * 어댑터가 준 것을 결과로 접는다.
24
+ * 어댑터가 준 것을 결과로 처리한다.
25
25
  *
26
26
  * **사이트가 없는 것을 실패로 만들지 않는다** — 연결이 되고 조회가 성공했는데 공장이 하나도 없는
27
27
  * 시스템은 있을 수 있다(권한이 좁거나 아직 등록되지 않은 경우). 그것은 사실이고, 화면은 "없다" 고
28
28
  * 말해야 한다. 실패로 합치면 사용자가 있지도 않은 문제를 찾는다.
29
29
  */
30
30
  export declare function discovered<S>(sites: readonly S[] | undefined | null): DiscoveryResult<S>;
31
- /** 실패를 결과로 접는다 — 사이트는 비어 있다(반쪽 목록을 성공처럼 보이게 하지 않는다). */
31
+ /** 실패를 결과로 처리한다 — 사이트는 비어 있다(반쪽 목록을 성공처럼 보이게 하지 않는다). */
32
32
  export declare function failed<S>(error: DiscoveryError): DiscoveryResult<S>;
33
33
  /** 어댑터가 오류를 낸 것에서 사람이 읽을 사유를 뽑는다 — 형태를 가정하지 않는다. */
34
34
  export declare function detailOf(e: unknown): string;
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * ── 왜 있나 (2026-08-06) ────────────────────────────────────────────────────
6
6
  * 실 시스템을 연결해 "거기 있는 것" 으로 트윈을 만드는 경로에서, 발견이 실패하면 화면이
7
- * **"사이트를 찾지 못했습니다"** 라고만 말했다. 네 가지가 그 한 문장으로 접혀 있었다.
7
+ * **"사이트를 찾지 못했습니다"** 라고만 말했다. 네 가지가 그 한 문장에 섞여 있었다.
8
8
  *
9
9
  * ① 그 레퍼런스가 등록돼 있지 않다 (`!ref → []`)
10
10
  * ② 어댑터 종류를 모른다 (`!adapter → []`)
@@ -59,7 +59,7 @@ const discoveryTimedOut = (source, seconds) => ({
59
59
  });
60
60
  exports.discoveryTimedOut = discoveryTimedOut;
61
61
  /**
62
- * 어댑터가 준 것을 결과로 접는다.
62
+ * 어댑터가 준 것을 결과로 처리한다.
63
63
  *
64
64
  * **사이트가 없는 것을 실패로 만들지 않는다** — 연결이 되고 조회가 성공했는데 공장이 하나도 없는
65
65
  * 시스템은 있을 수 있다(권한이 좁거나 아직 등록되지 않은 경우). 그것은 사실이고, 화면은 "없다" 고
@@ -68,7 +68,7 @@ exports.discoveryTimedOut = discoveryTimedOut;
68
68
  function discovered(sites) {
69
69
  return { sites: Array.isArray(sites) ? [...sites] : [] };
70
70
  }
71
- /** 실패를 결과로 접는다 — 사이트는 비어 있다(반쪽 목록을 성공처럼 보이게 하지 않는다). */
71
+ /** 실패를 결과로 처리한다 — 사이트는 비어 있다(반쪽 목록을 성공처럼 보이게 하지 않는다). */
72
72
  function failed(error) {
73
73
  return { sites: [], error };
74
74
  }
@@ -1 +1 @@
1
- {"version":3,"file":"discovery-result.js","sourceRoot":"","sources":["../../../server/service/reference/discovery-result.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;;;AAsDH,gCAEC;AAGD,wBAEC;AAGD,4BAKC;AAlDD,2CAA2C;AACpC,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAkB,EAAE,CAAC,CAAC;IACpE,IAAI,EAAE,qBAAqB;IAC3B,MAAM,EAAE,EAAE,MAAM,EAAE;IAClB,OAAO,EAAE,cAAc,MAAM,oCAAoC;CAClE,CAAC,CAAA;AAJW,QAAA,iBAAiB,qBAI5B;AAEF,+CAA+C;AACxC,MAAM,cAAc,GAAG,CAAC,WAAmB,EAAE,MAAc,EAAkB,EAAE,CAAC,CAAC;IACtF,IAAI,EAAE,iBAAiB;IACvB,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE;IAC/B,OAAO,EAAE,yBAAyB,WAAW,iCAAiC,MAAM,GAAG;CACxF,CAAC,CAAA;AAJW,QAAA,cAAc,kBAIzB;AAEF,0CAA0C;AACnC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAE,MAAc,EAAkB,EAAE,CAAC,CAAC;IAClF,IAAI,EAAE,kBAAkB;IACxB,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;IAC1B,OAAO,EAAE,8BAA8B,MAAM,MAAM,MAAM,EAAE;CAC5D,CAAC,CAAA;AAJW,QAAA,eAAe,mBAI1B;AAEF,wCAAwC;AACjC,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAE,OAAe,EAAkB,EAAE,CAAC,CAAC;IACrF,IAAI,EAAE,mBAAmB;IACzB,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;IAC3B,OAAO,EAAE,IAAI,MAAM,2BAA2B,OAAO,GAAG;CACzD,CAAC,CAAA;AAJW,QAAA,iBAAiB,qBAI5B;AAEF;;;;;;GAMG;AACH,SAAgB,UAAU,CAAI,KAAsC;IAClE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;AAC1D,CAAC;AAED,wDAAwD;AACxD,SAAgB,MAAM,CAAI,KAAqB;IAC7C,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;AAC7B,CAAC;AAED,oDAAoD;AACpD,SAAgB,QAAQ,CAAC,CAAU;IACjC,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC,OAAO,CAAA;IACrD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACxC,yDAAyD;IACzD,OAAO,wCAAwC,CAAA;AACjD,CAAC","sourcesContent":["/*\n * 사이트 발견 결과 — **\"못 찾았다\" 와 \"없다\" 를 구분한다.** 순수.\n *\n * ── 왜 있나 (2026-08-06) ────────────────────────────────────────────────────\n * 실 시스템을 연결해 \"거기 있는 것\" 으로 트윈을 만드는 경로에서, 발견이 실패하면 화면이\n * **\"사이트를 찾지 못했습니다\"** 라고만 말했다. 네 가지가 그 한 문장으로 접혀 있었다.\n *\n * ① 그 레퍼런스가 등록돼 있지 않다 (`!ref → []`)\n * ② 어댑터 종류를 모른다 (`!adapter → []`)\n * ③ 연결·조회가 실패했다 (`catch { return [] }`)\n * ④ 정말로 사이트가 없다 (빈 배열)\n *\n * ①②③ 은 **고칠 수 있는 문제**이고 ④ 는 사실이다. 그런데 화면이 같은 말을 하므로 사용자는 자격이\n * 틀렸는지, 주소가 틀렸는지, 정말 공장이 없는지 알 수 없다 — 실 시스템 연결에서 가장 자주 막히는\n * 자리인데 거기서 아무 단서도 주지 않았다.\n *\n * ── 왜 문장이 아니라 코드인가 ───────────────────────────────────────────────\n * 이 프로젝트가 이미 쓰는 규약을 따른다(주의 신호·커맨드 거절·인제스트 경고와 같은 모양):\n * `code`(언어 중립) + `params`(문장에 끼울 값) + `message`(영어 canonical, 로그·폴백).\n * 화면은 `twin.connect.discover.<code>` 로 사람 말을 만든다.\n *\n * ── 원 시스템의 오류 문장을 감추지 않는다 ────────────────────────────────────\n * 어댑터가 준 사유(자격 거부·타임아웃·404)는 **그 시스템만 아는 사실**이라 우리가 다시 쓸 수 없다.\n * `detail` 로 그대로 실어 보내 화면이 보조 문장으로 보인다 — 원문이 있으면 사용자가 자기 관리자에게\n * 물어볼 수 있고, 없으면 우리 짐작만 남는다.\n */\n\n/** 발견이 왜 아무것도 주지 못했나 — 언어 중립 코드. */\nexport type DiscoveryErrorCode = 'reference-not-found' | 'adapter-unknown' | 'discovery-failed' | 'discovery-timeout'\n\nexport interface DiscoveryError {\n code: DiscoveryErrorCode\n params?: Record<string, string | number>\n /** 영어 canonical — 로그에 남고, 번역이 없으면 그대로 보인다. */\n message: string\n}\n\nexport interface DiscoveryResult<S = unknown> {\n /** 발견된 사이트들. 실패했으면 빈 배열이고 `error` 가 이유를 말한다. */\n sites: S[]\n /** 실패 사유. **없으면 성공이다** — 빈 배열 + 사유 없음 = \"연결은 됐지만 사이트가 없다\". */\n error?: DiscoveryError\n}\n\n/** 등록된 레퍼런스가 없다 — 목록이 낡았거나 다른 테넌트의 것이다. */\nexport const referenceNotFound = (source: string): DiscoveryError => ({\n code: 'reference-not-found',\n params: { source },\n message: `reference \"${source}\" is not registered in this tenant`\n})\n\n/** 어댑터 종류를 모른다 — 배포에 그 커넥터가 없다(패키지 미설치·오타). */\nexport const adapterUnknown = (adapterType: string, source: string): DiscoveryError => ({\n code: 'adapter-unknown',\n params: { adapterType, source },\n message: `no connector of type \"${adapterType}\" is available for reference \"${source}\"`\n})\n\n/** 연결·조회가 실패했다 — 원 시스템이 준 사유를 그대로 싣는다. */\nexport const discoveryFailed = (source: string, detail: string): DiscoveryError => ({\n code: 'discovery-failed',\n params: { source, detail },\n message: `could not read sites from \"${source}\": ${detail}`\n})\n\n/** 기다려도 답이 없었다 — 무한히 도는 화면보다 사유가 낫다. */\nexport const discoveryTimedOut = (source: string, seconds: number): DiscoveryError => ({\n code: 'discovery-timeout',\n params: { source, seconds },\n message: `\"${source}\" did not answer within ${seconds}s`\n})\n\n/**\n * 어댑터가 준 것을 결과로 접는다.\n *\n * **사이트가 없는 것을 실패로 만들지 않는다** — 연결이 되고 조회가 성공했는데 공장이 하나도 없는\n * 시스템은 있을 수 있다(권한이 좁거나 아직 등록되지 않은 경우). 그것은 사실이고, 화면은 \"없다\" 고\n * 말해야 한다. 실패로 합치면 사용자가 있지도 않은 문제를 찾는다.\n */\nexport function discovered<S>(sites: readonly S[] | undefined | null): DiscoveryResult<S> {\n return { sites: Array.isArray(sites) ? [...sites] : [] }\n}\n\n/** 실패를 결과로 접는다 — 사이트는 비어 있다(반쪽 목록을 성공처럼 보이게 하지 않는다). */\nexport function failed<S>(error: DiscoveryError): DiscoveryResult<S> {\n return { sites: [], error }\n}\n\n/** 어댑터가 오류를 낸 것에서 사람이 읽을 사유를 뽑는다 — 형태를 가정하지 않는다. */\nexport function detailOf(e: unknown): string {\n if (e instanceof Error && e.message) return e.message\n if (typeof e === 'string' && e) return e\n /* 무엇이 왔는지 모르면 그렇게 말한다 — 빈 문장으로 \"이유 없음\" 처럼 보이게 하지 않는다. */\n return 'the connector failed without a message'\n}\n"]}
1
+ {"version":3,"file":"discovery-result.js","sourceRoot":"","sources":["../../../server/service/reference/discovery-result.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;;;AAsDH,gCAEC;AAGD,wBAEC;AAGD,4BAKC;AAlDD,2CAA2C;AACpC,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAkB,EAAE,CAAC,CAAC;IACpE,IAAI,EAAE,qBAAqB;IAC3B,MAAM,EAAE,EAAE,MAAM,EAAE;IAClB,OAAO,EAAE,cAAc,MAAM,oCAAoC;CAClE,CAAC,CAAA;AAJW,QAAA,iBAAiB,qBAI5B;AAEF,+CAA+C;AACxC,MAAM,cAAc,GAAG,CAAC,WAAmB,EAAE,MAAc,EAAkB,EAAE,CAAC,CAAC;IACtF,IAAI,EAAE,iBAAiB;IACvB,MAAM,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE;IAC/B,OAAO,EAAE,yBAAyB,WAAW,iCAAiC,MAAM,GAAG;CACxF,CAAC,CAAA;AAJW,QAAA,cAAc,kBAIzB;AAEF,0CAA0C;AACnC,MAAM,eAAe,GAAG,CAAC,MAAc,EAAE,MAAc,EAAkB,EAAE,CAAC,CAAC;IAClF,IAAI,EAAE,kBAAkB;IACxB,MAAM,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE;IAC1B,OAAO,EAAE,8BAA8B,MAAM,MAAM,MAAM,EAAE;CAC5D,CAAC,CAAA;AAJW,QAAA,eAAe,mBAI1B;AAEF,wCAAwC;AACjC,MAAM,iBAAiB,GAAG,CAAC,MAAc,EAAE,OAAe,EAAkB,EAAE,CAAC,CAAC;IACrF,IAAI,EAAE,mBAAmB;IACzB,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE;IAC3B,OAAO,EAAE,IAAI,MAAM,2BAA2B,OAAO,GAAG;CACzD,CAAC,CAAA;AAJW,QAAA,iBAAiB,qBAI5B;AAEF;;;;;;GAMG;AACH,SAAgB,UAAU,CAAI,KAAsC;IAClE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAA;AAC1D,CAAC;AAED,yDAAyD;AACzD,SAAgB,MAAM,CAAI,KAAqB;IAC7C,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,CAAA;AAC7B,CAAC;AAED,oDAAoD;AACpD,SAAgB,QAAQ,CAAC,CAAU;IACjC,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC,OAAO,CAAA;IACrD,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC;QAAE,OAAO,CAAC,CAAA;IACxC,yDAAyD;IACzD,OAAO,wCAAwC,CAAA;AACjD,CAAC","sourcesContent":["/*\n * 사이트 발견 결과 — **\"못 찾았다\" 와 \"없다\" 를 구분한다.** 순수.\n *\n * ── 왜 있나 (2026-08-06) ────────────────────────────────────────────────────\n * 실 시스템을 연결해 \"거기 있는 것\" 으로 트윈을 만드는 경로에서, 발견이 실패하면 화면이\n * **\"사이트를 찾지 못했습니다\"** 라고만 말했다. 네 가지가 그 한 문장에 섞여 있었다.\n *\n * ① 그 레퍼런스가 등록돼 있지 않다 (`!ref → []`)\n * ② 어댑터 종류를 모른다 (`!adapter → []`)\n * ③ 연결·조회가 실패했다 (`catch { return [] }`)\n * ④ 정말로 사이트가 없다 (빈 배열)\n *\n * ①②③ 은 **고칠 수 있는 문제**이고 ④ 는 사실이다. 그런데 화면이 같은 말을 하므로 사용자는 자격이\n * 틀렸는지, 주소가 틀렸는지, 정말 공장이 없는지 알 수 없다 — 실 시스템 연결에서 가장 자주 막히는\n * 자리인데 거기서 아무 단서도 주지 않았다.\n *\n * ── 왜 문장이 아니라 코드인가 ───────────────────────────────────────────────\n * 이 프로젝트가 이미 쓰는 규약을 따른다(주의 신호·커맨드 거절·인제스트 경고와 같은 모양):\n * `code`(언어 중립) + `params`(문장에 끼울 값) + `message`(영어 canonical, 로그·폴백).\n * 화면은 `twin.connect.discover.<code>` 로 사람 말을 만든다.\n *\n * ── 원 시스템의 오류 문장을 감추지 않는다 ────────────────────────────────────\n * 어댑터가 준 사유(자격 거부·타임아웃·404)는 **그 시스템만 아는 사실**이라 우리가 다시 쓸 수 없다.\n * `detail` 로 그대로 실어 보내 화면이 보조 문장으로 보인다 — 원문이 있으면 사용자가 자기 관리자에게\n * 물어볼 수 있고, 없으면 우리 짐작만 남는다.\n */\n\n/** 발견이 왜 아무것도 주지 못했나 — 언어 중립 코드. */\nexport type DiscoveryErrorCode = 'reference-not-found' | 'adapter-unknown' | 'discovery-failed' | 'discovery-timeout'\n\nexport interface DiscoveryError {\n code: DiscoveryErrorCode\n params?: Record<string, string | number>\n /** 영어 canonical — 로그에 남고, 번역이 없으면 그대로 보인다. */\n message: string\n}\n\nexport interface DiscoveryResult<S = unknown> {\n /** 발견된 사이트들. 실패했으면 빈 배열이고 `error` 가 이유를 말한다. */\n sites: S[]\n /** 실패 사유. **없으면 성공이다** — 빈 배열 + 사유 없음 = \"연결은 됐지만 사이트가 없다\". */\n error?: DiscoveryError\n}\n\n/** 등록된 레퍼런스가 없다 — 목록이 낡았거나 다른 테넌트의 것이다. */\nexport const referenceNotFound = (source: string): DiscoveryError => ({\n code: 'reference-not-found',\n params: { source },\n message: `reference \"${source}\" is not registered in this tenant`\n})\n\n/** 어댑터 종류를 모른다 — 배포에 그 커넥터가 없다(패키지 미설치·오타). */\nexport const adapterUnknown = (adapterType: string, source: string): DiscoveryError => ({\n code: 'adapter-unknown',\n params: { adapterType, source },\n message: `no connector of type \"${adapterType}\" is available for reference \"${source}\"`\n})\n\n/** 연결·조회가 실패했다 — 원 시스템이 준 사유를 그대로 싣는다. */\nexport const discoveryFailed = (source: string, detail: string): DiscoveryError => ({\n code: 'discovery-failed',\n params: { source, detail },\n message: `could not read sites from \"${source}\": ${detail}`\n})\n\n/** 기다려도 답이 없었다 — 무한히 도는 화면보다 사유가 낫다. */\nexport const discoveryTimedOut = (source: string, seconds: number): DiscoveryError => ({\n code: 'discovery-timeout',\n params: { source, seconds },\n message: `\"${source}\" did not answer within ${seconds}s`\n})\n\n/**\n * 어댑터가 준 것을 결과로 처리한다.\n *\n * **사이트가 없는 것을 실패로 만들지 않는다** — 연결이 되고 조회가 성공했는데 공장이 하나도 없는\n * 시스템은 있을 수 있다(권한이 좁거나 아직 등록되지 않은 경우). 그것은 사실이고, 화면은 \"없다\" 고\n * 말해야 한다. 실패로 합치면 사용자가 있지도 않은 문제를 찾는다.\n */\nexport function discovered<S>(sites: readonly S[] | undefined | null): DiscoveryResult<S> {\n return { sites: Array.isArray(sites) ? [...sites] : [] }\n}\n\n/** 실패를 결과로 처리한다 — 사이트는 비어 있다(반쪽 목록을 성공처럼 보이게 하지 않는다). */\nexport function failed<S>(error: DiscoveryError): DiscoveryResult<S> {\n return { sites: [], error }\n}\n\n/** 어댑터가 오류를 낸 것에서 사람이 읽을 사유를 뽑는다 — 형태를 가정하지 않는다. */\nexport function detailOf(e: unknown): string {\n if (e instanceof Error && e.message) return e.message\n if (typeof e === 'string' && e) return e\n /* 무엇이 왔는지 모르면 그렇게 말한다 — 빈 문장으로 \"이유 없음\" 처럼 보이게 하지 않는다. */\n return 'the connector failed without a message'\n}\n"]}
@@ -0,0 +1,43 @@
1
+ /** 훅 요청의 결과 — 상태 코드와 본문을 함께 정한다(부르는 쪽이 그대로 답한다). */
2
+ export interface HookOutcome {
3
+ status: number;
4
+ body: Record<string, unknown>;
5
+ }
6
+ /**
7
+ * 응답 코드 규약 — **재시도로 해결되는 것과 그렇지 않은 것을 가른다.**
8
+ *
9
+ * 밀어 주는 쪽은 응답 코드로 재시도를 정합니다. 그래서 우리가 코드를 아무렇게나 주면 두 가지가
10
+ * 일어납니다: 고칠 수 없는 것을 영원히 다시 보내거나, 잠깐의 문제로 사라진 사실을 아무도 모릅니다.
11
+ *
12
+ * 200 받아서 반영했다
13
+ * 401 비밀값이 다르다 재시도해도 같다
14
+ * 404 모르는 연결이거나 모르는 트윈 재시도해도 같다
15
+ * 400 본문을 우리 레코드로 옮길 수 없다 재시도해도 같다(그쪽 모양이 바뀐 것이다)
16
+ * 409 그 트윈이 지금 실시간으로 돌지 않는다 사람이 트윈을 띄워야 한다
17
+ * 501 그 커넥터가 훅을 받을 줄 모른다 코드가 없다
18
+ * 500 우리 쪽 오류 재시도하면 될 수 있다
19
+ */
20
+ export declare const HOOK_STATUS: {
21
+ readonly ok: 200;
22
+ readonly badSecret: 401;
23
+ readonly unknownTarget: 404;
24
+ readonly badPayload: 400;
25
+ readonly notLive: 409;
26
+ readonly unsupported: 501;
27
+ readonly failed: 500;
28
+ };
29
+ /** 헤더에서 비밀값을 꺼낸다 — 두 가지 방식을 받는다(밀어 주는 쪽의 관습이 갈린다). */
30
+ export declare function secretFromHeaders(headers: Record<string, unknown> | undefined): string;
31
+ /**
32
+ * 비밀값 비교 — **길이가 다르면 바로 거절하고, 같으면 끝까지 비교한다.**
33
+ *
34
+ * 앞에서 다른 것을 발견하고 곧바로 답하면 응답 시간이 달라지고, 그 차이로 비밀값을 한 글자씩 알아낼 수
35
+ * 있습니다. 그래서 같은 길이면 전부를 비교합니다.
36
+ */
37
+ export declare function secretMatches(given: string, expected: string): boolean;
38
+ /** 이 연결이 이 트윈을 만들었나 — 남의 트윈에 밀어 넣지 못하게. */
39
+ export declare function producedInstance(ref: {
40
+ scopeSpec?: any;
41
+ } | null | undefined, instanceId: string): {
42
+ siteId: string;
43
+ } | undefined;
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HOOK_STATUS = void 0;
4
+ exports.secretFromHeaders = secretFromHeaders;
5
+ exports.secretMatches = secretMatches;
6
+ exports.producedInstance = producedInstance;
7
+ /**
8
+ * 응답 코드 규약 — **재시도로 해결되는 것과 그렇지 않은 것을 가른다.**
9
+ *
10
+ * 밀어 주는 쪽은 응답 코드로 재시도를 정합니다. 그래서 우리가 코드를 아무렇게나 주면 두 가지가
11
+ * 일어납니다: 고칠 수 없는 것을 영원히 다시 보내거나, 잠깐의 문제로 사라진 사실을 아무도 모릅니다.
12
+ *
13
+ * 200 받아서 반영했다
14
+ * 401 비밀값이 다르다 재시도해도 같다
15
+ * 404 모르는 연결이거나 모르는 트윈 재시도해도 같다
16
+ * 400 본문을 우리 레코드로 옮길 수 없다 재시도해도 같다(그쪽 모양이 바뀐 것이다)
17
+ * 409 그 트윈이 지금 실시간으로 돌지 않는다 사람이 트윈을 띄워야 한다
18
+ * 501 그 커넥터가 훅을 받을 줄 모른다 코드가 없다
19
+ * 500 우리 쪽 오류 재시도하면 될 수 있다
20
+ */
21
+ exports.HOOK_STATUS = {
22
+ ok: 200,
23
+ badSecret: 401,
24
+ unknownTarget: 404,
25
+ badPayload: 400,
26
+ notLive: 409,
27
+ unsupported: 501,
28
+ failed: 500
29
+ };
30
+ /** 헤더에서 비밀값을 꺼낸다 — 두 가지 방식을 받는다(밀어 주는 쪽의 관습이 갈린다). */
31
+ function secretFromHeaders(headers) {
32
+ const pick = (k) => String((headers ?? {})[k] ?? '').trim();
33
+ const direct = pick('x-twin-hook-secret');
34
+ if (direct)
35
+ return direct;
36
+ const auth = pick('authorization');
37
+ return auth.toLowerCase().startsWith('bearer ') ? auth.slice(7).trim() : '';
38
+ }
39
+ /**
40
+ * 비밀값 비교 — **길이가 다르면 바로 거절하고, 같으면 끝까지 비교한다.**
41
+ *
42
+ * 앞에서 다른 것을 발견하고 곧바로 답하면 응답 시간이 달라지고, 그 차이로 비밀값을 한 글자씩 알아낼 수
43
+ * 있습니다. 그래서 같은 길이면 전부를 비교합니다.
44
+ */
45
+ function secretMatches(given, expected) {
46
+ if (!expected || !given || given.length !== expected.length)
47
+ return false;
48
+ let diff = 0;
49
+ for (let i = 0; i < expected.length; i++)
50
+ diff |= given.charCodeAt(i) ^ expected.charCodeAt(i);
51
+ return diff === 0;
52
+ }
53
+ /** 이 연결이 이 트윈을 만들었나 — 남의 트윈에 밀어 넣지 못하게. */
54
+ function producedInstance(ref, instanceId) {
55
+ const produced = ref?.scopeSpec?.produced ?? [];
56
+ const hit = produced.find(p => String(p?.instanceId ?? '') === instanceId);
57
+ return hit?.siteId ? { siteId: String(hit.siteId) } : undefined;
58
+ }
59
+ //# sourceMappingURL=hook-contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-contract.js","sourceRoot":"","sources":["../../../server/service/reference/hook-contract.ts"],"names":[],"mappings":";;;AA2EA,8CAMC;AAQD,sCAKC;AAGD,4CAIC;AAnDD;;;;;;;;;;;;;GAaG;AACU,QAAA,WAAW,GAAG;IACzB,EAAE,EAAE,GAAG;IACP,SAAS,EAAE,GAAG;IACd,aAAa,EAAE,GAAG;IAClB,UAAU,EAAE,GAAG;IACf,OAAO,EAAE,GAAG;IACZ,WAAW,EAAE,GAAG;IAChB,MAAM,EAAE,GAAG;CACH,CAAA;AAEV,sDAAsD;AACtD,SAAgB,iBAAiB,CAAC,OAA4C;IAC5E,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACnE,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,CAAA;IACzC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAA;IACzB,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,CAAC,CAAA;IAClC,OAAO,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AAC7E,CAAC;AAED;;;;;GAKG;AACH,SAAgB,aAAa,CAAC,KAAa,EAAE,QAAgB;IAC3D,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAA;IACzE,IAAI,IAAI,GAAG,CAAC,CAAA;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,IAAI,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IAC9F,OAAO,IAAI,KAAK,CAAC,CAAA;AACnB,CAAC;AAED,2CAA2C;AAC3C,SAAgB,gBAAgB,CAAC,GAA2C,EAAE,UAAkB;IAC9F,MAAM,QAAQ,GAAW,GAAG,EAAE,SAAiB,EAAE,QAAQ,IAAI,EAAE,CAAA;IAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU,IAAI,EAAE,CAAC,KAAK,UAAU,CAAC,CAAA;IAC1E,OAAO,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;AACjE,CAAC","sourcesContent":["/*\n * 웹훅의 규약 — 상태 코드 · 비밀값 · 어느 트윈인가.\n *\n * 데이터베이스를 부르는 부분과 갈라 둔다(§`reference-hook`): 규약만 있는 자리라야 시험이 엔티티를\n * 끌고 오지 않는다. 실제로 그것 때문에 시험이 서지 않았다.\n *\n * ── 왜 필요한가 ─────────────────────────────────────────────────────────────\n * 지금 모든 커넥터가 주기적으로 물어봅니다(폴링). 그 방식은 두 가지를 치릅니다. 연결된 시스템이 값을\n * 갱신하는 주기보다 자주 물으면 같은 값을 되풀이 받고, 그쪽 서버에 그만큼 부담을 줍니다. 실제로\n * 태양광 발전소에 10초마다 물으면서 10분마다 바뀌는 값을 받아 왔습니다.\n *\n * 연결된 시스템이 「바뀌었다」를 말해 줄 수 있으면 그것을 받는 것이 낫습니다. 이 파일이 그 입구입니다.\n *\n * ── 규약 ────────────────────────────────────────────────────────────────────\n *\n * 주소 POST /domain/<도메인>/twin/hook/<연결이름>/<트윈>\n * 인증 연결 설정에 저장한 비밀값(`hookSecret`)을 헤더로 보낸다\n * X-Twin-Hook-Secret: <비밀값> 또는 Authorization: Bearer <비밀값>\n * 본문 연결된 시스템이 정한 모양 그대로. 우리 어휘로 옮기는 것은 커넥터의 일이다\n * 응답 아래 §`hookStatus`\n *\n * ── 왜 사람 인증(JWT)이 아닌가 ──────────────────────────────────────────────\n * 밀어 주는 쪽은 사람이 아닙니다. 우리 토큰을 발급받아 갱신하며 관리하라고 요구하면 대부분의 현장에서\n * 연동이 서지 않습니다. 그래서 연결마다 비밀값을 두고 그것으로 확인합니다.\n *\n * **비밀값이 없는 연결은 훅을 받지 않습니다.** 기본이 거부입니다 — 인증 없는 입구를 열어 두는 것보다\n * 훅을 못 쓰는 것이 낫습니다.\n *\n * ── 왜 커넥터가 옮기나 (시나리오가 아니라) ──────────────────────────────────\n * 연결된 시스템의 웹훅은 그쪽이 정한 고정된 모양으로 옵니다. 그 모양을 아는 것은 그 커넥터이고,\n * 옮기는 판단은 코드여야 테스트로 지킬 수 있습니다. 실제로 지금 커넥터들이 코드로 판단합니다 —\n * 통신이 끊긴 설비의 값은 보내지 않고, 잰 시각이 나아가지 않은 줄은 거릅니다. 그 판단을 변환식으로\n * 옮기면 약해지고 테스트가 없어집니다.\n *\n * ── 밀어 주기만으로는 안 된다 ───────────────────────────────────────────────\n * 훅은 반드시 놓칩니다 — 우리가 내려가 있을 때, 그쪽이 못 보냈을 때, 네트워크가 끊겼을 때. 그래서\n * 훅을 쓰는 연결도 **드문 폴링을 유지합니다.** 폴링의 역할이 「값을 가져오는 것」에서 「놓친 것이 있나\n * 확인하는 것」으로 바뀌는 것입니다. 그 주기는 연결 설정이 정합니다.\n *\n * ── 같은 것이 두 번 오는 것 ─────────────────────────────────────────────────\n * 밀어 주는 방식은 재전송이 정상입니다(그쪽이 우리 응답을 못 받으면 다시 보냅니다). 그것은 유입\n * 경계가 이미 거릅니다(§`FactDeduper`) — 이 파일이 따로 하지 않습니다. 응답에 몇 건이 중복이었는지\n * 함께 알립니다.\n */\n/** 훅 요청의 결과 — 상태 코드와 본문을 함께 정한다(부르는 쪽이 그대로 답한다). */\nexport interface HookOutcome {\n status: number\n body: Record<string, unknown>\n}\n\n/**\n * 응답 코드 규약 — **재시도로 해결되는 것과 그렇지 않은 것을 가른다.**\n *\n * 밀어 주는 쪽은 응답 코드로 재시도를 정합니다. 그래서 우리가 코드를 아무렇게나 주면 두 가지가\n * 일어납니다: 고칠 수 없는 것을 영원히 다시 보내거나, 잠깐의 문제로 사라진 사실을 아무도 모릅니다.\n *\n * 200 받아서 반영했다\n * 401 비밀값이 다르다 재시도해도 같다\n * 404 모르는 연결이거나 모르는 트윈 재시도해도 같다\n * 400 본문을 우리 레코드로 옮길 수 없다 재시도해도 같다(그쪽 모양이 바뀐 것이다)\n * 409 그 트윈이 지금 실시간으로 돌지 않는다 사람이 트윈을 띄워야 한다\n * 501 그 커넥터가 훅을 받을 줄 모른다 코드가 없다\n * 500 우리 쪽 오류 재시도하면 될 수 있다\n */\nexport const HOOK_STATUS = {\n ok: 200,\n badSecret: 401,\n unknownTarget: 404,\n badPayload: 400,\n notLive: 409,\n unsupported: 501,\n failed: 500\n} as const\n\n/** 헤더에서 비밀값을 꺼낸다 — 두 가지 방식을 받는다(밀어 주는 쪽의 관습이 갈린다). */\nexport function secretFromHeaders(headers: Record<string, unknown> | undefined): string {\n const pick = (k: string) => String((headers ?? {})[k] ?? '').trim()\n const direct = pick('x-twin-hook-secret')\n if (direct) return direct\n const auth = pick('authorization')\n return auth.toLowerCase().startsWith('bearer ') ? auth.slice(7).trim() : ''\n}\n\n/**\n * 비밀값 비교 — **길이가 다르면 바로 거절하고, 같으면 끝까지 비교한다.**\n *\n * 앞에서 다른 것을 발견하고 곧바로 답하면 응답 시간이 달라지고, 그 차이로 비밀값을 한 글자씩 알아낼 수\n * 있습니다. 그래서 같은 길이면 전부를 비교합니다.\n */\nexport function secretMatches(given: string, expected: string): boolean {\n if (!expected || !given || given.length !== expected.length) return false\n let diff = 0\n for (let i = 0; i < expected.length; i++) diff |= given.charCodeAt(i) ^ expected.charCodeAt(i)\n return diff === 0\n}\n\n/** 이 연결이 이 트윈을 만들었나 — 남의 트윈에 밀어 넣지 못하게. */\nexport function producedInstance(ref: { scopeSpec?: any } | null | undefined, instanceId: string): { siteId: string } | undefined {\n const produced: any[] = (ref?.scopeSpec as any)?.produced ?? []\n const hit = produced.find(p => String(p?.instanceId ?? '') === instanceId)\n return hit?.siteId ? { siteId: String(hit.siteId) } : undefined\n}\n\n"]}
@@ -13,7 +13,7 @@ export declare const INGEST_SPACE_NOT_FOUND = "space-not-found";
13
13
  * @param masterSpaceId 마스터에서 파생된 공간 id(요청이 없을 때의 기본).
14
14
  * @param requested 사용자가 고른 기존 공간 id. 없으면 빈 값/undefined.
15
15
  * @param requestedExists 그 공간이 이 테넌트에 실제로 있나(호출측이 조회해 넘긴다).
16
- * @throws 요청한 공간이 없으면 — 조용히 새로 만들지 않는다.
16
+ * @throws 요청한 공간이 없으면 — 알리지 않고 새로 만들지 않는다.
17
17
  */
18
18
  export declare function resolveIngestSpace(masterSpaceId: string, requested: string | undefined | null, requestedExists: boolean): IngestSpaceChoice;
19
19
  /**
@@ -10,14 +10,14 @@
10
10
  * `<source>-site` 로 파생돼, 새 트윈은 늘 새 현장처럼 생겼다. 데이터로는 가능한 일이 저작으로는
11
11
  * 불가능했다.
12
12
  *
13
- * ── 없는 공간에 조용히 새 공간을 만들지 않는다 ────────────────────────────────
13
+ * ── 없는 공간에 알리지 않고 새 공간을 만들지 않는다 ────────────────────────────────
14
14
  * "이 현장에 더한다" 는 요청이 오타·낡은 목록으로 빗나갔을 때 새 공간을 만들어 주면, 사용자는
15
15
  * 합쳤다고 믿고 화면에서는 따로 놀게 된다 — 나중에 두 현장을 손으로 합쳐야 하고, 그때는 이미
16
16
  * 이벤트가 양쪽에 쌓여 있다. 그래서 **모르는 공간이면 거절한다.**
17
17
  *
18
- * ── 같은 id 를 쓰는 구역은 조용히 합쳐지므로 알린다 ──────────────────────────
18
+ * ── 같은 id 를 쓰는 구역은 알리지 않고 합쳐지므로 알린다 ──────────────────────────
19
19
  * 공간 content 의 구역·랜드마크는 id 로 합집합을 만든다(`unionById`). 두 렌즈가 우연히 같은 구역
20
- * id(`a-yard` 따위)를 쓰면 서로 다른 구역이 하나로 접힌다. 막을 일은 아니다(같은 현장의 같은 구역을
20
+ * id(`a-yard` 따위)를 쓰면 서로 다른 구역이 하나로 합쳐진다. 막을 일은 아니다(같은 현장의 같은 구역을
21
21
  * 가리키는 정당한 경우가 많다) — 다만 **모르고 지나가지 않게** 경고로 돌려준다.
22
22
  */
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -33,7 +33,7 @@ exports.INGEST_SPACE_NOT_FOUND = 'space-not-found';
33
33
  * @param masterSpaceId 마스터에서 파생된 공간 id(요청이 없을 때의 기본).
34
34
  * @param requested 사용자가 고른 기존 공간 id. 없으면 빈 값/undefined.
35
35
  * @param requestedExists 그 공간이 이 테넌트에 실제로 있나(호출측이 조회해 넘긴다).
36
- * @throws 요청한 공간이 없으면 — 조용히 새로 만들지 않는다.
36
+ * @throws 요청한 공간이 없으면 — 알리지 않고 새로 만들지 않는다.
37
37
  */
38
38
  function resolveIngestSpace(masterSpaceId, requested, requestedExists) {
39
39
  const want = (requested ?? '').trim();
@@ -1 +1 @@
1
- {"version":3,"file":"ingest-space.js","sourceRoot":"","sources":["../../../server/service/reference/ingest-space.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAqBH,gDAUC;AA0BD,8CAQC;AAaD,oCAKC;AAzED,0CAA0C;AAC7B,QAAA,sBAAsB,GAAG,iBAAiB,CAAA;AAEvD;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,aAAqB,EAAE,SAAoC,EAAE,eAAwB;IACtH,MAAM,IAAI,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACrC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;IAC3D,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,UAAU,IAAI,iEAAiE,CAAC,CACnG;QAAC,CAAS,CAAC,IAAI,GAAG,8BAAsB,CAAA;QACzC,MAAM,CAAC,CAAA;IACT,CAAC;IACD,kDAAkD;IAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,KAAK,aAAa,EAAE,CAAA;AAC1D,CAAC;AAqBD;;;;GAIG;AACH,SAAgB,iBAAiB,CAAC,SAAiB,EAAE,SAAyB;IAC5E,MAAM,IAAI,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACrC,IAAI,CAAC,IAAI,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IAC7C,OAAO;QACL,IAAI,EAAE,2BAA2B;QACjC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE;QAC3C,OAAO,EAAE,oBAAoB,SAAS,sBAAsB,IAAI,gEAAgE;KACjI,CAAA;AACH,CAAC;AAOD;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,QAAkD,EAAE,QAAkD;IACjI,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC,CAAA;IAClF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC3E,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;AACzB,CAAC","sourcesContent":["/*\n * 인제스트가 어느 공간으로 들어갈지 정한다 — **순수**.\n *\n * ── 왜 있나 (2026-08-05) ────────────────────────────────────────────────────\n * 한 현실(공장·물류센터)을 여러 렌즈가 비춘다: 창고(WMS)·공정(MES)·야드(YMS) 가 같은 부지에 있다.\n * 엔진은 이미 그것을 지원한다 — 같은 `spaceId` 로 들어오면 공간 content 를 병합하고 기존 값을 이긴다.\n *\n * 그런데 **만드는 흐름에 그 선택이 없었다.** 템플릿은 `space.spaceId` 를 정하지 않으므로 항상\n * `<source>-site` 로 파생돼, 새 트윈은 늘 새 현장처럼 생겼다. 데이터로는 가능한 일이 저작으로는\n * 불가능했다.\n *\n * ── 없는 공간에 조용히 새 공간을 만들지 않는다 ────────────────────────────────\n * \"이 현장에 더한다\" 는 요청이 오타·낡은 목록으로 빗나갔을 때 새 공간을 만들어 주면, 사용자는\n * 합쳤다고 믿고 화면에서는 따로 놀게 된다 — 나중에 두 현장을 손으로 합쳐야 하고, 그때는 이미\n * 이벤트가 양쪽에 쌓여 있다. 그래서 **모르는 공간이면 거절한다.**\n *\n * ── 같은 id 를 쓰는 구역은 조용히 합쳐지므로 알린다 ──────────────────────────\n * 공간 content 의 구역·랜드마크는 id 로 합집합을 만든다(`unionById`). 두 렌즈가 우연히 같은 구역\n * id(`a-yard` 따위)를 쓰면 서로 다른 구역이 하나로 접힌다. 막을 일은 아니다(같은 현장의 같은 구역을\n * 가리키는 정당한 경우가 많다) — 다만 **모르고 지나가지 않게** 경고로 돌려준다.\n */\n\n/** 공간 판정 결과. */\nexport interface IngestSpaceChoice {\n /** 실제로 쓸 공간 id. */\n spaceId: string\n /** 사용자가 기존 현장에 합치기를 골랐나(마스터가 파생한 공간과 다른 곳으로 들어가나). */\n joined: boolean\n}\n\n/** 거절 사유 — 호출측이 문장을 만들 때 쓴다(언어 중립 코드). */\nexport const INGEST_SPACE_NOT_FOUND = 'space-not-found'\n\n/**\n * 요청받은 공간과 마스터가 파생한 공간 중 무엇으로 들어갈지 정한다.\n *\n * @param masterSpaceId 마스터에서 파생된 공간 id(요청이 없을 때의 기본).\n * @param requested 사용자가 고른 기존 공간 id. 없으면 빈 값/undefined.\n * @param requestedExists 그 공간이 이 테넌트에 실제로 있나(호출측이 조회해 넘긴다).\n * @throws 요청한 공간이 없으면 — 조용히 새로 만들지 않는다.\n */\nexport function resolveIngestSpace(masterSpaceId: string, requested: string | undefined | null, requestedExists: boolean): IngestSpaceChoice {\n const want = (requested ?? '').trim()\n if (!want) return { spaceId: masterSpaceId, joined: false }\n if (!requestedExists) {\n const e = new Error(`space \"${want}\" not found — cannot co-locate into a space that does not exist`)\n ;(e as any).code = INGEST_SPACE_NOT_FOUND\n throw e\n }\n /* 마스터가 이미 그 공간을 가리키면 합치기가 아니다 — 같은 공간의 재인제스트다. */\n return { spaceId: want, joined: want !== masterSpaceId }\n}\n\n/**\n * 실 시스템 import 가 현장을 고를 때의 거절 판정 — **순수**.\n *\n * 레퍼런스 하나는 사이트를 여럿 발견할 수 있고(`discoverSites`), 그 사이트마다 트윈이 하나씩 생긴다.\n * 그런데 \"이 현장에 더한다\" 는 **한 곳**을 가리키는 말이다. 사이트 여럿을 한 공간에 넣으면 서로 다른\n * 현장의 구역·랜드마크가 id 로 합쳐지고(`unionById`), 그 사실을 알아차릴 때는 이미 이벤트가 양쪽에\n * 쌓여 있다 — 손으로 되돌릴 수 없는 종류다. 그래서 **묻지 않고 합치지 않고, 거절한다.**\n *\n * 공간을 고르지 않으면 지금까지의 거동 그대로다: 사이트마다 마스터가 파생한 공간으로 들어간다.\n */\nexport type ImportSpaceRefusalCode = 'space-with-multiple-sites'\n\nexport interface ImportSpaceRefusal {\n code: ImportSpaceRefusalCode\n params?: Record<string, string | number>\n /** 영어 canonical — 로그에 남고, 번역이 없으면 그대로 보인다(발견 오류와 같은 규약). */\n message: string\n}\n\n/**\n * @param siteCount 실제로 만들 사이트 수(필터 적용 후).\n * @param requested 사용자가 고른 기존 공간 id. 없으면 판정할 것이 없다.\n * @returns 거절 사유. 없으면 진행해도 된다.\n */\nexport function refuseImportSpace(siteCount: number, requested?: string | null): ImportSpaceRefusal | undefined {\n const want = (requested ?? '').trim()\n if (!want || siteCount <= 1) return undefined\n return {\n code: 'space-with-multiple-sites',\n params: { spaceId: want, count: siteCount },\n message: `cannot co-locate ${siteCount} sites into space \"${want}\" — pick one site, or omit the space so each site gets its own`\n }\n}\n\n/** 구역·랜드마크처럼 id 로 합쳐지는 것들. */\ninterface Identified {\n id?: string\n}\n\n/**\n * 합치는 쪽과 기존 쪽이 같은 id 를 쓰는 것들을 찾아 경고 문장을 만든다.\n *\n * 정당한 경우(같은 현장의 같은 구역)와 사고(서로 다른 구역이 우연히 같은 이름)를 기계가 가릴 수는\n * 없다. 구분할 수 없는 것을 고르지 않고, **무엇이 합쳐졌는지 말한다.**\n */\nexport function collidingIds(existing: readonly Identified[] | undefined | null, incoming: readonly Identified[] | undefined | null): string[] {\n const have = new Set((existing ?? []).map(x => x?.id).filter(Boolean) as string[])\n const hits = new Set<string>()\n for (const x of incoming ?? []) if (x?.id && have.has(x.id)) hits.add(x.id)\n return [...hits].sort()\n}\n"]}
1
+ {"version":3,"file":"ingest-space.js","sourceRoot":"","sources":["../../../server/service/reference/ingest-space.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AAqBH,gDAUC;AA0BD,8CAQC;AAaD,oCAKC;AAzED,0CAA0C;AAC7B,QAAA,sBAAsB,GAAG,iBAAiB,CAAA;AAEvD;;;;;;;GAOG;AACH,SAAgB,kBAAkB,CAAC,aAAqB,EAAE,SAAoC,EAAE,eAAwB;IACtH,MAAM,IAAI,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACrC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;IAC3D,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,UAAU,IAAI,iEAAiE,CAAC,CACnG;QAAC,CAAS,CAAC,IAAI,GAAG,8BAAsB,CAAA;QACzC,MAAM,CAAC,CAAA;IACT,CAAC;IACD,kDAAkD;IAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,KAAK,aAAa,EAAE,CAAA;AAC1D,CAAC;AAqBD;;;;GAIG;AACH,SAAgB,iBAAiB,CAAC,SAAiB,EAAE,SAAyB;IAC5E,MAAM,IAAI,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAA;IACrC,IAAI,CAAC,IAAI,IAAI,SAAS,IAAI,CAAC;QAAE,OAAO,SAAS,CAAA;IAC7C,OAAO;QACL,IAAI,EAAE,2BAA2B;QACjC,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE;QAC3C,OAAO,EAAE,oBAAoB,SAAS,sBAAsB,IAAI,gEAAgE;KACjI,CAAA;AACH,CAAC;AAOD;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,QAAkD,EAAE,QAAkD;IACjI,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC,CAAA;IAClF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,CAAC,IAAI,QAAQ,IAAI,EAAE;QAAE,IAAI,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC3E,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;AACzB,CAAC","sourcesContent":["/*\n * 인제스트가 어느 공간으로 들어갈지 정한다 — **순수**.\n *\n * ── 왜 있나 (2026-08-05) ────────────────────────────────────────────────────\n * 한 현실(공장·물류센터)을 여러 렌즈가 비춘다: 창고(WMS)·공정(MES)·야드(YMS) 가 같은 부지에 있다.\n * 엔진은 이미 그것을 지원한다 — 같은 `spaceId` 로 들어오면 공간 content 를 병합하고 기존 값을 이긴다.\n *\n * 그런데 **만드는 흐름에 그 선택이 없었다.** 템플릿은 `space.spaceId` 를 정하지 않으므로 항상\n * `<source>-site` 로 파생돼, 새 트윈은 늘 새 현장처럼 생겼다. 데이터로는 가능한 일이 저작으로는\n * 불가능했다.\n *\n * ── 없는 공간에 알리지 않고 새 공간을 만들지 않는다 ────────────────────────────────\n * \"이 현장에 더한다\" 는 요청이 오타·낡은 목록으로 빗나갔을 때 새 공간을 만들어 주면, 사용자는\n * 합쳤다고 믿고 화면에서는 따로 놀게 된다 — 나중에 두 현장을 손으로 합쳐야 하고, 그때는 이미\n * 이벤트가 양쪽에 쌓여 있다. 그래서 **모르는 공간이면 거절한다.**\n *\n * ── 같은 id 를 쓰는 구역은 알리지 않고 합쳐지므로 알린다 ──────────────────────────\n * 공간 content 의 구역·랜드마크는 id 로 합집합을 만든다(`unionById`). 두 렌즈가 우연히 같은 구역\n * id(`a-yard` 따위)를 쓰면 서로 다른 구역이 하나로 합쳐진다. 막을 일은 아니다(같은 현장의 같은 구역을\n * 가리키는 정당한 경우가 많다) — 다만 **모르고 지나가지 않게** 경고로 돌려준다.\n */\n\n/** 공간 판정 결과. */\nexport interface IngestSpaceChoice {\n /** 실제로 쓸 공간 id. */\n spaceId: string\n /** 사용자가 기존 현장에 합치기를 골랐나(마스터가 파생한 공간과 다른 곳으로 들어가나). */\n joined: boolean\n}\n\n/** 거절 사유 — 호출측이 문장을 만들 때 쓴다(언어 중립 코드). */\nexport const INGEST_SPACE_NOT_FOUND = 'space-not-found'\n\n/**\n * 요청받은 공간과 마스터가 파생한 공간 중 무엇으로 들어갈지 정한다.\n *\n * @param masterSpaceId 마스터에서 파생된 공간 id(요청이 없을 때의 기본).\n * @param requested 사용자가 고른 기존 공간 id. 없으면 빈 값/undefined.\n * @param requestedExists 그 공간이 이 테넌트에 실제로 있나(호출측이 조회해 넘긴다).\n * @throws 요청한 공간이 없으면 — 알리지 않고 새로 만들지 않는다.\n */\nexport function resolveIngestSpace(masterSpaceId: string, requested: string | undefined | null, requestedExists: boolean): IngestSpaceChoice {\n const want = (requested ?? '').trim()\n if (!want) return { spaceId: masterSpaceId, joined: false }\n if (!requestedExists) {\n const e = new Error(`space \"${want}\" not found — cannot co-locate into a space that does not exist`)\n ;(e as any).code = INGEST_SPACE_NOT_FOUND\n throw e\n }\n /* 마스터가 이미 그 공간을 가리키면 합치기가 아니다 — 같은 공간의 재인제스트다. */\n return { spaceId: want, joined: want !== masterSpaceId }\n}\n\n/**\n * 실 시스템 import 가 현장을 고를 때의 거절 판정 — **순수**.\n *\n * 레퍼런스 하나는 사이트를 여럿 발견할 수 있고(`discoverSites`), 그 사이트마다 트윈이 하나씩 생긴다.\n * 그런데 \"이 현장에 더한다\" 는 **한 곳**을 가리키는 말이다. 사이트 여럿을 한 공간에 넣으면 서로 다른\n * 현장의 구역·랜드마크가 id 로 합쳐지고(`unionById`), 그 사실을 알아차릴 때는 이미 이벤트가 양쪽에\n * 쌓여 있다 — 손으로 되돌릴 수 없는 종류다. 그래서 **묻지 않고 합치지 않고, 거절한다.**\n *\n * 공간을 고르지 않으면 지금까지의 거동 그대로다: 사이트마다 마스터가 파생한 공간으로 들어간다.\n */\nexport type ImportSpaceRefusalCode = 'space-with-multiple-sites'\n\nexport interface ImportSpaceRefusal {\n code: ImportSpaceRefusalCode\n params?: Record<string, string | number>\n /** 영어 canonical — 로그에 남고, 번역이 없으면 그대로 보인다(발견 오류와 같은 규약). */\n message: string\n}\n\n/**\n * @param siteCount 실제로 만들 사이트 수(필터 적용 후).\n * @param requested 사용자가 고른 기존 공간 id. 없으면 판정할 것이 없다.\n * @returns 거절 사유. 없으면 진행해도 된다.\n */\nexport function refuseImportSpace(siteCount: number, requested?: string | null): ImportSpaceRefusal | undefined {\n const want = (requested ?? '').trim()\n if (!want || siteCount <= 1) return undefined\n return {\n code: 'space-with-multiple-sites',\n params: { spaceId: want, count: siteCount },\n message: `cannot co-locate ${siteCount} sites into space \"${want}\" — pick one site, or omit the space so each site gets its own`\n }\n}\n\n/** 구역·랜드마크처럼 id 로 합쳐지는 것들. */\ninterface Identified {\n id?: string\n}\n\n/**\n * 합치는 쪽과 기존 쪽이 같은 id 를 쓰는 것들을 찾아 경고 문장을 만든다.\n *\n * 정당한 경우(같은 현장의 같은 구역)와 사고(서로 다른 구역이 우연히 같은 이름)를 기계가 가릴 수는\n * 없다. 구분할 수 없는 것을 고르지 않고, **무엇이 합쳐졌는지 말한다.**\n */\nexport function collidingIds(existing: readonly Identified[] | undefined | null, incoming: readonly Identified[] | undefined | null): string[] {\n const have = new Set((existing ?? []).map(x => x?.id).filter(Boolean) as string[])\n const hits = new Set<string>()\n for (const x of incoming ?? []) if (x?.id && have.has(x.id)) hits.add(x.id)\n return [...hits].sort()\n}\n"]}
@@ -14,7 +14,7 @@ export declare function applyKnobDefaults(knobs: readonly KnobLike[] | undefined
14
14
  /**
15
15
  * 기본값으로 채운 노브 이름들 — 호출자에게 "무엇을 내가 정해 줬는지" 알릴 때 쓴다.
16
16
  *
17
- * 조용히 채우는 것도 조용히 비우는 것만큼 위험하다: 사용자가 준 적 없는 값으로 트윈이 만들어졌는데
17
+ * 알리지 않고 채우는 것도 알리지 않고 비우는 것만큼 위험하다: 사용자가 준 적 없는 값으로 트윈이 만들어졌는데
18
18
  * 아무 말이 없으면, 나중에 "왜 이 수치인가" 를 아무도 답할 수 없다.
19
19
  */
20
20
  export declare function filledKnobKeys(knobs: readonly KnobLike[] | undefined | null, params: Record<string, unknown> | undefined | null): string[];