@operato/twin-kernel 0.7.39 → 0.7.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract.d.ts +176 -10
- package/dist/contract.js +46 -5
- package/dist/domain-catalog.d.ts +1 -1
- package/dist/domain-catalog.js +1 -1
- package/dist/domain-definition.d.ts +17 -0
- package/dist/domain-definition.js +7 -0
- package/dist/ems-kernel.js +13 -1
- package/dist/epcis.d.ts +22 -0
- package/dist/epcis.js +91 -2
- package/dist/face2-adapter.d.ts +21 -1
- package/dist/face2-adapter.js +12 -1
- package/dist/flow-engine.d.ts +156 -8
- package/dist/flow-engine.js +324 -21
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/kernel.d.ts +15 -0
- package/dist/kernel.js +50 -16
- package/dist/mes-kernel.d.ts +117 -27
- package/dist/mes-kernel.js +354 -170
- package/dist/observed-reducer.d.ts +1 -1
- package/dist/observed-reducer.js +7 -4
- package/dist/yms-kernel.js +12 -5
- package/dist-cjs/index.cjs +648 -187
- package/package.json +1 -1
|
@@ -55,7 +55,7 @@ export interface ProjectedState {
|
|
|
55
55
|
* 아무것도 담기지 않는다. 그것을 조용히 두면 트윈은 「정상인데 빈」 모습이 된다.
|
|
56
56
|
*
|
|
57
57
|
* 비어 있지 않으면 뜻은 하나다: **이 트윈에 맞지 않는 어휘가 들어오고 있다**(커넥터 배선 오류이거나
|
|
58
|
-
* 커널이 낡았다). 세는 것에 그치고 판단은 소비처가 한다 — 여기서
|
|
58
|
+
* 커널이 낡았다). 세는 것에 그치고 판단은 소비처가 한다 — 여기서 오류를 내면 저널 재생이 멈춘다.
|
|
59
59
|
*/
|
|
60
60
|
unhandled?: {
|
|
61
61
|
eventType: string;
|
package/dist/observed-reducer.js
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* - 운영 델타(task/equipment/order.status) → tasks·equipment·orders (EPCIS 로 재구성 불가한 절반)
|
|
20
20
|
* 마스터(로케이션)는 board 초기화 + applyMaster 로 갱신(마스터 동기).
|
|
21
21
|
*/
|
|
22
|
-
import { OP_EVENT, capabilityOf, requiredTestsFor, locationStatusOf, readBoardEquipment, readBoardLocations, readBoardAssets, effectivityAt, offCalendarAt, offCalendarReasonAt, activeShiftAt } from "./contract.js";
|
|
22
|
+
import { OP_EVENT, capabilityOf, itemKeyOf, requiredTestsFor, locationStatusOf, readBoardEquipment, readBoardLocations, readBoardAssets, effectivityAt, offCalendarAt, offCalendarReasonAt, activeShiftAt } from "./contract.js";
|
|
23
23
|
import { ILMD_ATTR, parseEpc } from "./epcis.js";
|
|
24
24
|
/**
|
|
25
25
|
* 투영이 들고 있는 물품 — **계약(ItemState)을 축소하지 않는다.**
|
|
@@ -364,6 +364,8 @@ export class ObservedReducer {
|
|
|
364
364
|
/* 진행 중 확보분과 거래번호 — **미러도 같은 필드를 채운다.** 시뮬만 아는 사실을 두면
|
|
365
365
|
그 위에서 세운 예측이 두 구동에서 달라진다(패리티 검사가 지키는 것이 이것이다). */
|
|
366
366
|
...(d.gtin ? { gtin: d.gtin } : {}),
|
|
367
|
+
/* 어느 레시피로 만드는가 — 품목만으로는 「무엇으로」가 남지 않는다(같은 품목에 대체 레시피). */
|
|
368
|
+
...(d.recipeKey ? { recipeKey: d.recipeKey } : {}),
|
|
367
369
|
...(d.allocated?.length ? { allocated: d.allocated.slice() } : {}),
|
|
368
370
|
...(d.bizTransaction ? { bizTransaction: d.bizTransaction } : {}),
|
|
369
371
|
/* 약속해 둔 자리·시각창도 채운다 — 시뮬만 알면 미러 위 예측이 「어디로 들일지」를 모른다.
|
|
@@ -471,7 +473,7 @@ export class ObservedReducer {
|
|
|
471
473
|
if (!cur)
|
|
472
474
|
this.pendingQuantities.set(ev.parentID, [...ev.childQuantityList]);
|
|
473
475
|
else {
|
|
474
|
-
this.items.set(cur
|
|
476
|
+
this.items.set(itemKeyOf(cur), this.withContainedQuantity(cur, q, ev.childQuantityList));
|
|
475
477
|
this.qtyAggregation.set(ev.parentID, [...ev.childQuantityList]);
|
|
476
478
|
}
|
|
477
479
|
}
|
|
@@ -507,7 +509,7 @@ export class ObservedReducer {
|
|
|
507
509
|
const cur = this.items.get(ev.parentID);
|
|
508
510
|
if (cur) {
|
|
509
511
|
const { gtin, gtinKey, qty, uom, quantities, lot, ...rest } = cur;
|
|
510
|
-
this.items.set(cur
|
|
512
|
+
this.items.set(itemKeyOf(cur), { ...rest, qty: 1 });
|
|
511
513
|
}
|
|
512
514
|
}
|
|
513
515
|
this.pendingQuantities.delete(ev.parentID);
|
|
@@ -593,7 +595,8 @@ export class ObservedReducer {
|
|
|
593
595
|
all,
|
|
594
596
|
/** 로트의 부분 식별자(표준 `MaterialSubLot.ID`) — 비직렬 로트가 자리마다 갈릴 때. */
|
|
595
597
|
subLotId) {
|
|
596
|
-
|
|
598
|
+
/* 키 규칙은 한 곳에서만 정한다(§itemKeyOf) — 여기서 다시 적으면 두 벌이 되고 한쪽만 고쳐진다. */
|
|
599
|
+
const cur = this.items.get(itemKeyOf({ epc, subLotId }));
|
|
597
600
|
/* 클래스는 수량 목록에서 오거나, 물품 자신이 클래스 식별자일 수 있다(비직렬 입고). */
|
|
598
601
|
const parsedClass = q?.epcClass ? parseEpc(q.epcClass) : undefined;
|
|
599
602
|
const parsedSelf = parseEpc(epc);
|
package/dist/yms-kernel.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* - drop(기본): 트레일러를 야드 슬롯에 내려놓고(주차) 창 도래 시 호슬러가 도크로 pull. 야드 버퍼 사용.
|
|
16
16
|
* - live: 게이트에서 대기하다 창 도래 시 도크로 직행(야드 미경유). 게이트/도크를 더 오래 점유.
|
|
17
17
|
*/
|
|
18
|
+
import { itemKeyOf } from "./contract.js";
|
|
18
19
|
import { firstFitPolicy } from "./allocation-policy.js";
|
|
19
20
|
import { FlowEngine } from "./flow-engine.js";
|
|
20
21
|
import { DISP, objectEvent, transactionEvent, gdtiUri, ssccUri } from "./epcis.js";
|
|
@@ -33,7 +34,12 @@ const WINDOW_DELAY_MS = 40_000; // 도착 후 어포인트먼트 창까지(early
|
|
|
33
34
|
*/
|
|
34
35
|
const WINDOW_LENGTH_MS = 20 * 60_000;
|
|
35
36
|
const CARGO_PER_TRAILER = 2; // 트레일러 적재/하역 화물(SSCC) 수
|
|
36
|
-
|
|
37
|
+
/**
|
|
38
|
+
* 이 내장 시나리오가 쓰는 **날조된 회사 프리픽스** — 선언이 없는 트윈만 이 길로 온다.
|
|
39
|
+
* 근거·처분은 WMS 커널의 같은 상수 주석에 있다(`kernel.ts`). 이름의 `LEGACY_` 는 새 코드가 무심코
|
|
40
|
+
* 집어 들지 못하게 하는 표시다 — 이 상수를 지나는 트윈은 `fabricated` 로 판정된다.
|
|
41
|
+
*/
|
|
42
|
+
const LEGACY_CP = '0614141';
|
|
37
43
|
export class YmsKernel extends FlowEngine {
|
|
38
44
|
doorRR = 0;
|
|
39
45
|
cargoSeq = 0;
|
|
@@ -58,19 +64,19 @@ export class YmsKernel extends FlowEngine {
|
|
|
58
64
|
if (!gate || doors.length === 0)
|
|
59
65
|
return;
|
|
60
66
|
const inbound = kind === 'appointment';
|
|
61
|
-
const epc = graiUri(
|
|
67
|
+
const epc = graiUri(LEGACY_CP, '10', ++this.epcSeq);
|
|
62
68
|
this.items.set(epc, { epc, location: gate.id, disposition: DISP.in_progress });
|
|
63
69
|
gate.occupancy++;
|
|
64
70
|
this.emit(objectEvent({ eventTime: this.now(), action: 'ADD', bizStep: YARD_BIZSTEP.arriving, disposition: DISP.in_progress, epcList: [epc], readPoint: gate.id, bizLocation: gate.id }));
|
|
65
71
|
// 인바운드: 화물 적재된 채 도착 → 조립(트레일러←화물) 기록. 아웃바운드: 빈 트레일러(화물은 도크에서 적재).
|
|
66
72
|
if (inbound) {
|
|
67
|
-
const cargo = Array.from({ length: CARGO_PER_TRAILER }, () => ssccUri(
|
|
73
|
+
const cargo = Array.from({ length: CARGO_PER_TRAILER }, () => ssccUri(LEGACY_CP, ++this.cargoSeq));
|
|
68
74
|
this.trailerCargo.set(epc, cargo);
|
|
69
75
|
this.aggregate(epc, cargo, { bizStep: YARD_BIZSTEP.arriving, readPoint: gate.id }); // 적재된 채 도착(자식 opaque, 미materialize)
|
|
70
76
|
}
|
|
71
77
|
const door = doors[this.doorRR++ % doors.length];
|
|
72
78
|
const id = `order-${++this.orderSeq}`;
|
|
73
|
-
const appt = gdtiUri(
|
|
79
|
+
const appt = gdtiUri(LEGACY_CP, '404', ++this.soSeq);
|
|
74
80
|
const order = { id, kind, status: 'created', requested: 1, fulfilled: 0, bizTransaction: appt, allocated: [epc], picked: [], dockDoor: door.id,
|
|
75
81
|
/* 내부 스케줄 게이트(시뮬 ms) — 표준 `EarliestStartTime` 과 같은 개념의 우리 단위. */
|
|
76
82
|
windowStartMs: this.clockMs + WINDOW_DELAY_MS,
|
|
@@ -163,7 +169,8 @@ export class YmsKernel extends FlowEngine {
|
|
|
163
169
|
const to = this.locations.get(t.toNode);
|
|
164
170
|
from.occupancy--;
|
|
165
171
|
to.occupancy++;
|
|
166
|
-
|
|
172
|
+
/* 자리 이동은 저장소 통로로 — 직접 고치면 자리별 색인이 어긋난다. */
|
|
173
|
+
this.items.relocate(itemKeyOf(trailer), to.id);
|
|
167
174
|
if (t.kind === 'dwell') {
|
|
168
175
|
// 도크 체류(무자원 dwell) 완료 → 출차 이동(transport). 체류 중 호슬러 미점유(drop-and-hook 충실).
|
|
169
176
|
const gate = this.locationByType('gate');
|