@g1cloud/entity-modeler-next 5.0.0-beta.36 → 5.0.0-beta.38
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/command/op.d.ts +16 -1
- package/dist/command/opSync.d.ts +11 -1
- package/dist/command/stack.d.ts +11 -1
- package/dist/core/opSubject.d.ts +54 -0
- package/dist/core/projectActionLog.d.ts +7 -10
- package/dist/core/resolve.d.ts +0 -3
- package/dist/editor/controller.d.ts +5 -3
- package/dist/entity-modeler.js +10076 -9970
- package/dist/entity-modeler.umd.cjs +25 -25
- package/package.json +1 -1
package/dist/command/op.d.ts
CHANGED
|
@@ -81,7 +81,22 @@ export interface PersistedOpBatch {
|
|
|
81
81
|
/** 멱등 키 — 재시도 중복 적용 차단(호스트가 직전 결과 반환). */
|
|
82
82
|
clientOpId: string;
|
|
83
83
|
}
|
|
84
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* 하드 프리즈 사유 — **방출 주체가 kind마다 다르다**(선언과 실제를 맞춘 기록, 2026-08-15 실측).
|
|
86
|
+
*
|
|
87
|
+
* - `rev` — **호스트가 내는 유일한 kind**. CAS filter 불일치(`matchedCount:0`)를 전부 이걸로 접는다.
|
|
88
|
+
* 호스트는 rev 불일치와 layout.version 불일치를 구분하지 않으므로(단일 updateOne filter) 두 원인이
|
|
89
|
+
* 모두 여기로 들어온다. = "다른 곳에서 이미 변경됨".
|
|
90
|
+
* - `layout` — **현재 어떤 writer도 방출하지 않는다**(예약). 위 사유로 호스트가 `rev`로 접고, 클라도
|
|
91
|
+
* 합성하지 않는다. 소비처(배너·호스트 watch)는 `rev`와 같은 경로로 처리한다.
|
|
92
|
+
* - `missing` — **클라이언트 합성 전용 = op 전송 실패**(4xx/5xx/네트워크로 transport가 throw).
|
|
93
|
+
* 동시편집이 아니라 혼자 편집 중에도 발생하므로 "다른 사용자가 변경"으로 안내하면 오진이다
|
|
94
|
+
* (`opConflictNotice`·호스트 watch가 이 kind로 분기해 손실 고지 후 재적재를 확인받는다).
|
|
95
|
+
* ★이름이 "대상 소실"처럼 읽히지만 그 의미로 쓰인 적이 없다 — 호스트 op 어휘엔 대상 소실 응답이 없다.
|
|
96
|
+
*
|
|
97
|
+
* ⚠️ 새 kind를 늘리기 전에 **소비처 분기**(`opConflictNotice` + 호스트 `opConflict` watch)를 함께 넓힐 것.
|
|
98
|
+
* 넓히지 않으면 새 kind가 else 분기로 떨어져 조용히 다른 복구 경로를 탄다(CC-9의 무신호 실패 모드).
|
|
99
|
+
*/
|
|
85
100
|
export interface OpConflict {
|
|
86
101
|
kind: 'rev' | 'layout' | 'missing';
|
|
87
102
|
ref?: ModelId;
|
package/dist/command/opSync.d.ts
CHANGED
|
@@ -40,14 +40,24 @@ export interface OpSyncOptions {
|
|
|
40
40
|
newClientOpId?: () => string;
|
|
41
41
|
/** 충돌(또는 전송 실패)로 하드 프리즈 진입 시 — controller가 editable=false + reload UX 연동. */
|
|
42
42
|
onFreeze?: (conflict: OpConflict) => void;
|
|
43
|
-
/**
|
|
43
|
+
/**
|
|
44
|
+
* 전송 거부(네트워크 등) 통지 — 진단용(프리즈는 별도 onFreeze로).
|
|
45
|
+
* 재시도하는 경우 **시도마다** 발화한다(회복돼도 원인을 추적할 수 있어야 하므로).
|
|
46
|
+
*/
|
|
44
47
|
onError?: (err: unknown) => void;
|
|
48
|
+
/**
|
|
49
|
+
* 전송 실패 재시도 지연(ms) — 배열 길이가 곧 재시도 횟수. 기본 `[400, 1200]`(총 3회 시도).
|
|
50
|
+
* `[]`이면 재시도 없이 즉시 프리즈. 같은 배치를 **같은 `clientOpId`로** 재전송하므로 호스트
|
|
51
|
+
* 멱등 ring이 중복 적용을 흡수한다(응답만 유실된 경우 직전 결과를 그대로 돌려받는다).
|
|
52
|
+
*/
|
|
53
|
+
retryDelaysMs?: number[];
|
|
45
54
|
}
|
|
46
55
|
export declare class OpSyncAdapter {
|
|
47
56
|
private readonly opts;
|
|
48
57
|
private readonly cache;
|
|
49
58
|
private readonly newClientOpId;
|
|
50
59
|
private readonly debounceMs;
|
|
60
|
+
private readonly retryDelaysMs;
|
|
51
61
|
private readonly emissions;
|
|
52
62
|
private open;
|
|
53
63
|
private debounceHandle;
|
package/dist/command/stack.d.ts
CHANGED
|
@@ -32,7 +32,17 @@ export declare class CommandStack {
|
|
|
32
32
|
sealCoalesce(): void;
|
|
33
33
|
get canUndo(): boolean;
|
|
34
34
|
get canRedo(): boolean;
|
|
35
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* 저장 시점 표시 — 이후 dirty 판정 기준.
|
|
37
|
+
*
|
|
38
|
+
* ★저장 경계는 곧 **undo 단위 경계**여야 한다. 봉인하지 않으면 직후의 동일 `coalesceKey` 명령이
|
|
39
|
+
* savePoint가 가리키는 스택 top을 **슬롯째 교체**해(execute의 coalesce 분기) savePoint 객체가
|
|
40
|
+
* 스택에서 사라진다 — 그러면 `isDirty`가 다시 false가 될 수 없어 **영구 dirty로 고착**된다.
|
|
41
|
+
* 플래그 문제가 아니라 경계 문제다: 병합된 단위의 invert는 그룹 시작으로 되돌아가므로 저장 지점
|
|
42
|
+
* 상태 자체가 undo로 **도달 불가**해진다. 근거는 op 어댑터의 flush 봉인과 동일하다(영속 경계
|
|
43
|
+
* 이후 동일 키는 새 단위). op-mode에서는 `controller.markSaved`가 `adapter.flush()`로 이미
|
|
44
|
+
* 봉인하지만, 그건 전송 경계라는 다른 이유의 우연한 커버라 여기서 구조적으로 닫는다.
|
|
45
|
+
*/
|
|
36
46
|
markSavePoint(): void;
|
|
37
47
|
/** 마지막 저장 이후 변경 여부 (undo로 저장 지점에 정확히 돌아오면 clean) */
|
|
38
48
|
get isDirty(): boolean;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ModelId } from './types';
|
|
2
|
+
import { OpShape } from '../command/op';
|
|
3
|
+
/** 감사 대상 종류 — 논리 모델의 편집 단위. 레이아웃 축은 대상이 아니다. */
|
|
4
|
+
export type OpSubjectKind = 'entity' | 'attribute' | 'operation' | 'index' | 'association' | 'associationEnd' | 'group';
|
|
5
|
+
/** 무엇이 바뀐 대상인가. `entityRef`는 자식(속성/연산/인덱스)의 부모(이름 조회·복원 스코프). */
|
|
6
|
+
export interface OpSubject {
|
|
7
|
+
kind: OpSubjectKind;
|
|
8
|
+
ref: ModelId;
|
|
9
|
+
entityRef?: ModelId;
|
|
10
|
+
end?: 'end1' | 'end2';
|
|
11
|
+
}
|
|
12
|
+
/** op이 한 대상에 가하는 접촉 — 존재 변화(add/remove) 또는 내용 변경(existence 없음). */
|
|
13
|
+
export interface OpSubjectTouch {
|
|
14
|
+
subject: OpSubject;
|
|
15
|
+
/** 대상의 생성/삭제. 내용 변경(update)·기타는 undefined. */
|
|
16
|
+
existence?: 'add' | 'remove';
|
|
17
|
+
/** `entity.add` value에 인라인돼 태어난 자식(자기 op 없음) — 소비자가 top-level만 볼 때 거른다. */
|
|
18
|
+
inline?: true;
|
|
19
|
+
}
|
|
20
|
+
/** 인벤토리 한 행 — 이 kind를 감사 축이 어떻게 다루는가. */
|
|
21
|
+
export interface OpAuditHandling {
|
|
22
|
+
/** 이 op이 지목하는 대상 종류. `null`=감사 범위 밖(레이아웃 축). */
|
|
23
|
+
subject: OpSubjectKind | null;
|
|
24
|
+
/** 대상의 존재 변화 여부. */
|
|
25
|
+
existence: 'add' | 'remove' | null;
|
|
26
|
+
/** `projectFieldAudit`가 필드 변경(born/patch/tombstone)으로 투영하는가. */
|
|
27
|
+
fieldAudit: boolean;
|
|
28
|
+
/** 범위 밖이거나 예외적인 행의 근거. */
|
|
29
|
+
note?: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* **전 op 어휘 인벤토리.** lib이 방출하는 kind는 전부 여기 있어야 한다 —
|
|
33
|
+
* `opSubject.coverage.test.ts`가 소스의 `kind:` 리터럴과 대조해 누락을 실패로 만든다.
|
|
34
|
+
* (새 어휘를 추가하면 그 테스트가 깨진다 = "조용히 무시"가 "명시적 결정"으로 바뀌는 지점.)
|
|
35
|
+
*/
|
|
36
|
+
export declare const OP_AUDIT_INVENTORY: Record<string, OpAuditHandling>;
|
|
37
|
+
/**
|
|
38
|
+
* op이 건드리는 감사 대상 목록. 인벤토리에 없는(=이 lib이 모르는) kind는 빈 배열 — 발굴은
|
|
39
|
+
* `describeContainer`의 접두 폴백이 계속 덮는다.
|
|
40
|
+
*
|
|
41
|
+
* `entity.add`는 자신 + value에 인라인된 자식(속성/연산/인덱스)을 함께 낸다(`inline: true`).
|
|
42
|
+
* 인라인 자식을 볼지 여부는 소비자가 정한다 — 필드 감사가 이미 필드로 잡는 축이면 거른다.
|
|
43
|
+
*/
|
|
44
|
+
export declare function describeOpSubjects(op: OpShape): OpSubjectTouch[];
|
|
45
|
+
/** 발굴용 top-level 소속 대상. */
|
|
46
|
+
export interface OpContainer {
|
|
47
|
+
kind: 'entity' | 'association' | 'group';
|
|
48
|
+
ref: ModelId;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* op이 속한 top-level 대상(엔티티/연관/그룹). **접두 매칭**이라 같은 계열의 미지 어휘도 덮는다
|
|
52
|
+
* (모듈 헤더 ★ 참조 — 발굴 누락은 그 seq를 이력에서 통째로 지운다).
|
|
53
|
+
*/
|
|
54
|
+
export declare function describeContainer(op: OpShape): OpContainer | null;
|
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
import { ModelId } from './types';
|
|
2
1
|
import { FieldAuditRecord } from './projectFieldAudit';
|
|
3
|
-
import {
|
|
4
|
-
export type ActionSubjectKind =
|
|
5
|
-
/**
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
end?: 'end1' | 'end2';
|
|
11
|
-
}
|
|
2
|
+
import { OpSubject, OpSubjectKind } from './opSubject';
|
|
3
|
+
export type ActionSubjectKind = OpSubjectKind;
|
|
4
|
+
/**
|
|
5
|
+
* 무엇이 바뀐 대상인가. entityRef는 자식(속성/연산/인덱스) subject의 부모(이름 조회·복원 스코프).
|
|
6
|
+
* 정의는 `opSubject`(어휘 해석 단일 출처)가 갖고 여기선 공개 이름만 유지한다.
|
|
7
|
+
*/
|
|
8
|
+
export type ActionSubject = OpSubject;
|
|
12
9
|
/** 한 대상의 한 필드 변경(old→new / tombstone). */
|
|
13
10
|
export interface ActionFieldChange {
|
|
14
11
|
field: string;
|
package/dist/core/resolve.d.ts
CHANGED
|
@@ -49,9 +49,6 @@ export interface ResolvedDiagram {
|
|
|
49
49
|
notes: ResolvedNote[];
|
|
50
50
|
/** 노트 → 대상 엔티티 연결선 (대상이 존재하는 것만; dangling은 prune) */
|
|
51
51
|
noteConnections: ResolvedNoteConnection[];
|
|
52
|
-
/** 레이아웃에만 있던(논리에 없는) 정리 대상 항목 */
|
|
53
|
-
prunedEntityRefs: ModelId[];
|
|
54
|
-
prunedAssociationRefs: ModelId[];
|
|
55
52
|
}
|
|
56
53
|
export interface AutoLayoutOptions {
|
|
57
54
|
startX: number;
|
|
@@ -496,9 +496,11 @@ export declare function createEditorController(initial?: EditorState, options?:
|
|
|
496
496
|
/** 시점 복원 transport(`restoreEntityDiagram` 라우트). 주입 + op-mode + editable 시 감사 패널 '복원' 활성. */
|
|
497
497
|
restoreTransport?: RestoreTransport;
|
|
498
498
|
/**
|
|
499
|
-
* op 전송 실패(4xx/5xx/네트워크로 transport가 throw) 통지 — 진단용(opt-in).
|
|
500
|
-
*
|
|
501
|
-
*
|
|
499
|
+
* op 전송 실패(4xx/5xx/네트워크로 transport가 throw) 통지 — 진단용(opt-in). 이 콜백은 소실될 원
|
|
500
|
+
* 에러를 호스트가 로깅/리포팅하도록 넘긴다. 미주입이어도 어댑터가 콘솔에 남긴다(정상 rev 충돌은
|
|
501
|
+
* 이 경로가 아님 — throw만).
|
|
502
|
+
* ⚠️ **발화 ≠ 프리즈**: 어댑터가 제한 재시도하므로 회복되는 시도도 통지된다(시도마다 1회).
|
|
503
|
+
* 하드 프리즈는 재시도 소진 후에만 발생하며 `opConflict.kind='missing'`으로 별도 노출된다.
|
|
502
504
|
*/
|
|
503
505
|
onOpError?: (err: unknown) => void;
|
|
504
506
|
/**
|