@things-factory/headless-twin 10.0.0-zeta.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/README.md +35 -0
- package/dist-server/engine/index.d.ts +1 -0
- package/dist-server/engine/index.js +5 -0
- package/dist-server/engine/index.js.map +1 -0
- package/dist-server/engine/twin-engine.d.ts +34 -0
- package/dist-server/engine/twin-engine.js +135 -0
- package/dist-server/engine/twin-engine.js.map +1 -0
- package/dist-server/index.d.ts +3 -0
- package/dist-server/index.js +18 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/routes.d.ts +0 -0
- package/dist-server/routes.js +6 -0
- package/dist-server/routes.js.map +1 -0
- package/dist-server/service/index.d.ts +10 -0
- package/dist-server/service/index.js +33 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/twin-control/index.d.ts +2 -0
- package/dist-server/service/twin-control/index.js +6 -0
- package/dist-server/service/twin-control/index.js.map +1 -0
- package/dist-server/service/twin-control/twin-control-mutation.d.ts +6 -0
- package/dist-server/service/twin-control/twin-control-mutation.js +59 -0
- package/dist-server/service/twin-control/twin-control-mutation.js.map +1 -0
- package/dist-server/service/twin-event/index.d.ts +2 -0
- package/dist-server/service/twin-event/index.js +6 -0
- package/dist-server/service/twin-event/index.js.map +1 -0
- package/dist-server/service/twin-event/twin-event.d.ts +13 -0
- package/dist-server/service/twin-event/twin-event.js +72 -0
- package/dist-server/service/twin-event/twin-event.js.map +1 -0
- package/dist-server/service/twin-instance/index.d.ts +2 -0
- package/dist-server/service/twin-instance/index.js +6 -0
- package/dist-server/service/twin-instance/index.js.map +1 -0
- package/dist-server/service/twin-instance/twin-instance.d.ts +13 -0
- package/dist-server/service/twin-instance/twin-instance.js +72 -0
- package/dist-server/service/twin-instance/twin-instance.js.map +1 -0
- package/dist-server/service/twin-journal/index.d.ts +2 -0
- package/dist-server/service/twin-journal/index.js +6 -0
- package/dist-server/service/twin-journal/index.js.map +1 -0
- package/dist-server/service/twin-journal/twin-journal-query.d.ts +5 -0
- package/dist-server/service/twin-journal/twin-journal-query.js +64 -0
- package/dist-server/service/twin-journal/twin-journal-query.js.map +1 -0
- package/dist-server/service/twin-lifecycle/index.d.ts +2 -0
- package/dist-server/service/twin-lifecycle/index.js +6 -0
- package/dist-server/service/twin-lifecycle/index.js.map +1 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.d.ts +5 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js +60 -0
- package/dist-server/service/twin-lifecycle/twin-lifecycle-mutation.js.map +1 -0
- package/dist-server/service/twin-state/index.d.ts +2 -0
- package/dist-server/service/twin-state/index.js +6 -0
- package/dist-server/service/twin-state/index.js.map +1 -0
- package/dist-server/service/twin-state/twin-state-subscription.d.ts +11 -0
- package/dist-server/service/twin-state/twin-state-subscription.js +67 -0
- package/dist-server/service/twin-state/twin-state-subscription.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/package.json +33 -0
- package/server/engine/index.ts +1 -0
- package/server/engine/twin-engine.ts +160 -0
- package/server/index.ts +16 -0
- package/server/routes.ts +5 -0
- package/server/service/index.ts +32 -0
- package/server/service/twin-control/index.ts +3 -0
- package/server/service/twin-control/twin-control-mutation.ts +41 -0
- package/server/service/twin-event/index.ts +3 -0
- package/server/service/twin-event/twin-event.ts +55 -0
- package/server/service/twin-instance/index.ts +3 -0
- package/server/service/twin-instance/twin-instance.ts +55 -0
- package/server/service/twin-journal/index.ts +3 -0
- package/server/service/twin-journal/twin-journal-query.ts +49 -0
- package/server/service/twin-lifecycle/index.ts +3 -0
- package/server/service/twin-lifecycle/twin-lifecycle-mutation.ts +44 -0
- package/server/service/twin-state/index.ts +3 -0
- package/server/service/twin-state/twin-state-subscription.ts +53 -0
- package/server/types/global.d.ts +22 -0
- package/things-factory.config.js +2 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TwinInstance = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
/*
|
|
9
|
+
* TwinInstance — 트윈 인스턴스 레지스트리(재부팅 복구의 앵커).
|
|
10
|
+
* 복구(DB→replay)는 board(마스터 청사진)가 있어야 이벤트를 상태로 되짚을 수 있다 → board·kind 를 영속.
|
|
11
|
+
* 이벤트(TwinEvent)와 달리 가변(status/revision 갱신) — 인스턴스의 "현재 등록 상태".
|
|
12
|
+
* board 는 simple-json(멀티DB 이식 — postgres/mysql/sqlite/mssql/oracle 공통).
|
|
13
|
+
* (CLAUDE.md: 모든 @ObjectType/@Field 는 영문 description 필수.)
|
|
14
|
+
*/
|
|
15
|
+
let TwinInstance = class TwinInstance {
|
|
16
|
+
};
|
|
17
|
+
exports.TwinInstance = TwinInstance;
|
|
18
|
+
tslib_1.__decorate([
|
|
19
|
+
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
|
20
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.ID, { description: 'Unique identifier of the registry record.' }),
|
|
21
|
+
tslib_1.__metadata("design:type", String)
|
|
22
|
+
], TwinInstance.prototype, "id", void 0);
|
|
23
|
+
tslib_1.__decorate([
|
|
24
|
+
(0, typeorm_1.ManyToOne)(type => shell_1.Domain),
|
|
25
|
+
(0, type_graphql_1.Field)(type => shell_1.Domain, { nullable: true, description: 'Owning tenant domain.' }),
|
|
26
|
+
tslib_1.__metadata("design:type", shell_1.Domain)
|
|
27
|
+
], TwinInstance.prototype, "domain", void 0);
|
|
28
|
+
tslib_1.__decorate([
|
|
29
|
+
(0, typeorm_1.RelationId)((e) => e.domain),
|
|
30
|
+
tslib_1.__metadata("design:type", String)
|
|
31
|
+
], TwinInstance.prototype, "domainId", void 0);
|
|
32
|
+
tslib_1.__decorate([
|
|
33
|
+
(0, typeorm_1.Column)(),
|
|
34
|
+
(0, type_graphql_1.Field)({ description: 'Twin runtime instance id (unique within a domain).' }),
|
|
35
|
+
tslib_1.__metadata("design:type", String)
|
|
36
|
+
], TwinInstance.prototype, "instanceId", void 0);
|
|
37
|
+
tslib_1.__decorate([
|
|
38
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
39
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Domain kernel kind: wms | yms | mes.' }),
|
|
40
|
+
tslib_1.__metadata("design:type", String)
|
|
41
|
+
], TwinInstance.prototype, "kind", void 0);
|
|
42
|
+
tslib_1.__decorate([
|
|
43
|
+
(0, typeorm_1.Column)({ type: 'simple-json', nullable: true }),
|
|
44
|
+
(0, type_graphql_1.Field)(type => shell_1.ScalarObject, { nullable: true, description: 'BoardDef blueprint (nodes/movers) required to replay events into state.' }),
|
|
45
|
+
tslib_1.__metadata("design:type", Object)
|
|
46
|
+
], TwinInstance.prototype, "board", void 0);
|
|
47
|
+
tslib_1.__decorate([
|
|
48
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
49
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Lifecycle status: running | stopped.' }),
|
|
50
|
+
tslib_1.__metadata("design:type", String)
|
|
51
|
+
], TwinInstance.prototype, "status", void 0);
|
|
52
|
+
tslib_1.__decorate([
|
|
53
|
+
(0, typeorm_1.Column)({ type: 'int', nullable: true }),
|
|
54
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'Last persisted state revision observed for this instance.' }),
|
|
55
|
+
tslib_1.__metadata("design:type", Number)
|
|
56
|
+
], TwinInstance.prototype, "revision", void 0);
|
|
57
|
+
tslib_1.__decorate([
|
|
58
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
59
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Timestamp when the instance was first registered.' }),
|
|
60
|
+
tslib_1.__metadata("design:type", Date)
|
|
61
|
+
], TwinInstance.prototype, "createdAt", void 0);
|
|
62
|
+
tslib_1.__decorate([
|
|
63
|
+
(0, typeorm_1.UpdateDateColumn)(),
|
|
64
|
+
(0, type_graphql_1.Field)({ nullable: true, description: 'Timestamp when the instance registry row was last updated.' }),
|
|
65
|
+
tslib_1.__metadata("design:type", Date)
|
|
66
|
+
], TwinInstance.prototype, "updatedAt", void 0);
|
|
67
|
+
exports.TwinInstance = TwinInstance = tslib_1.__decorate([
|
|
68
|
+
(0, typeorm_1.Entity)(),
|
|
69
|
+
(0, typeorm_1.Index)('ix_twin_instance_0', (e) => [e.domain, e.instanceId], { unique: true }),
|
|
70
|
+
(0, type_graphql_1.ObjectType)({ description: 'Registry of a hosted twin runtime instance — anchors reboot recovery (board + kind).' })
|
|
71
|
+
], TwinInstance);
|
|
72
|
+
//# sourceMappingURL=twin-instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twin-instance.js","sourceRoot":"","sources":["../../../server/service/twin-instance/twin-instance.ts"],"names":[],"mappings":";;;;AAAA,qCAAkI;AAClI,+CAAyD;AAEzD,iDAA4D;AAE5D;;;;;;GAMG;AAII,IAAM,YAAY,GAAlB,MAAM,YAAY;CAuCxB,CAAA;AAvCY,oCAAY;AAGd;IAFR,IAAA,gCAAsB,EAAC,MAAM,CAAC;IAC9B,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,iBAAE,EAAE,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC;;wCAC7D;AAInB;IAFC,IAAA,mBAAS,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,CAAC;IACzB,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,cAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;sCACvE,cAAM;4CAAA;AAGf;IADC,IAAA,oBAAU,EAAC,CAAC,CAAe,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;;8CACzB;AAIjB;IAFC,IAAA,gBAAM,GAAE;IACR,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,oDAAoD,EAAE,CAAC;;gDAC3D;AAIlB;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;;0CAClE;AAIb;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC/C,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,yEAAyE,EAAE,CAAC;;2CAC7H;AAIX;IAFC,IAAA,gBAAM,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1B,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,sCAAsC,EAAE,CAAC;;4CAChE;AAIf;IAFC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2DAA2D,EAAE,CAAC;;8CAChG;AAIjB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;sCAChF,IAAI;+CAAA;AAIhB;IAFC,IAAA,0BAAgB,GAAE;IAClB,IAAA,oBAAK,EAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,4DAA4D,EAAE,CAAC;sCACzF,IAAI;+CAAA;uBAtCL,YAAY;IAHxB,IAAA,gBAAM,GAAE;IACR,IAAA,eAAK,EAAC,oBAAoB,EAAE,CAAC,CAAe,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC5F,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,sFAAsF,EAAE,CAAC;GACvG,YAAY,CAuCxB","sourcesContent":["import { CreateDateColumn, Entity, Index, Column, RelationId, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm'\nimport { ObjectType, Field, ID, Int } from 'type-graphql'\n\nimport { Domain, ScalarObject } from '@things-factory/shell'\n\n/*\n * TwinInstance — 트윈 인스턴스 레지스트리(재부팅 복구의 앵커).\n * 복구(DB→replay)는 board(마스터 청사진)가 있어야 이벤트를 상태로 되짚을 수 있다 → board·kind 를 영속.\n * 이벤트(TwinEvent)와 달리 가변(status/revision 갱신) — 인스턴스의 \"현재 등록 상태\".\n * board 는 simple-json(멀티DB 이식 — postgres/mysql/sqlite/mssql/oracle 공통).\n * (CLAUDE.md: 모든 @ObjectType/@Field 는 영문 description 필수.)\n */\n@Entity()\n@Index('ix_twin_instance_0', (e: TwinInstance) => [e.domain, e.instanceId], { unique: true })\n@ObjectType({ description: 'Registry of a hosted twin runtime instance — anchors reboot recovery (board + kind).' })\nexport class TwinInstance {\n @PrimaryGeneratedColumn('uuid')\n @Field(type => ID, { description: 'Unique identifier of the registry record.' })\n readonly id: string\n\n @ManyToOne(type => Domain)\n @Field(type => Domain, { nullable: true, description: 'Owning tenant domain.' })\n domain?: Domain\n\n @RelationId((e: TwinInstance) => e.domain)\n domainId?: string\n\n @Column()\n @Field({ description: 'Twin runtime instance id (unique within a domain).' })\n instanceId: string\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Domain kernel kind: wms | yms | mes.' })\n kind?: string\n\n @Column({ type: 'simple-json', nullable: true })\n @Field(type => ScalarObject, { nullable: true, description: 'BoardDef blueprint (nodes/movers) required to replay events into state.' })\n board?: any\n\n @Column({ nullable: true })\n @Field({ nullable: true, description: 'Lifecycle status: running | stopped.' })\n status?: string\n\n @Column({ type: 'int', nullable: true })\n @Field(type => Int, { nullable: true, description: 'Last persisted state revision observed for this instance.' })\n revision?: number\n\n @CreateDateColumn()\n @Field({ nullable: true, description: 'Timestamp when the instance was first registered.' })\n createdAt?: Date\n\n @UpdateDateColumn()\n @Field({ nullable: true, description: 'Timestamp when the instance registry row was last updated.' })\n updatedAt?: Date\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvers = void 0;
|
|
4
|
+
const twin_journal_query_js_1 = require("./twin-journal-query.js");
|
|
5
|
+
exports.resolvers = [twin_journal_query_js_1.TwinJournalQuery];
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-journal/index.ts"],"names":[],"mappings":";;;AAAA,mEAA0D;AAE7C,QAAA,SAAS,GAAG,CAAC,wCAAgB,CAAC,CAAA","sourcesContent":["import { TwinJournalQuery } from './twin-journal-query.js'\n\nexport const resolvers = [TwinJournalQuery]\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { TwinEvent } from '../twin-event/twin-event.js';
|
|
2
|
+
export declare class TwinJournalQuery {
|
|
3
|
+
twinEvents(instanceId: string, fromRevision: number, toRevision: number, eventType: string, limit: number, context: ResolverContext): Promise<TwinEvent[]>;
|
|
4
|
+
twinReplay(instanceId: string, untilRevision: number, context: ResolverContext): Promise<any>;
|
|
5
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TwinJournalQuery = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const twin_event_js_1 = require("../twin-event/twin-event.js");
|
|
9
|
+
const index_js_1 = require("../../engine/index.js");
|
|
10
|
+
/*
|
|
11
|
+
* 저널 읽기 채널 — 상향 query.
|
|
12
|
+
* twinEvents : append-only 이벤트 저널 조회(Ledger/History/Entity360) — instanceId·revision 범위·eventType 필터.
|
|
13
|
+
* twinReplay : 내구 저널을 replay 해 상태 재구성(재부팅 복구·시간여행) — untilRevision 으로 임의 과거.
|
|
14
|
+
* (실시간 스트림은 twinState subscription, 명령은 twin-control mutation. 이건 '질의' 표면.)
|
|
15
|
+
*/
|
|
16
|
+
let TwinJournalQuery = class TwinJournalQuery {
|
|
17
|
+
async twinEvents(instanceId, fromRevision, toRevision, eventType, limit, context) {
|
|
18
|
+
const where = { domain: { id: context.state.domain.id }, instanceId };
|
|
19
|
+
if (eventType)
|
|
20
|
+
where.eventType = eventType;
|
|
21
|
+
if (fromRevision != null && toRevision != null)
|
|
22
|
+
where.revision = (0, typeorm_1.Between)(fromRevision, toRevision);
|
|
23
|
+
else if (fromRevision != null)
|
|
24
|
+
where.revision = (0, typeorm_1.MoreThanOrEqual)(fromRevision);
|
|
25
|
+
else if (toRevision != null)
|
|
26
|
+
where.revision = (0, typeorm_1.LessThanOrEqual)(toRevision);
|
|
27
|
+
/* 최신순(DESC) 기본 — Ledger/recent 뷰. 범위 필터로 시간여행 구간 조회도 가능. */
|
|
28
|
+
return (0, shell_1.getRepository)(twin_event_js_1.TwinEvent).find({ where, order: { revision: 'DESC' }, take: limit ?? 200 });
|
|
29
|
+
}
|
|
30
|
+
async twinReplay(instanceId, untilRevision, context) {
|
|
31
|
+
return index_js_1.TwinEngine.recover(context.state.domain.id, instanceId, untilRevision ?? undefined);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
exports.TwinJournalQuery = TwinJournalQuery;
|
|
35
|
+
tslib_1.__decorate([
|
|
36
|
+
(0, type_graphql_1.Query)(returns => [twin_event_js_1.TwinEvent], {
|
|
37
|
+
description: 'Read the append-only twin event journal (Ledger / History / audit), filtered and ordered by revision.'
|
|
38
|
+
}),
|
|
39
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
|
|
40
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('fromRevision', type => type_graphql_1.Int, { nullable: true })),
|
|
41
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('toRevision', type => type_graphql_1.Int, { nullable: true })),
|
|
42
|
+
tslib_1.__param(3, (0, type_graphql_1.Arg)('eventType', { nullable: true })),
|
|
43
|
+
tslib_1.__param(4, (0, type_graphql_1.Arg)('limit', type => type_graphql_1.Int, { nullable: true })),
|
|
44
|
+
tslib_1.__param(5, (0, type_graphql_1.Ctx)()),
|
|
45
|
+
tslib_1.__metadata("design:type", Function),
|
|
46
|
+
tslib_1.__metadata("design:paramtypes", [String, Number, Number, String, Number, Object]),
|
|
47
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
48
|
+
], TwinJournalQuery.prototype, "twinEvents", null);
|
|
49
|
+
tslib_1.__decorate([
|
|
50
|
+
(0, type_graphql_1.Query)(returns => shell_1.ScalarObject, {
|
|
51
|
+
nullable: true,
|
|
52
|
+
description: 'Reconstruct twin state from the durable journal (DB → replay). untilRevision for time-travel; omit for latest.'
|
|
53
|
+
}),
|
|
54
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
|
|
55
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('untilRevision', type => type_graphql_1.Int, { nullable: true })),
|
|
56
|
+
tslib_1.__param(2, (0, type_graphql_1.Ctx)()),
|
|
57
|
+
tslib_1.__metadata("design:type", Function),
|
|
58
|
+
tslib_1.__metadata("design:paramtypes", [String, Number, Object]),
|
|
59
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
60
|
+
], TwinJournalQuery.prototype, "twinReplay", null);
|
|
61
|
+
exports.TwinJournalQuery = TwinJournalQuery = tslib_1.__decorate([
|
|
62
|
+
(0, type_graphql_1.Resolver)()
|
|
63
|
+
], TwinJournalQuery);
|
|
64
|
+
//# sourceMappingURL=twin-journal-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twin-journal-query.js","sourceRoot":"","sources":["../../../server/service/twin-journal/twin-journal-query.ts"],"names":[],"mappings":";;;;AAAA,qCAAmE;AACnE,+CAA6D;AAE7D,iDAAmE;AAEnE,+DAAuD;AACvD,oDAAkD;AAElD;;;;;GAKG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;IAIrB,AAAN,KAAK,CAAC,UAAU,CACK,UAAkB,EACiB,YAAoB,EACtB,UAAkB,EAChC,SAAiB,EACR,KAAa,EACrD,OAAwB;QAE/B,MAAM,KAAK,GAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAA;QAC1E,IAAI,SAAS;YAAE,KAAK,CAAC,SAAS,GAAG,SAAS,CAAA;QAC1C,IAAI,YAAY,IAAI,IAAI,IAAI,UAAU,IAAI,IAAI;YAAE,KAAK,CAAC,QAAQ,GAAG,IAAA,iBAAO,EAAC,YAAY,EAAE,UAAU,CAAC,CAAA;aAC7F,IAAI,YAAY,IAAI,IAAI;YAAE,KAAK,CAAC,QAAQ,GAAG,IAAA,yBAAe,EAAC,YAAY,CAAC,CAAA;aACxE,IAAI,UAAU,IAAI,IAAI;YAAE,KAAK,CAAC,QAAQ,GAAG,IAAA,yBAAe,EAAC,UAAU,CAAC,CAAA;QAEzE,4DAA4D;QAC5D,OAAO,IAAA,qBAAa,EAAC,yBAAS,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,KAAK,IAAI,GAAG,EAAE,CAAC,CAAA;IAClG,CAAC;IAMK,AAAN,KAAK,CAAC,UAAU,CACK,UAAkB,EACkB,aAAqB,EACrE,OAAwB;QAE/B,OAAO,qBAAU,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,UAAU,EAAE,aAAa,IAAI,SAAS,CAAC,CAAA;IAC5F,CAAC;CACF,CAAA;AAjCY,4CAAgB;AAIrB;IAHL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,yBAAS,CAAC,EAAE;QAC7B,WAAW,EAAE,uGAAuG;KACrH,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IACjB,mBAAA,IAAA,kBAAG,EAAC,cAAc,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACpD,mBAAA,IAAA,kBAAG,EAAC,YAAY,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAClD,mBAAA,IAAA,kBAAG,EAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACpC,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;kDAUP;AAMK;IAJL,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,oBAAY,EAAE;QAC9B,QAAQ,EAAE,IAAI;QACd,WAAW,EAAE,gHAAgH;KAC9H,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IACjB,mBAAA,IAAA,kBAAG,EAAC,eAAe,EAAE,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IACrD,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;kDAGP;2BAhCU,gBAAgB;IAD5B,IAAA,uBAAQ,GAAE;GACE,gBAAgB,CAiC5B","sourcesContent":["import { Between, LessThanOrEqual, MoreThanOrEqual } from 'typeorm'\nimport { Arg, Ctx, Int, Query, Resolver } from 'type-graphql'\n\nimport { getRepository, ScalarObject } from '@things-factory/shell'\n\nimport { TwinEvent } from '../twin-event/twin-event.js'\nimport { TwinEngine } from '../../engine/index.js'\n\n/*\n * 저널 읽기 채널 — 상향 query.\n * twinEvents : append-only 이벤트 저널 조회(Ledger/History/Entity360) — instanceId·revision 범위·eventType 필터.\n * twinReplay : 내구 저널을 replay 해 상태 재구성(재부팅 복구·시간여행) — untilRevision 으로 임의 과거.\n * (실시간 스트림은 twinState subscription, 명령은 twin-control mutation. 이건 '질의' 표면.)\n */\n@Resolver()\nexport class TwinJournalQuery {\n @Query(returns => [TwinEvent], {\n description: 'Read the append-only twin event journal (Ledger / History / audit), filtered and ordered by revision.'\n })\n async twinEvents(\n @Arg('instanceId') instanceId: string,\n @Arg('fromRevision', type => Int, { nullable: true }) fromRevision: number,\n @Arg('toRevision', type => Int, { nullable: true }) toRevision: number,\n @Arg('eventType', { nullable: true }) eventType: string,\n @Arg('limit', type => Int, { nullable: true }) limit: number,\n @Ctx() context: ResolverContext\n ): Promise<TwinEvent[]> {\n const where: any = { domain: { id: context.state.domain.id }, instanceId }\n if (eventType) where.eventType = eventType\n if (fromRevision != null && toRevision != null) where.revision = Between(fromRevision, toRevision)\n else if (fromRevision != null) where.revision = MoreThanOrEqual(fromRevision)\n else if (toRevision != null) where.revision = LessThanOrEqual(toRevision)\n\n /* 최신순(DESC) 기본 — Ledger/recent 뷰. 범위 필터로 시간여행 구간 조회도 가능. */\n return getRepository(TwinEvent).find({ where, order: { revision: 'DESC' }, take: limit ?? 200 })\n }\n\n @Query(returns => ScalarObject, {\n nullable: true,\n description: 'Reconstruct twin state from the durable journal (DB → replay). untilRevision for time-travel; omit for latest.'\n })\n async twinReplay(\n @Arg('instanceId') instanceId: string,\n @Arg('untilRevision', type => Int, { nullable: true }) untilRevision: number,\n @Ctx() context: ResolverContext\n ): Promise<any> {\n return TwinEngine.recover(context.state.domain.id, instanceId, untilRevision ?? undefined)\n }\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvers = void 0;
|
|
4
|
+
const twin_lifecycle_mutation_js_1 = require("./twin-lifecycle-mutation.js");
|
|
5
|
+
exports.resolvers = [twin_lifecycle_mutation_js_1.TwinLifecycleMutation];
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-lifecycle/index.ts"],"names":[],"mappings":";;;AAAA,6EAAoE;AAEvD,QAAA,SAAS,GAAG,CAAC,kDAAqB,CAAC,CAAA","sourcesContent":["import { TwinLifecycleMutation } from './twin-lifecycle-mutation.js'\n\nexport const resolvers = [TwinLifecycleMutation]\n"]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TwinLifecycleMutation = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const type_graphql_1 = require("type-graphql");
|
|
6
|
+
const shell_1 = require("@things-factory/shell");
|
|
7
|
+
const index_js_1 = require("../../engine/index.js");
|
|
8
|
+
/*
|
|
9
|
+
* 트윈 인스턴스 생명주기 채널 — 프로비저닝(상향).
|
|
10
|
+
* State/Command/Scenario 는 이미 running 인 인스턴스를 다루지만, 이 채널은 인스턴스 자체를 만들고/없앤다.
|
|
11
|
+
* (TwinEngine.start/stop 을 GraphQL 로 노출 — 설계 Tier-1 갭: 커널은 start/stop 을 가졌으나 진입점이 없었다.)
|
|
12
|
+
* board(BoardDef)=구조, scenario=자극 은 분리 — 여기선 구조만 세운다. 자극은 controlTwinScenario 로.
|
|
13
|
+
*/
|
|
14
|
+
let TwinLifecycleMutation = class TwinLifecycleMutation {
|
|
15
|
+
async startTwinInstance(instanceId, kind, board, context) {
|
|
16
|
+
index_js_1.TwinEngine.start(instanceId, context.state.domain.id, kind, board);
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
async stopTwinInstance(instanceId) {
|
|
20
|
+
await index_js_1.TwinEngine.stop(instanceId);
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
twinInstances() {
|
|
24
|
+
return Object.keys(index_js_1.TwinEngine.instances);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
exports.TwinLifecycleMutation = TwinLifecycleMutation;
|
|
28
|
+
tslib_1.__decorate([
|
|
29
|
+
(0, type_graphql_1.Mutation)(returns => Boolean, {
|
|
30
|
+
description: 'Provision and start a twin runtime instance (kind: wms|yms|mes) from a BoardDef, and begin the worker tick.'
|
|
31
|
+
}),
|
|
32
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
|
|
33
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('kind')),
|
|
34
|
+
tslib_1.__param(2, (0, type_graphql_1.Arg)('board', type => shell_1.ScalarObject)),
|
|
35
|
+
tslib_1.__param(3, (0, type_graphql_1.Ctx)()),
|
|
36
|
+
tslib_1.__metadata("design:type", Function),
|
|
37
|
+
tslib_1.__metadata("design:paramtypes", [String, String, Object, Object]),
|
|
38
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
39
|
+
], TwinLifecycleMutation.prototype, "startTwinInstance", null);
|
|
40
|
+
tslib_1.__decorate([
|
|
41
|
+
(0, type_graphql_1.Mutation)(returns => Boolean, {
|
|
42
|
+
description: 'Stop and dispose a running twin runtime instance by its id.'
|
|
43
|
+
}),
|
|
44
|
+
tslib_1.__param(0, (0, type_graphql_1.Arg)('instanceId')),
|
|
45
|
+
tslib_1.__metadata("design:type", Function),
|
|
46
|
+
tslib_1.__metadata("design:paramtypes", [String]),
|
|
47
|
+
tslib_1.__metadata("design:returntype", Promise)
|
|
48
|
+
], TwinLifecycleMutation.prototype, "stopTwinInstance", null);
|
|
49
|
+
tslib_1.__decorate([
|
|
50
|
+
(0, type_graphql_1.Query)(returns => [String], {
|
|
51
|
+
description: 'List ids of currently running twin runtime instances.'
|
|
52
|
+
}),
|
|
53
|
+
tslib_1.__metadata("design:type", Function),
|
|
54
|
+
tslib_1.__metadata("design:paramtypes", []),
|
|
55
|
+
tslib_1.__metadata("design:returntype", Array)
|
|
56
|
+
], TwinLifecycleMutation.prototype, "twinInstances", null);
|
|
57
|
+
exports.TwinLifecycleMutation = TwinLifecycleMutation = tslib_1.__decorate([
|
|
58
|
+
(0, type_graphql_1.Resolver)()
|
|
59
|
+
], TwinLifecycleMutation);
|
|
60
|
+
//# sourceMappingURL=twin-lifecycle-mutation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twin-lifecycle-mutation.js","sourceRoot":"","sources":["../../../server/service/twin-lifecycle/twin-lifecycle-mutation.ts"],"names":[],"mappings":";;;;AAAA,+CAAkE;AAElE,iDAAoD;AAEpD,oDAAkD;AAIlD;;;;;GAKG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAI1B,AAAN,KAAK,CAAC,iBAAiB,CACF,UAAkB,EACxB,IAAY,EACW,KAAU,EACvC,OAAwB;QAE/B,qBAAU,CAAC,KAAK,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAiB,CAAC,CAAA;QAC9E,OAAO,IAAI,CAAA;IACb,CAAC;IAKK,AAAN,KAAK,CAAC,gBAAgB,CAAoB,UAAkB;QAC1D,MAAM,qBAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QACjC,OAAO,IAAI,CAAA;IACb,CAAC;IAKD,aAAa;QACX,OAAO,MAAM,CAAC,IAAI,CAAC,qBAAU,CAAC,SAAS,CAAC,CAAA;IAC1C,CAAC;CACF,CAAA;AA5BY,sDAAqB;AAI1B;IAHL,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EAAE,6GAA6G;KAC3H,CAAC;IAEC,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;IACjB,mBAAA,IAAA,kBAAG,EAAC,MAAM,CAAC,CAAA;IACX,mBAAA,IAAA,kBAAG,EAAC,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC,oBAAY,CAAC,CAAA;IAClC,mBAAA,IAAA,kBAAG,GAAE,CAAA;;;;8DAIP;AAKK;IAHL,IAAA,uBAAQ,EAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE;QAC5B,WAAW,EAAE,6DAA6D;KAC3E,CAAC;IACsB,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;;;;6DAGxC;AAKD;IAHC,IAAA,oBAAK,EAAC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE;QAC1B,WAAW,EAAE,uDAAuD;KACrE,CAAC;;;;0DAGD;gCA3BU,qBAAqB;IADjC,IAAA,uBAAQ,GAAE;GACE,qBAAqB,CA4BjC","sourcesContent":["import { Arg, Ctx, Mutation, Query, Resolver } from 'type-graphql'\n\nimport { ScalarObject } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\n\nimport type { BoardDef } from '@operato/twin-kernel'\n\n/*\n * 트윈 인스턴스 생명주기 채널 — 프로비저닝(상향).\n * State/Command/Scenario 는 이미 running 인 인스턴스를 다루지만, 이 채널은 인스턴스 자체를 만들고/없앤다.\n * (TwinEngine.start/stop 을 GraphQL 로 노출 — 설계 Tier-1 갭: 커널은 start/stop 을 가졌으나 진입점이 없었다.)\n * board(BoardDef)=구조, scenario=자극 은 분리 — 여기선 구조만 세운다. 자극은 controlTwinScenario 로.\n */\n@Resolver()\nexport class TwinLifecycleMutation {\n @Mutation(returns => Boolean, {\n description: 'Provision and start a twin runtime instance (kind: wms|yms|mes) from a BoardDef, and begin the worker tick.'\n })\n async startTwinInstance(\n @Arg('instanceId') instanceId: string,\n @Arg('kind') kind: string,\n @Arg('board', type => ScalarObject) board: any,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n TwinEngine.start(instanceId, context.state.domain.id, kind, board as BoardDef)\n return true\n }\n\n @Mutation(returns => Boolean, {\n description: 'Stop and dispose a running twin runtime instance by its id.'\n })\n async stopTwinInstance(@Arg('instanceId') instanceId: string): Promise<boolean> {\n await TwinEngine.stop(instanceId)\n return true\n }\n\n @Query(returns => [String], {\n description: 'List ids of currently running twin runtime instances.'\n })\n twinInstances(): string[] {\n return Object.keys(TwinEngine.instances)\n }\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolvers = void 0;
|
|
4
|
+
const twin_state_subscription_js_1 = require("./twin-state-subscription.js");
|
|
5
|
+
exports.resolvers = [twin_state_subscription_js_1.TwinStateSubscription];
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/twin-state/index.ts"],"names":[],"mappings":";;;AAAA,6EAAoE;AAEvD,QAAA,SAAS,GAAG,CAAC,kDAAqB,CAAC,CAAA","sourcesContent":["import { TwinStateSubscription } from './twin-state-subscription.js'\n\nexport const resolvers = [TwinStateSubscription]\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class TwinStateMessage {
|
|
2
|
+
instanceId: string;
|
|
3
|
+
kind: string;
|
|
4
|
+
revision?: number;
|
|
5
|
+
payload?: any;
|
|
6
|
+
}
|
|
7
|
+
export declare class TwinStateSubscription {
|
|
8
|
+
twinState(payload: {
|
|
9
|
+
twinState: TwinStateMessage;
|
|
10
|
+
}, instanceId: string): TwinStateMessage;
|
|
11
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TwinStateSubscription = exports.TwinStateMessage = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const graphql_yoga_1 = require("graphql-yoga");
|
|
6
|
+
const type_graphql_1 = require("type-graphql");
|
|
7
|
+
const shell_1 = require("@things-factory/shell");
|
|
8
|
+
const index_js_1 = require("../../engine/index.js");
|
|
9
|
+
/* State 채널 메시지 — snapshot | delta | clock 멀티플렉싱(커널 SubscriptionMessage 대응). */
|
|
10
|
+
let TwinStateMessage = class TwinStateMessage {
|
|
11
|
+
};
|
|
12
|
+
exports.TwinStateMessage = TwinStateMessage;
|
|
13
|
+
tslib_1.__decorate([
|
|
14
|
+
(0, type_graphql_1.Field)({ description: 'Twin runtime instance id this message belongs to.' }),
|
|
15
|
+
tslib_1.__metadata("design:type", String)
|
|
16
|
+
], TwinStateMessage.prototype, "instanceId", void 0);
|
|
17
|
+
tslib_1.__decorate([
|
|
18
|
+
(0, type_graphql_1.Field)({ description: 'Message kind: snapshot | delta | clock.' }),
|
|
19
|
+
tslib_1.__metadata("design:type", String)
|
|
20
|
+
], TwinStateMessage.prototype, "kind", void 0);
|
|
21
|
+
tslib_1.__decorate([
|
|
22
|
+
(0, type_graphql_1.Field)(type => type_graphql_1.Int, { nullable: true, description: 'Monotonic state revision.' }),
|
|
23
|
+
tslib_1.__metadata("design:type", Number)
|
|
24
|
+
], TwinStateMessage.prototype, "revision", void 0);
|
|
25
|
+
tslib_1.__decorate([
|
|
26
|
+
(0, type_graphql_1.Field)(type => shell_1.ScalarObject, { nullable: true, description: 'Payload — snapshot: StateSnapshot / delta: CanonicalEnvelope / clock: { simClockMs }.' }),
|
|
27
|
+
tslib_1.__metadata("design:type", Object)
|
|
28
|
+
], TwinStateMessage.prototype, "payload", void 0);
|
|
29
|
+
exports.TwinStateMessage = TwinStateMessage = tslib_1.__decorate([
|
|
30
|
+
(0, type_graphql_1.ObjectType)({ description: 'Twin State channel message multiplexing snapshot | delta | clock.' })
|
|
31
|
+
], TwinStateMessage);
|
|
32
|
+
/*
|
|
33
|
+
* 트윈 State 구독 — state-register/data-resolver 패턴 미러.
|
|
34
|
+
* 구독 즉시 현재 snapshot 발행(process.nextTick) 후 delta/clock 스트림. instanceId 로 필터.
|
|
35
|
+
*/
|
|
36
|
+
let TwinStateSubscription = class TwinStateSubscription {
|
|
37
|
+
twinState(payload, instanceId) {
|
|
38
|
+
return payload.twinState;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
exports.TwinStateSubscription = TwinStateSubscription;
|
|
42
|
+
tslib_1.__decorate([
|
|
43
|
+
(0, type_graphql_1.Subscription)(returns => TwinStateMessage, {
|
|
44
|
+
subscribe: ({ args, context }) => {
|
|
45
|
+
const { instanceId } = args;
|
|
46
|
+
/* 구독 순간 현재 상태를 먼저 발행(late 구독자도 snapshot→delta 순서 보장). */
|
|
47
|
+
process.nextTick(() => {
|
|
48
|
+
const snap = index_js_1.TwinEngine.snapshot(instanceId);
|
|
49
|
+
if (snap) {
|
|
50
|
+
shell_1.pubsub.publish('twin-state', {
|
|
51
|
+
twinState: { instanceId, kind: 'snapshot', revision: snap.revision, payload: snap }
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return (0, graphql_yoga_1.pipe)(shell_1.pubsub.subscribe('twin-state'), (0, graphql_yoga_1.filter)((payload) => payload.twinState.instanceId === instanceId));
|
|
56
|
+
}
|
|
57
|
+
}),
|
|
58
|
+
tslib_1.__param(0, (0, type_graphql_1.Root)()),
|
|
59
|
+
tslib_1.__param(1, (0, type_graphql_1.Arg)('instanceId')),
|
|
60
|
+
tslib_1.__metadata("design:type", Function),
|
|
61
|
+
tslib_1.__metadata("design:paramtypes", [Object, String]),
|
|
62
|
+
tslib_1.__metadata("design:returntype", TwinStateMessage)
|
|
63
|
+
], TwinStateSubscription.prototype, "twinState", null);
|
|
64
|
+
exports.TwinStateSubscription = TwinStateSubscription = tslib_1.__decorate([
|
|
65
|
+
(0, type_graphql_1.Resolver)()
|
|
66
|
+
], TwinStateSubscription);
|
|
67
|
+
//# sourceMappingURL=twin-state-subscription.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"twin-state-subscription.js","sourceRoot":"","sources":["../../../server/service/twin-state/twin-state-subscription.ts"],"names":[],"mappings":";;;;AAAA,+CAA2C;AAC3C,+CAAwF;AAExF,iDAA4D;AAE5D,oDAAkD;AAElD,+EAA+E;AAExE,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAY5B,CAAA;AAZY,4CAAgB;AAE3B;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;;oDAC1D;AAGlB;IADC,IAAA,oBAAK,EAAC,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC;;8CACtD;AAGZ;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,kBAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,2BAA2B,EAAE,CAAC;;kDAChE;AAGjB;IADC,IAAA,oBAAK,EAAC,IAAI,CAAC,EAAE,CAAC,oBAAY,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uFAAuF,EAAE,CAAC;;iDACzI;2BAXF,gBAAgB;IAD5B,IAAA,yBAAU,EAAC,EAAE,WAAW,EAAE,mEAAmE,EAAE,CAAC;GACpF,gBAAgB,CAY5B;AAED;;;GAGG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAqB;IAqBhC,SAAS,CAAS,OAAwC,EAAqB,UAAkB;QAC/F,OAAO,OAAO,CAAC,SAAS,CAAA;IAC1B,CAAC;CACF,CAAA;AAxBY,sDAAqB;AAqBhC;IApBC,IAAA,2BAAY,EAAC,OAAO,CAAC,EAAE,CAAC,gBAAgB,EAAE;QACzC,SAAS,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;YAC/B,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAA;YAE3B,yDAAyD;YACzD,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE;gBACpB,MAAM,IAAI,GAAG,qBAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAA;gBAC5C,IAAI,IAAI,EAAE,CAAC;oBACT,cAAM,CAAC,OAAO,CAAC,YAAY,EAAE;wBAC3B,SAAS,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE;qBACpF,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC,CAAC,CAAA;YAEF,OAAO,IAAA,mBAAI,EACT,cAAM,CAAC,SAAS,CAAC,YAAY,CAAC,EAC9B,IAAA,qBAAM,EAAC,CAAC,OAAwC,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,KAAK,UAAU,CAAC,CAClG,CAAA;QACH,CAAC;KACF,CAAC;IACS,mBAAA,IAAA,mBAAI,GAAE,CAAA;IAA4C,mBAAA,IAAA,kBAAG,EAAC,YAAY,CAAC,CAAA;;;4CAAsB,gBAAgB;sDAEnH;gCAvBU,qBAAqB;IADjC,IAAA,uBAAQ,GAAE;GACE,qBAAqB,CAwBjC","sourcesContent":["import { filter, pipe } from 'graphql-yoga'\nimport { Arg, Field, Int, ObjectType, Resolver, Root, Subscription } from 'type-graphql'\n\nimport { pubsub, ScalarObject } from '@things-factory/shell'\n\nimport { TwinEngine } from '../../engine/index.js'\n\n/* State 채널 메시지 — snapshot | delta | clock 멀티플렉싱(커널 SubscriptionMessage 대응). */\n@ObjectType({ description: 'Twin State channel message multiplexing snapshot | delta | clock.' })\nexport class TwinStateMessage {\n @Field({ description: 'Twin runtime instance id this message belongs to.' })\n instanceId: string\n\n @Field({ description: 'Message kind: snapshot | delta | clock.' })\n kind: string\n\n @Field(type => Int, { nullable: true, description: 'Monotonic state revision.' })\n revision?: number\n\n @Field(type => ScalarObject, { nullable: true, description: 'Payload — snapshot: StateSnapshot / delta: CanonicalEnvelope / clock: { simClockMs }.' })\n payload?: any\n}\n\n/*\n * 트윈 State 구독 — state-register/data-resolver 패턴 미러.\n * 구독 즉시 현재 snapshot 발행(process.nextTick) 후 delta/clock 스트림. instanceId 로 필터.\n */\n@Resolver()\nexport class TwinStateSubscription {\n @Subscription(returns => TwinStateMessage, {\n subscribe: ({ args, context }) => {\n const { instanceId } = args\n\n /* 구독 순간 현재 상태를 먼저 발행(late 구독자도 snapshot→delta 순서 보장). */\n process.nextTick(() => {\n const snap = TwinEngine.snapshot(instanceId)\n if (snap) {\n pubsub.publish('twin-state', {\n twinState: { instanceId, kind: 'snapshot', revision: snap.revision, payload: snap }\n })\n }\n })\n\n return pipe(\n pubsub.subscribe('twin-state'),\n filter((payload: { twinState: TwinStateMessage }) => payload.twinState.instanceId === instanceId)\n )\n }\n })\n twinState(@Root() payload: { twinState: TwinStateMessage }, @Arg('instanceId') instanceId: string): TwinStateMessage {\n return payload.twinState\n }\n}\n"]}
|