@aigne/afs-ui 1.11.0-beta.12
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/LICENSE.md +26 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
- package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
- package/dist/aup-protocol.cjs +235 -0
- package/dist/aup-protocol.d.cts +78 -0
- package/dist/aup-protocol.d.cts.map +1 -0
- package/dist/aup-protocol.d.mts +78 -0
- package/dist/aup-protocol.d.mts.map +1 -0
- package/dist/aup-protocol.mjs +235 -0
- package/dist/aup-protocol.mjs.map +1 -0
- package/dist/aup-registry.cjs +2489 -0
- package/dist/aup-registry.mjs +2487 -0
- package/dist/aup-registry.mjs.map +1 -0
- package/dist/aup-spec.cjs +1467 -0
- package/dist/aup-spec.mjs +1466 -0
- package/dist/aup-spec.mjs.map +1 -0
- package/dist/aup-types.cjs +165 -0
- package/dist/aup-types.d.cts +157 -0
- package/dist/aup-types.d.cts.map +1 -0
- package/dist/aup-types.d.mts +157 -0
- package/dist/aup-types.d.mts.map +1 -0
- package/dist/aup-types.mjs +157 -0
- package/dist/aup-types.mjs.map +1 -0
- package/dist/backend.cjs +14 -0
- package/dist/backend.d.cts +104 -0
- package/dist/backend.d.cts.map +1 -0
- package/dist/backend.d.mts +104 -0
- package/dist/backend.d.mts.map +1 -0
- package/dist/backend.mjs +13 -0
- package/dist/backend.mjs.map +1 -0
- package/dist/degradation.cjs +85 -0
- package/dist/degradation.d.cts +17 -0
- package/dist/degradation.d.cts.map +1 -0
- package/dist/degradation.d.mts +17 -0
- package/dist/degradation.d.mts.map +1 -0
- package/dist/degradation.mjs +84 -0
- package/dist/degradation.mjs.map +1 -0
- package/dist/index.cjs +36 -0
- package/dist/index.d.cts +12 -0
- package/dist/index.d.mts +12 -0
- package/dist/index.mjs +13 -0
- package/dist/runtime.cjs +117 -0
- package/dist/runtime.d.cts +59 -0
- package/dist/runtime.d.cts.map +1 -0
- package/dist/runtime.d.mts +59 -0
- package/dist/runtime.d.mts.map +1 -0
- package/dist/runtime.mjs +118 -0
- package/dist/runtime.mjs.map +1 -0
- package/dist/session.cjs +159 -0
- package/dist/session.d.cts +80 -0
- package/dist/session.d.cts.map +1 -0
- package/dist/session.d.mts +80 -0
- package/dist/session.d.mts.map +1 -0
- package/dist/session.mjs +159 -0
- package/dist/session.mjs.map +1 -0
- package/dist/snapshot.cjs +162 -0
- package/dist/snapshot.mjs +163 -0
- package/dist/snapshot.mjs.map +1 -0
- package/dist/term-page.cjs +264 -0
- package/dist/term-page.mjs +264 -0
- package/dist/term-page.mjs.map +1 -0
- package/dist/term.cjs +295 -0
- package/dist/term.d.cts +84 -0
- package/dist/term.d.cts.map +1 -0
- package/dist/term.d.mts +84 -0
- package/dist/term.d.mts.map +1 -0
- package/dist/term.mjs +296 -0
- package/dist/term.mjs.map +1 -0
- package/dist/tty.cjs +136 -0
- package/dist/tty.d.cts +53 -0
- package/dist/tty.d.cts.map +1 -0
- package/dist/tty.d.mts +53 -0
- package/dist/tty.d.mts.map +1 -0
- package/dist/tty.mjs +135 -0
- package/dist/tty.mjs.map +1 -0
- package/dist/ui-provider.cjs +4615 -0
- package/dist/ui-provider.d.cts +307 -0
- package/dist/ui-provider.d.cts.map +1 -0
- package/dist/ui-provider.d.mts +307 -0
- package/dist/ui-provider.d.mts.map +1 -0
- package/dist/ui-provider.mjs +4616 -0
- package/dist/ui-provider.mjs.map +1 -0
- package/dist/web-page/core.cjs +1388 -0
- package/dist/web-page/core.mjs +1387 -0
- package/dist/web-page/core.mjs.map +1 -0
- package/dist/web-page/css.cjs +1699 -0
- package/dist/web-page/css.mjs +1698 -0
- package/dist/web-page/css.mjs.map +1 -0
- package/dist/web-page/icons.cjs +248 -0
- package/dist/web-page/icons.mjs +248 -0
- package/dist/web-page/icons.mjs.map +1 -0
- package/dist/web-page/overlay-themes.cjs +514 -0
- package/dist/web-page/overlay-themes.mjs +513 -0
- package/dist/web-page/overlay-themes.mjs.map +1 -0
- package/dist/web-page/renderers/action.cjs +72 -0
- package/dist/web-page/renderers/action.mjs +72 -0
- package/dist/web-page/renderers/action.mjs.map +1 -0
- package/dist/web-page/renderers/broadcast.cjs +160 -0
- package/dist/web-page/renderers/broadcast.mjs +160 -0
- package/dist/web-page/renderers/broadcast.mjs.map +1 -0
- package/dist/web-page/renderers/calendar.cjs +137 -0
- package/dist/web-page/renderers/calendar.mjs +137 -0
- package/dist/web-page/renderers/calendar.mjs.map +1 -0
- package/dist/web-page/renderers/canvas.cjs +173 -0
- package/dist/web-page/renderers/canvas.mjs +173 -0
- package/dist/web-page/renderers/canvas.mjs.map +1 -0
- package/dist/web-page/renderers/cdn-loader.cjs +25 -0
- package/dist/web-page/renderers/cdn-loader.mjs +25 -0
- package/dist/web-page/renderers/cdn-loader.mjs.map +1 -0
- package/dist/web-page/renderers/chart.cjs +101 -0
- package/dist/web-page/renderers/chart.mjs +101 -0
- package/dist/web-page/renderers/chart.mjs.map +1 -0
- package/dist/web-page/renderers/deck.cjs +390 -0
- package/dist/web-page/renderers/deck.mjs +390 -0
- package/dist/web-page/renderers/deck.mjs.map +1 -0
- package/dist/web-page/renderers/device.cjs +1015 -0
- package/dist/web-page/renderers/device.mjs +1015 -0
- package/dist/web-page/renderers/device.mjs.map +1 -0
- package/dist/web-page/renderers/editor.cjs +127 -0
- package/dist/web-page/renderers/editor.mjs +127 -0
- package/dist/web-page/renderers/editor.mjs.map +1 -0
- package/dist/web-page/renderers/finance-chart.cjs +178 -0
- package/dist/web-page/renderers/finance-chart.mjs +178 -0
- package/dist/web-page/renderers/finance-chart.mjs.map +1 -0
- package/dist/web-page/renderers/frame.cjs +274 -0
- package/dist/web-page/renderers/frame.mjs +274 -0
- package/dist/web-page/renderers/frame.mjs.map +1 -0
- package/dist/web-page/renderers/globe.cjs +119 -0
- package/dist/web-page/renderers/globe.mjs +119 -0
- package/dist/web-page/renderers/globe.mjs.map +1 -0
- package/dist/web-page/renderers/input.cjs +137 -0
- package/dist/web-page/renderers/input.mjs +137 -0
- package/dist/web-page/renderers/input.mjs.map +1 -0
- package/dist/web-page/renderers/list.cjs +1243 -0
- package/dist/web-page/renderers/list.mjs +1243 -0
- package/dist/web-page/renderers/list.mjs.map +1 -0
- package/dist/web-page/renderers/map.cjs +126 -0
- package/dist/web-page/renderers/map.mjs +126 -0
- package/dist/web-page/renderers/map.mjs.map +1 -0
- package/dist/web-page/renderers/media.cjs +106 -0
- package/dist/web-page/renderers/media.mjs +106 -0
- package/dist/web-page/renderers/media.mjs.map +1 -0
- package/dist/web-page/renderers/moonphase.cjs +105 -0
- package/dist/web-page/renderers/moonphase.mjs +105 -0
- package/dist/web-page/renderers/moonphase.mjs.map +1 -0
- package/dist/web-page/renderers/natal-chart.cjs +222 -0
- package/dist/web-page/renderers/natal-chart.mjs +222 -0
- package/dist/web-page/renderers/natal-chart.mjs.map +1 -0
- package/dist/web-page/renderers/overlay.cjs +531 -0
- package/dist/web-page/renderers/overlay.mjs +531 -0
- package/dist/web-page/renderers/overlay.mjs.map +1 -0
- package/dist/web-page/renderers/table.cjs +74 -0
- package/dist/web-page/renderers/table.mjs +74 -0
- package/dist/web-page/renderers/table.mjs.map +1 -0
- package/dist/web-page/renderers/terminal.cjs +30 -0
- package/dist/web-page/renderers/terminal.mjs +30 -0
- package/dist/web-page/renderers/terminal.mjs.map +1 -0
- package/dist/web-page/renderers/text.cjs +109 -0
- package/dist/web-page/renderers/text.mjs +109 -0
- package/dist/web-page/renderers/text.mjs.map +1 -0
- package/dist/web-page/renderers/ticker.cjs +133 -0
- package/dist/web-page/renderers/ticker.mjs +133 -0
- package/dist/web-page/renderers/ticker.mjs.map +1 -0
- package/dist/web-page/renderers/time.cjs +69 -0
- package/dist/web-page/renderers/time.mjs +69 -0
- package/dist/web-page/renderers/time.mjs.map +1 -0
- package/dist/web-page/renderers/unknown.cjs +20 -0
- package/dist/web-page/renderers/unknown.mjs +20 -0
- package/dist/web-page/renderers/unknown.mjs.map +1 -0
- package/dist/web-page/renderers/view.cjs +161 -0
- package/dist/web-page/renderers/view.mjs +161 -0
- package/dist/web-page/renderers/view.mjs.map +1 -0
- package/dist/web-page/renderers/wm.cjs +669 -0
- package/dist/web-page/renderers/wm.mjs +669 -0
- package/dist/web-page/renderers/wm.mjs.map +1 -0
- package/dist/web-page/skeleton.cjs +103 -0
- package/dist/web-page/skeleton.mjs +103 -0
- package/dist/web-page/skeleton.mjs.map +1 -0
- package/dist/web-page.cjs +114 -0
- package/dist/web-page.d.cts +19 -0
- package/dist/web-page.d.cts.map +1 -0
- package/dist/web-page.d.mts +19 -0
- package/dist/web-page.d.mts.map +1 -0
- package/dist/web-page.mjs +115 -0
- package/dist/web-page.mjs.map +1 -0
- package/dist/web.cjs +827 -0
- package/dist/web.d.cts +144 -0
- package/dist/web.d.cts.map +1 -0
- package/dist/web.d.mts +144 -0
- package/dist/web.d.mts.map +1 -0
- package/dist/web.mjs +828 -0
- package/dist/web.mjs.map +1 -0
- package/dist/wm-state.cjs +172 -0
- package/dist/wm-state.mjs +171 -0
- package/dist/wm-state.mjs.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//#region src/aup-types.ts
|
|
2
|
+
/** Validate DeviceCaps has required fields. Returns error string or null. */
|
|
3
|
+
function validateDeviceCaps(caps) {
|
|
4
|
+
if (!caps || typeof caps !== "object") return "caps must be an object";
|
|
5
|
+
const c = caps;
|
|
6
|
+
if (!c.platform || typeof c.platform !== "string") return "caps.platform is required and must be a string";
|
|
7
|
+
if (!c.formFactor || typeof c.formFactor !== "string") return "caps.formFactor is required and must be a string";
|
|
8
|
+
if (!c.primitives || typeof c.primitives !== "object" || Array.isArray(c.primitives)) return "caps.primitives is required and must be an object";
|
|
9
|
+
const validCaps = new Set([
|
|
10
|
+
"native",
|
|
11
|
+
"webview",
|
|
12
|
+
"partial",
|
|
13
|
+
"unsupported"
|
|
14
|
+
]);
|
|
15
|
+
for (const [key, val] of Object.entries(c.primitives)) if (typeof val !== "string" || !validCaps.has(val)) return `caps.primitives.${key} must be one of: native, webview, partial, unsupported`;
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
/** All AUP primitives */
|
|
19
|
+
const AUP_PRIMITIVES = [
|
|
20
|
+
"view",
|
|
21
|
+
"text",
|
|
22
|
+
"media",
|
|
23
|
+
"input",
|
|
24
|
+
"action",
|
|
25
|
+
"overlay",
|
|
26
|
+
"table",
|
|
27
|
+
"time",
|
|
28
|
+
"chart",
|
|
29
|
+
"map",
|
|
30
|
+
"calendar",
|
|
31
|
+
"chat",
|
|
32
|
+
"terminal",
|
|
33
|
+
"rtc",
|
|
34
|
+
"explorer",
|
|
35
|
+
"editor",
|
|
36
|
+
"canvas",
|
|
37
|
+
"afs-list"
|
|
38
|
+
];
|
|
39
|
+
/** Build a primitives map with overrides and a fallback for unspecified primitives. */
|
|
40
|
+
function fillPrimitives(overrides, fallback) {
|
|
41
|
+
const result = {};
|
|
42
|
+
for (const p of AUP_PRIMITIVES) result[p] = overrides[p] ?? fallback;
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
/** TTY: stdin/stdout, text only. Everything else unsupported → degraded to text by server. */
|
|
46
|
+
const DEVICE_CAPS_TTY = {
|
|
47
|
+
platform: "cli",
|
|
48
|
+
formFactor: "terminal",
|
|
49
|
+
input: { keyboard: true },
|
|
50
|
+
primitives: fillPrimitives({ text: "native" }, "unsupported")
|
|
51
|
+
};
|
|
52
|
+
/** Term: xterm.js in browser, text + terminal subsystem. */
|
|
53
|
+
const DEVICE_CAPS_TERM = {
|
|
54
|
+
platform: "web",
|
|
55
|
+
formFactor: "terminal",
|
|
56
|
+
display: {
|
|
57
|
+
type: "visual",
|
|
58
|
+
color: "full",
|
|
59
|
+
refresh: "realtime"
|
|
60
|
+
},
|
|
61
|
+
input: { keyboard: true },
|
|
62
|
+
primitives: fillPrimitives({
|
|
63
|
+
text: "native",
|
|
64
|
+
terminal: "native"
|
|
65
|
+
}, "unsupported")
|
|
66
|
+
};
|
|
67
|
+
/** Web chat: browser with chat + basic UI. No full AUP. */
|
|
68
|
+
const DEVICE_CAPS_WEB_CHAT = {
|
|
69
|
+
platform: "web",
|
|
70
|
+
formFactor: "desktop",
|
|
71
|
+
display: {
|
|
72
|
+
type: "visual",
|
|
73
|
+
color: "full",
|
|
74
|
+
refresh: "realtime"
|
|
75
|
+
},
|
|
76
|
+
input: {
|
|
77
|
+
keyboard: true,
|
|
78
|
+
touch: true
|
|
79
|
+
},
|
|
80
|
+
primitives: fillPrimitives({
|
|
81
|
+
text: "webview",
|
|
82
|
+
chat: "webview",
|
|
83
|
+
overlay: "webview",
|
|
84
|
+
media: "webview",
|
|
85
|
+
action: "webview"
|
|
86
|
+
}, "unsupported")
|
|
87
|
+
};
|
|
88
|
+
/** Web full: browser with all primitives via WebView rendering. Default for web clients. */
|
|
89
|
+
const DEVICE_CAPS_WEB_FULL = {
|
|
90
|
+
platform: "web",
|
|
91
|
+
formFactor: "desktop",
|
|
92
|
+
display: {
|
|
93
|
+
type: "visual",
|
|
94
|
+
color: "full",
|
|
95
|
+
refresh: "realtime"
|
|
96
|
+
},
|
|
97
|
+
input: {
|
|
98
|
+
keyboard: true,
|
|
99
|
+
touch: true
|
|
100
|
+
},
|
|
101
|
+
primitives: fillPrimitives({}, "webview")
|
|
102
|
+
};
|
|
103
|
+
/** Validate an AUPNode has required fields. Returns error string or null. */
|
|
104
|
+
function validateNode(node) {
|
|
105
|
+
if (!node || typeof node !== "object") return "node must be an object";
|
|
106
|
+
const n = node;
|
|
107
|
+
if (!n.id || typeof n.id !== "string") return "node.id is required and must be a string";
|
|
108
|
+
if (!n.type || typeof n.type !== "string") return "node.type is required and must be a string";
|
|
109
|
+
if (n.src !== void 0) {
|
|
110
|
+
if (typeof n.src !== "string") return "node.src must be a string";
|
|
111
|
+
if (n.src.toLowerCase().startsWith("javascript:")) return "node.src cannot use javascript: protocol";
|
|
112
|
+
}
|
|
113
|
+
if (n.bind !== void 0) {
|
|
114
|
+
if (typeof n.bind !== "string") return "node.bind must be a string";
|
|
115
|
+
if (n.bind.toLowerCase().startsWith("javascript:")) return "node.bind cannot use javascript: protocol";
|
|
116
|
+
}
|
|
117
|
+
if (n.events && typeof n.events === "object") {
|
|
118
|
+
for (const [, evt] of Object.entries(n.events)) if (evt && typeof evt === "object") {
|
|
119
|
+
const e = evt;
|
|
120
|
+
if (typeof e.exec === "string" && e.exec.toLowerCase().startsWith("javascript:")) return "event exec path cannot use javascript: protocol";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (n.children && Array.isArray(n.children)) for (const child of n.children) {
|
|
124
|
+
const err = validateNode(child);
|
|
125
|
+
if (err) return err;
|
|
126
|
+
}
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
/** Validate a patch op has required fields. Returns error string or null. */
|
|
130
|
+
function validatePatchOp(op) {
|
|
131
|
+
if (!op || typeof op !== "object") return "patch op must be an object";
|
|
132
|
+
const o = op;
|
|
133
|
+
const opType = o.op;
|
|
134
|
+
switch (opType) {
|
|
135
|
+
case "create":
|
|
136
|
+
if (!o.id || typeof o.id !== "string") return "create op requires id";
|
|
137
|
+
if (!o.parentId || typeof o.parentId !== "string") return "create op requires parentId";
|
|
138
|
+
if (!o.node) return "create op requires node";
|
|
139
|
+
return validateNode(o.node);
|
|
140
|
+
case "update":
|
|
141
|
+
if (!o.id || typeof o.id !== "string") return "update op requires id";
|
|
142
|
+
return null;
|
|
143
|
+
case "remove":
|
|
144
|
+
if (!o.id || typeof o.id !== "string") return "remove op requires id";
|
|
145
|
+
return null;
|
|
146
|
+
case "reorder":
|
|
147
|
+
if (!o.id || typeof o.id !== "string") return "reorder op requires id";
|
|
148
|
+
if (!o.parentId || typeof o.parentId !== "string") return "reorder op requires parentId";
|
|
149
|
+
if (typeof o.index !== "number") return "reorder op requires numeric index";
|
|
150
|
+
return null;
|
|
151
|
+
default: return `unknown patch op type: ${String(opType)}`;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
//#endregion
|
|
156
|
+
export { AUP_PRIMITIVES, DEVICE_CAPS_TERM, DEVICE_CAPS_TTY, DEVICE_CAPS_WEB_CHAT, DEVICE_CAPS_WEB_FULL, fillPrimitives, validateDeviceCaps, validateNode, validatePatchOp };
|
|
157
|
+
//# sourceMappingURL=aup-types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aup-types.mjs","names":[],"sources":["../src/aup-types.ts"],"sourcesContent":["/**\n * AUP (Agentic UI Protocol) — Type definitions.\n *\n * Semantic node graph for structured UI rendering.\n * Zero visual attributes — only semantic tokens.\n */\n\n// ── Node Graph ──\n\nexport interface AUPNode {\n /** Stable identity */\n id: string;\n /** Primitive name (from registry): view, text, media, input, action, overlay, table, chat, terminal */\n type: string;\n /** Static attributes (label, src, placeholder, columns, etc.) */\n props?: Record<string, unknown>;\n /** AFS path — read-only data binding (client subscribes for updates) */\n src?: string;\n /** AFS path — read-write data binding (input writes back) */\n bind?: string;\n /** UI-local state (selected tab, expanded, open, etc.) */\n state?: Record<string, unknown>;\n /** Event bindings — each maps to an AFS exec call */\n events?: Record<string, AUPEvent>;\n /** Child nodes */\n children?: AUPNode[];\n}\n\nexport interface AUPEvent {\n /** AFS path to exec */\n exec: string;\n /** Arguments to pass to exec */\n args?: Record<string, unknown>;\n}\n\n// ── Semantic Tokens ──\n\nexport type AUPVariant = \"primary\" | \"secondary\" | \"ghost\" | \"destructive\";\nexport type AUPSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\nexport type AUPIntent = \"info\" | \"success\" | \"warning\" | \"error\";\n\n// ── Patch Operations ──\n\nexport type AUPPatchOp = AUPCreateOp | AUPUpdateOp | AUPRemoveOp | AUPReorderOp;\n\nexport interface AUPCreateOp {\n op: \"create\";\n id: string;\n parentId: string;\n node: AUPNode;\n index?: number;\n}\n\nexport interface AUPUpdateOp {\n op: \"update\";\n id: string;\n props?: Record<string, unknown>;\n state?: Record<string, unknown>;\n events?: Record<string, AUPEvent>;\n}\n\nexport interface AUPRemoveOp {\n op: \"remove\";\n id: string;\n}\n\nexport interface AUPReorderOp {\n op: \"reorder\";\n id: string;\n parentId: string;\n index: number;\n}\n\n// ── WebSocket Messages ──\n\n/** Server → Client: full render */\nexport interface AUPRenderMessage {\n type: \"aup\";\n action: \"render\";\n root: AUPNode;\n}\n\n/** Server → Client: incremental patch */\nexport interface AUPPatchMessage {\n type: \"aup\";\n action: \"patch\";\n ops: AUPPatchOp[];\n}\n\n/** Client → Server: event fired */\nexport interface AUPEventMessage {\n type: \"aup_event\";\n nodeId: string;\n event: string;\n}\n\n/** Server → Client: event result */\nexport interface AUPEventResultMessage {\n type: \"aup_event_result\";\n nodeId: string;\n event: string;\n result?: unknown;\n error?: string;\n}\n\nexport type AUPServerMessage = AUPRenderMessage | AUPPatchMessage | AUPEventResultMessage;\nexport type AUPClientMessage = AUPEventMessage;\n\n// ── Device Capabilities (D13) ──\n\n/**\n * How a device can render a specific AUP primitive.\n *\n * - \"native\" — native renderer, full functionality\n * - \"webview\" — WebView renderer, full functionality\n * - \"partial\" — renderable, but some props unsupported\n * - \"unsupported\" — cannot render; server applies degradation chain (D14)\n */\nexport type PrimitiveCap = \"native\" | \"webview\" | \"partial\" | \"unsupported\";\n\n/** Display characteristics of a device. All fields optional — informational context. */\nexport interface DeviceDisplay {\n type?: \"visual\" | \"spatial\" | \"audio-only\" | \"tactile\";\n color?: \"full\" | \"limited\" | \"mono\";\n refresh?: \"realtime\" | \"slow\";\n resolution?: { w: number; h: number };\n depth?: \"2d\" | \"3d\";\n}\n\n/** Input modalities available on a device. */\nexport interface DeviceInput {\n touch?: boolean;\n keyboard?: boolean;\n voice?: boolean;\n gaze?: boolean;\n gesture?: boolean;\n controller?: boolean;\n}\n\n/**\n * Device capability declaration (D13).\n *\n * Sent by client during session handshake. Agent reads via AFS path.\n * Server uses `primitives` map + degradation chain (D14) to adapt AUP tree.\n */\nexport interface DeviceCaps {\n /** Platform identifier: \"web\", \"ios\", \"android\", \"vr\", etc. */\n platform: string;\n /** Form factor: \"desktop\", \"phone\", \"tablet\", \"watch\", \"tv\", \"headset\", etc. */\n formFactor: string;\n /** Display characteristics (optional, informational) */\n display?: DeviceDisplay;\n /** Input modalities (optional, informational) */\n input?: DeviceInput;\n /** Per-primitive rendering capability */\n primitives: Record<string, PrimitiveCap>;\n /** Platform features: camera, gps, biometric, haptic, etc. */\n features?: Record<string, boolean>;\n}\n\n/** Validate DeviceCaps has required fields. Returns error string or null. */\nexport function validateDeviceCaps(caps: unknown): string | null {\n if (!caps || typeof caps !== \"object\") return \"caps must be an object\";\n const c = caps as Record<string, unknown>;\n if (!c.platform || typeof c.platform !== \"string\")\n return \"caps.platform is required and must be a string\";\n if (!c.formFactor || typeof c.formFactor !== \"string\")\n return \"caps.formFactor is required and must be a string\";\n if (!c.primitives || typeof c.primitives !== \"object\" || Array.isArray(c.primitives))\n return \"caps.primitives is required and must be an object\";\n\n const validCaps = new Set([\"native\", \"webview\", \"partial\", \"unsupported\"]);\n for (const [key, val] of Object.entries(c.primitives as Record<string, unknown>)) {\n if (typeof val !== \"string\" || !validCaps.has(val)) {\n return `caps.primitives.${key} must be one of: native, webview, partial, unsupported`;\n }\n }\n return null;\n}\n\n// ── Default Device Caps Presets (D16) ──\n\n/** All AUP primitives */\nexport const AUP_PRIMITIVES = [\n \"view\",\n \"text\",\n \"media\",\n \"input\",\n \"action\",\n \"overlay\",\n \"table\",\n \"time\",\n \"chart\",\n \"map\",\n \"calendar\",\n \"chat\",\n \"terminal\",\n \"rtc\",\n \"explorer\",\n \"editor\",\n \"canvas\",\n \"afs-list\",\n] as const;\n\n/** Build a primitives map with overrides and a fallback for unspecified primitives. */\nexport function fillPrimitives(\n overrides: Partial<Record<string, PrimitiveCap>>,\n fallback: PrimitiveCap,\n): Record<string, PrimitiveCap> {\n const result: Record<string, PrimitiveCap> = {};\n for (const p of AUP_PRIMITIVES) {\n result[p] = overrides[p] ?? fallback;\n }\n return result;\n}\n\n/** TTY: stdin/stdout, text only. Everything else unsupported → degraded to text by server. */\nexport const DEVICE_CAPS_TTY: DeviceCaps = {\n platform: \"cli\",\n formFactor: \"terminal\",\n input: { keyboard: true },\n primitives: fillPrimitives({ text: \"native\" }, \"unsupported\"),\n};\n\n/** Term: xterm.js in browser, text + terminal subsystem. */\nexport const DEVICE_CAPS_TERM: DeviceCaps = {\n platform: \"web\",\n formFactor: \"terminal\",\n display: { type: \"visual\", color: \"full\", refresh: \"realtime\" },\n input: { keyboard: true },\n primitives: fillPrimitives({ text: \"native\", terminal: \"native\" }, \"unsupported\"),\n};\n\n/** Web chat: browser with chat + basic UI. No full AUP. */\nexport const DEVICE_CAPS_WEB_CHAT: DeviceCaps = {\n platform: \"web\",\n formFactor: \"desktop\",\n display: { type: \"visual\", color: \"full\", refresh: \"realtime\" },\n input: { keyboard: true, touch: true },\n primitives: fillPrimitives(\n { text: \"webview\", chat: \"webview\", overlay: \"webview\", media: \"webview\", action: \"webview\" },\n \"unsupported\",\n ),\n};\n\n/** Web full: browser with all primitives via WebView rendering. Default for web clients. */\nexport const DEVICE_CAPS_WEB_FULL: DeviceCaps = {\n platform: \"web\",\n formFactor: \"desktop\",\n display: { type: \"visual\", color: \"full\", refresh: \"realtime\" },\n input: { keyboard: true, touch: true },\n primitives: fillPrimitives({}, \"webview\"),\n};\n\n// ── Validation ──\n\n/** Validate an AUPNode has required fields. Returns error string or null. */\nexport function validateNode(node: unknown): string | null {\n if (!node || typeof node !== \"object\") return \"node must be an object\";\n const n = node as Record<string, unknown>;\n if (!n.id || typeof n.id !== \"string\") return \"node.id is required and must be a string\";\n if (!n.type || typeof n.type !== \"string\") return \"node.type is required and must be a string\";\n\n // Validate src/bind — must be strings, no javascript:\n if (n.src !== undefined) {\n if (typeof n.src !== \"string\") return \"node.src must be a string\";\n if (n.src.toLowerCase().startsWith(\"javascript:\"))\n return \"node.src cannot use javascript: protocol\";\n }\n if (n.bind !== undefined) {\n if (typeof n.bind !== \"string\") return \"node.bind must be a string\";\n if (n.bind.toLowerCase().startsWith(\"javascript:\"))\n return \"node.bind cannot use javascript: protocol\";\n }\n\n // Validate events — exec paths must not contain javascript:\n if (n.events && typeof n.events === \"object\") {\n for (const [, evt] of Object.entries(n.events as Record<string, unknown>)) {\n if (evt && typeof evt === \"object\") {\n const e = evt as Record<string, unknown>;\n if (typeof e.exec === \"string\" && e.exec.toLowerCase().startsWith(\"javascript:\")) {\n return \"event exec path cannot use javascript: protocol\";\n }\n }\n }\n }\n\n // Recurse children\n if (n.children && Array.isArray(n.children)) {\n for (const child of n.children) {\n const err = validateNode(child);\n if (err) return err;\n }\n }\n return null;\n}\n\n/** Validate a patch op has required fields. Returns error string or null. */\nexport function validatePatchOp(op: unknown): string | null {\n if (!op || typeof op !== \"object\") return \"patch op must be an object\";\n const o = op as Record<string, unknown>;\n const opType = o.op;\n\n switch (opType) {\n case \"create\":\n if (!o.id || typeof o.id !== \"string\") return \"create op requires id\";\n if (!o.parentId || typeof o.parentId !== \"string\") return \"create op requires parentId\";\n if (!o.node) return \"create op requires node\";\n return validateNode(o.node);\n case \"update\":\n if (!o.id || typeof o.id !== \"string\") return \"update op requires id\";\n return null;\n case \"remove\":\n if (!o.id || typeof o.id !== \"string\") return \"remove op requires id\";\n return null;\n case \"reorder\":\n if (!o.id || typeof o.id !== \"string\") return \"reorder op requires id\";\n if (!o.parentId || typeof o.parentId !== \"string\") return \"reorder op requires parentId\";\n if (typeof o.index !== \"number\") return \"reorder op requires numeric index\";\n return null;\n default:\n return `unknown patch op type: ${String(opType)}`;\n }\n}\n"],"mappings":"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"}
|
package/dist/backend.cjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/backend.ts
|
|
3
|
+
/** Type guard: does this backend support per-client session management? */
|
|
4
|
+
function isSessionAware(b) {
|
|
5
|
+
return "setSessionFactory" in b && typeof b.setSessionFactory === "function";
|
|
6
|
+
}
|
|
7
|
+
/** Type guard: does this backend support AUP message push to sessions/channels? */
|
|
8
|
+
function isAUPTransport(b) {
|
|
9
|
+
return "sendToSession" in b && typeof b.sendToSession === "function";
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
//#endregion
|
|
13
|
+
exports.isAUPTransport = isAUPTransport;
|
|
14
|
+
exports.isSessionAware = isSessionAware;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//#region src/backend.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* UIBackend — pluggable I/O backend interface.
|
|
4
|
+
*
|
|
5
|
+
* Each backend (tty, web, telegram) implements this interface
|
|
6
|
+
* to provide the actual I/O channel for the UI provider.
|
|
7
|
+
*/
|
|
8
|
+
interface UIBackend {
|
|
9
|
+
/** Backend type identifier */
|
|
10
|
+
readonly type: string;
|
|
11
|
+
/** Supported output formats */
|
|
12
|
+
readonly supportedFormats: string[];
|
|
13
|
+
/** Capabilities of this backend */
|
|
14
|
+
readonly capabilities: string[];
|
|
15
|
+
/** Write content to the output channel */
|
|
16
|
+
write(content: string, options?: WriteOptions): Promise<void>;
|
|
17
|
+
/** Read input from the user (blocks until input available or timeout) */
|
|
18
|
+
read(options?: ReadOptions): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Prompt the user for input with specific type.
|
|
21
|
+
* Returns the user's response.
|
|
22
|
+
*/
|
|
23
|
+
prompt(options: PromptOptions): Promise<PromptResult>;
|
|
24
|
+
/** Send a non-blocking notification */
|
|
25
|
+
notify(message: string): Promise<void>;
|
|
26
|
+
/** Clear the output channel */
|
|
27
|
+
clear(): Promise<void>;
|
|
28
|
+
/** Check if there is pending input available */
|
|
29
|
+
hasPendingInput(): boolean;
|
|
30
|
+
/** Get viewport/dimension info */
|
|
31
|
+
getViewport(): ViewportInfo;
|
|
32
|
+
/** Cleanup resources */
|
|
33
|
+
dispose(): Promise<void>;
|
|
34
|
+
/** Navigate to a page (optional — for page-capable backends) */
|
|
35
|
+
navigate?(pageId: string, content: string, format?: string, layout?: Record<string, string>): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
interface WriteOptions {
|
|
38
|
+
format?: string;
|
|
39
|
+
component?: string;
|
|
40
|
+
componentProps?: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
interface ReadOptions {
|
|
43
|
+
timeout?: number;
|
|
44
|
+
}
|
|
45
|
+
interface PromptOptions {
|
|
46
|
+
message: string;
|
|
47
|
+
type: "text" | "password" | "confirm" | "select" | "multiselect";
|
|
48
|
+
options?: string[];
|
|
49
|
+
defaultValue?: string | boolean;
|
|
50
|
+
}
|
|
51
|
+
type PromptResult = string | boolean | string[];
|
|
52
|
+
interface ViewportInfo {
|
|
53
|
+
cols?: number;
|
|
54
|
+
rows?: number;
|
|
55
|
+
width?: number;
|
|
56
|
+
height?: number;
|
|
57
|
+
}
|
|
58
|
+
interface FormField {
|
|
59
|
+
name: string;
|
|
60
|
+
label: string;
|
|
61
|
+
type: "text" | "number" | "password" | "select" | "checkbox" | "textarea";
|
|
62
|
+
options?: string[];
|
|
63
|
+
defaultValue?: string | number | boolean;
|
|
64
|
+
required?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** Callback types for transport handler registration */
|
|
67
|
+
type SessionFactory = (endpoint: string, requestedSessionId?: string, requestedSessionToken?: string, caps?: Record<string, unknown>) => {
|
|
68
|
+
sessionId: string;
|
|
69
|
+
sessionToken?: string;
|
|
70
|
+
};
|
|
71
|
+
type AupEventHandler = (msg: {
|
|
72
|
+
nodeId: string;
|
|
73
|
+
event: string;
|
|
74
|
+
data?: Record<string, unknown>;
|
|
75
|
+
}, sessionId?: string, channelId?: string) => Promise<unknown>;
|
|
76
|
+
type ChannelJoinHandler = (channelId: string, send: (msg: Record<string, unknown>) => void) => void;
|
|
77
|
+
type SessionJoinHandler = (sessionId: string, clientVersion: number, send: (msg: Record<string, unknown>) => void) => void;
|
|
78
|
+
type PageResolver = (pageId: string, sessionId?: string, sessionToken?: string) => Promise<{
|
|
79
|
+
content: string;
|
|
80
|
+
format: string;
|
|
81
|
+
} | null>;
|
|
82
|
+
/** Backend that manages per-client sessions (e.g. WebSocket-based backends). */
|
|
83
|
+
interface SessionAwareBackend {
|
|
84
|
+
setSessionFactory(fn: SessionFactory): void;
|
|
85
|
+
}
|
|
86
|
+
/** Backend that can push AUP messages to sessions and live channels. */
|
|
87
|
+
interface AUPTransportBackend extends SessionAwareBackend {
|
|
88
|
+
sendToSession(sessionId: string, msg: Record<string, unknown>): void;
|
|
89
|
+
sendToLiveChannel(channelId: string, msg: Record<string, unknown>): void;
|
|
90
|
+
broadcastRaw(msg: Record<string, unknown>): void;
|
|
91
|
+
getActiveChannelIds(): string[];
|
|
92
|
+
setAupEventHandler(fn: AupEventHandler): void;
|
|
93
|
+
setChannelJoinHandler(fn: ChannelJoinHandler): void;
|
|
94
|
+
setSessionJoinHandler(fn: SessionJoinHandler): void;
|
|
95
|
+
setPageResolver(fn: PageResolver): void;
|
|
96
|
+
setAFS(afs: unknown): void;
|
|
97
|
+
}
|
|
98
|
+
/** Type guard: does this backend support per-client session management? */
|
|
99
|
+
declare function isSessionAware(b: UIBackend): b is UIBackend & SessionAwareBackend;
|
|
100
|
+
/** Type guard: does this backend support AUP message push to sessions/channels? */
|
|
101
|
+
declare function isAUPTransport(b: UIBackend): b is UIBackend & AUPTransportBackend;
|
|
102
|
+
//#endregion
|
|
103
|
+
export { AUPTransportBackend, AupEventHandler, ChannelJoinHandler, FormField, PageResolver, PromptOptions, PromptResult, ReadOptions, SessionAwareBackend, SessionFactory, SessionJoinHandler, UIBackend, ViewportInfo, WriteOptions, isAUPTransport, isSessionAware };
|
|
104
|
+
//# sourceMappingURL=backend.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.cts","names":[],"sources":["../src/backend.ts"],"mappings":";;AAMA;;;;;UAAiB,SAAA;EAcc;EAAA,SAZpB,IAAA;EAkB+B;EAAA,SAf/B,gBAAA;EAkBgB;EAAA,SAfhB,YAAA;EAwBM;EArBf,KAAA,CAAM,OAAA,UAAiB,OAAA,GAAU,YAAA,GAAe,OAAA;EA+BrC;EA5BX,IAAA,CAAK,OAAA,GAAU,WAAA,GAAc,OAAA;EA6BnB;;;;EAvBV,MAAA,CAAO,OAAA,EAAS,aAAA,GAAgB,OAAA,CAAQ,YAAA;EATxC;EAYA,MAAA,CAAO,OAAA,WAAkB,OAAA;EAZQ;EAejC,KAAA,IAAS,OAAA;EAfuC;EAkBhD,eAAA;EAfe;EAkBf,WAAA,IAAe,YAAA;EAlBc;EAqB7B,OAAA,IAAW,OAAA;EAfK;EAkBhB,QAAA,EACE,MAAA,UACA,OAAA,UACA,MAAA,WACA,MAAA,GAAS,MAAA,mBACR,OAAA;AAAA;AAAA,UAGY,YAAA;EACf,MAAA;EACA,SAAA;EACA,cAAA,GAAiB,MAAA;AAAA;AAAA,UAGF,WAAA;EACf,OAAA;AAAA;AAAA,UAGe,aAAA;EACf,OAAA;EACA,IAAA;EACA,OAAA;EACA,YAAA;AAAA;AAAA,KAGU,YAAA;AAAA,UAEK,YAAA;EACf,IAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA;EACA,YAAA;EACA,QAAA;AAAA;;KAMU,cAAA,IACV,QAAA,UACA,kBAAA,WACA,qBAAA,WACA,IAAA,GAAO,MAAA;EACF,SAAA;EAAmB,YAAA;AAAA;AAAA,KAEd,eAAA,IACV,GAAA;EAAO,MAAA;EAAgB,KAAA;EAAe,IAAA,GAAO,MAAA;AAAA,GAC7C,SAAA,WACA,SAAA,cACG,OAAA;AAAA,KAEO,kBAAA,IACV,SAAA,UACA,IAAA,GAAO,GAAA,EAAK,MAAA;AAAA,KAGF,kBAAA,IACV,SAAA,UACA,aAAA,UACA,IAAA,GAAO,GAAA,EAAK,MAAA;AAAA,KAGF,YAAA,IACV,MAAA,UACA,SAAA,WACA,YAAA,cACG,OAAA;EAAU,OAAA;EAAiB,MAAA;AAAA;AAjDhC;AAAA,UAoDiB,mBAAA;EACf,iBAAA,CAAkB,EAAA,EAAI,cAAA;AAAA;;UAIP,mBAAA,SAA4B,mBAAA;EAC3C,aAAA,CAAc,SAAA,UAAmB,GAAA,EAAK,MAAA;EACtC,iBAAA,CAAkB,SAAA,UAAmB,GAAA,EAAK,MAAA;EAC1C,YAAA,CAAa,GAAA,EAAK,MAAA;EAClB,mBAAA;EACA,kBAAA,CAAmB,EAAA,EAAI,eAAA;EACvB,qBAAA,CAAsB,EAAA,EAAI,kBAAA;EAC1B,qBAAA,CAAsB,EAAA,EAAI,kBAAA;EAC1B,eAAA,CAAgB,EAAA,EAAI,YAAA;EACpB,MAAA,CAAO,GAAA;AAAA;;iBAIO,cAAA,CAAe,CAAA,EAAG,SAAA,GAAY,CAAA,IAAK,SAAA,GAAY,mBAAA;;iBAQ/C,cAAA,CAAe,CAAA,EAAG,SAAA,GAAY,CAAA,IAAK,SAAA,GAAY,mBAAA"}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//#region src/backend.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* UIBackend — pluggable I/O backend interface.
|
|
4
|
+
*
|
|
5
|
+
* Each backend (tty, web, telegram) implements this interface
|
|
6
|
+
* to provide the actual I/O channel for the UI provider.
|
|
7
|
+
*/
|
|
8
|
+
interface UIBackend {
|
|
9
|
+
/** Backend type identifier */
|
|
10
|
+
readonly type: string;
|
|
11
|
+
/** Supported output formats */
|
|
12
|
+
readonly supportedFormats: string[];
|
|
13
|
+
/** Capabilities of this backend */
|
|
14
|
+
readonly capabilities: string[];
|
|
15
|
+
/** Write content to the output channel */
|
|
16
|
+
write(content: string, options?: WriteOptions): Promise<void>;
|
|
17
|
+
/** Read input from the user (blocks until input available or timeout) */
|
|
18
|
+
read(options?: ReadOptions): Promise<string>;
|
|
19
|
+
/**
|
|
20
|
+
* Prompt the user for input with specific type.
|
|
21
|
+
* Returns the user's response.
|
|
22
|
+
*/
|
|
23
|
+
prompt(options: PromptOptions): Promise<PromptResult>;
|
|
24
|
+
/** Send a non-blocking notification */
|
|
25
|
+
notify(message: string): Promise<void>;
|
|
26
|
+
/** Clear the output channel */
|
|
27
|
+
clear(): Promise<void>;
|
|
28
|
+
/** Check if there is pending input available */
|
|
29
|
+
hasPendingInput(): boolean;
|
|
30
|
+
/** Get viewport/dimension info */
|
|
31
|
+
getViewport(): ViewportInfo;
|
|
32
|
+
/** Cleanup resources */
|
|
33
|
+
dispose(): Promise<void>;
|
|
34
|
+
/** Navigate to a page (optional — for page-capable backends) */
|
|
35
|
+
navigate?(pageId: string, content: string, format?: string, layout?: Record<string, string>): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
interface WriteOptions {
|
|
38
|
+
format?: string;
|
|
39
|
+
component?: string;
|
|
40
|
+
componentProps?: Record<string, unknown>;
|
|
41
|
+
}
|
|
42
|
+
interface ReadOptions {
|
|
43
|
+
timeout?: number;
|
|
44
|
+
}
|
|
45
|
+
interface PromptOptions {
|
|
46
|
+
message: string;
|
|
47
|
+
type: "text" | "password" | "confirm" | "select" | "multiselect";
|
|
48
|
+
options?: string[];
|
|
49
|
+
defaultValue?: string | boolean;
|
|
50
|
+
}
|
|
51
|
+
type PromptResult = string | boolean | string[];
|
|
52
|
+
interface ViewportInfo {
|
|
53
|
+
cols?: number;
|
|
54
|
+
rows?: number;
|
|
55
|
+
width?: number;
|
|
56
|
+
height?: number;
|
|
57
|
+
}
|
|
58
|
+
interface FormField {
|
|
59
|
+
name: string;
|
|
60
|
+
label: string;
|
|
61
|
+
type: "text" | "number" | "password" | "select" | "checkbox" | "textarea";
|
|
62
|
+
options?: string[];
|
|
63
|
+
defaultValue?: string | number | boolean;
|
|
64
|
+
required?: boolean;
|
|
65
|
+
}
|
|
66
|
+
/** Callback types for transport handler registration */
|
|
67
|
+
type SessionFactory = (endpoint: string, requestedSessionId?: string, requestedSessionToken?: string, caps?: Record<string, unknown>) => {
|
|
68
|
+
sessionId: string;
|
|
69
|
+
sessionToken?: string;
|
|
70
|
+
};
|
|
71
|
+
type AupEventHandler = (msg: {
|
|
72
|
+
nodeId: string;
|
|
73
|
+
event: string;
|
|
74
|
+
data?: Record<string, unknown>;
|
|
75
|
+
}, sessionId?: string, channelId?: string) => Promise<unknown>;
|
|
76
|
+
type ChannelJoinHandler = (channelId: string, send: (msg: Record<string, unknown>) => void) => void;
|
|
77
|
+
type SessionJoinHandler = (sessionId: string, clientVersion: number, send: (msg: Record<string, unknown>) => void) => void;
|
|
78
|
+
type PageResolver = (pageId: string, sessionId?: string, sessionToken?: string) => Promise<{
|
|
79
|
+
content: string;
|
|
80
|
+
format: string;
|
|
81
|
+
} | null>;
|
|
82
|
+
/** Backend that manages per-client sessions (e.g. WebSocket-based backends). */
|
|
83
|
+
interface SessionAwareBackend {
|
|
84
|
+
setSessionFactory(fn: SessionFactory): void;
|
|
85
|
+
}
|
|
86
|
+
/** Backend that can push AUP messages to sessions and live channels. */
|
|
87
|
+
interface AUPTransportBackend extends SessionAwareBackend {
|
|
88
|
+
sendToSession(sessionId: string, msg: Record<string, unknown>): void;
|
|
89
|
+
sendToLiveChannel(channelId: string, msg: Record<string, unknown>): void;
|
|
90
|
+
broadcastRaw(msg: Record<string, unknown>): void;
|
|
91
|
+
getActiveChannelIds(): string[];
|
|
92
|
+
setAupEventHandler(fn: AupEventHandler): void;
|
|
93
|
+
setChannelJoinHandler(fn: ChannelJoinHandler): void;
|
|
94
|
+
setSessionJoinHandler(fn: SessionJoinHandler): void;
|
|
95
|
+
setPageResolver(fn: PageResolver): void;
|
|
96
|
+
setAFS(afs: unknown): void;
|
|
97
|
+
}
|
|
98
|
+
/** Type guard: does this backend support per-client session management? */
|
|
99
|
+
declare function isSessionAware(b: UIBackend): b is UIBackend & SessionAwareBackend;
|
|
100
|
+
/** Type guard: does this backend support AUP message push to sessions/channels? */
|
|
101
|
+
declare function isAUPTransport(b: UIBackend): b is UIBackend & AUPTransportBackend;
|
|
102
|
+
//#endregion
|
|
103
|
+
export { AUPTransportBackend, AupEventHandler, ChannelJoinHandler, FormField, PageResolver, PromptOptions, PromptResult, ReadOptions, SessionAwareBackend, SessionFactory, SessionJoinHandler, UIBackend, ViewportInfo, WriteOptions, isAUPTransport, isSessionAware };
|
|
104
|
+
//# sourceMappingURL=backend.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.mts","names":[],"sources":["../src/backend.ts"],"mappings":";;AAMA;;;;;UAAiB,SAAA;EAcc;EAAA,SAZpB,IAAA;EAkB+B;EAAA,SAf/B,gBAAA;EAkBgB;EAAA,SAfhB,YAAA;EAwBM;EArBf,KAAA,CAAM,OAAA,UAAiB,OAAA,GAAU,YAAA,GAAe,OAAA;EA+BrC;EA5BX,IAAA,CAAK,OAAA,GAAU,WAAA,GAAc,OAAA;EA6BnB;;;;EAvBV,MAAA,CAAO,OAAA,EAAS,aAAA,GAAgB,OAAA,CAAQ,YAAA;EATxC;EAYA,MAAA,CAAO,OAAA,WAAkB,OAAA;EAZQ;EAejC,KAAA,IAAS,OAAA;EAfuC;EAkBhD,eAAA;EAfe;EAkBf,WAAA,IAAe,YAAA;EAlBc;EAqB7B,OAAA,IAAW,OAAA;EAfK;EAkBhB,QAAA,EACE,MAAA,UACA,OAAA,UACA,MAAA,WACA,MAAA,GAAS,MAAA,mBACR,OAAA;AAAA;AAAA,UAGY,YAAA;EACf,MAAA;EACA,SAAA;EACA,cAAA,GAAiB,MAAA;AAAA;AAAA,UAGF,WAAA;EACf,OAAA;AAAA;AAAA,UAGe,aAAA;EACf,OAAA;EACA,IAAA;EACA,OAAA;EACA,YAAA;AAAA;AAAA,KAGU,YAAA;AAAA,UAEK,YAAA;EACf,IAAA;EACA,IAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,KAAA;EACA,IAAA;EACA,OAAA;EACA,YAAA;EACA,QAAA;AAAA;;KAMU,cAAA,IACV,QAAA,UACA,kBAAA,WACA,qBAAA,WACA,IAAA,GAAO,MAAA;EACF,SAAA;EAAmB,YAAA;AAAA;AAAA,KAEd,eAAA,IACV,GAAA;EAAO,MAAA;EAAgB,KAAA;EAAe,IAAA,GAAO,MAAA;AAAA,GAC7C,SAAA,WACA,SAAA,cACG,OAAA;AAAA,KAEO,kBAAA,IACV,SAAA,UACA,IAAA,GAAO,GAAA,EAAK,MAAA;AAAA,KAGF,kBAAA,IACV,SAAA,UACA,aAAA,UACA,IAAA,GAAO,GAAA,EAAK,MAAA;AAAA,KAGF,YAAA,IACV,MAAA,UACA,SAAA,WACA,YAAA,cACG,OAAA;EAAU,OAAA;EAAiB,MAAA;AAAA;AAjDhC;AAAA,UAoDiB,mBAAA;EACf,iBAAA,CAAkB,EAAA,EAAI,cAAA;AAAA;;UAIP,mBAAA,SAA4B,mBAAA;EAC3C,aAAA,CAAc,SAAA,UAAmB,GAAA,EAAK,MAAA;EACtC,iBAAA,CAAkB,SAAA,UAAmB,GAAA,EAAK,MAAA;EAC1C,YAAA,CAAa,GAAA,EAAK,MAAA;EAClB,mBAAA;EACA,kBAAA,CAAmB,EAAA,EAAI,eAAA;EACvB,qBAAA,CAAsB,EAAA,EAAI,kBAAA;EAC1B,qBAAA,CAAsB,EAAA,EAAI,kBAAA;EAC1B,eAAA,CAAgB,EAAA,EAAI,YAAA;EACpB,MAAA,CAAO,GAAA;AAAA;;iBAIO,cAAA,CAAe,CAAA,EAAG,SAAA,GAAY,CAAA,IAAK,SAAA,GAAY,mBAAA;;iBAQ/C,cAAA,CAAe,CAAA,EAAG,SAAA,GAAY,CAAA,IAAK,SAAA,GAAY,mBAAA"}
|
package/dist/backend.mjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/backend.ts
|
|
2
|
+
/** Type guard: does this backend support per-client session management? */
|
|
3
|
+
function isSessionAware(b) {
|
|
4
|
+
return "setSessionFactory" in b && typeof b.setSessionFactory === "function";
|
|
5
|
+
}
|
|
6
|
+
/** Type guard: does this backend support AUP message push to sessions/channels? */
|
|
7
|
+
function isAUPTransport(b) {
|
|
8
|
+
return "sendToSession" in b && typeof b.sendToSession === "function";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
//#endregion
|
|
12
|
+
export { isAUPTransport, isSessionAware };
|
|
13
|
+
//# sourceMappingURL=backend.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.mjs","names":[],"sources":["../src/backend.ts"],"sourcesContent":["/**\n * UIBackend — pluggable I/O backend interface.\n *\n * Each backend (tty, web, telegram) implements this interface\n * to provide the actual I/O channel for the UI provider.\n */\nexport interface UIBackend {\n /** Backend type identifier */\n readonly type: string;\n\n /** Supported output formats */\n readonly supportedFormats: string[];\n\n /** Capabilities of this backend */\n readonly capabilities: string[];\n\n /** Write content to the output channel */\n write(content: string, options?: WriteOptions): Promise<void>;\n\n /** Read input from the user (blocks until input available or timeout) */\n read(options?: ReadOptions): Promise<string>;\n\n /**\n * Prompt the user for input with specific type.\n * Returns the user's response.\n */\n prompt(options: PromptOptions): Promise<PromptResult>;\n\n /** Send a non-blocking notification */\n notify(message: string): Promise<void>;\n\n /** Clear the output channel */\n clear(): Promise<void>;\n\n /** Check if there is pending input available */\n hasPendingInput(): boolean;\n\n /** Get viewport/dimension info */\n getViewport(): ViewportInfo;\n\n /** Cleanup resources */\n dispose(): Promise<void>;\n\n /** Navigate to a page (optional — for page-capable backends) */\n navigate?(\n pageId: string,\n content: string,\n format?: string,\n layout?: Record<string, string>,\n ): Promise<void>;\n}\n\nexport interface WriteOptions {\n format?: string;\n component?: string;\n componentProps?: Record<string, unknown>;\n}\n\nexport interface ReadOptions {\n timeout?: number;\n}\n\nexport interface PromptOptions {\n message: string;\n type: \"text\" | \"password\" | \"confirm\" | \"select\" | \"multiselect\";\n options?: string[];\n defaultValue?: string | boolean;\n}\n\nexport type PromptResult = string | boolean | string[];\n\nexport interface ViewportInfo {\n cols?: number;\n rows?: number;\n width?: number;\n height?: number;\n}\n\nexport interface FormField {\n name: string;\n label: string;\n type: \"text\" | \"number\" | \"password\" | \"select\" | \"checkbox\" | \"textarea\";\n options?: string[];\n defaultValue?: string | number | boolean;\n required?: boolean;\n}\n\n// ── Transport Interfaces (D16: Transport ≠ Capability) ──\n\n/** Callback types for transport handler registration */\nexport type SessionFactory = (\n endpoint: string,\n requestedSessionId?: string,\n requestedSessionToken?: string,\n caps?: Record<string, unknown>,\n) => { sessionId: string; sessionToken?: string };\n\nexport type AupEventHandler = (\n msg: { nodeId: string; event: string; data?: Record<string, unknown> },\n sessionId?: string,\n channelId?: string,\n) => Promise<unknown>;\n\nexport type ChannelJoinHandler = (\n channelId: string,\n send: (msg: Record<string, unknown>) => void,\n) => void;\n\nexport type SessionJoinHandler = (\n sessionId: string,\n clientVersion: number,\n send: (msg: Record<string, unknown>) => void,\n) => void;\n\nexport type PageResolver = (\n pageId: string,\n sessionId?: string,\n sessionToken?: string,\n) => Promise<{ content: string; format: string } | null>;\n\n/** Backend that manages per-client sessions (e.g. WebSocket-based backends). */\nexport interface SessionAwareBackend {\n setSessionFactory(fn: SessionFactory): void;\n}\n\n/** Backend that can push AUP messages to sessions and live channels. */\nexport interface AUPTransportBackend extends SessionAwareBackend {\n sendToSession(sessionId: string, msg: Record<string, unknown>): void;\n sendToLiveChannel(channelId: string, msg: Record<string, unknown>): void;\n broadcastRaw(msg: Record<string, unknown>): void;\n getActiveChannelIds(): string[];\n setAupEventHandler(fn: AupEventHandler): void;\n setChannelJoinHandler(fn: ChannelJoinHandler): void;\n setSessionJoinHandler(fn: SessionJoinHandler): void;\n setPageResolver(fn: PageResolver): void;\n setAFS(afs: unknown): void;\n}\n\n/** Type guard: does this backend support per-client session management? */\nexport function isSessionAware(b: UIBackend): b is UIBackend & SessionAwareBackend {\n return (\n \"setSessionFactory\" in b &&\n typeof (b as Record<string, unknown>).setSessionFactory === \"function\"\n );\n}\n\n/** Type guard: does this backend support AUP message push to sessions/channels? */\nexport function isAUPTransport(b: UIBackend): b is UIBackend & AUPTransportBackend {\n return \"sendToSession\" in b && typeof (b as Record<string, unknown>).sendToSession === \"function\";\n}\n"],"mappings":";;AA2IA,SAAgB,eAAe,GAAoD;AACjF,QACE,uBAAuB,KACvB,OAAQ,EAA8B,sBAAsB;;;AAKhE,SAAgB,eAAe,GAAoD;AACjF,QAAO,mBAAmB,KAAK,OAAQ,EAA8B,kBAAkB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/degradation.ts
|
|
3
|
+
/**
|
|
4
|
+
* Each entry maps a primitive type to its ordered degradation chain.
|
|
5
|
+
* The chain is tried left-to-right; the first supported type wins.
|
|
6
|
+
* "unsupported" means no meaningful fallback exists.
|
|
7
|
+
*/
|
|
8
|
+
const DEGRADATION_CHAINS = {
|
|
9
|
+
globe: [
|
|
10
|
+
"map",
|
|
11
|
+
"media",
|
|
12
|
+
"text"
|
|
13
|
+
],
|
|
14
|
+
chart: ["table", "text"],
|
|
15
|
+
map: ["media", "text"],
|
|
16
|
+
editor: ["input", "text"],
|
|
17
|
+
terminal: ["text"],
|
|
18
|
+
canvas: ["media", "text"],
|
|
19
|
+
rtc: ["unsupported"],
|
|
20
|
+
calendar: ["table", "text"],
|
|
21
|
+
time: ["text"],
|
|
22
|
+
overlay: ["text"]
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Walk the AUP tree and degrade unsupported primitives.
|
|
26
|
+
* Returns a new tree (does not mutate the original).
|
|
27
|
+
*/
|
|
28
|
+
function degradeTree(node, caps) {
|
|
29
|
+
return degradeNode(node, caps);
|
|
30
|
+
}
|
|
31
|
+
function isSupported(primitiveType, caps) {
|
|
32
|
+
const cap = caps.primitives[primitiveType];
|
|
33
|
+
return cap === "native" || cap === "webview" || cap === "partial";
|
|
34
|
+
}
|
|
35
|
+
function degradeNode(node, caps) {
|
|
36
|
+
let result = degradeNodeType(node, caps);
|
|
37
|
+
if (result.children && result.children.length > 0) {
|
|
38
|
+
const degradedChildren = result.children.map((child) => degradeNode(child, caps));
|
|
39
|
+
if (degradedChildren.some((c, i) => c !== result.children[i])) result = {
|
|
40
|
+
...result,
|
|
41
|
+
children: degradedChildren
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
function degradeNodeType(node, caps) {
|
|
47
|
+
const nodeType = node.type;
|
|
48
|
+
if (isSupported(nodeType, caps)) return node;
|
|
49
|
+
const chain = DEGRADATION_CHAINS[nodeType];
|
|
50
|
+
if (!chain) return node;
|
|
51
|
+
const originalType = nodeType;
|
|
52
|
+
for (const fallbackType of chain) {
|
|
53
|
+
if (fallbackType === "unsupported") return {
|
|
54
|
+
...node,
|
|
55
|
+
type: "text",
|
|
56
|
+
props: {
|
|
57
|
+
...node.props,
|
|
58
|
+
_degradedFrom: originalType,
|
|
59
|
+
_unsupported: true,
|
|
60
|
+
content: node.props?.content ?? `[${originalType}: unsupported on this device]`
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
if (isSupported(fallbackType, caps)) return {
|
|
64
|
+
...node,
|
|
65
|
+
type: fallbackType,
|
|
66
|
+
props: {
|
|
67
|
+
...node.props,
|
|
68
|
+
_degradedFrom: originalType
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
...node,
|
|
74
|
+
type: "text",
|
|
75
|
+
props: {
|
|
76
|
+
...node.props,
|
|
77
|
+
_degradedFrom: originalType,
|
|
78
|
+
content: node.props?.content ?? `[${originalType}: degraded to text]`
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
//#endregion
|
|
84
|
+
exports.DEGRADATION_CHAINS = DEGRADATION_CHAINS;
|
|
85
|
+
exports.degradeTree = degradeTree;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AUPNode, DeviceCaps } from "./aup-types.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/degradation.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Each entry maps a primitive type to its ordered degradation chain.
|
|
6
|
+
* The chain is tried left-to-right; the first supported type wins.
|
|
7
|
+
* "unsupported" means no meaningful fallback exists.
|
|
8
|
+
*/
|
|
9
|
+
declare const DEGRADATION_CHAINS: Record<string, string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Walk the AUP tree and degrade unsupported primitives.
|
|
12
|
+
* Returns a new tree (does not mutate the original).
|
|
13
|
+
*/
|
|
14
|
+
declare function degradeTree(node: AUPNode, caps: DeviceCaps): AUPNode;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { DEGRADATION_CHAINS, degradeTree };
|
|
17
|
+
//# sourceMappingURL=degradation.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"degradation.d.cts","names":[],"sources":["../src/degradation.ts"],"mappings":";;;AAqCA;;;;;AAAA,cApBa,kBAAA,EAAoB,MAAA;;;;;iBAoBjB,WAAA,CAAY,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,UAAA,GAAa,OAAA"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { AUPNode, DeviceCaps } from "./aup-types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/degradation.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Each entry maps a primitive type to its ordered degradation chain.
|
|
6
|
+
* The chain is tried left-to-right; the first supported type wins.
|
|
7
|
+
* "unsupported" means no meaningful fallback exists.
|
|
8
|
+
*/
|
|
9
|
+
declare const DEGRADATION_CHAINS: Record<string, string[]>;
|
|
10
|
+
/**
|
|
11
|
+
* Walk the AUP tree and degrade unsupported primitives.
|
|
12
|
+
* Returns a new tree (does not mutate the original).
|
|
13
|
+
*/
|
|
14
|
+
declare function degradeTree(node: AUPNode, caps: DeviceCaps): AUPNode;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { DEGRADATION_CHAINS, degradeTree };
|
|
17
|
+
//# sourceMappingURL=degradation.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"degradation.d.mts","names":[],"sources":["../src/degradation.ts"],"mappings":";;;AAqCA;;;;;AAAA,cApBa,kBAAA,EAAoB,MAAA;;;;;iBAoBjB,WAAA,CAAY,IAAA,EAAM,OAAA,EAAS,IAAA,EAAM,UAAA,GAAa,OAAA"}
|