@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.
Files changed (196) hide show
  1. package/LICENSE.md +26 -0
  2. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.cjs +11 -0
  3. package/dist/_virtual/_@oxc-project_runtime@0.108.0/helpers/decorate.mjs +10 -0
  4. package/dist/aup-protocol.cjs +235 -0
  5. package/dist/aup-protocol.d.cts +78 -0
  6. package/dist/aup-protocol.d.cts.map +1 -0
  7. package/dist/aup-protocol.d.mts +78 -0
  8. package/dist/aup-protocol.d.mts.map +1 -0
  9. package/dist/aup-protocol.mjs +235 -0
  10. package/dist/aup-protocol.mjs.map +1 -0
  11. package/dist/aup-registry.cjs +2489 -0
  12. package/dist/aup-registry.mjs +2487 -0
  13. package/dist/aup-registry.mjs.map +1 -0
  14. package/dist/aup-spec.cjs +1467 -0
  15. package/dist/aup-spec.mjs +1466 -0
  16. package/dist/aup-spec.mjs.map +1 -0
  17. package/dist/aup-types.cjs +165 -0
  18. package/dist/aup-types.d.cts +157 -0
  19. package/dist/aup-types.d.cts.map +1 -0
  20. package/dist/aup-types.d.mts +157 -0
  21. package/dist/aup-types.d.mts.map +1 -0
  22. package/dist/aup-types.mjs +157 -0
  23. package/dist/aup-types.mjs.map +1 -0
  24. package/dist/backend.cjs +14 -0
  25. package/dist/backend.d.cts +104 -0
  26. package/dist/backend.d.cts.map +1 -0
  27. package/dist/backend.d.mts +104 -0
  28. package/dist/backend.d.mts.map +1 -0
  29. package/dist/backend.mjs +13 -0
  30. package/dist/backend.mjs.map +1 -0
  31. package/dist/degradation.cjs +85 -0
  32. package/dist/degradation.d.cts +17 -0
  33. package/dist/degradation.d.cts.map +1 -0
  34. package/dist/degradation.d.mts +17 -0
  35. package/dist/degradation.d.mts.map +1 -0
  36. package/dist/degradation.mjs +84 -0
  37. package/dist/degradation.mjs.map +1 -0
  38. package/dist/index.cjs +36 -0
  39. package/dist/index.d.cts +12 -0
  40. package/dist/index.d.mts +12 -0
  41. package/dist/index.mjs +13 -0
  42. package/dist/runtime.cjs +117 -0
  43. package/dist/runtime.d.cts +59 -0
  44. package/dist/runtime.d.cts.map +1 -0
  45. package/dist/runtime.d.mts +59 -0
  46. package/dist/runtime.d.mts.map +1 -0
  47. package/dist/runtime.mjs +118 -0
  48. package/dist/runtime.mjs.map +1 -0
  49. package/dist/session.cjs +159 -0
  50. package/dist/session.d.cts +80 -0
  51. package/dist/session.d.cts.map +1 -0
  52. package/dist/session.d.mts +80 -0
  53. package/dist/session.d.mts.map +1 -0
  54. package/dist/session.mjs +159 -0
  55. package/dist/session.mjs.map +1 -0
  56. package/dist/snapshot.cjs +162 -0
  57. package/dist/snapshot.mjs +163 -0
  58. package/dist/snapshot.mjs.map +1 -0
  59. package/dist/term-page.cjs +264 -0
  60. package/dist/term-page.mjs +264 -0
  61. package/dist/term-page.mjs.map +1 -0
  62. package/dist/term.cjs +295 -0
  63. package/dist/term.d.cts +84 -0
  64. package/dist/term.d.cts.map +1 -0
  65. package/dist/term.d.mts +84 -0
  66. package/dist/term.d.mts.map +1 -0
  67. package/dist/term.mjs +296 -0
  68. package/dist/term.mjs.map +1 -0
  69. package/dist/tty.cjs +136 -0
  70. package/dist/tty.d.cts +53 -0
  71. package/dist/tty.d.cts.map +1 -0
  72. package/dist/tty.d.mts +53 -0
  73. package/dist/tty.d.mts.map +1 -0
  74. package/dist/tty.mjs +135 -0
  75. package/dist/tty.mjs.map +1 -0
  76. package/dist/ui-provider.cjs +4615 -0
  77. package/dist/ui-provider.d.cts +307 -0
  78. package/dist/ui-provider.d.cts.map +1 -0
  79. package/dist/ui-provider.d.mts +307 -0
  80. package/dist/ui-provider.d.mts.map +1 -0
  81. package/dist/ui-provider.mjs +4616 -0
  82. package/dist/ui-provider.mjs.map +1 -0
  83. package/dist/web-page/core.cjs +1388 -0
  84. package/dist/web-page/core.mjs +1387 -0
  85. package/dist/web-page/core.mjs.map +1 -0
  86. package/dist/web-page/css.cjs +1699 -0
  87. package/dist/web-page/css.mjs +1698 -0
  88. package/dist/web-page/css.mjs.map +1 -0
  89. package/dist/web-page/icons.cjs +248 -0
  90. package/dist/web-page/icons.mjs +248 -0
  91. package/dist/web-page/icons.mjs.map +1 -0
  92. package/dist/web-page/overlay-themes.cjs +514 -0
  93. package/dist/web-page/overlay-themes.mjs +513 -0
  94. package/dist/web-page/overlay-themes.mjs.map +1 -0
  95. package/dist/web-page/renderers/action.cjs +72 -0
  96. package/dist/web-page/renderers/action.mjs +72 -0
  97. package/dist/web-page/renderers/action.mjs.map +1 -0
  98. package/dist/web-page/renderers/broadcast.cjs +160 -0
  99. package/dist/web-page/renderers/broadcast.mjs +160 -0
  100. package/dist/web-page/renderers/broadcast.mjs.map +1 -0
  101. package/dist/web-page/renderers/calendar.cjs +137 -0
  102. package/dist/web-page/renderers/calendar.mjs +137 -0
  103. package/dist/web-page/renderers/calendar.mjs.map +1 -0
  104. package/dist/web-page/renderers/canvas.cjs +173 -0
  105. package/dist/web-page/renderers/canvas.mjs +173 -0
  106. package/dist/web-page/renderers/canvas.mjs.map +1 -0
  107. package/dist/web-page/renderers/cdn-loader.cjs +25 -0
  108. package/dist/web-page/renderers/cdn-loader.mjs +25 -0
  109. package/dist/web-page/renderers/cdn-loader.mjs.map +1 -0
  110. package/dist/web-page/renderers/chart.cjs +101 -0
  111. package/dist/web-page/renderers/chart.mjs +101 -0
  112. package/dist/web-page/renderers/chart.mjs.map +1 -0
  113. package/dist/web-page/renderers/deck.cjs +390 -0
  114. package/dist/web-page/renderers/deck.mjs +390 -0
  115. package/dist/web-page/renderers/deck.mjs.map +1 -0
  116. package/dist/web-page/renderers/device.cjs +1015 -0
  117. package/dist/web-page/renderers/device.mjs +1015 -0
  118. package/dist/web-page/renderers/device.mjs.map +1 -0
  119. package/dist/web-page/renderers/editor.cjs +127 -0
  120. package/dist/web-page/renderers/editor.mjs +127 -0
  121. package/dist/web-page/renderers/editor.mjs.map +1 -0
  122. package/dist/web-page/renderers/finance-chart.cjs +178 -0
  123. package/dist/web-page/renderers/finance-chart.mjs +178 -0
  124. package/dist/web-page/renderers/finance-chart.mjs.map +1 -0
  125. package/dist/web-page/renderers/frame.cjs +274 -0
  126. package/dist/web-page/renderers/frame.mjs +274 -0
  127. package/dist/web-page/renderers/frame.mjs.map +1 -0
  128. package/dist/web-page/renderers/globe.cjs +119 -0
  129. package/dist/web-page/renderers/globe.mjs +119 -0
  130. package/dist/web-page/renderers/globe.mjs.map +1 -0
  131. package/dist/web-page/renderers/input.cjs +137 -0
  132. package/dist/web-page/renderers/input.mjs +137 -0
  133. package/dist/web-page/renderers/input.mjs.map +1 -0
  134. package/dist/web-page/renderers/list.cjs +1243 -0
  135. package/dist/web-page/renderers/list.mjs +1243 -0
  136. package/dist/web-page/renderers/list.mjs.map +1 -0
  137. package/dist/web-page/renderers/map.cjs +126 -0
  138. package/dist/web-page/renderers/map.mjs +126 -0
  139. package/dist/web-page/renderers/map.mjs.map +1 -0
  140. package/dist/web-page/renderers/media.cjs +106 -0
  141. package/dist/web-page/renderers/media.mjs +106 -0
  142. package/dist/web-page/renderers/media.mjs.map +1 -0
  143. package/dist/web-page/renderers/moonphase.cjs +105 -0
  144. package/dist/web-page/renderers/moonphase.mjs +105 -0
  145. package/dist/web-page/renderers/moonphase.mjs.map +1 -0
  146. package/dist/web-page/renderers/natal-chart.cjs +222 -0
  147. package/dist/web-page/renderers/natal-chart.mjs +222 -0
  148. package/dist/web-page/renderers/natal-chart.mjs.map +1 -0
  149. package/dist/web-page/renderers/overlay.cjs +531 -0
  150. package/dist/web-page/renderers/overlay.mjs +531 -0
  151. package/dist/web-page/renderers/overlay.mjs.map +1 -0
  152. package/dist/web-page/renderers/table.cjs +74 -0
  153. package/dist/web-page/renderers/table.mjs +74 -0
  154. package/dist/web-page/renderers/table.mjs.map +1 -0
  155. package/dist/web-page/renderers/terminal.cjs +30 -0
  156. package/dist/web-page/renderers/terminal.mjs +30 -0
  157. package/dist/web-page/renderers/terminal.mjs.map +1 -0
  158. package/dist/web-page/renderers/text.cjs +109 -0
  159. package/dist/web-page/renderers/text.mjs +109 -0
  160. package/dist/web-page/renderers/text.mjs.map +1 -0
  161. package/dist/web-page/renderers/ticker.cjs +133 -0
  162. package/dist/web-page/renderers/ticker.mjs +133 -0
  163. package/dist/web-page/renderers/ticker.mjs.map +1 -0
  164. package/dist/web-page/renderers/time.cjs +69 -0
  165. package/dist/web-page/renderers/time.mjs +69 -0
  166. package/dist/web-page/renderers/time.mjs.map +1 -0
  167. package/dist/web-page/renderers/unknown.cjs +20 -0
  168. package/dist/web-page/renderers/unknown.mjs +20 -0
  169. package/dist/web-page/renderers/unknown.mjs.map +1 -0
  170. package/dist/web-page/renderers/view.cjs +161 -0
  171. package/dist/web-page/renderers/view.mjs +161 -0
  172. package/dist/web-page/renderers/view.mjs.map +1 -0
  173. package/dist/web-page/renderers/wm.cjs +669 -0
  174. package/dist/web-page/renderers/wm.mjs +669 -0
  175. package/dist/web-page/renderers/wm.mjs.map +1 -0
  176. package/dist/web-page/skeleton.cjs +103 -0
  177. package/dist/web-page/skeleton.mjs +103 -0
  178. package/dist/web-page/skeleton.mjs.map +1 -0
  179. package/dist/web-page.cjs +114 -0
  180. package/dist/web-page.d.cts +19 -0
  181. package/dist/web-page.d.cts.map +1 -0
  182. package/dist/web-page.d.mts +19 -0
  183. package/dist/web-page.d.mts.map +1 -0
  184. package/dist/web-page.mjs +115 -0
  185. package/dist/web-page.mjs.map +1 -0
  186. package/dist/web.cjs +827 -0
  187. package/dist/web.d.cts +144 -0
  188. package/dist/web.d.cts.map +1 -0
  189. package/dist/web.d.mts +144 -0
  190. package/dist/web.d.mts.map +1 -0
  191. package/dist/web.mjs +828 -0
  192. package/dist/web.mjs.map +1 -0
  193. package/dist/wm-state.cjs +172 -0
  194. package/dist/wm-state.mjs +171 -0
  195. package/dist/wm-state.mjs.map +1 -0
  196. package/package.json +59 -0
