@things-factory/headless-twin 10.1.8 → 10.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.d.ts +5 -0
- package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js +44 -0
- package/dist-server/migrations/1786800000000-CreateTwinReferenceReconciliations.js.map +1 -0
- package/dist-server/migrations/index.js +3 -1
- package/dist-server/migrations/index.js.map +1 -1
- package/dist-server/service/index.d.ts +4 -2
- package/dist-server/service/index.js +2 -0
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/reference/index.d.ts +5 -2
- package/dist-server/service/reference/index.js +5 -2
- package/dist-server/service/reference/index.js.map +1 -1
- package/dist-server/service/reference/reference-fill-run.js +13 -0
- package/dist-server/service/reference/reference-fill-run.js.map +1 -1
- package/dist-server/service/reference/reference-reconciliation-query.d.ts +5 -0
- package/dist-server/service/reference/reference-reconciliation-query.js +42 -0
- package/dist-server/service/reference/reference-reconciliation-query.js.map +1 -0
- package/dist-server/service/reference/reference-reconciliation-writer.d.ts +10 -0
- package/dist-server/service/reference/reference-reconciliation-writer.js +33 -0
- package/dist-server/service/reference/reference-reconciliation-writer.js.map +1 -0
- package/dist-server/service/reference/reference-reconciliation.d.ts +19 -0
- package/dist-server/service/reference/reference-reconciliation.js +33 -0
- package/dist-server/service/reference/reference-reconciliation.js.map +1 -0
- package/dist-server/service/reference/twin-reference-reconciliation.d.ts +19 -0
- package/dist-server/service/reference/twin-reference-reconciliation.js +95 -0
- package/dist-server/service/reference/twin-reference-reconciliation.js.map +1 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +9 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +41 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -1
- package/package.json +2 -2
- package/server/migrations/1786800000000-CreateTwinReferenceReconciliations.ts +39 -0
- package/server/migrations/index.ts +3 -1
- package/server/service/index.ts +2 -0
- package/server/service/reference/index.ts +5 -2
- package/server/service/reference/reference-fill-run.ts +15 -1
- package/server/service/reference/reference-reconciliation-query.ts +28 -0
- package/server/service/reference/reference-reconciliation-writer.ts +38 -0
- package/server/service/reference/reference-reconciliation.ts +55 -0
- package/server/service/reference/twin-reference-reconciliation.ts +27 -0
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +38 -0
- package/test/reference-reconciliation.test.ts +39 -0
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -6,6 +6,7 @@ import { TwinEngine } from '../../engine/index.js'
|
|
|
6
6
|
/* 정책 읽기는 그 모듈에서 직접 가져온다 — 다른 소비처(`reference-resolver`)와 같은 길이다. */
|
|
7
7
|
import { readRestartPolicy } from '../../engine/restart-policy.js'
|
|
8
8
|
import { TwinInstance } from '../twin-instance/twin-instance.js'
|
|
9
|
+
import { TwinEvent } from '../twin-event/twin-event.js'
|
|
9
10
|
|
|
10
11
|
import type { TwinModelDef } from '@operato/ops-contract'
|
|
11
12
|
|
|
@@ -160,6 +161,43 @@ export class TwinLifecycleMutation {
|
|
|
160
161
|
return { instanceId, name: next, previous: before || null, changed: true }
|
|
161
162
|
}
|
|
162
163
|
|
|
164
|
+
/**
|
|
165
|
+
* 폐기 전에 사라질 것을 읽는다.
|
|
166
|
+
*
|
|
167
|
+
* 삭제는 레지스트리 행 하나만 없애는 일이 아니다. `TwinEngine.remove` 는 같은 트윈의 저널도
|
|
168
|
+
* purge 한다. 그래서 확인 창이 추측한 숫자를 쓰지 않고, **삭제와 같은 domain·instance 범위**를
|
|
169
|
+
* 직접 센다. 저널이 비어 있는 트윈도 `0` 과 null 기간을 돌려준다 — 없는 기록을 기간으로
|
|
170
|
+
* 꾸며내면 "아무것도 안 지워진다"와 "언제부터인지 모른다"가 섞인다.
|
|
171
|
+
*/
|
|
172
|
+
@Query(returns => ScalarObject, {
|
|
173
|
+
nullable: true,
|
|
174
|
+
description:
|
|
175
|
+
'Describe what deleting one twin would purge before it is deleted: its registry identity and the count plus first/last event time of its journal. Null means this twin is not in the current domain.'
|
|
176
|
+
})
|
|
177
|
+
async twinDeletionPreview(@Arg('instanceId') instanceId: string, @Ctx() context: ResolverContext): Promise<any | null> {
|
|
178
|
+
const domainId = context.state.domain.id
|
|
179
|
+
const instance = await getRepository(TwinInstance).findOne({ where: { domain: { id: domainId }, instanceId } })
|
|
180
|
+
|
|
181
|
+
if (!instance) return null
|
|
182
|
+
|
|
183
|
+
const journal = await getRepository(TwinEvent)
|
|
184
|
+
.createQueryBuilder('event')
|
|
185
|
+
.select('COUNT(event.id)', 'count')
|
|
186
|
+
.addSelect('MIN(event.eventTime)', 'firstEventAt')
|
|
187
|
+
.addSelect('MAX(event.eventTime)', 'lastEventAt')
|
|
188
|
+
.where('event.domain = :domainId', { domainId })
|
|
189
|
+
.andWhere('event.instanceId = :instanceId', { instanceId })
|
|
190
|
+
.getRawOne<{ count?: string | number; firstEventAt?: unknown; lastEventAt?: unknown }>()
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
instanceId,
|
|
194
|
+
name: instance.name ?? null,
|
|
195
|
+
journalCount: Number(journal?.count ?? 0),
|
|
196
|
+
firstEventAt: journal?.firstEventAt ?? null,
|
|
197
|
+
lastEventAt: journal?.lastEventAt ?? null
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
163
201
|
/** 삭제 — 정지 + 레지스트리 삭제 + 저널 purge(domain 스코프). */
|
|
164
202
|
@Directive('@privilege(category: "twin", privilege: "mutation", domainOwnerGranted: true, superUserGranted: true)')
|
|
165
203
|
@Mutation(returns => Boolean, { description: 'Delete a twin instance: stop it, remove the registry entry and purge its event journal.' })
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import test from 'node:test'
|
|
3
|
+
import { readFileSync } from 'node:fs'
|
|
4
|
+
import { join } from 'node:path'
|
|
5
|
+
import { reconcileReferenceSequence } from '../server/service/reference/reference-reconciliation.ts'
|
|
6
|
+
|
|
7
|
+
test('reports work waiting after the Twin cursor', () => {
|
|
8
|
+
const got = reconcileReferenceSequence({ source: { first: 1, last: 48 }, cursorSeq: 30, firstSeqSeen: 1 })
|
|
9
|
+
assert.equal(got.status, 'gap')
|
|
10
|
+
assert.equal(got.behind, 18)
|
|
11
|
+
assert.equal(got.headMissing, undefined)
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('reports the leading range only when the first received sequence proves it', () => {
|
|
15
|
+
const got = reconcileReferenceSequence({ source: { first: 1, last: 48 }, cursorSeq: 48, firstSeqSeen: 21 })
|
|
16
|
+
assert.equal(got.status, 'gap')
|
|
17
|
+
assert.equal(got.headMissing, 20)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('does not claim alignment when the source range or first received sequence is unknown', () => {
|
|
21
|
+
assert.equal(reconcileReferenceSequence({ source: { first: 1 }, cursorSeq: 1, firstSeqSeen: 1 }).status, 'unknown')
|
|
22
|
+
assert.equal(reconcileReferenceSequence({ source: { first: 1, last: 1 }, cursorSeq: 1 }).status, 'unknown')
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
test('reports alignment only with both source bounds and a recorded first sequence', () => {
|
|
26
|
+
const got = reconcileReferenceSequence({ source: { first: 1, last: 48 }, cursorSeq: 48, firstSeqSeen: 1 })
|
|
27
|
+
assert.equal(got.status, 'aligned')
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
test('registers the durable reconciliation table and its migration', () => {
|
|
31
|
+
const root = join(import.meta.dirname, '..', 'server')
|
|
32
|
+
const migration = readFileSync(join(root, 'migrations', '1786800000000-CreateTwinReferenceReconciliations.ts'), 'utf8')
|
|
33
|
+
const list = readFileSync(join(root, 'migrations', 'index.ts'), 'utf8')
|
|
34
|
+
const referenceIndex = readFileSync(join(root, 'service', 'reference', 'index.ts'), 'utf8')
|
|
35
|
+
assert.match(migration, /twin_reference_reconciliations/)
|
|
36
|
+
assert.match(migration, /uq_twin_reference_reconciliation_0/)
|
|
37
|
+
assert.match(list, /CreateTwinReferenceReconciliations1786800000000/)
|
|
38
|
+
assert.match(referenceIndex, /TwinReferenceReconciliation/)
|
|
39
|
+
})
|