@underdogai/mesh-app-sdk 0.1.0

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.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * 카드/패널 빌더 — "이미 있는 닫힌 블록/바디"를 조합해 데이터(UiCardContent / PanelSpec)를 만든다.
3
+ *
4
+ * 핵심: 새 블록을 만들지 않는다(코어 어휘만 조합). 그래서 결과가 "데이터"로 남고 — App Service 가
5
+ * 그대로 와이어에 실어 보내면 클라가 가진 렌더러로 그린다(클라 무변경 = "AS만 추가해도 UI 등록").
6
+ */
7
+ import { buildUiCardContent, } from "@underdogai/mesh-event-schemas";
8
+ /** 타임라인 카드(UiCardContent) 빌더 — 기존 블록 조합 → 검증된 데이터. */
9
+ export const card = {
10
+ /** 닫힌 블록 트리로 카드를 구성(반환 즉시 zod 검증된 UiCardContent). */
11
+ build(card_id, blocks, opts = {}) {
12
+ return buildUiCardContent({
13
+ card_id,
14
+ title: opts.title,
15
+ fallback: opts.fallback ?? opts.title ?? card_id,
16
+ state: opts.state,
17
+ context: opts.context,
18
+ blocks,
19
+ });
20
+ },
21
+ fields(items) {
22
+ return { type: "fields", items };
23
+ },
24
+ text(text) {
25
+ return { type: "text", text };
26
+ },
27
+ actions(elements) {
28
+ return { type: "actions", elements };
29
+ },
30
+ // --- 폼 입력 블록(2단계 폼 카드용 — 폼 방식 결정: 모달 폼 대신 폼 카드) ---
31
+ // 클라가 name 으로 값을 모아 제출 버튼의 action_id 로 org.corp.ui.action.values 에 실어 보낸다.
32
+ // 핸들러는 action.values.parse(ctx.values) 로 타입 확보(defineAction 의 values 스키마와 짝).
33
+ /** 텍스트/숫자/날짜 입력 — input 종류는 "text"(기본)·"textarea"·"number"·"date"·"datetime"·"time". */
34
+ input(name, opts = {}) {
35
+ return { type: "input", name, ...opts };
36
+ },
37
+ /** 드롭다운 선택(단일/다중). */
38
+ select(name, options, opts = {}) {
39
+ return { type: "select", name, options, ...opts };
40
+ },
41
+ /** 라디오 그룹(옵션이 펼쳐져 보이는 단일 선택). */
42
+ radio(name, options, opts = {}) {
43
+ return { type: "radio", name, options, ...opts };
44
+ },
45
+ /** 체크박스(불리언 수집). */
46
+ checkbox(name, label, opts = {}) {
47
+ return { type: "checkbox", name, label, ...opts };
48
+ },
49
+ /** 토글 스위치(불리언 수집, on/off 어포던스). */
50
+ toggle(name, label, opts = {}) {
51
+ return { type: "toggle", name, label, ...opts };
52
+ },
53
+ };
54
+ /** 우측 셸 패널(PanelSpec) 빌더 — 닫힌 SurfaceBody 조합. value 문자열의 {{entity.path}} 는 클라가 바인딩. */
55
+ export const panel = {
56
+ sections(sections) {
57
+ return { sections };
58
+ },
59
+ fields(id, title, items) {
60
+ return { id, title, body: { kind: "fields", items } };
61
+ },
62
+ list(id, title, items) {
63
+ return { id, title, body: { kind: "list", items } };
64
+ },
65
+ memo(id, title, summary, updates) {
66
+ return { id, title, body: { kind: "memo", summary, updates } };
67
+ },
68
+ card(id, title, embedded) {
69
+ return { id, title, body: { kind: "card", card: embedded } };
70
+ },
71
+ };
72
+ //# sourceMappingURL=builders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builders.js","sourceRoot":"","sources":["../src/builders.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,kBAAkB,GAKnB,MAAM,gCAAgC,CAAC;AAUxC,sDAAsD;AACtD,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,qDAAqD;IACrD,KAAK,CAAC,OAAe,EAAE,MAAe,EAAE,OAAiB,EAAE;QACzD,OAAO,kBAAkB,CAAC;YACxB,OAAO;YACP,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,IAAI,OAAO;YAChD,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM;SACP,CAAC,CAAC;IACL,CAAC;IACD,MAAM,CAAC,KAA0D;QAC/D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;IACnC,CAAC;IACD,IAAI,CAAC,IAAY;QACf,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAChC,CAAC;IACD,OAAO,CAAC,QAAyB;QAC/B,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC;IACvC,CAAC;IACD,qDAAqD;IACrD,2EAA2E;IAC3E,8EAA8E;IAC9E,wFAAwF;IACxF,KAAK,CAAC,IAAY,EAAE,OAA4J,EAAE;QAChL,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;IAC1C,CAAC;IACD,sBAAsB;IACtB,MAAM,CAAC,IAAY,EAAE,OAA2C,EAAE,OAAkF,EAAE;QACpJ,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACpD,CAAC;IACD,iCAAiC;IACjC,KAAK,CAAC,IAAY,EAAE,OAA2C,EAAE,OAA2C,EAAE;QAC5G,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACnD,CAAC;IACD,oBAAoB;IACpB,QAAQ,CAAC,IAAY,EAAE,KAAa,EAAE,OAA8B,EAAE;QACpE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC;IACpD,CAAC;IACD,mCAAmC;IACnC,MAAM,CAAC,IAAY,EAAE,KAAa,EAAE,OAAiE,EAAE;QACrG,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC;IAClD,CAAC;CACF,CAAC;AAEF,uFAAuF;AACvF,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,QAAQ,CAAC,QAA0B;QACjC,OAAO,EAAE,QAAQ,EAAE,CAAC;IACtB,CAAC;IACD,MAAM,CAAC,EAAU,EAAE,KAAa,EAAE,KAAyC;QACzE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC;IACxD,CAAC;IACD,IAAI,CAAC,EAAU,EAAE,KAAa,EAAE,KAAgD;QAC9E,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;IACtD,CAAC;IACD,IAAI,CAAC,EAAU,EAAE,KAAa,EAAE,OAAe,EAAE,OAAkB;QACjE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,CAAC,EAAU,EAAE,KAAa,EAAE,QAAuB;QACrD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC;IAC/D,CAAC;CACF,CAAC"}
package/dist/host.d.ts ADDED
@@ -0,0 +1,38 @@
1
+ import type { App } from "./app.js";
2
+ import type { MatrixSendClient } from "./runtime.js";
3
+ /**
4
+ * 호스트가 주입하는 Matrix 핸들(활성화용) — matrix-bot-sdk 의 MatrixClient 가 구조적으로 그대로 만족한다.
5
+ * getRoomStateEvent 는 선택(중복 발행 방지용) — 없거나 실패하면 무조건 발행으로 폴백한다.
6
+ */
7
+ export interface MatrixHostClient extends MatrixSendClient {
8
+ /** 초대 수락(참여). */
9
+ joinRoom(roomId: string): Promise<unknown>;
10
+ /** 현재 상태 읽기(있으면 중복 발행 방지에 쓴다). 상태 없음은 throw 로 신호해도 된다(M_NOT_FOUND 등). */
11
+ getRoomStateEvent?(roomId: string, eventType: string, stateKey: string): Promise<unknown>;
12
+ }
13
+ export type PublishSurfaceResult = "published" | "unchanged" | "no_surface";
14
+ export interface PublishSurfaceInput {
15
+ client: MatrixHostClient | (MatrixSendClient & Pick<MatrixHostClient, "getRoomStateEvent">);
16
+ app: App;
17
+ roomId: string;
18
+ /** 멀티앱 방 키잉(보통 app.app). 레거시 단일-앱 방은 ""(기본). */
19
+ stateKey?: string;
20
+ }
21
+ /**
22
+ * 앱 서피스(org.corp.app.surface)를 방에 **1회** 발행한다 — 이미 같은 내용이 올라가 있으면 재발행하지 않는다.
23
+ * (킥오프 §7 함정: 상태 이벤트를 매 틱 재발행하면 타임라인이 설정값으로 덮여 방을 열었을 때 카드가 안 보인다.
24
+ * 서피스는 상태 이벤트라 한 번 올리면 영속한다 — 부팅/초대/바인딩 변경마다 불러도 안전한 멱등 연산이어야 한다.)
25
+ * sidebar 없는 앱은 발행할 것이 없다(no_surface).
26
+ */
27
+ export declare function publishSurface(input: PublishSurfaceInput): Promise<PublishSurfaceResult>;
28
+ /**
29
+ * 초대 활성화 시퀀스 — 참여 → 서피스 1회 발행. "봇을 초대하면 활성화된다, 사용자가 따로 설정할 게 없다"(§2.4)
30
+ * 의 앱-제너릭 절반. 호스트는 자기 정책(capability 게시·멀티앱 키잉 등)을 이 앞뒤에 끼운다.
31
+ */
32
+ export declare function activateOnInvite(input: {
33
+ client: MatrixHostClient;
34
+ app: App;
35
+ roomId: string;
36
+ stateKey?: string;
37
+ }): Promise<PublishSurfaceResult>;
38
+ //# sourceMappingURL=host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACxD,iBAAiB;IACjB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,yEAAyE;IACzE,iBAAiB,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3F;AAED,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;AAE5E,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,gBAAgB,GAAG,CAAC,gBAAgB,GAAG,IAAI,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAC5F,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAiB9F;AAmBD;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE;IAC5C,MAAM,EAAE,gBAAgB,CAAC;IACzB,GAAG,EAAE,GAAG,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAGhC"}
package/dist/host.js ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * 호스트 활성화 배선 — "봇이 초대되면 자동으로 참여하고, 그 방에 서피스를 **한 번** 발행한다"(킥오프 §2.4)를
3
+ * 호스트 무관으로 제공한다. AS 에이전트(appservice-agent)와 봇 모드 serve()(Phase 3)가 같은 코드를 쓴다.
4
+ *
5
+ * 여기 있는 것은 *앱-제너릭* 절반뿐이다 — 어떤 방이 어떤 앱을 호스팅하는가(room.apps/space.apps 거버넌스),
6
+ * capability 게시, 잔존 서피스 정리 같은 호스트 정책은 호스트가 소유한다(applyEffects 와 같은 의존성 역전).
7
+ */
8
+ import { EventType } from "@underdogai/mesh-event-schemas";
9
+ /**
10
+ * 앱 서피스(org.corp.app.surface)를 방에 **1회** 발행한다 — 이미 같은 내용이 올라가 있으면 재발행하지 않는다.
11
+ * (킥오프 §7 함정: 상태 이벤트를 매 틱 재발행하면 타임라인이 설정값으로 덮여 방을 열었을 때 카드가 안 보인다.
12
+ * 서피스는 상태 이벤트라 한 번 올리면 영속한다 — 부팅/초대/바인딩 변경마다 불러도 안전한 멱등 연산이어야 한다.)
13
+ * sidebar 없는 앱은 발행할 것이 없다(no_surface).
14
+ */
15
+ export async function publishSurface(input) {
16
+ const surface = input.app.surfaceState();
17
+ if (!surface)
18
+ return "no_surface";
19
+ const stateKey = input.stateKey ?? "";
20
+ if (input.client.getRoomStateEvent) {
21
+ try {
22
+ const existing = await input.client.getRoomStateEvent(input.roomId, EventType.AppSurface, stateKey);
23
+ // 서버가 돌려준 현재 상태가 지금 발행하려는 내용과 같으면 중복 — 재발행하지 않는다.
24
+ // ⚠️ 비교는 canonical(키 정렬) — 홈서버는 canonical JSON(키 알파벳순)으로 재직렬화해 돌려주는 반면
25
+ // zod 산출물은 스키마 선언 순서(v 가 맨 앞)라, 순서 민감 비교면 실서버 상대로 unchanged 가 절대 안 나온다.
26
+ if (existing && canonicalStringify(existing) === canonicalStringify(surface))
27
+ return "unchanged";
28
+ }
29
+ catch {
30
+ // 상태 없음(M_NOT_FOUND)/조회 실패 → 발행 진행(중복 방지는 best-effort, 발행이 우선).
31
+ }
32
+ }
33
+ await input.client.sendStateEvent(input.roomId, EventType.AppSurface, stateKey, surface);
34
+ return "published";
35
+ }
36
+ /** 키 순서 무관 비교용 canonical 직렬화(재귀 키 정렬) — Matrix canonical JSON 과 같은 정렬 기준(코드 유닛). */
37
+ function canonicalStringify(v) {
38
+ return JSON.stringify(sortKeysDeep(v));
39
+ }
40
+ function sortKeysDeep(v) {
41
+ if (Array.isArray(v))
42
+ return v.map(sortKeysDeep);
43
+ if (v && typeof v === "object") {
44
+ return Object.fromEntries(Object.entries(v)
45
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
46
+ .map(([k, val]) => [k, sortKeysDeep(val)]));
47
+ }
48
+ return v;
49
+ }
50
+ /**
51
+ * 초대 활성화 시퀀스 — 참여 → 서피스 1회 발행. "봇을 초대하면 활성화된다, 사용자가 따로 설정할 게 없다"(§2.4)
52
+ * 의 앱-제너릭 절반. 호스트는 자기 정책(capability 게시·멀티앱 키잉 등)을 이 앞뒤에 끼운다.
53
+ */
54
+ export async function activateOnInvite(input) {
55
+ await input.client.joinRoom(input.roomId);
56
+ return publishSurface(input);
57
+ }
58
+ //# sourceMappingURL=host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host.js","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAyB3D;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAA0B;IAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC;IACzC,IAAI,CAAC,OAAO;QAAE,OAAO,YAAY,CAAC;IAClC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACpG,kDAAkD;YAClD,uEAAuE;YACvE,wEAAwE;YACxE,IAAI,QAAQ,IAAI,kBAAkB,CAAC,QAAQ,CAAC,KAAK,kBAAkB,CAAC,OAAO,CAAC;gBAAE,OAAO,WAAW,CAAC;QACnG,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;IACH,CAAC;IACD,MAAM,KAAK,CAAC,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,SAAS,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACzF,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,oFAAoF;AACpF,SAAS,kBAAkB,CAAC,CAAU;IACpC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,YAAY,CAAC,CAAU;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACjD,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,CAA4B,CAAC;aACzC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aAChD,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAC7C,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAKtC;IACC,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC1C,OAAO,cAAc,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @underdogai/mesh-app-sdk — App Service ↔ UI 연결 SDK (v0).
3
+ *
4
+ * 한 폴더(한 App)에서 커스텀 이벤트 ↔ 카드(데이터) · 카드 버튼 ↔ 타입드 액션/핸들러 · 우측 셸 서피스(데이터)를
5
+ * 함께 선언한다. App = Plugin 상위집합 → enabledPlugins 한 줄로 클라/AS/브리지가 같은 스키마를 등록한다.
6
+ * 보안(권한 게이트)은 호스트가 주입(의존성 역전) — SDK 는 scope/destructive 를 데이터로만 공급한다.
7
+ *
8
+ * 설계/로드맵: docs/sdk-plan.md, 필요성 기록: docs/sdk.md.
9
+ */
10
+ export * from "./action.js";
11
+ export * from "./builders.js";
12
+ export * from "./app.js";
13
+ export * from "./runtime.js";
14
+ export * from "./host.js";
15
+ export * from "./serve.js";
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @underdogai/mesh-app-sdk — App Service ↔ UI 연결 SDK (v0).
3
+ *
4
+ * 한 폴더(한 App)에서 커스텀 이벤트 ↔ 카드(데이터) · 카드 버튼 ↔ 타입드 액션/핸들러 · 우측 셸 서피스(데이터)를
5
+ * 함께 선언한다. App = Plugin 상위집합 → enabledPlugins 한 줄로 클라/AS/브리지가 같은 스키마를 등록한다.
6
+ * 보안(권한 게이트)은 호스트가 주입(의존성 역전) — SDK 는 scope/destructive 를 데이터로만 공급한다.
7
+ *
8
+ * 설계/로드맵: docs/sdk-plan.md, 필요성 기록: docs/sdk.md.
9
+ */
10
+ export * from "./action.js";
11
+ export * from "./builders.js";
12
+ export * from "./app.js";
13
+ export * from "./runtime.js";
14
+ export * from "./host.js";
15
+ export * from "./serve.js";
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * 액션 라우터 — 들어온 org.corp.ui.action 을 (멱등은 호스트가) → 발행자격(SEC-3) → 레지스트리 검증
3
+ * → 권한 게이트 → 핸들러 실행(효과 수집) 으로 흘린다.
4
+ *
5
+ * 보안 게이트(evaluateAction)는 SDK 가 소유하지 않고 **호스트가 주입**한다(의존성 역전) — SDK 는
6
+ * "어떤 액션이 어떤 scope/destructive 인지"만 게이트에 데이터로 넘긴다(보안의 권위는 서버 policy 에 그대로).
7
+ *
8
+ * 핸들러는 부작용을 직접 실행하지 않고 "효과(Effect)"를 선언한다 → 실 AS 는 matrix client 로 적용,
9
+ * 증명 스크립트는 효과 배열을 검사한다(같은 SDK 코드를 양쪽에서 검증 = 테스트성).
10
+ */
11
+ import { type UiCardContent } from "@underdogai/mesh-event-schemas";
12
+ import type { App } from "./app.js";
13
+ /**
14
+ * 발행 형태 — 같은 사실을 어떤 Matrix 형태로 보낼지(킥오프 §2.3).
15
+ * - "message": m.room.message + 카드(사람용 — 타임라인에 남고 알림도 간다). events 에 선언된 view 가 그린다.
16
+ * - "event"(기본): 커스텀 이벤트 타입 그대로(기계가 읽을 사실·봇 사이 연쇄 — 남지만 조용하다).
17
+ * - "state": 상태 이벤트(최신값 하나 — 방 구성·현재 상태).
18
+ */
19
+ export type EmitForm = "message" | "event" | "state";
20
+ export interface EmitOptions {
21
+ /** 발행 형태(기본 "event"). */
22
+ form?: EmitForm;
23
+ /** form:"state" 의 state_key(기본 ""). 다른 form 에선 무시된다. */
24
+ stateKey?: string;
25
+ }
26
+ /** 핸들러가 선언하는 효과 — 호스트가 matrix 로 적용한다. */
27
+ export type Effect = {
28
+ kind: "edit";
29
+ card: UiCardContent;
30
+ } | {
31
+ kind: "send";
32
+ card: UiCardContent;
33
+ } | {
34
+ kind: "workflow";
35
+ status: string;
36
+ } | {
37
+ kind: "delegate";
38
+ intent: string;
39
+ payload: Record<string, unknown>;
40
+ } | {
41
+ kind: "emit";
42
+ type: string;
43
+ content: Record<string, unknown>;
44
+ form: EmitForm;
45
+ stateKey?: string;
46
+ } | {
47
+ kind: "invoke";
48
+ actionId: string;
49
+ values: Record<string, unknown>;
50
+ };
51
+ /**
52
+ * 호스트가 주입하는 백엔드 핸들 — 핸들러가 "권위 데이터를 읽고 → 판단 → 효과 선언"(read-then-decide)할 때 쓴다.
53
+ * SDK 는 호출 형태(도구 이름 + 구조화 인자)만 정의하고, 구현(MCP 도구/HTTP)·권한 스코프는 호스트가 소유한다
54
+ * (GateFn 과 같은 의존성 역전). 앱은 ctx.backend 가 있으면 권위 재조회로 쓰고, 없으면(증명/오프라인) 분기로 처리한다.
55
+ * ⚠️ 카드/이벤트의 ctx.values 는 신뢰하지 말고, 여기로 권위 데이터를 다시 읽는 것이 시스템-오브-레코드 원칙.
56
+ */
57
+ export interface ActionBackend {
58
+ call<T = unknown>(tool: string, args?: Record<string, unknown>): Promise<T>;
59
+ }
60
+ export interface ActionCtx {
61
+ /** 홈서버가 귀속한 발신자 MXID(권위). */
62
+ sender: string;
63
+ /** 카드 context.entity (있으면) — 핸들러가 권위 데이터 재조회 키로 사용. */
64
+ entity: {
65
+ type?: string;
66
+ id?: string;
67
+ };
68
+ /** 원본 카드의 논리 card_id(action.card_id) — 편집 카드가 같은 card_id 를 유지해 같은 카드를 m.replace 하도록. */
69
+ cardId?: string;
70
+ /** 폼 입력(원본). 핸들러는 action.values.parse(ctx.values) 로 타입 확보. */
71
+ values: Record<string, unknown>;
72
+ /** 편집 대상 원본 카드 event_id(있으면). */
73
+ cardEventId?: string;
74
+ /** 호스트 주입 백엔드(있으면) — 권위 데이터 read-then-decide. 없으면 write-only(증명/오프라인). */
75
+ backend?: ActionBackend;
76
+ /**
77
+ * 호스트가 주입하는 앱 정책 설정(읽기 전용 데이터) — 예: finance 승인 임계값(approvalThreshold).
78
+ * 배포 설정(env 등)을 핸들러로 흘리는 의존성 주입 채널. 핸들러는 ctx.config?.<key> 로 읽는다(없으면 undefined).
79
+ */
80
+ config?: Record<string, unknown>;
81
+ /** 효과 선언 헬퍼 — 원본 카드를 편집한다(m.replace). */
82
+ editCard(card: UiCardContent): void;
83
+ /** 효과 선언 헬퍼 — 새 카드를 보낸다. */
84
+ send(card: UiCardContent): void;
85
+ /** 효과 선언 헬퍼 — 엔티티 워크플로 상태를 갱신한다. */
86
+ workflow(status: string): void;
87
+ /** 효과 선언 헬퍼 — 다른 에이전트에게 위임(intent + payload). 호스트가 A2A 프로토콜로 실행한다. */
88
+ delegate(d: {
89
+ intent: string;
90
+ payload: Record<string, unknown>;
91
+ }): void;
92
+ /**
93
+ * 효과 선언 헬퍼 — 사실을 커스텀 이벤트로 발행한다(emit). 자기 앱 네임스페이스(org.corp.<app>.) 밖 타입은
94
+ * throw(소유 강제 — 남의 사실 위조 금지, 구독은 on 으로). events 에 선언된 타입이면 스키마를 outbound-strict
95
+ * 로 검증하고(불일치 throw), form:"message" 는 선언된 view 가 있어야 한다.
96
+ */
97
+ emit(type: string, content: Record<string, unknown>, opts?: EmitOptions): void;
98
+ /**
99
+ * 효과 선언 헬퍼 — 다른 앱의 액션을 이름으로 호출한다(invoke = UI 없이 org.corp.ui.action 발행).
100
+ * 받는 쪽은 버튼에서 왔는지 봇이 보냈는지 구분하지 않는다. action_id 접두사(<app>.)가 라우팅 주소다.
101
+ */
102
+ invoke(actionId: string, values?: Record<string, unknown>): void;
103
+ }
104
+ export type ActionHandler = (ctx: ActionCtx) => void | Promise<void>;
105
+ /** 호스트가 주입하는 권한 게이트(= appservice-agent/policy.evaluateAction 의 얇은 래퍼). */
106
+ export type GateFn = (input: {
107
+ senderId: string;
108
+ actionId: string;
109
+ requiredScope: string;
110
+ destructive: boolean;
111
+ powerLevels: unknown;
112
+ capability: unknown;
113
+ }) => {
114
+ allowed: boolean;
115
+ reason: string;
116
+ };
117
+ export interface DispatchInput {
118
+ app: App;
119
+ /** 들어온 org.corp.ui.action 의 content. */
120
+ actionContent: unknown;
121
+ /** 홈서버가 귀속한 발신자 MXID(권위 — 본문 from_* 아님). */
122
+ sender: string;
123
+ powerLevels?: unknown;
124
+ capability?: unknown;
125
+ cardEventId?: string;
126
+ entity?: {
127
+ type?: string;
128
+ id?: string;
129
+ };
130
+ gate: GateFn;
131
+ /** 호스트 주입 백엔드(선택) — 핸들러가 권위 데이터를 읽고 분기할 때 ctx.backend 로 전달된다. */
132
+ backend?: ActionBackend;
133
+ /** 호스트 주입 앱 정책 설정(선택) — ctx.config 로 핸들러에 전달(예: { approvalThreshold }). */
134
+ config?: Record<string, unknown>;
135
+ }
136
+ export interface DispatchResult {
137
+ status: "ran" | "denied" | "ignored";
138
+ actionId?: string;
139
+ reason?: string;
140
+ effects: Effect[];
141
+ }
142
+ /** 액션 한 건을 라우팅한다. 게이트는 호스트가 주입(보안 권위는 서버). 효과는 호스트가 적용. */
143
+ export declare function dispatchAction(input: DispatchInput): Promise<DispatchResult>;
144
+ /** 구독 핸들러가 받는 컨텍스트 — 반응은 효과(send/emit/invoke)로만 선언한다(부작용은 호스트가 적용). */
145
+ export interface EventCtx {
146
+ /** 구독한 이벤트 타입. */
147
+ type: string;
148
+ /** 이벤트가 발생한 방. */
149
+ roomId: string;
150
+ /** 홈서버가 귀속한 발신자 MXID(권위 — 본문 from_* 아님). */
151
+ sender: string;
152
+ /** 이벤트 content(레지스트리가 아는 타입이면 파싱된 값, 모르면 원본). 구독 앱이 자기 스키마로 parse 해 타입 확보. */
153
+ content: Record<string, unknown>;
154
+ /** 원본 이벤트 id(있으면). */
155
+ eventId?: string;
156
+ /** 효과 선언 헬퍼 — 새 카드를 보낸다. */
157
+ send(card: UiCardContent): void;
158
+ /** 효과 선언 헬퍼 — 자기 사실을 발행한다(규칙은 ActionCtx.emit 과 동일). */
159
+ emit(type: string, content: Record<string, unknown>, opts?: EmitOptions): void;
160
+ /** 효과 선언 헬퍼 — 다른 앱의 액션을 호출한다(규칙은 ActionCtx.invoke 와 동일). */
161
+ invoke(actionId: string, values?: Record<string, unknown>): void;
162
+ }
163
+ export type EventHandler = (ctx: EventCtx) => void | Promise<void>;
164
+ export interface DispatchEventInput {
165
+ app: App;
166
+ /** 들어온 이벤트 타입. */
167
+ type: string;
168
+ /** 들어온 이벤트 content. */
169
+ content: unknown;
170
+ /** 홈서버가 귀속한 발신자 MXID. */
171
+ sender: string;
172
+ roomId: string;
173
+ eventId?: string;
174
+ }
175
+ export interface DispatchEventResult {
176
+ status: "ran" | "ignored";
177
+ reason?: string;
178
+ effects: Effect[];
179
+ }
180
+ /**
181
+ * 구독 이벤트 한 건을 라우팅한다 — 구독하지 않은 타입은 조용히 넘긴다(ignored, 거부 메시지 없음).
182
+ *
183
+ * 검증은 "로컬 지식 한정": 이 프로세스의 레지스트리가 아는 타입이면 스키마 불일치를 거르고(schema_mismatch),
184
+ * 모르는 타입(외부 앱의 사실)은 원본 그대로 핸들러에 넘긴다 — Matrix 는 임의 이벤트를 막지 못하므로 레지스트리는
185
+ * 강제가 아니라 합의 도구다(킥오프 §5). 발행 자격(canPublish) 게이트도 걸지 않는다 — 외부 봇은 human 으로
186
+ * 분류되어 정당한 연쇄가 막히기 때문에, 발신자 신뢰 판단은 sender 를 보고 호스트/핸들러가 한다.
187
+ *
188
+ * ⚠️ 루프 방지는 호스트 책임 — 자기(봇 계정)가 보낸 이벤트는 dispatchEvent 에 넣지 말 것(emit→on 무한 연쇄).
189
+ */
190
+ export declare function dispatchEvent(input: DispatchEventInput): Promise<DispatchEventResult>;
191
+ /**
192
+ * 호스트가 주입하는 최소 Matrix 전송 핸들 — matrix-bot-sdk 의 MatrixClient(및 Intent.underlyingClient)가
193
+ * 구조적으로 그대로 만족한다. SDK 는 이 두 메서드 외 어떤 클라이언트 능력도 요구하지 않는다.
194
+ */
195
+ export interface MatrixSendClient {
196
+ sendEvent(roomId: string, eventType: string, content: Record<string, unknown>): Promise<unknown>;
197
+ sendStateEvent(roomId: string, eventType: string, stateKey: string, content: Record<string, unknown>): Promise<unknown>;
198
+ }
199
+ export interface ApplyEffectsInput {
200
+ /** 전송 핸들(호스트 주입) — 봇 계정 클라이언트든 AS Intent 든 무관. */
201
+ client: MatrixSendClient;
202
+ /** 효과를 선언한 앱 — emit(form:"message") 의 view 해석과 invoke 의 발신 표기(card_id)에 쓴다. */
203
+ app: App;
204
+ roomId: string;
205
+ effects: Effect[];
206
+ /** edit 효과의 원본 카드 event_id — 없으면 새 카드로 graceful(참조 유실 대비). */
207
+ cardEventId?: string;
208
+ /** workflow 효과의 엔티티(state_key=entity.id). id 없으면 workflow 는 경고 후 생략. */
209
+ entity?: {
210
+ type?: string;
211
+ id?: string;
212
+ };
213
+ /** workflow.updated_by 로 기록할 주체(보통 액션 발신자). */
214
+ sender?: string;
215
+ /**
216
+ * delegate 효과 콜백 — stateful·교차에이전트(A2A) 프로토콜은 호스트가 소유한다. 미주입 호스트(1회 발행·
217
+ * 단순 봇)에서 delegate 가 나오면 경고 후 무시한다(조용한 유실 방지 로그).
218
+ */
219
+ onDelegate?: (eff: Extract<Effect, {
220
+ kind: "delegate";
221
+ }>) => void | Promise<void>;
222
+ /** 진단 로그 훅(기본 console.warn/error) — 증명/테스트가 경고 경로를 관찰할 때 주입. */
223
+ warn?: (msg: string) => void;
224
+ error?: (msg: string) => void;
225
+ }
226
+ /**
227
+ * 핸들러가 선언한 효과를 Matrix 로 적용한다 — 호스트 무관(AS 에이전트·봇 계정·증명 스크립트가 같은 코드 사용).
228
+ * 배열 순서대로 적용한다. edit/send/emit/invoke 전송 실패는 throw(호스트가 회복 정책 소유),
229
+ * workflow 는 상태 이벤트 특성상 로그 후 계속(agent 레거시 동작 보존 — 카드 갱신을 막지 않는다).
230
+ */
231
+ export declare function applyEffects(input: ApplyEffectsInput): Promise<void>;
232
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"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"}