@@ -0,0 +1,159 @@
1
+ const require_aup_types = require('./aup-types.cjs');
2
+ let node_crypto = require("node:crypto");
3
+
4
+ //#region src/session.ts
5
+ var Session = class {
6
+ id;
7
+ endpoint;
8
+ created;
9
+ _resumeToken;
10
+ _lastActive;
11
+ _deviceCaps;
12
+ messages = [];
13
+ pages = /* @__PURE__ */ new Map();
14
+ msgCounter = 0;
15
+ constructor(id, endpoint, caps) {
16
+ this.id = id;
17
+ this.endpoint = endpoint;
18
+ this.created = Date.now();
19
+ this._resumeToken = (0, node_crypto.randomBytes)(16).toString("hex");
20
+ this._lastActive = this.created;
21
+ this._deviceCaps = caps ?? require_aup_types.DEVICE_CAPS_WEB_FULL;
22
+ }
23
+ addMessage(input) {
24
+ if (!input.type || typeof input.type !== "string") throw new Error("Message requires a 'type' field");
25
+ if (!input.from || typeof input.from !== "string") throw new Error("Message requires a 'from' field");
26
+ this.msgCounter++;
27
+ const msg = {
28
+ ...input,
29
+ id: `msg_${this.msgCounter.toString().padStart(4, "0")}`,
30
+ type: input.type,
31
+ from: input.from,
32
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
33
+ };
34
+ this.messages.push(msg);
35
+ this._lastActive = Date.now();
36
+ return msg;
37
+ }
38
+ listMessages() {
39
+ return [...this.messages];
40
+ }
41
+ findMessage(id) {
42
+ return this.messages.find((m) => m.id === id);
43
+ }
44
+ filterMessages(filter) {
45
+ return this.messages.filter((m) => {
46
+ if (filter.type && m.type !== filter.type) return false;
47
+ if (filter.from && m.from !== filter.from) return false;
48
+ if (filter.ref && m.ref !== filter.ref) return false;
49
+ return true;
50
+ });
51
+ }
52
+ setPage(id, data) {
53
+ const existing = this.pages.get(id);
54
+ const now = Date.now();
55
+ this.pages.set(id, {
56
+ content: data.content,
57
+ format: data.format,
58
+ layout: data.layout,
59
+ createdAt: existing?.createdAt ?? now,
60
+ updatedAt: now
61
+ });
62
+ this._lastActive = now;
63
+ }
64
+ getPage(id) {
65
+ return this.pages.get(id);
66
+ }
67
+ listPages() {
68
+ return Array.from(this.pages, ([id, page]) => ({
69
+ id,
70
+ page
71
+ }));
72
+ }
73
+ deletePage(id) {
74
+ this.pages.delete(id);
75
+ }
76
+ touch() {
77
+ this._lastActive = Date.now();
78
+ }
79
+ clear() {
80
+ this.messages = [];
81
+ this.pages.clear();
82
+ }
83
+ toMeta() {
84
+ return {
85
+ id: this.id,
86
+ endpoint: this.endpoint,
87
+ created: this.created,
88
+ lastActive: this._lastActive,
89
+ messageCount: this.messages.length,
90
+ pageCount: this.pages.size
91
+ };
92
+ }
93
+ get lastActive() {
94
+ return this._lastActive;
95
+ }
96
+ get resumeToken() {
97
+ return this._resumeToken;
98
+ }
99
+ get deviceCaps() {
100
+ return this._deviceCaps;
101
+ }
102
+ /** Update device caps. Validates before accepting. Returns error string or null. */
103
+ setDeviceCaps(caps) {
104
+ const err = require_aup_types.validateDeviceCaps(caps);
105
+ if (err) return err;
106
+ this._deviceCaps = caps;
107
+ this._lastActive = Date.now();
108
+ return null;
109
+ }
110
+ };
111
+ var SessionManager = class SessionManager {
112
+ static SESSION_ID_RE = /^[a-f0-9]{16,64}$/i;
113
+ sessions = /* @__PURE__ */ new Map();
114
+ create(endpoint, caps) {
115
+ const id = (0, node_crypto.randomBytes)(8).toString("hex");
116
+ const session = new Session(id, endpoint, caps);
117
+ this.sessions.set(id, session);
118
+ return session;
119
+ }
120
+ /** Create (or reclaim) a session with a specific ID — used for sticky reconnect after service restart. */
121
+ createWithId(id, endpoint, caps) {
122
+ if (!SessionManager.isValidSessionId(id)) throw new Error("Invalid session id format");
123
+ const session = new Session(id, endpoint, caps);
124
+ this.sessions.set(id, session);
125
+ return session;
126
+ }
127
+ get(id) {
128
+ const session = this.sessions.get(id);
129
+ if (!session) throw new Error(`Session not found: ${id}`);
130
+ return session;
131
+ }
132
+ list(endpoint) {
133
+ const all = Array.from(this.sessions.values());
134
+ if (endpoint) return all.filter((s) => s.endpoint === endpoint);
135
+ return all;
136
+ }
137
+ delete(id) {
138
+ if (!this.sessions.has(id)) throw new Error(`Session not found: ${id}`);
139
+ this.sessions.get(id).clear();
140
+ this.sessions.delete(id);
141
+ }
142
+ gc(maxInactiveMs) {
143
+ const now = Date.now();
144
+ for (const [id, session] of this.sessions) if (now - session.lastActive > maxInactiveMs) {
145
+ session.clear();
146
+ this.sessions.delete(id);
147
+ }
148
+ }
149
+ has(id) {
150
+ return this.sessions.has(id);
151
+ }
152
+ static isValidSessionId(id) {
153
+ return SessionManager.SESSION_ID_RE.test(id);
154
+ }
155
+ };
156
+
157
+ //#endregion
158
+ exports.Session = Session;
159
+ exports.SessionManager = SessionManager;
@@ -0,0 +1,80 @@
1
+ import { DeviceCaps } from "./aup-types.cjs";
2
+
3
+ //#region src/session.d.ts
4
+ interface Message {
5
+ id: string;
6
+ type: string;
7
+ from: string;
8
+ timestamp: string;
9
+ [key: string]: unknown;
10
+ }
11
+ interface MessageFilter {
12
+ type?: string;
13
+ from?: string;
14
+ ref?: string;
15
+ }
16
+ interface PageData {
17
+ content: string;
18
+ format: string;
19
+ layout?: Record<string, string>;
20
+ createdAt: number;
21
+ updatedAt: number;
22
+ }
23
+ declare class Session {
24
+ readonly id: string;
25
+ readonly endpoint: string;
26
+ readonly created: number;
27
+ private readonly _resumeToken;
28
+ private _lastActive;
29
+ private _deviceCaps;
30
+ private messages;
31
+ private pages;
32
+ private msgCounter;
33
+ constructor(id: string, endpoint: string, caps?: DeviceCaps);
34
+ addMessage(input: Record<string, unknown>): Message;
35
+ listMessages(): Message[];
36
+ findMessage(id: string): Message | undefined;
37
+ filterMessages(filter: MessageFilter): Message[];
38
+ setPage(id: string, data: {
39
+ content: string;
40
+ format: string;
41
+ layout?: Record<string, string>;
42
+ }): void;
43
+ getPage(id: string): PageData | undefined;
44
+ listPages(): Array<{
45
+ id: string;
46
+ page: PageData;
47
+ }>;
48
+ deletePage(id: string): void;
49
+ touch(): void;
50
+ clear(): void;
51
+ toMeta(): {
52
+ id: string;
53
+ endpoint: string;
54
+ created: number;
55
+ lastActive: number;
56
+ messageCount: number;
57
+ pageCount: number;
58
+ };
59
+ get lastActive(): number;
60
+ get resumeToken(): string;
61
+ get deviceCaps(): DeviceCaps;
62
+ /** Update device caps. Validates before accepting. Returns error string or null. */
63
+ setDeviceCaps(caps: unknown): string | null;
64
+ }
65
+ declare class SessionManager {
66
+ private static readonly SESSION_ID_RE;
67
+ private sessions;
68
+ create(endpoint: string, caps?: DeviceCaps): Session;
69
+ /** Create (or reclaim) a session with a specific ID — used for sticky reconnect after service restart. */
70
+ createWithId(id: string, endpoint: string, caps?: DeviceCaps): Session;
71
+ get(id: string): Session;
72
+ list(endpoint?: string): Session[];
73
+ delete(id: string): void;
74
+ gc(maxInactiveMs: number): void;
75
+ has(id: string): boolean;
76
+ static isValidSessionId(id: string): boolean;
77
+ }
78
+ //#endregion
79
+ export { Message, MessageFilter, PageData, Session, SessionManager };
80
+ //# sourceMappingURL=session.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.cts","names":[],"sources":["../src/session.ts"],"mappings":";;;UAKiB,OAAA;EACf,EAAA;EACA,IAAA;EACA,IAAA;EACA,SAAA;EAAA,CACC,GAAA;AAAA;AAAA,UAGc,aAAA;EACf,IAAA;EACA,IAAA;EACA,GAAA;AAAA;AAAA,UAKe,QAAA;EACf,OAAA;EACA,MAAA;EACA,MAAA,GAAS,MAAA;EACT,SAAA;EACA,SAAA;AAAA;AAAA,cAKW,OAAA;EAAA,SACF,EAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA;EAAA,iBACQ,YAAA;EAAA,QACT,WAAA;EAAA,QACA,WAAA;EAAA,QACA,QAAA;EAAA,QACA,KAAA;EAAA,QACA,UAAA;cAEI,EAAA,UAAY,QAAA,UAAkB,IAAA,GAAO,UAAA;EAWjD,UAAA,CAAW,KAAA,EAAO,MAAA,oBAA0B,OAAA;EAoB5C,YAAA,CAAA,GAAgB,OAAA;EAIhB,WAAA,CAAY,EAAA,WAAa,OAAA;EAIzB,cAAA,CAAe,MAAA,EAAQ,aAAA,GAAgB,OAAA;EAWvC,OAAA,CAAQ,EAAA,UAAY,IAAA;IAAQ,OAAA;IAAiB,MAAA;IAAgB,MAAA,GAAS,MAAA;EAAA;EAatE,OAAA,CAAQ,EAAA,WAAa,QAAA;EAIrB,SAAA,CAAA,GAAa,KAAA;IAAQ,EAAA;IAAY,IAAA,EAAM,QAAA;EAAA;EAIvC,UAAA,CAAW,EAAA;EAMX,KAAA,CAAA;EAIA,KAAA,CAAA;EAKA,MAAA,CAAA;;;;;;;;MAWI,UAAA,CAAA;EAAA,IAIA,WAAA,CAAA;EAAA,IAMA,UAAA,CAAA,GAAc,UAAA;EA9GV;EAmHR,aAAA,CAAc,IAAA;AAAA;AAAA,cAWH,cAAA;EAAA,wBACa,aAAA;EAAA,QAChB,QAAA;EAER,MAAA,CAAO,QAAA,UAAkB,IAAA,GAAO,UAAA,GAAa,OAAA;EApH7C;EA4HA,YAAA,CAAa,EAAA,UAAY,QAAA,UAAkB,IAAA,GAAO,UAAA,GAAa,OAAA;EAS/D,GAAA,CAAI,EAAA,WAAa,OAAA;EAMjB,IAAA,CAAK,QAAA,YAAoB,OAAA;EAMzB,MAAA,CAAO,EAAA;EAMP,EAAA,CAAG,aAAA;EAUH,GAAA,CAAI,EAAA;EAAA,OAIG,gBAAA,CAAiB,EAAA;AAAA"}
@@ -0,0 +1,80 @@
1
+ import { DeviceCaps } from "./aup-types.mjs";
2
+
3
+ //#region src/session.d.ts
4
+ interface Message {
5
+ id: string;
6
+ type: string;
7
+ from: string;
8
+ timestamp: string;
9
+ [key: string]: unknown;
10
+ }
11
+ interface MessageFilter {
12
+ type?: string;
13
+ from?: string;
14
+ ref?: string;
15
+ }
16
+ interface PageData {
17
+ content: string;
18
+ format: string;
19
+ layout?: Record<string, string>;
20
+ createdAt: number;
21
+ updatedAt: number;
22
+ }
23
+ declare class Session {
24
+ readonly id: string;
25
+ readonly endpoint: string;
26
+ readonly created: number;
27
+ private readonly _resumeToken;
28
+ private _lastActive;
29
+ private _deviceCaps;
30
+ private messages;
31
+ private pages;
32
+ private msgCounter;
33
+ constructor(id: string, endpoint: string, caps?: DeviceCaps);
34
+ addMessage(input: Record<string, unknown>): Message;
35
+ listMessages(): Message[];
36
+ findMessage(id: string): Message | undefined;
37
+ filterMessages(filter: MessageFilter): Message[];
38
+ setPage(id: string, data: {
39
+ content: string;
40
+ format: string;
41
+ layout?: Record<string, string>;
42
+ }): void;
43
+ getPage(id: string): PageData | undefined;
44
+ listPages(): Array<{
45
+ id: string;
46
+ page: PageData;
47
+ }>;
48
+ deletePage(id: string): void;
49
+ touch(): void;
50
+ clear(): void;
51
+ toMeta(): {
52
+ id: string;
53
+ endpoint: string;
54
+ created: number;
55
+ lastActive: number;
56
+ messageCount: number;
57
+ pageCount: number;
58
+ };
59
+ get lastActive(): number;
60
+ get resumeToken(): string;
61
+ get deviceCaps(): DeviceCaps;
62
+ /** Update device caps. Validates before accepting. Returns error string or null. */
63
+ setDeviceCaps(caps: unknown): string | null;
64
+ }
65
+ declare class SessionManager {
66
+ private static readonly SESSION_ID_RE;
67
+ private sessions;
68
+ create(endpoint: string, caps?: DeviceCaps): Session;
69
+ /** Create (or reclaim) a session with a specific ID — used for sticky reconnect after service restart. */
70
+ createWithId(id: string, endpoint: string, caps?: DeviceCaps): Session;
71
+ get(id: string): Session;
72
+ list(endpoint?: string): Session[];
73
+ delete(id: string): void;
74
+ gc(maxInactiveMs: number): void;
75
+ has(id: string): boolean;
76
+ static isValidSessionId(id: string): boolean;
77
+ }
78
+ //#endregion
79
+ export { Message, MessageFilter, PageData, Session, SessionManager };
80
+ //# sourceMappingURL=session.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.mts","names":[],"sources":["../src/session.ts"],"mappings":";;;UAKiB,OAAA;EACf,EAAA;EACA,IAAA;EACA,IAAA;EACA,SAAA;EAAA,CACC,GAAA;AAAA;AAAA,UAGc,aAAA;EACf,IAAA;EACA,IAAA;EACA,GAAA;AAAA;AAAA,UAKe,QAAA;EACf,OAAA;EACA,MAAA;EACA,MAAA,GAAS,MAAA;EACT,SAAA;EACA,SAAA;AAAA;AAAA,cAKW,OAAA;EAAA,SACF,EAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA;EAAA,iBACQ,YAAA;EAAA,QACT,WAAA;EAAA,QACA,WAAA;EAAA,QACA,QAAA;EAAA,QACA,KAAA;EAAA,QACA,UAAA;cAEI,EAAA,UAAY,QAAA,UAAkB,IAAA,GAAO,UAAA;EAWjD,UAAA,CAAW,KAAA,EAAO,MAAA,oBAA0B,OAAA;EAoB5C,YAAA,CAAA,GAAgB,OAAA;EAIhB,WAAA,CAAY,EAAA,WAAa,OAAA;EAIzB,cAAA,CAAe,MAAA,EAAQ,aAAA,GAAgB,OAAA;EAWvC,OAAA,CAAQ,EAAA,UAAY,IAAA;IAAQ,OAAA;IAAiB,MAAA;IAAgB,MAAA,GAAS,MAAA;EAAA;EAatE,OAAA,CAAQ,EAAA,WAAa,QAAA;EAIrB,SAAA,CAAA,GAAa,KAAA;IAAQ,EAAA;IAAY,IAAA,EAAM,QAAA;EAAA;EAIvC,UAAA,CAAW,EAAA;EAMX,KAAA,CAAA;EAIA,KAAA,CAAA;EAKA,MAAA,CAAA;;;;;;;;MAWI,UAAA,CAAA;EAAA,IAIA,WAAA,CAAA;EAAA,IAMA,UAAA,CAAA,GAAc,UAAA;EA9GV;EAmHR,aAAA,CAAc,IAAA;AAAA;AAAA,cAWH,cAAA;EAAA,wBACa,aAAA;EAAA,QAChB,QAAA;EAER,MAAA,CAAO,QAAA,UAAkB,IAAA,GAAO,UAAA,GAAa,OAAA;EApH7C;EA4HA,YAAA,CAAa,EAAA,UAAY,QAAA,UAAkB,IAAA,GAAO,UAAA,GAAa,OAAA;EAS/D,GAAA,CAAI,EAAA,WAAa,OAAA;EAMjB,IAAA,CAAK,QAAA,YAAoB,OAAA;EAMzB,MAAA,CAAO,EAAA;EAMP,EAAA,CAAG,aAAA;EAUH,GAAA,CAAI,EAAA;EAAA,OAIG,gBAAA,CAAiB,EAAA;AAAA"}
@@ -0,0 +1,159 @@
1
+ import { DEVICE_CAPS_WEB_FULL, validateDeviceCaps } from "./aup-types.mjs";
2
+ import { randomBytes } from "node:crypto";
3
+
4
+ //#region src/session.ts
5
+ var Session = class {
6
+ id;
7
+ endpoint;
8
+ created;
9
+ _resumeToken;
10
+ _lastActive;
11
+ _deviceCaps;
12
+ messages = [];
13
+ pages = /* @__PURE__ */ new Map();
14
+ msgCounter = 0;
15
+ constructor(id, endpoint, caps) {
16
+ this.id = id;
17
+ this.endpoint = endpoint;
18
+ this.created = Date.now();
19
+ this._resumeToken = randomBytes(16).toString("hex");
20
+ this._lastActive = this.created;
21
+ this._deviceCaps = caps ?? DEVICE_CAPS_WEB_FULL;
22
+ }
23
+ addMessage(input) {
24
+ if (!input.type || typeof input.type !== "string") throw new Error("Message requires a 'type' field");
25
+ if (!input.from || typeof input.from !== "string") throw new Error("Message requires a 'from' field");
26
+ this.msgCounter++;
27
+ const msg = {
28
+ ...input,
29
+ id: `msg_${this.msgCounter.toString().padStart(4, "0")}`,
30
+ type: input.type,
31
+ from: input.from,
32
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
33
+ };
34
+ this.messages.push(msg);
35
+ this._lastActive = Date.now();
36
+ return msg;
37
+ }
38
+ listMessages() {
39
+ return [...this.messages];
40
+ }
41
+ findMessage(id) {
42
+ return this.messages.find((m) => m.id === id);
43
+ }
44
+ filterMessages(filter) {
45
+ return this.messages.filter((m) => {
46
+ if (filter.type && m.type !== filter.type) return false;
47
+ if (filter.from && m.from !== filter.from) return false;
48
+ if (filter.ref && m.ref !== filter.ref) return false;
49
+ return true;
50
+ });
51
+ }
52
+ setPage(id, data) {
53
+ const existing = this.pages.get(id);
54
+ const now = Date.now();
55
+ this.pages.set(id, {
56
+ content: data.content,
57
+ format: data.format,
58
+ layout: data.layout,
59
+ createdAt: existing?.createdAt ?? now,
60
+ updatedAt: now
61
+ });
62
+ this._lastActive = now;
63
+ }
64
+ getPage(id) {
65
+ return this.pages.get(id);
66
+ }
67
+ listPages() {
68
+ return Array.from(this.pages, ([id, page]) => ({
69
+ id,
70
+ page
71
+ }));
72
+ }
73
+ deletePage(id) {
74
+ this.pages.delete(id);
75
+ }
76
+ touch() {
77
+ this._lastActive = Date.now();
78
+ }
79
+ clear() {
80
+ this.messages = [];
81
+ this.pages.clear();
82
+ }
83
+ toMeta() {
84
+ return {
85
+ id: this.id,
86
+ endpoint: this.endpoint,
87
+ created: this.created,
88
+ lastActive: this._lastActive,
89
+ messageCount: this.messages.length,
90
+ pageCount: this.pages.size
91
+ };
92
+ }
93
+ get lastActive() {
94
+ return this._lastActive;
95
+ }
96
+ get resumeToken() {
97
+ return this._resumeToken;
98
+ }
99
+ get deviceCaps() {
100
+ return this._deviceCaps;
101
+ }
102
+ /** Update device caps. Validates before accepting. Returns error string or null. */
103
+ setDeviceCaps(caps) {
104
+ const err = validateDeviceCaps(caps);
105
+ if (err) return err;
106
+ this._deviceCaps = caps;
107
+ this._lastActive = Date.now();
108
+ return null;
109
+ }
110
+ };
111
+ var SessionManager = class SessionManager {
112
+ static SESSION_ID_RE = /^[a-f0-9]{16,64}$/i;
113
+ sessions = /* @__PURE__ */ new Map();
114
+ create(endpoint, caps) {
115
+ const id = randomBytes(8).toString("hex");
116
+ const session = new Session(id, endpoint, caps);
117
+ this.sessions.set(id, session);
118
+ return session;
119
+ }
120
+ /** Create (or reclaim) a session with a specific ID — used for sticky reconnect after service restart. */
121
+ createWithId(id, endpoint, caps) {
122
+ if (!SessionManager.isValidSessionId(id)) throw new Error("Invalid session id format");
123
+ const session = new Session(id, endpoint, caps);
124
+ this.sessions.set(id, session);
125
+ return session;
126
+ }
127
+ get(id) {
128
+ const session = this.sessions.get(id);
129
+ if (!session) throw new Error(`Session not found: ${id}`);
130
+ return session;
131
+ }
132
+ list(endpoint) {
133
+ const all = Array.from(this.sessions.values());
134
+ if (endpoint) return all.filter((s) => s.endpoint === endpoint);
135
+ return all;
136
+ }
137
+ delete(id) {
138
+ if (!this.sessions.has(id)) throw new Error(`Session not found: ${id}`);
139
+ this.sessions.get(id).clear();
140
+ this.sessions.delete(id);
141
+ }
142
+ gc(maxInactiveMs) {
143
+ const now = Date.now();
144
+ for (const [id, session] of this.sessions) if (now - session.lastActive > maxInactiveMs) {
145
+ session.clear();
146
+ this.sessions.delete(id);
147
+ }
148
+ }
149
+ has(id) {
150
+ return this.sessions.has(id);
151
+ }
152
+ static isValidSessionId(id) {
153
+ return SessionManager.SESSION_ID_RE.test(id);
154
+ }
155
+ };
156
+
157
+ //#endregion
158
+ export { Session, SessionManager };
159
+ //# sourceMappingURL=session.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.mjs","names":[],"sources":["../src/session.ts"],"sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport { DEVICE_CAPS_WEB_FULL, type DeviceCaps, validateDeviceCaps } from \"./aup-types.js\";\n\n// ── Message ──\n\nexport interface Message {\n id: string;\n type: string;\n from: string;\n timestamp: string;\n [key: string]: unknown;\n}\n\nexport interface MessageFilter {\n type?: string;\n from?: string;\n ref?: string;\n}\n\n// ── Page ──\n\nexport interface PageData {\n content: string;\n format: string;\n layout?: Record<string, string>;\n createdAt: number;\n updatedAt: number;\n}\n\n// ── Session ──\n\nexport class Session {\n readonly id: string;\n readonly endpoint: string;\n readonly created: number;\n private readonly _resumeToken: string;\n private _lastActive: number;\n private _deviceCaps: DeviceCaps;\n private messages: Message[] = [];\n private pages = new Map<string, PageData>();\n private msgCounter = 0;\n\n constructor(id: string, endpoint: string, caps?: DeviceCaps) {\n this.id = id;\n this.endpoint = endpoint;\n this.created = Date.now();\n this._resumeToken = randomBytes(16).toString(\"hex\");\n this._lastActive = this.created;\n this._deviceCaps = caps ?? DEVICE_CAPS_WEB_FULL;\n }\n\n // ── Messages ──\n\n addMessage(input: Record<string, unknown>): Message {\n if (!input.type || typeof input.type !== \"string\") {\n throw new Error(\"Message requires a 'type' field\");\n }\n if (!input.from || typeof input.from !== \"string\") {\n throw new Error(\"Message requires a 'from' field\");\n }\n this.msgCounter++;\n const msg: Message = {\n ...input,\n id: `msg_${this.msgCounter.toString().padStart(4, \"0\")}`,\n type: input.type as string,\n from: input.from as string,\n timestamp: new Date().toISOString(),\n };\n this.messages.push(msg);\n this._lastActive = Date.now();\n return msg;\n }\n\n listMessages(): Message[] {\n return [...this.messages];\n }\n\n findMessage(id: string): Message | undefined {\n return this.messages.find((m) => m.id === id);\n }\n\n filterMessages(filter: MessageFilter): Message[] {\n return this.messages.filter((m) => {\n if (filter.type && m.type !== filter.type) return false;\n if (filter.from && m.from !== filter.from) return false;\n if (filter.ref && m.ref !== filter.ref) return false;\n return true;\n });\n }\n\n // ── Pages ──\n\n setPage(id: string, data: { content: string; format: string; layout?: Record<string, string> }) {\n const existing = this.pages.get(id);\n const now = Date.now();\n this.pages.set(id, {\n content: data.content,\n format: data.format,\n layout: data.layout,\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n });\n this._lastActive = now;\n }\n\n getPage(id: string): PageData | undefined {\n return this.pages.get(id);\n }\n\n listPages(): Array<{ id: string; page: PageData }> {\n return Array.from(this.pages, ([id, page]) => ({ id, page }));\n }\n\n deletePage(id: string) {\n this.pages.delete(id);\n }\n\n // ── Lifecycle ──\n\n touch() {\n this._lastActive = Date.now();\n }\n\n clear() {\n this.messages = [];\n this.pages.clear();\n }\n\n toMeta() {\n return {\n id: this.id,\n endpoint: this.endpoint,\n created: this.created,\n lastActive: this._lastActive,\n messageCount: this.messages.length,\n pageCount: this.pages.size,\n };\n }\n\n get lastActive(): number {\n return this._lastActive;\n }\n\n get resumeToken(): string {\n return this._resumeToken;\n }\n\n // ── Device Capabilities (D13) ──\n\n get deviceCaps(): DeviceCaps {\n return this._deviceCaps;\n }\n\n /** Update device caps. Validates before accepting. Returns error string or null. */\n setDeviceCaps(caps: unknown): string | null {\n const err = validateDeviceCaps(caps);\n if (err) return err;\n this._deviceCaps = caps as DeviceCaps;\n this._lastActive = Date.now();\n return null;\n }\n}\n\n// ── SessionManager ──\n\nexport class SessionManager {\n private static readonly SESSION_ID_RE = /^[a-f0-9]{16,64}$/i;\n private sessions = new Map<string, Session>();\n\n create(endpoint: string, caps?: DeviceCaps): Session {\n const id = randomBytes(8).toString(\"hex\");\n const session = new Session(id, endpoint, caps);\n this.sessions.set(id, session);\n return session;\n }\n\n /** Create (or reclaim) a session with a specific ID — used for sticky reconnect after service restart. */\n createWithId(id: string, endpoint: string, caps?: DeviceCaps): Session {\n if (!SessionManager.isValidSessionId(id)) {\n throw new Error(\"Invalid session id format\");\n }\n const session = new Session(id, endpoint, caps);\n this.sessions.set(id, session);\n return session;\n }\n\n get(id: string): Session {\n const session = this.sessions.get(id);\n if (!session) throw new Error(`Session not found: ${id}`);\n return session;\n }\n\n list(endpoint?: string): Session[] {\n const all = Array.from(this.sessions.values());\n if (endpoint) return all.filter((s) => s.endpoint === endpoint);\n return all;\n }\n\n delete(id: string) {\n if (!this.sessions.has(id)) throw new Error(`Session not found: ${id}`);\n this.sessions.get(id)!.clear();\n this.sessions.delete(id);\n }\n\n gc(maxInactiveMs: number) {\n const now = Date.now();\n for (const [id, session] of this.sessions) {\n if (now - session.lastActive > maxInactiveMs) {\n session.clear();\n this.sessions.delete(id);\n }\n }\n }\n\n has(id: string): boolean {\n return this.sessions.has(id);\n }\n\n static isValidSessionId(id: string): boolean {\n return SessionManager.SESSION_ID_RE.test(id);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,162 @@
1
+ const require_core = require('./web-page/core.cjs');
2
+ const require_css = require('./web-page/css.cjs');
3
+ const require_icons = require('./web-page/icons.cjs');
4
+ const require_overlay_themes = require('./web-page/overlay-themes.cjs');
5
+ const require_action = require('./web-page/renderers/action.cjs');
6
+ const require_broadcast = require('./web-page/renderers/broadcast.cjs');
7
+ const require_calendar = require('./web-page/renderers/calendar.cjs');
8
+ const require_canvas = require('./web-page/renderers/canvas.cjs');
9
+ const require_cdn_loader = require('./web-page/renderers/cdn-loader.cjs');
10
+ const require_chart = require('./web-page/renderers/chart.cjs');
11
+ const require_deck = require('./web-page/renderers/deck.cjs');
12
+ const require_device = require('./web-page/renderers/device.cjs');
13
+ const require_editor = require('./web-page/renderers/editor.cjs');
14
+ const require_finance_chart = require('./web-page/renderers/finance-chart.cjs');
15
+ const require_frame = require('./web-page/renderers/frame.cjs');
16
+ const require_globe = require('./web-page/renderers/globe.cjs');
17
+ const require_input = require('./web-page/renderers/input.cjs');
18
+ const require_list = require('./web-page/renderers/list.cjs');
19
+ const require_map = require('./web-page/renderers/map.cjs');
20
+ const require_media = require('./web-page/renderers/media.cjs');
21
+ const require_moonphase = require('./web-page/renderers/moonphase.cjs');
22
+ const require_natal_chart = require('./web-page/renderers/natal-chart.cjs');
23
+ const require_overlay = require('./web-page/renderers/overlay.cjs');
24
+ const require_table = require('./web-page/renderers/table.cjs');
25
+ const require_terminal = require('./web-page/renderers/terminal.cjs');
26
+ const require_text = require('./web-page/renderers/text.cjs');
27
+ const require_ticker = require('./web-page/renderers/ticker.cjs');
28
+ const require_time = require('./web-page/renderers/time.cjs');
29
+ const require_unknown = require('./web-page/renderers/unknown.cjs');
30
+ const require_view = require('./web-page/renderers/view.cjs');
31
+ let node_module = require("node:module");
32
+
33
+ //#region src/snapshot.ts
34
+ /**
35
+ * AUP Snapshot Generator — Freeze an AUP tree into a self-contained HTML file.
36
+ *
37
+ * The snapshot HTML includes:
38
+ * - All CSS (inlined)
39
+ * - All renderer JS (inlined)
40
+ * - AUP tree data (embedded as JSON)
41
+ * - CDN dependencies (marked.js, highlight.js, DOMPurify, Google Fonts)
42
+ * - SEO metadata (og tags, title, description)
43
+ *
44
+ * The snapshot does NOT include:
45
+ * - WebSocket connection code
46
+ * - Session/token management
47
+ * - Input/prompt handling
48
+ * - Chat UI elements
49
+ */
50
+ const AFS_VERSION = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href)("../package.json").version || "unknown";
51
+ const AFS_VERSION_LITERAL = JSON.stringify(String(AFS_VERSION)).replace(/</g, "\\u003c");
52
+ /** HTML-escape a string for safe embedding in HTML attributes and content */
53
+ function escapeHtml(str) {
54
+ return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#x27;");
55
+ }
56
+ /** Build SEO meta tags for the <head> section */
57
+ function buildSeoTags(slug, meta) {
58
+ const tags = [];
59
+ const title = meta?.title || slug;
60
+ tags.push(`<title>${escapeHtml(title)}</title>`);
61
+ if (meta?.description) {
62
+ const desc = meta.description.length > 200 ? `${meta.description.slice(0, 200)}...` : meta.description;
63
+ tags.push(`<meta name="description" content="${escapeHtml(desc)}">`);
64
+ }
65
+ tags.push(`<meta property="og:title" content="${escapeHtml(title)}">`);
66
+ tags.push(`<meta property="og:type" content="website">`);
67
+ tags.push(`<meta property="og:url" content="/s/${escapeHtml(slug)}">`);
68
+ if (meta?.description) {
69
+ const ogDesc = meta.description.length > 200 ? `${meta.description.slice(0, 200)}...` : meta.description;
70
+ tags.push(`<meta property="og:description" content="${escapeHtml(ogDesc)}">`);
71
+ }
72
+ if (meta?.image && /^https?:\/\//i.test(meta.image)) tags.push(`<meta property="og:image" content="${escapeHtml(meta.image)}">`);
73
+ return tags.join("\n");
74
+ }
75
+ /** Generate a self-contained HTML snapshot of an AUP tree */
76
+ function generateSnapshot(options) {
77
+ const { tree, slug, meta, style, locale } = options;
78
+ const treeJson = JSON.stringify(tree).replace(/<\/script>/gi, "<\\/script>");
79
+ const seoTags = buildSeoTags(slug, meta);
80
+ return `<!DOCTYPE html>
81
+ <html lang="${locale ? escapeHtml(locale) : "en"}">
82
+ <head>
83
+ <meta charset="UTF-8">
84
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
85
+ ${seoTags}
86
+ <link rel="preconnect" href="https://fonts.googleapis.com">
87
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
88
+ <link href="https://fonts.googleapis.com/css2?family=DM+Sans:opsz,wght@9..40,400;9..40,500;9..40,600;9..40,700&family=Manrope:wght@400;500;600;700&family=Sora:wght@300;400;500;600;700&family=Outfit:wght@400;500;600;700&family=Share+Tech+Mono&family=JetBrains+Mono:wght@400;500&family=DM+Serif+Display:ital@0;1&family=Noto+Sans+SC:wght@300;400;500;600&family=Space+Mono:ital,wght@0,400;0,700;1,400&family=Instrument+Serif:ital@0;1&family=Playfair+Display:ital,wght@0,400;0,700;0,900;1,400&family=Plus+Jakarta+Sans:wght@400;500;600;700;800&family=Fraunces:ital,opsz,wght@0,9..144,400;0,9..144,700;1,9..144,400&family=Crimson+Pro:ital,wght@0,400;0,600;1,400&display=swap" rel="stylesheet">
89
+ <script src="https://cdn.jsdelivr.net/npm/marked@15/marked.min.js"><\/script>
90
+ <script src="https://cdn.jsdelivr.net/npm/marked-highlight@2/lib/index.umd.min.js"><\/script>
91
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/styles/github-dark-dimmed.min.css">
92
+ <script src="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11/build/highlight.min.js"><\/script>
93
+ <script src="https://cdn.jsdelivr.net/npm/dompurify@3/dist/purify.min.js"><\/script>
94
+ <style>
95
+ ${require_css.CSS}
96
+ </style>
97
+ </head>
98
+ <body>
99
+ <div id="aup-display" class="active full-page" style="display:flex">
100
+ <div id="aup-root" class="aup-animating"></div>
101
+ </div>
102
+ <script>
103
+ (function() {
104
+ var _AFS_VERSION = ${AFS_VERSION_LITERAL};
105
+ var _SNAPSHOT_MODE = true;
106
+ ${require_core.CORE_HEAD_JS}
107
+ ${require_icons.ICONS_JS}
108
+
109
+ ${require_view.VIEW_JS}
110
+ ${require_text.TEXT_JS}
111
+ ${require_action.ACTION_JS}
112
+ ${require_input.INPUT_JS}
113
+ ${require_media.MEDIA_JS}
114
+ ${require_overlay.OVERLAY_JS}
115
+ ${require_table.TABLE_JS}
116
+ ${require_terminal.TERMINAL_JS}
117
+ ${require_cdn_loader.CDN_LOADER_JS}
118
+ ${require_time.TIME_JS}
119
+ ${require_chart.CHART_JS}
120
+ ${require_finance_chart.FINANCE_CHART_JS}
121
+ ${require_map.MAP_JS}
122
+ ${require_globe.GLOBE_JS}
123
+ ${require_calendar.CALENDAR_JS}
124
+ ${require_moonphase.MOONPHASE_JS}
125
+ ${require_natal_chart.NATAL_CHART_JS}
126
+ ${require_editor.EDITOR_JS}
127
+ ${require_frame.FRAME_JS}
128
+ ${require_canvas.CANVAS_JS}
129
+ ${require_ticker.TICKER_JS}
130
+ ${require_broadcast.BROADCAST_JS}
131
+ ${require_list.LIST_JS}
132
+ ${require_device.DEVICE_JS}
133
+ var _OVERLAY_THEMES_CSS = ${JSON.stringify(require_overlay_themes.OVERLAY_THEMES_CSS)};
134
+ ${require_overlay_themes.OVERLAY_THEMES_JS}
135
+ var _DECK_SHADOW_CSS = ${JSON.stringify(require_css.DECK_SHADOW_CSS)};
136
+ ${require_deck.DECK_JS}
137
+ ${require_unknown.UNKNOWN_JS}
138
+
139
+ // ── Snapshot: static render (no WebSocket) ──
140
+ var aupDisplayEl = document.getElementById("aup-display");
141
+ var aupRootEl = document.getElementById("aup-root");
142
+ var aupNodeTree = ${treeJson};
143
+
144
+ ${style ? `setStyle(${JSON.stringify(style)});` : ""}
145
+
146
+ function renderAupTree() {
147
+ if (!aupNodeTree || !aupRootEl) return;
148
+ aupRootEl.innerHTML = "";
149
+ var el = renderAupNode(aupNodeTree);
150
+ if (el) aupRootEl.appendChild(el);
151
+ aupRootEl.classList.remove("aup-animating");
152
+ }
153
+
154
+ renderAupTree();
155
+ })();
156
+ <\/script>
157
+ </body>
158
+ </html>`;
159
+ }
160
+
161
+ //#endregion
162
+ exports.generateSnapshot = generateSnapshot;