@operato/ops-contract 0.9.17 → 0.9.19
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/README.md +58 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/operational-attention.d.ts +43 -0
- package/dist/operational-attention.js +35 -0
- package/dist/webhook.d.ts +17 -0
- package/dist/webhook.js +17 -0
- package/dist-cjs/index.cjs +42 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,64 @@ IEC 61850 · ISO 50001 전기 계통과 성과지표
|
|
|
14
14
|
|
|
15
15
|
여기 없는 것은 **정책과 엔진**입니다. 그 사실로 무엇을 할지는 `@operato/twin-kernel` 이 정합니다.
|
|
16
16
|
|
|
17
|
+
## 제품 간 AI 분석 입력 — `OperationalAttentionV1`
|
|
18
|
+
|
|
19
|
+
`OperationalAttentionV1`은 Plant·WMS·YMS·EMS가 자신이 관측한 운영 주의 사실을 Twin 또는 AI 분석기에
|
|
20
|
+
보낼 때 쓰는 공통 봉투입니다. 국제 표준의 알람 포맷을 새로 만드는 것이 아닙니다. EPCIS/ISA-95 등의
|
|
21
|
+
원본 사실을 **어떤 제품이, 어떤 근거로, 무엇을 분석 대상으로 열었거나 닫았는지** 안전하게 전달하는
|
|
22
|
+
Operato의 제품 간 계약입니다.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import {
|
|
26
|
+
OPERATIONAL_ATTENTION_CONTRACT,
|
|
27
|
+
assertOperationalAttentionV1,
|
|
28
|
+
type OperationalAttentionV1
|
|
29
|
+
} from '@operato/ops-contract'
|
|
30
|
+
|
|
31
|
+
const attention: OperationalAttentionV1 = {
|
|
32
|
+
contract: OPERATIONAL_ATTENTION_CONTRACT,
|
|
33
|
+
domainId: 'factory-a',
|
|
34
|
+
attentionId: 'schedule-overdue:line-a:101',
|
|
35
|
+
dedupeKey: 'schedule-overdue:line-a:101',
|
|
36
|
+
kind: 'plant.schedule-overdue',
|
|
37
|
+
subjectLabel: 'Line A schedule 101',
|
|
38
|
+
transition: 'opened',
|
|
39
|
+
impact: 'high',
|
|
40
|
+
observedAt: '2026-09-12T01:00:00.000Z',
|
|
41
|
+
evidenceFingerprint: 'sha256:...',
|
|
42
|
+
facts: [{ system: 'operato-plant', type: 'schedule-entry', id: '101' }]
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
assertOperationalAttentionV1(attention)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 공통으로 고정한 것
|
|
49
|
+
|
|
50
|
+
- 식별·재전송: `attentionId`, `dedupeKey`
|
|
51
|
+
- 분석 수명주기: `opened`, `changed`, `resolved`, `reopened`
|
|
52
|
+
- 분석 우선순위: `medium`, `high`
|
|
53
|
+
- 근거: 최소 하나 이상의 안정된 `{ system, type, id }` 원본 사실 참조와 `evidenceFingerprint`
|
|
54
|
+
|
|
55
|
+
사람이 읽는 제목만 있고 원본 사실 ID가 없는 입력은 거부합니다. AI가 그럴듯한 설명을 만들더라도
|
|
56
|
+
근거를 다시 열어 볼 수 없으면 운영 분석의 입력이 될 수 없기 때문입니다.
|
|
57
|
+
|
|
58
|
+
### 제품별로 남기는 것
|
|
59
|
+
|
|
60
|
+
`kind`와 `facts[].type`은 생산자가 소유합니다. 예를 들어 Plant는 `plant.schedule-overdue`, WMS는
|
|
61
|
+
`wms.short-pick`을 쓰며 서로의 업무 모델을 흉내 내지 않습니다. 또한 `acknowledged`, `suppressed`,
|
|
62
|
+
승인, 실제 조치 결과는 생산 제품의 업무 흐름에 남습니다. 이 계약은 분석에 필요한 **사실 변화**만
|
|
63
|
+
전달하며, 수신자가 현장을 조치할 권한을 주지 않습니다.
|
|
64
|
+
|
|
65
|
+
새 제품이 붙을 때는 공통 봉투를 넓히기 전에 그 제품의 adapter에서 자기 `kind`·사실 유형·판정 기준을
|
|
66
|
+
검증합니다. 모든 제품이 실제로 공유하는 필드만 이 계약에 추가합니다.
|
|
67
|
+
|
|
68
|
+
### 기존 webhook을 통한 전송
|
|
69
|
+
|
|
70
|
+
새 URL은 만들지 않는다. attention도 기존 `POST /domain/{domain}/twin/hook/{source}/{instanceId}`로 보내며,
|
|
71
|
+
봉투의 `lane: 'ATTENTIONS'`가 Twin의 AI inbox 경로를 고른다. `scope`는 계속 원천의 순번 흐름 이름이며
|
|
72
|
+
`lane`과 합치지 않는다. `lane`을 생략한 기존 커넥터는 `FACTS`로 읽혀 기존 canonical ingest 경로를 그대로
|
|
73
|
+
쓴다. 따라서 주소·서명·재시도·순번 규약은 하나이고, 사실과 attention의 저장·처리만 Twin 내부에서 갈린다.
|
|
74
|
+
|
|
17
75
|
## 왜 나뉘어 있나
|
|
18
76
|
|
|
19
77
|
사실을 **만드는 쪽**(MES · 커넥터)은 계약만 필요하고 엔진은 필요 없습니다. 한 패키지에 두면 레코드
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ISOTime } from './contract.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Product-neutral evidence for an operational concern that another product's
|
|
4
|
+
* Twin/AI may analyse. It is not an alarm protocol and never authorises work.
|
|
5
|
+
*
|
|
6
|
+
* A producer owns how it detects and manages an attention. Consumers receive
|
|
7
|
+
* only its evidence-backed lifecycle change; acknowledgement, suppression,
|
|
8
|
+
* approval, and outcome remain in the producer's workflow.
|
|
9
|
+
*/
|
|
10
|
+
export declare const OPERATIONAL_ATTENTION_CONTRACT: "operational.attention.v1";
|
|
11
|
+
export declare const OPERATIONAL_ATTENTION_TRANSITIONS: readonly ["opened", "changed", "resolved", "reopened"];
|
|
12
|
+
export declare const OPERATIONAL_ATTENTION_IMPACTS: readonly ["medium", "high"];
|
|
13
|
+
export type OperationalAttentionTransition = (typeof OPERATIONAL_ATTENTION_TRANSITIONS)[number];
|
|
14
|
+
export type OperationalAttentionImpact = (typeof OPERATIONAL_ATTENTION_IMPACTS)[number];
|
|
15
|
+
/** Stable reference to a fact held by the producing product. */
|
|
16
|
+
export interface OperationalFactReference {
|
|
17
|
+
/** Product/system that owns the source fact, e.g. operato-plant or operato-wms. */
|
|
18
|
+
system: string;
|
|
19
|
+
/** Producer-owned entity vocabulary, e.g. schedule-entry or inventory. */
|
|
20
|
+
type: string;
|
|
21
|
+
id: string;
|
|
22
|
+
observedAt?: ISOTime;
|
|
23
|
+
label?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface OperationalAttentionV1 {
|
|
26
|
+
contract: typeof OPERATIONAL_ATTENTION_CONTRACT;
|
|
27
|
+
domainId: string;
|
|
28
|
+
/** Stable producer identifier; unchanged across lifecycle updates. */
|
|
29
|
+
attentionId: string;
|
|
30
|
+
dedupeKey: string;
|
|
31
|
+
/** Producer-owned, namespaced reason code (for example plant.schedule-overdue). */
|
|
32
|
+
kind: string;
|
|
33
|
+
subjectLabel: string;
|
|
34
|
+
transition: OperationalAttentionTransition;
|
|
35
|
+
impact: OperationalAttentionImpact;
|
|
36
|
+
observedAt: ISOTime;
|
|
37
|
+
/** Deterministic hash of the evidence used for this particular observation. */
|
|
38
|
+
evidenceFingerprint: string;
|
|
39
|
+
/** At least one stable producer fact is mandatory; labels alone are not evidence. */
|
|
40
|
+
facts: OperationalFactReference[];
|
|
41
|
+
}
|
|
42
|
+
export declare function isOperationalAttentionV1(value: unknown): value is OperationalAttentionV1;
|
|
43
|
+
export declare function assertOperationalAttentionV1(value: unknown): asserts value is OperationalAttentionV1;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Product-neutral evidence for an operational concern that another product's
|
|
3
|
+
* Twin/AI may analyse. It is not an alarm protocol and never authorises work.
|
|
4
|
+
*
|
|
5
|
+
* A producer owns how it detects and manages an attention. Consumers receive
|
|
6
|
+
* only its evidence-backed lifecycle change; acknowledgement, suppression,
|
|
7
|
+
* approval, and outcome remain in the producer's workflow.
|
|
8
|
+
*/
|
|
9
|
+
export const OPERATIONAL_ATTENTION_CONTRACT = 'operational.attention.v1';
|
|
10
|
+
export const OPERATIONAL_ATTENTION_TRANSITIONS = ['opened', 'changed', 'resolved', 'reopened'];
|
|
11
|
+
export const OPERATIONAL_ATTENTION_IMPACTS = ['medium', 'high'];
|
|
12
|
+
export function isOperationalAttentionV1(value) {
|
|
13
|
+
const one = value;
|
|
14
|
+
return !!one && typeof one === 'object' &&
|
|
15
|
+
one.contract === OPERATIONAL_ATTENTION_CONTRACT &&
|
|
16
|
+
nonEmpty(one.domainId) && nonEmpty(one.attentionId) && nonEmpty(one.dedupeKey) &&
|
|
17
|
+
nonEmpty(one.kind) && nonEmpty(one.subjectLabel) && nonEmpty(one.observedAt) && nonEmpty(one.evidenceFingerprint) &&
|
|
18
|
+
OPERATIONAL_ATTENTION_TRANSITIONS.includes(one.transition) &&
|
|
19
|
+
OPERATIONAL_ATTENTION_IMPACTS.includes(one.impact) &&
|
|
20
|
+
Array.isArray(one.facts) && one.facts.length > 0 && one.facts.every(isOperationalFactReference);
|
|
21
|
+
}
|
|
22
|
+
export function assertOperationalAttentionV1(value) {
|
|
23
|
+
if (!isOperationalAttentionV1(value)) {
|
|
24
|
+
throw new Error('invalid operational.attention.v1: lifecycle fields and stable source-fact references are required');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function isOperationalFactReference(value) {
|
|
28
|
+
const one = value;
|
|
29
|
+
return !!one && typeof one === 'object' && nonEmpty(one.system) && nonEmpty(one.type) && nonEmpty(one.id) &&
|
|
30
|
+
(one.observedAt === undefined || nonEmpty(one.observedAt)) &&
|
|
31
|
+
(one.label === undefined || nonEmpty(one.label));
|
|
32
|
+
}
|
|
33
|
+
function nonEmpty(value) {
|
|
34
|
+
return typeof value === 'string' && value.trim().length > 0;
|
|
35
|
+
}
|
package/dist/webhook.d.ts
CHANGED
|
@@ -30,6 +30,18 @@ export declare const WEBHOOK_STATUS: {
|
|
|
30
30
|
readonly notLive: 503;
|
|
31
31
|
};
|
|
32
32
|
export type WebhookStatus = (typeof WEBHOOK_STATUS)[keyof typeof WEBHOOK_STATUS];
|
|
33
|
+
/**
|
|
34
|
+
* A webhook lane says what the envelope is for; it is deliberately separate
|
|
35
|
+
* from `scope`, which names the producer's sequence stream.
|
|
36
|
+
*
|
|
37
|
+
* Omitting it means FACTS so every existing connector remains compatible.
|
|
38
|
+
*/
|
|
39
|
+
export declare const WEBHOOK_LANE: {
|
|
40
|
+
readonly facts: "FACTS";
|
|
41
|
+
readonly attentions: "ATTENTIONS";
|
|
42
|
+
};
|
|
43
|
+
export type WebhookLane = (typeof WEBHOOK_LANE)[keyof typeof WEBHOOK_LANE];
|
|
44
|
+
export declare function webhookLaneOf(value: unknown): WebhookLane | undefined;
|
|
33
45
|
/**
|
|
34
46
|
* 그 응답을 받은 뒤 보내는 쪽이 할 일.
|
|
35
47
|
*
|
|
@@ -217,6 +229,11 @@ export interface WebhookEnvelope {
|
|
|
217
229
|
seq: number;
|
|
218
230
|
/** 번호를 매기는 단위의 이름. 보내는 쪽이 정하고 받는 쪽은 열쇠로만 다룬다. */
|
|
219
231
|
scope: string;
|
|
232
|
+
/**
|
|
233
|
+
* Delivery purpose. `scope` remains the source-owned numbering stream;
|
|
234
|
+
* `lane` selects the receiver path. Missing means `FACTS` for compatibility.
|
|
235
|
+
*/
|
|
236
|
+
lane?: WebhookLane;
|
|
220
237
|
/** 멱등 키. 같은 값이 두 번 와도 결과가 같아야 한다. */
|
|
221
238
|
eventId?: string;
|
|
222
239
|
/** 사실이 일어난 시각. */
|
package/dist/webhook.js
CHANGED
|
@@ -45,6 +45,23 @@ export const WEBHOOK_STATUS = {
|
|
|
45
45
|
unsupported: 501,
|
|
46
46
|
notLive: 503
|
|
47
47
|
};
|
|
48
|
+
/**
|
|
49
|
+
* A webhook lane says what the envelope is for; it is deliberately separate
|
|
50
|
+
* from `scope`, which names the producer's sequence stream.
|
|
51
|
+
*
|
|
52
|
+
* Omitting it means FACTS so every existing connector remains compatible.
|
|
53
|
+
*/
|
|
54
|
+
export const WEBHOOK_LANE = {
|
|
55
|
+
facts: 'FACTS',
|
|
56
|
+
attentions: 'ATTENTIONS'
|
|
57
|
+
};
|
|
58
|
+
export function webhookLaneOf(value) {
|
|
59
|
+
return value === undefined || value === WEBHOOK_LANE.facts
|
|
60
|
+
? WEBHOOK_LANE.facts
|
|
61
|
+
: value === WEBHOOK_LANE.attentions
|
|
62
|
+
? WEBHOOK_LANE.attentions
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
48
65
|
/**
|
|
49
66
|
* 응답 코드 → 보내는 쪽의 행동. **모르는 코드도 답을 낸다.**
|
|
50
67
|
*
|
package/dist-cjs/index.cjs
CHANGED
|
@@ -58,6 +58,9 @@ __export(index_exports, {
|
|
|
58
58
|
MES_TYPES: () => MES_TYPES,
|
|
59
59
|
METER_DIRECTION: () => METER_DIRECTION,
|
|
60
60
|
OBSERVATION_BASIS: () => OBSERVATION_BASIS,
|
|
61
|
+
OPERATIONAL_ATTENTION_CONTRACT: () => OPERATIONAL_ATTENTION_CONTRACT,
|
|
62
|
+
OPERATIONAL_ATTENTION_IMPACTS: () => OPERATIONAL_ATTENTION_IMPACTS,
|
|
63
|
+
OPERATIONAL_ATTENTION_TRANSITIONS: () => OPERATIONAL_ATTENTION_TRANSITIONS,
|
|
61
64
|
OP_EVENT: () => OP_EVENT,
|
|
62
65
|
OP_PARAM: () => OP_PARAM,
|
|
63
66
|
ORDER_TERMINAL_STATUS: () => ORDER_TERMINAL_STATUS,
|
|
@@ -72,6 +75,7 @@ __export(index_exports, {
|
|
|
72
75
|
UTC_OFFSET: () => UTC_OFFSET,
|
|
73
76
|
VOCABULARY_EXCEPTIONS: () => VOCABULARY_EXCEPTIONS,
|
|
74
77
|
VOCABULARY_TYPE: () => VOCABULARY_TYPE,
|
|
78
|
+
WEBHOOK_LANE: () => WEBHOOK_LANE,
|
|
75
79
|
WEBHOOK_SECRET_BASE: () => WEBHOOK_SECRET_BASE,
|
|
76
80
|
WEBHOOK_SECRET_NAME_SHAPE: () => WEBHOOK_SECRET_NAME_SHAPE,
|
|
77
81
|
WEBHOOK_STATUS: () => WEBHOOK_STATUS,
|
|
@@ -88,6 +92,7 @@ __export(index_exports, {
|
|
|
88
92
|
analyzeCapacity: () => analyzeCapacity,
|
|
89
93
|
approveCommand: () => approveCommand,
|
|
90
94
|
asApproved: () => asApproved,
|
|
95
|
+
assertOperationalAttentionV1: () => assertOperationalAttentionV1,
|
|
91
96
|
axesOfSystem: () => axesOfSystem,
|
|
92
97
|
axisAppliesTo: () => axisAppliesTo,
|
|
93
98
|
axisInfo: () => axisInfo,
|
|
@@ -154,6 +159,7 @@ __export(index_exports, {
|
|
|
154
159
|
isEquipmentStatus: () => isEquipmentStatus,
|
|
155
160
|
isFailureStatus: () => isFailureStatus,
|
|
156
161
|
isMasterDataRecord: () => isMasterDataRecord,
|
|
162
|
+
isOperationalAttentionV1: () => isOperationalAttentionV1,
|
|
157
163
|
isOperationalRecord: () => isOperationalRecord,
|
|
158
164
|
isOrderTerminal: () => isOrderTerminal,
|
|
159
165
|
isPlannedStopStatus: () => isPlannedStopStatus,
|
|
@@ -222,6 +228,7 @@ __export(index_exports, {
|
|
|
222
228
|
validateEpcisEvent: () => validateEpcisEvent,
|
|
223
229
|
validatePerformance: () => validatePerformance,
|
|
224
230
|
validateScenario: () => validateScenario,
|
|
231
|
+
webhookLaneOf: () => webhookLaneOf,
|
|
225
232
|
webhookSecretCandidates: () => webhookSecretCandidates,
|
|
226
233
|
webhookSecretEnvName: () => webhookSecretEnvName,
|
|
227
234
|
webhookSecretFrom: () => webhookSecretFrom,
|
|
@@ -4050,6 +4057,13 @@ var WEBHOOK_STATUS = {
|
|
|
4050
4057
|
unsupported: 501,
|
|
4051
4058
|
notLive: 503
|
|
4052
4059
|
};
|
|
4060
|
+
var WEBHOOK_LANE = {
|
|
4061
|
+
facts: "FACTS",
|
|
4062
|
+
attentions: "ATTENTIONS"
|
|
4063
|
+
};
|
|
4064
|
+
function webhookLaneOf(value) {
|
|
4065
|
+
return value === void 0 || value === WEBHOOK_LANE.facts ? WEBHOOK_LANE.facts : value === WEBHOOK_LANE.attentions ? WEBHOOK_LANE.attentions : void 0;
|
|
4066
|
+
}
|
|
4053
4067
|
function webhookSenderAction(status) {
|
|
4054
4068
|
switch (status) {
|
|
4055
4069
|
case WEBHOOK_STATUS.ok:
|
|
@@ -4453,6 +4467,27 @@ function commandSpecGaps(specs, command) {
|
|
|
4453
4467
|
}
|
|
4454
4468
|
return gaps;
|
|
4455
4469
|
}
|
|
4470
|
+
|
|
4471
|
+
// src/operational-attention.ts
|
|
4472
|
+
var OPERATIONAL_ATTENTION_CONTRACT = "operational.attention.v1";
|
|
4473
|
+
var OPERATIONAL_ATTENTION_TRANSITIONS = ["opened", "changed", "resolved", "reopened"];
|
|
4474
|
+
var OPERATIONAL_ATTENTION_IMPACTS = ["medium", "high"];
|
|
4475
|
+
function isOperationalAttentionV1(value) {
|
|
4476
|
+
const one = value;
|
|
4477
|
+
return !!one && typeof one === "object" && one.contract === OPERATIONAL_ATTENTION_CONTRACT && nonEmpty(one.domainId) && nonEmpty(one.attentionId) && nonEmpty(one.dedupeKey) && nonEmpty(one.kind) && nonEmpty(one.subjectLabel) && nonEmpty(one.observedAt) && nonEmpty(one.evidenceFingerprint) && OPERATIONAL_ATTENTION_TRANSITIONS.includes(one.transition) && OPERATIONAL_ATTENTION_IMPACTS.includes(one.impact) && Array.isArray(one.facts) && one.facts.length > 0 && one.facts.every(isOperationalFactReference);
|
|
4478
|
+
}
|
|
4479
|
+
function assertOperationalAttentionV1(value) {
|
|
4480
|
+
if (!isOperationalAttentionV1(value)) {
|
|
4481
|
+
throw new Error("invalid operational.attention.v1: lifecycle fields and stable source-fact references are required");
|
|
4482
|
+
}
|
|
4483
|
+
}
|
|
4484
|
+
function isOperationalFactReference(value) {
|
|
4485
|
+
const one = value;
|
|
4486
|
+
return !!one && typeof one === "object" && nonEmpty(one.system) && nonEmpty(one.type) && nonEmpty(one.id) && (one.observedAt === void 0 || nonEmpty(one.observedAt)) && (one.label === void 0 || nonEmpty(one.label));
|
|
4487
|
+
}
|
|
4488
|
+
function nonEmpty(value) {
|
|
4489
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
4490
|
+
}
|
|
4456
4491
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4457
4492
|
0 && (module.exports = {
|
|
4458
4493
|
BIZSTEP,
|
|
@@ -4494,6 +4529,9 @@ function commandSpecGaps(specs, command) {
|
|
|
4494
4529
|
MES_TYPES,
|
|
4495
4530
|
METER_DIRECTION,
|
|
4496
4531
|
OBSERVATION_BASIS,
|
|
4532
|
+
OPERATIONAL_ATTENTION_CONTRACT,
|
|
4533
|
+
OPERATIONAL_ATTENTION_IMPACTS,
|
|
4534
|
+
OPERATIONAL_ATTENTION_TRANSITIONS,
|
|
4497
4535
|
OP_EVENT,
|
|
4498
4536
|
OP_PARAM,
|
|
4499
4537
|
ORDER_TERMINAL_STATUS,
|
|
@@ -4508,6 +4546,7 @@ function commandSpecGaps(specs, command) {
|
|
|
4508
4546
|
UTC_OFFSET,
|
|
4509
4547
|
VOCABULARY_EXCEPTIONS,
|
|
4510
4548
|
VOCABULARY_TYPE,
|
|
4549
|
+
WEBHOOK_LANE,
|
|
4511
4550
|
WEBHOOK_SECRET_BASE,
|
|
4512
4551
|
WEBHOOK_SECRET_NAME_SHAPE,
|
|
4513
4552
|
WEBHOOK_STATUS,
|
|
@@ -4524,6 +4563,7 @@ function commandSpecGaps(specs, command) {
|
|
|
4524
4563
|
analyzeCapacity,
|
|
4525
4564
|
approveCommand,
|
|
4526
4565
|
asApproved,
|
|
4566
|
+
assertOperationalAttentionV1,
|
|
4527
4567
|
axesOfSystem,
|
|
4528
4568
|
axisAppliesTo,
|
|
4529
4569
|
axisInfo,
|
|
@@ -4590,6 +4630,7 @@ function commandSpecGaps(specs, command) {
|
|
|
4590
4630
|
isEquipmentStatus,
|
|
4591
4631
|
isFailureStatus,
|
|
4592
4632
|
isMasterDataRecord,
|
|
4633
|
+
isOperationalAttentionV1,
|
|
4593
4634
|
isOperationalRecord,
|
|
4594
4635
|
isOrderTerminal,
|
|
4595
4636
|
isPlannedStopStatus,
|
|
@@ -4658,6 +4699,7 @@ function commandSpecGaps(specs, command) {
|
|
|
4658
4699
|
validateEpcisEvent,
|
|
4659
4700
|
validatePerformance,
|
|
4660
4701
|
validateScenario,
|
|
4702
|
+
webhookLaneOf,
|
|
4661
4703
|
webhookSecretCandidates,
|
|
4662
4704
|
webhookSecretEnvName,
|
|
4663
4705
|
webhookSecretFrom,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@operato/ops-contract",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.19",
|
|
4
4
|
"description": "Operations domain contract — the standard vocabulary that producers and readers agree on (EPCIS 2.0/GS1, ISA-95, IEC 61850/ISO 50001). Types, guards, validation. No state, no engine.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist-cjs/index.cjs",
|