@alloy-js/core 0.23.0-dev.0 → 0.23.0-dev.8

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 (269) hide show
  1. package/CHANGELOG.md +0 -22
  2. package/dist/devtools/index.html +68 -0
  3. package/dist/src/binder.d.ts +2 -0
  4. package/dist/src/binder.d.ts.map +1 -1
  5. package/dist/src/binder.js +55 -12
  6. package/dist/src/binder.js.map +1 -1
  7. package/dist/src/components/AppendFile.d.ts.map +1 -1
  8. package/dist/src/components/AppendFile.js +14 -3
  9. package/dist/src/components/AppendFile.js.map +1 -1
  10. package/dist/src/components/Block.js +1 -1
  11. package/dist/src/components/Block.js.map +1 -1
  12. package/dist/src/components/Declaration.d.ts.map +1 -1
  13. package/dist/src/components/Declaration.js +2 -1
  14. package/dist/src/components/Declaration.js.map +1 -1
  15. package/dist/src/components/Scope.d.ts.map +1 -1
  16. package/dist/src/components/Scope.js +4 -1
  17. package/dist/src/components/Scope.js.map +1 -1
  18. package/dist/src/components/TemplateFile.d.ts.map +1 -1
  19. package/dist/src/components/TemplateFile.js +18 -3
  20. package/dist/src/components/TemplateFile.js.map +1 -1
  21. package/dist/src/content-slot.d.ts.map +1 -1
  22. package/dist/src/content-slot.js +6 -5
  23. package/dist/src/content-slot.js.map +1 -1
  24. package/dist/src/context.d.ts.map +1 -1
  25. package/dist/src/context.js +8 -1
  26. package/dist/src/context.js.map +1 -1
  27. package/dist/src/debug/cli.d.ts +6 -0
  28. package/dist/src/debug/cli.d.ts.map +1 -0
  29. package/dist/src/{debug.js → debug/cli.js} +78 -84
  30. package/dist/src/debug/cli.js.map +1 -0
  31. package/dist/src/debug/diagnostics.test.d.ts +2 -0
  32. package/dist/src/debug/diagnostics.test.d.ts.map +1 -0
  33. package/dist/src/debug/diagnostics.test.js +45 -0
  34. package/dist/src/debug/diagnostics.test.js.map +1 -0
  35. package/dist/src/debug/effects.d.ts +69 -0
  36. package/dist/src/debug/effects.d.ts.map +1 -0
  37. package/dist/src/debug/effects.js +228 -0
  38. package/dist/src/debug/effects.js.map +1 -0
  39. package/dist/src/debug/effects.test.d.ts +2 -0
  40. package/dist/src/debug/effects.test.d.ts.map +1 -0
  41. package/dist/src/debug/effects.test.js +86 -0
  42. package/dist/src/debug/effects.test.js.map +1 -0
  43. package/dist/src/debug/files.d.ts +14 -0
  44. package/dist/src/debug/files.d.ts.map +1 -0
  45. package/dist/src/debug/files.js +40 -0
  46. package/dist/src/debug/files.js.map +1 -0
  47. package/dist/src/debug/files.test.d.ts +2 -0
  48. package/dist/src/debug/files.test.d.ts.map +1 -0
  49. package/dist/src/debug/files.test.js +89 -0
  50. package/dist/src/debug/files.test.js.map +1 -0
  51. package/dist/src/debug/index.d.ts +60 -0
  52. package/dist/src/debug/index.d.ts.map +1 -0
  53. package/dist/src/debug/index.js +68 -0
  54. package/dist/src/debug/index.js.map +1 -0
  55. package/dist/src/debug/render.d.ts +57 -0
  56. package/dist/src/debug/render.d.ts.map +1 -0
  57. package/dist/src/debug/render.js +519 -0
  58. package/dist/src/debug/render.js.map +1 -0
  59. package/dist/src/debug/render.test.d.ts +2 -0
  60. package/dist/src/debug/render.test.d.ts.map +1 -0
  61. package/dist/src/debug/render.test.js +328 -0
  62. package/dist/src/debug/render.test.js.map +1 -0
  63. package/dist/src/debug/serialize.d.ts +9 -0
  64. package/dist/src/debug/serialize.d.ts.map +1 -0
  65. package/dist/src/debug/serialize.js +70 -0
  66. package/dist/src/debug/serialize.js.map +1 -0
  67. package/dist/src/debug/symbols.d.ts +9 -0
  68. package/dist/src/debug/symbols.d.ts.map +1 -0
  69. package/dist/src/debug/symbols.js +164 -0
  70. package/dist/src/debug/symbols.js.map +1 -0
  71. package/dist/src/debug/symbols.test.d.ts +2 -0
  72. package/dist/src/debug/symbols.test.d.ts.map +1 -0
  73. package/dist/src/debug/symbols.test.js +104 -0
  74. package/dist/src/debug/symbols.test.js.map +1 -0
  75. package/dist/src/debug/trace.d.ts +342 -0
  76. package/dist/src/debug/trace.d.ts.map +1 -0
  77. package/dist/src/debug/trace.js +443 -0
  78. package/dist/src/debug/trace.js.map +1 -0
  79. package/dist/src/devtools/devtools-protocol.d.ts +232 -0
  80. package/dist/src/devtools/devtools-protocol.d.ts.map +1 -0
  81. package/dist/src/devtools/devtools-protocol.js +2 -0
  82. package/dist/src/devtools/devtools-protocol.js.map +1 -0
  83. package/dist/src/devtools/devtools-server.browser.d.ts +28 -0
  84. package/dist/src/devtools/devtools-server.browser.d.ts.map +1 -0
  85. package/dist/src/devtools/devtools-server.browser.js +36 -0
  86. package/dist/src/devtools/devtools-server.browser.js.map +1 -0
  87. package/dist/src/devtools/devtools-server.d.ts +72 -0
  88. package/dist/src/devtools/devtools-server.d.ts.map +1 -0
  89. package/dist/src/devtools/devtools-server.js +256 -0
  90. package/dist/src/devtools/devtools-server.js.map +1 -0
  91. package/dist/src/devtools/devtools-transport.d.ts +23 -0
  92. package/dist/src/devtools/devtools-transport.d.ts.map +1 -0
  93. package/dist/src/devtools/devtools-transport.js +114 -0
  94. package/dist/src/devtools/devtools-transport.js.map +1 -0
  95. package/dist/src/devtools-entry.browser.d.ts +4 -0
  96. package/dist/src/devtools-entry.browser.d.ts.map +1 -0
  97. package/dist/src/devtools-entry.browser.js +2 -0
  98. package/dist/src/devtools-entry.browser.js.map +1 -0
  99. package/dist/src/devtools-entry.d.ts +4 -0
  100. package/dist/src/devtools-entry.d.ts.map +1 -0
  101. package/dist/src/devtools-entry.js +2 -0
  102. package/dist/src/devtools-entry.js.map +1 -0
  103. package/dist/src/diagnostics.d.ts +34 -0
  104. package/dist/src/diagnostics.d.ts.map +1 -0
  105. package/dist/src/diagnostics.js +89 -0
  106. package/dist/src/diagnostics.js.map +1 -0
  107. package/dist/src/index.d.ts +3 -2
  108. package/dist/src/index.d.ts.map +1 -1
  109. package/dist/src/index.js +3 -2
  110. package/dist/src/index.js.map +1 -1
  111. package/dist/src/print-hook.d.ts +14 -0
  112. package/dist/src/print-hook.d.ts.map +1 -0
  113. package/dist/src/print-hook.js +10 -0
  114. package/dist/src/print-hook.js.map +1 -0
  115. package/dist/src/reactive-union-set.d.ts.map +1 -1
  116. package/dist/src/reactive-union-set.js +15 -0
  117. package/dist/src/reactive-union-set.js.map +1 -1
  118. package/dist/src/reactivity.d.ts +17 -3
  119. package/dist/src/reactivity.d.ts.map +1 -1
  120. package/dist/src/reactivity.js +162 -14
  121. package/dist/src/reactivity.js.map +1 -1
  122. package/dist/src/render-stack.d.ts +29 -0
  123. package/dist/src/render-stack.d.ts.map +1 -0
  124. package/dist/src/render-stack.js +247 -0
  125. package/dist/src/render-stack.js.map +1 -0
  126. package/dist/src/render.d.ts +9 -19
  127. package/dist/src/render.d.ts.map +1 -1
  128. package/dist/src/render.js +363 -153
  129. package/dist/src/render.js.map +1 -1
  130. package/dist/src/resource.d.ts.map +1 -1
  131. package/dist/src/resource.js +5 -0
  132. package/dist/src/resource.js.map +1 -1
  133. package/dist/src/runtime/component.d.ts +7 -1
  134. package/dist/src/runtime/component.d.ts.map +1 -1
  135. package/dist/src/runtime/component.js +4 -1
  136. package/dist/src/runtime/component.js.map +1 -1
  137. package/dist/src/scheduler.d.ts +3 -0
  138. package/dist/src/scheduler.d.ts.map +1 -1
  139. package/dist/src/scheduler.js +45 -2
  140. package/dist/src/scheduler.js.map +1 -1
  141. package/dist/src/symbols/basic-symbol.d.ts.map +1 -1
  142. package/dist/src/symbols/basic-symbol.js +6 -1
  143. package/dist/src/symbols/basic-symbol.js.map +1 -1
  144. package/dist/src/symbols/decl.d.ts.map +1 -1
  145. package/dist/src/symbols/decl.js +5 -1
  146. package/dist/src/symbols/decl.js.map +1 -1
  147. package/dist/src/symbols/output-scope.d.ts +2 -1
  148. package/dist/src/symbols/output-scope.d.ts.map +1 -1
  149. package/dist/src/symbols/output-scope.js +13 -8
  150. package/dist/src/symbols/output-scope.js.map +1 -1
  151. package/dist/src/symbols/output-symbol.d.ts +1 -0
  152. package/dist/src/symbols/output-symbol.d.ts.map +1 -1
  153. package/dist/src/symbols/output-symbol.js +23 -6
  154. package/dist/src/symbols/output-symbol.js.map +1 -1
  155. package/dist/src/symbols/symbol-flow.d.ts.map +1 -1
  156. package/dist/src/symbols/symbol-flow.js +22 -6
  157. package/dist/src/symbols/symbol-flow.js.map +1 -1
  158. package/dist/src/symbols/symbol-slot.d.ts.map +1 -1
  159. package/dist/src/symbols/symbol-slot.js +15 -0
  160. package/dist/src/symbols/symbol-slot.js.map +1 -1
  161. package/dist/src/symbols/symbol-slot.test.d.ts +2 -0
  162. package/dist/src/symbols/symbol-slot.test.d.ts.map +1 -0
  163. package/dist/src/symbols/symbol-slot.test.js +35 -0
  164. package/dist/src/symbols/symbol-slot.test.js.map +1 -0
  165. package/dist/src/symbols/symbol-table.d.ts.map +1 -1
  166. package/dist/src/symbols/symbol-table.js +6 -5
  167. package/dist/src/symbols/symbol-table.js.map +1 -1
  168. package/dist/src/trace.d.ts +2 -0
  169. package/dist/src/trace.d.ts.map +1 -0
  170. package/dist/src/trace.js +2 -0
  171. package/dist/src/trace.js.map +1 -0
  172. package/dist/src/tracer.d.ts +2 -228
  173. package/dist/src/tracer.d.ts.map +1 -1
  174. package/dist/src/tracer.js +5 -298
  175. package/dist/src/tracer.js.map +1 -1
  176. package/dist/src/utils.d.ts.map +1 -1
  177. package/dist/src/utils.js +5 -0
  178. package/dist/src/utils.js.map +1 -1
  179. package/dist/test/components/append-file.test.d.ts.map +1 -1
  180. package/dist/test/components/append-file.test.js +18 -10
  181. package/dist/test/components/append-file.test.js.map +1 -1
  182. package/dist/test/components/template-file.test.d.ts.map +1 -1
  183. package/dist/test/components/template-file.test.js +6 -4
  184. package/dist/test/components/template-file.test.js.map +1 -1
  185. package/dist/test/rendering/basic.test.js +3 -0
  186. package/dist/test/rendering/basic.test.js.map +1 -1
  187. package/dist/test/rendering/print-render-stack.test.d.ts +2 -0
  188. package/dist/test/rendering/print-render-stack.test.d.ts.map +1 -0
  189. package/dist/test/rendering/print-render-stack.test.js +207 -0
  190. package/dist/test/rendering/print-render-stack.test.js.map +1 -0
  191. package/dist/testing/create-test-wrapper.d.ts +1 -1
  192. package/dist/testing/create-test-wrapper.d.ts.map +1 -1
  193. package/dist/testing/create-test-wrapper.js +1 -1
  194. package/dist/testing/create-test-wrapper.js.map +1 -1
  195. package/dist/testing/devtools-utils.d.ts +26 -0
  196. package/dist/testing/devtools-utils.d.ts.map +1 -0
  197. package/dist/testing/devtools-utils.js +140 -0
  198. package/dist/testing/devtools-utils.js.map +1 -0
  199. package/dist/testing/extend-expect.d.ts.map +1 -1
  200. package/dist/testing/extend-expect.js +63 -1
  201. package/dist/testing/extend-expect.js.map +1 -1
  202. package/dist/testing/render.d.ts +2 -2
  203. package/dist/testing/render.d.ts.map +1 -1
  204. package/dist/testing/render.js +2 -2
  205. package/dist/testing/render.js.map +1 -1
  206. package/dist/tsconfig.tsbuildinfo +1 -1
  207. package/package.json +21 -7
  208. package/scripts/copy-devtools-ui.mjs +26 -0
  209. package/src/binder.ts +71 -16
  210. package/src/components/AppendFile.tsx +14 -9
  211. package/src/components/Block.tsx +1 -1
  212. package/src/components/Declaration.tsx +2 -1
  213. package/src/components/Scope.tsx +4 -1
  214. package/src/components/TemplateFile.tsx +18 -9
  215. package/src/content-slot.tsx +6 -6
  216. package/src/context.ts +15 -4
  217. package/src/{debug.ts → debug/cli.ts} +112 -127
  218. package/src/debug/diagnostics.test.tsx +55 -0
  219. package/src/debug/effects.test.tsx +96 -0
  220. package/src/debug/effects.ts +313 -0
  221. package/src/debug/files.test.tsx +96 -0
  222. package/src/debug/files.ts +40 -0
  223. package/src/debug/index.ts +126 -0
  224. package/src/debug/render.test.tsx +379 -0
  225. package/src/debug/render.ts +639 -0
  226. package/src/debug/serialize.ts +85 -0
  227. package/src/debug/symbols.test.tsx +106 -0
  228. package/src/debug/symbols.ts +230 -0
  229. package/src/debug/trace.ts +312 -0
  230. package/src/devtools/devtools-protocol.ts +312 -0
  231. package/src/devtools/devtools-server.browser.ts +71 -0
  232. package/src/devtools/devtools-server.ts +290 -0
  233. package/src/devtools/devtools-transport.ts +154 -0
  234. package/src/devtools-entry.browser.ts +52 -0
  235. package/src/devtools-entry.ts +54 -0
  236. package/src/diagnostics.ts +141 -0
  237. package/src/index.ts +2 -6
  238. package/src/print-hook.ts +22 -0
  239. package/src/reactive-union-set.ts +71 -41
  240. package/src/reactivity.ts +206 -23
  241. package/src/render-stack.ts +289 -0
  242. package/src/render.ts +464 -212
  243. package/src/resource.ts +28 -19
  244. package/src/runtime/component.ts +11 -0
  245. package/src/scheduler.ts +55 -3
  246. package/src/symbols/basic-symbol.ts +6 -1
  247. package/src/symbols/decl.ts +5 -1
  248. package/src/symbols/output-scope.ts +21 -12
  249. package/src/symbols/output-symbol.ts +33 -12
  250. package/src/symbols/symbol-flow.ts +68 -37
  251. package/src/symbols/symbol-slot.test.tsx +41 -0
  252. package/src/symbols/symbol-slot.tsx +47 -20
  253. package/src/symbols/symbol-table.ts +6 -10
  254. package/src/trace.ts +1 -0
  255. package/src/tracer.ts +13 -242
  256. package/src/utils.tsx +22 -13
  257. package/temp/api.json +1811 -277
  258. package/test/components/append-file.test.tsx +36 -29
  259. package/test/components/template-file.test.tsx +11 -11
  260. package/test/rendering/basic.test.tsx +4 -0
  261. package/test/rendering/print-render-stack.test.tsx +244 -0
  262. package/testing/create-test-wrapper.tsx +1 -1
  263. package/testing/devtools-utils.ts +203 -0
  264. package/testing/extend-expect.ts +89 -0
  265. package/testing/render.ts +2 -2
  266. package/testing/vitest.d.ts +9 -0
  267. package/dist/src/debug.d.ts +0 -15
  268. package/dist/src/debug.d.ts.map +0 -1
  269. package/dist/src/debug.js.map +0 -1
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Shared protocol types for communication between the Alloy devtools server
3
+ * and the devtools UI client. Both sides import these types to ensure
4
+ * compile-time safety and prevent protocol drift.
5
+ */
6
+
7
+ import type { SourceLocation } from "../debug/effects.js";
8
+
9
+ export type { SourceLocation };
10
+
11
+ // ─────────────────────────────────────────────────────────────────────────────
12
+ // Shared types
13
+ // ─────────────────────────────────────────────────────────────────────────────
14
+
15
+ export interface RenderTreeNode {
16
+ id: number;
17
+ kind:
18
+ | "root"
19
+ | "component"
20
+ | "intrinsic"
21
+ | "printHook"
22
+ | "text"
23
+ | "memo"
24
+ | "customContext"
25
+ | "fragment";
26
+ name?: string;
27
+ propsSerialized?: string;
28
+ value?: string;
29
+ source?: SourceLocation;
30
+ }
31
+
32
+ export interface EffectInfo {
33
+ id: number;
34
+ name?: string;
35
+ type?: string;
36
+ createdAt?: SourceLocation;
37
+ lastTriggeredByRefId?: number;
38
+ lastTriggeredAt?: SourceLocation;
39
+ }
40
+
41
+ export interface RefInfo {
42
+ id: number;
43
+ kind?: string;
44
+ createdAt?: SourceLocation;
45
+ createdByEffectId?: number;
46
+ }
47
+
48
+ export interface EffectEdgeInfo {
49
+ id: number;
50
+ type: "track" | "trigger" | "triggered-by";
51
+ effectId: number;
52
+ refId?: number;
53
+ targetId?: number;
54
+ targetKind?: "ref" | "target";
55
+ targetLabel?: string;
56
+ targetKey?: string | number;
57
+ location?: SourceLocation;
58
+ count?: number;
59
+ }
60
+
61
+ export interface ScopeInfo {
62
+ id: number;
63
+ name: string;
64
+ parentId: number | null;
65
+ ownerSymbolId: number | null;
66
+ renderNodeId?: number | null;
67
+ isMemberScope: boolean;
68
+ isTransient?: boolean;
69
+ metadata?: Record<string, unknown>;
70
+ debugInfo?: Record<string, unknown>;
71
+ children?: Array<{ id: number; name?: string }>;
72
+ spaces?: Array<{
73
+ key: string;
74
+ symbols: Array<{ id: number; name?: string }>;
75
+ }>;
76
+ }
77
+
78
+ export interface SymbolInfo {
79
+ id: number;
80
+ name: string;
81
+ originalName: string;
82
+ scopeId: number | null;
83
+ ownerSymbolId: number | null;
84
+ renderNodeId?: number | null;
85
+ isMemberSymbol: boolean;
86
+ isTransient: boolean;
87
+ isAlias: boolean;
88
+ movedToId: number | null;
89
+ metadata?: Record<string, unknown>;
90
+ debugInfo?: Record<string, unknown>;
91
+ memberSpaces?: Array<{
92
+ key: string;
93
+ symbols: Array<{ id: number; name?: string }>;
94
+ }>;
95
+ }
96
+
97
+ export interface RenderErrorStackEntry {
98
+ name: string;
99
+ propsSerialized?: string;
100
+ renderNodeId?: number;
101
+ source?: SourceLocation;
102
+ }
103
+
104
+ export interface DiagnosticInfo {
105
+ id: string;
106
+ message: string;
107
+ severity: string;
108
+ source?: SourceLocation;
109
+ componentStack?: Array<{
110
+ name: string;
111
+ renderNodeId?: number;
112
+ source?: SourceLocation;
113
+ }>;
114
+ }
115
+
116
+ // ─────────────────────────────────────────────────────────────────────────────
117
+ // Server → Client messages
118
+ // ─────────────────────────────────────────────────────────────────────────────
119
+
120
+ export interface DebuggerInfoMessage {
121
+ type: "debugger:info";
122
+ version: string;
123
+ cwd?: string;
124
+ }
125
+
126
+ export interface RenderResetMessage {
127
+ type: "render:reset";
128
+ }
129
+
130
+ export interface RenderNodeAddedMessage {
131
+ type: "render:nodeAdded";
132
+ parentId: number | null;
133
+ node: RenderTreeNode;
134
+ }
135
+
136
+ export interface RenderNodeUpdatedMessage {
137
+ type: "render:nodeUpdated";
138
+ id: number;
139
+ propsSerialized?: string;
140
+ }
141
+
142
+ export interface RenderNodeRemovedMessage {
143
+ type: "render:nodeRemoved";
144
+ parentId: number | null;
145
+ id: number;
146
+ name?: string;
147
+ }
148
+
149
+ export interface RenderErrorMessage {
150
+ type: "render:error";
151
+ id: number;
152
+ name?: string;
153
+ message?: string;
154
+ stack?: string;
155
+ componentStack: RenderErrorStackEntry[];
156
+ }
157
+
158
+ export interface RenderCompleteMessage {
159
+ type: "render:complete";
160
+ }
161
+
162
+ export interface FlushJobsCompleteMessage {
163
+ type: "flushJobs:complete";
164
+ }
165
+
166
+ export interface DirectoryAddedMessage {
167
+ type: "files:directoryAdded";
168
+ path: string;
169
+ }
170
+
171
+ export interface DirectoryRemovedMessage {
172
+ type: "files:directoryRemoved";
173
+ path: string;
174
+ }
175
+
176
+ export interface FileAddedMessage {
177
+ type: "files:fileAdded";
178
+ path: string;
179
+ filetype: string;
180
+ renderNodeId?: number;
181
+ }
182
+
183
+ export interface FileRemovedMessage {
184
+ type: "files:fileRemoved";
185
+ path: string;
186
+ }
187
+
188
+ export interface FileUpdatedMessage {
189
+ type: "files:fileUpdated";
190
+ path: string;
191
+ filetype: string;
192
+ contents: string;
193
+ }
194
+
195
+ export interface ScopeCreateMessage {
196
+ type: "scope:create";
197
+ scope: ScopeInfo;
198
+ }
199
+
200
+ export interface ScopeUpdateMessage {
201
+ type: "scope:update";
202
+ scope: ScopeInfo;
203
+ }
204
+
205
+ export interface ScopeDeleteMessage {
206
+ type: "scope:delete";
207
+ id: number;
208
+ }
209
+
210
+ export interface SymbolCreateMessage {
211
+ type: "symbol:create";
212
+ symbol: SymbolInfo;
213
+ }
214
+
215
+ export interface SymbolUpdateMessage {
216
+ type: "symbol:update";
217
+ symbol: SymbolInfo;
218
+ }
219
+
220
+ export interface SymbolDeleteMessage {
221
+ type: "symbol:delete";
222
+ id: number;
223
+ }
224
+
225
+ export interface EffectAddedMessage {
226
+ type: "effect:effectAdded";
227
+ effect: EffectInfo;
228
+ }
229
+
230
+ export interface EffectUpdatedMessage {
231
+ type: "effect:effectUpdated";
232
+ effect: EffectInfo;
233
+ }
234
+
235
+ export interface RefAddedMessage {
236
+ type: "effect:refAdded";
237
+ ref: RefInfo;
238
+ }
239
+
240
+ export interface EffectTrackMessage {
241
+ type: "effect:track";
242
+ edge: EffectEdgeInfo;
243
+ message?: string;
244
+ }
245
+
246
+ export interface EffectTriggerMessage {
247
+ type: "effect:trigger";
248
+ edge: EffectEdgeInfo;
249
+ message?: string;
250
+ }
251
+
252
+ export interface EffectEdgeUpdatedMessage {
253
+ type: "effect:edgeUpdated";
254
+ edge: EffectEdgeInfo;
255
+ }
256
+
257
+ export interface DiagnosticsReportMessage {
258
+ type: "diagnostics:report";
259
+ diagnostics: DiagnosticInfo[];
260
+ }
261
+
262
+ export interface BatchMessage {
263
+ type: "batch";
264
+ messages: ServerToClientMessage[];
265
+ }
266
+
267
+ export type ServerToClientMessage =
268
+ | DebuggerInfoMessage
269
+ | RenderResetMessage
270
+ | RenderNodeAddedMessage
271
+ | RenderNodeUpdatedMessage
272
+ | RenderNodeRemovedMessage
273
+ | RenderErrorMessage
274
+ | RenderCompleteMessage
275
+ | FlushJobsCompleteMessage
276
+ | DirectoryAddedMessage
277
+ | DirectoryRemovedMessage
278
+ | FileAddedMessage
279
+ | FileRemovedMessage
280
+ | FileUpdatedMessage
281
+ | ScopeCreateMessage
282
+ | ScopeUpdateMessage
283
+ | ScopeDeleteMessage
284
+ | SymbolCreateMessage
285
+ | SymbolUpdateMessage
286
+ | SymbolDeleteMessage
287
+ | EffectAddedMessage
288
+ | EffectUpdatedMessage
289
+ | RefAddedMessage
290
+ | EffectTrackMessage
291
+ | EffectTriggerMessage
292
+ | EffectEdgeUpdatedMessage
293
+ | DiagnosticsReportMessage
294
+ | BatchMessage;
295
+
296
+ // ─────────────────────────────────────────────────────────────────────────────
297
+ // Client → Server messages
298
+ // ─────────────────────────────────────────────────────────────────────────────
299
+
300
+ export interface RerenderRequestMessage {
301
+ type: "render:rerender";
302
+ id: number;
303
+ }
304
+
305
+ export interface RerenderBreakRequestMessage {
306
+ type: "render:rerenderAndBreak";
307
+ id: number;
308
+ }
309
+
310
+ export type ClientToServerMessage =
311
+ | RerenderRequestMessage
312
+ | RerenderBreakRequestMessage;
@@ -0,0 +1,71 @@
1
+ // Browser stub for devtools-server - devtools are not supported in browsers
2
+
3
+ export interface DevtoolsMessage {
4
+ type: string;
5
+ [key: string]: unknown;
6
+ }
7
+
8
+ export interface DevtoolsIncomingMessage {
9
+ type: string;
10
+ [key: string]: unknown;
11
+ }
12
+
13
+ export interface DevtoolsServerInfo {
14
+ port: number;
15
+ connected: boolean;
16
+ }
17
+
18
+ export function isDevtoolsEnabled(): boolean {
19
+ return false;
20
+ }
21
+
22
+ export async function waitForDevtoolsConnection(): Promise<void> {
23
+ // No-op in browser
24
+ }
25
+
26
+ export interface EnableDevtoolsOptions {
27
+ port?: number;
28
+ waitForConnection?: boolean;
29
+ }
30
+
31
+ export async function enableDevtools(
32
+ _options?: EnableDevtoolsOptions,
33
+ ): Promise<void> {
34
+ // No-op in browser
35
+ }
36
+
37
+ export async function initDevtoolsIfEnabled(): Promise<void> {
38
+ // No-op in browser
39
+ }
40
+
41
+ export function broadcastDevtoolsMessage(_message: DevtoolsMessage): void {
42
+ // No-op in browser
43
+ }
44
+
45
+ export function registerDevtoolsMessageHandler(
46
+ _handler: (message: DevtoolsIncomingMessage) => void,
47
+ ): () => void {
48
+ return () => {};
49
+ }
50
+
51
+ export function assertDevtoolsConnectedForSyncRender(): void {
52
+ // No-op in browser
53
+ }
54
+
55
+ export function isDevtoolsConnected(): boolean {
56
+ return false;
57
+ }
58
+
59
+ export function getDevtoolsServerInfo(): DevtoolsServerInfo | null {
60
+ return null;
61
+ }
62
+
63
+ export async function enableDevtoolsAndConnect(
64
+ _options?: EnableDevtoolsOptions,
65
+ ): Promise<DevtoolsServerInfo | null> {
66
+ return null;
67
+ }
68
+
69
+ export async function resetDevtoolsServerForTests(): Promise<void> {
70
+ // No-op in browser
71
+ }
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Devtools session manager.
3
+ *
4
+ * Manages the lifecycle of a devtools session: enable, connect, broadcast
5
+ * messages, and reset. Transport details (HTTP/WebSocket) are delegated
6
+ * to devtools-transport.ts.
7
+ */
8
+ import {
9
+ createTransport,
10
+ getAlloyVersion,
11
+ type DevtoolsTransportState,
12
+ } from "./devtools-transport.js";
13
+
14
+ // ─────────────────────────────────────────────────────────────────────────────
15
+ // Public types
16
+ // ─────────────────────────────────────────────────────────────────────────────
17
+
18
+ export interface DevtoolsMessage {
19
+ type: string;
20
+ [key: string]: unknown;
21
+ }
22
+
23
+ export interface DevtoolsIncomingMessage {
24
+ type: string;
25
+ [key: string]: unknown;
26
+ }
27
+
28
+ export interface DevtoolsServerInfo {
29
+ port: number;
30
+ connected: boolean;
31
+ }
32
+
33
+ export interface EnableDevtoolsOptions {
34
+ /** Port to listen on. Use 0 for a random available port. Defaults to ALLOY_DEBUG_PORT or 8123. */
35
+ port?: number;
36
+ }
37
+
38
+ // ─────────────────────────────────────────────────────────────────────────────
39
+ // Session state
40
+ // ─────────────────────────────────────────────────────────────────────────────
41
+
42
+ let transportState: DevtoolsTransportState | null = null;
43
+ let transportPromise: Promise<DevtoolsTransportState> | null = null;
44
+ const messageHandlers = new Set<(message: DevtoolsIncomingMessage) => void>();
45
+ let devtoolsExplicitlyEnabled = false;
46
+ let devtoolsInitialized = false;
47
+ let loggedDevtoolsLinks = false;
48
+ let waitingForConnection = false;
49
+ let configuredPort: number | undefined;
50
+
51
+ // ─────────────────────────────────────────────────────────────────────────────
52
+ // Environment helpers
53
+ // ─────────────────────────────────────────────────────────────────────────────
54
+
55
+ function isNodeEnvironment() {
56
+ return (
57
+ typeof process !== "undefined" &&
58
+ typeof process.versions === "object" &&
59
+ Boolean(process.versions?.node)
60
+ );
61
+ }
62
+
63
+ function getCwd() {
64
+ if (!isNodeEnvironment()) return undefined;
65
+ try {
66
+ return process.cwd();
67
+ } catch {
68
+ return undefined;
69
+ }
70
+ }
71
+
72
+ function resolveDebugPort() {
73
+ const raw = process.env.ALLOY_DEBUG_PORT;
74
+ if (!raw) return 8123;
75
+ const parsed = Number.parseInt(raw, 10);
76
+ if (Number.isNaN(parsed)) return 8123;
77
+ return parsed;
78
+ }
79
+
80
+ // ─────────────────────────────────────────────────────────────────────────────
81
+ // Query functions
82
+ // ─────────────────────────────────────────────────────────────────────────────
83
+
84
+ /** Returns true when devtools are enabled (via env var or explicit call). */
85
+ export function isDevtoolsEnabled() {
86
+ if (!isNodeEnvironment()) return false;
87
+ return devtoolsExplicitlyEnabled || Boolean(process.env.ALLOY_DEBUG);
88
+ }
89
+
90
+ /** Returns true when a devtools client is currently connected. */
91
+ export function isDevtoolsConnected(): boolean {
92
+ return Boolean(transportState?.connected);
93
+ }
94
+
95
+ /** Get the current server info, or null if not running. */
96
+ export function getDevtoolsServerInfo(): DevtoolsServerInfo | null {
97
+ if (!transportState) return null;
98
+ return { port: transportState.port, connected: transportState.connected };
99
+ }
100
+
101
+ // ─────────────────────────────────────────────────────────────────────────────
102
+ // Server lifecycle
103
+ // ─────────────────────────────────────────────────────────────────────────────
104
+
105
+ async function ensureServer(): Promise<DevtoolsTransportState> {
106
+ if (transportState) return transportState;
107
+ if (!transportPromise) {
108
+ transportPromise = createTransport({
109
+ port: configuredPort ?? resolveDebugPort(),
110
+ onConnection(socket) {
111
+ if (waitingForConnection) {
112
+ waitingForConnection = false;
113
+ process.stdout.write(" Connected!\n");
114
+ }
115
+ socket.send(
116
+ JSON.stringify({
117
+ type: "debugger:info",
118
+ version: getAlloyVersion(),
119
+ cwd: getCwd(),
120
+ }),
121
+ );
122
+ },
123
+ onMessage(raw) {
124
+ const message = raw as DevtoolsIncomingMessage;
125
+ if (!message || !message.type) return;
126
+ for (const handler of messageHandlers) {
127
+ handler(message);
128
+ }
129
+ },
130
+ onDisconnect() {
131
+ // Currently no-op; transport handles client set management
132
+ },
133
+ }).then((state) => {
134
+ transportState = state;
135
+ if (!loggedDevtoolsLinks) {
136
+ loggedDevtoolsLinks = true;
137
+ // eslint-disable-next-line no-console
138
+ console.log(`Alloy ${getAlloyVersion()}`);
139
+ // eslint-disable-next-line no-console
140
+ console.log(`➜ Debug UI: http://localhost:${state.port}/`);
141
+ // eslint-disable-next-line no-console
142
+ console.log(`➜ Websocket: ws://localhost:${state.port}/`);
143
+ // eslint-disable-next-line no-console
144
+ console.log("");
145
+ waitingForConnection = true;
146
+ process.stdout.write("Waiting for connection...");
147
+ }
148
+ return state;
149
+ });
150
+ }
151
+ return transportPromise;
152
+ }
153
+
154
+ // ─────────────────────────────────────────────────────────────────────────────
155
+ // Public API
156
+ // ─────────────────────────────────────────────────────────────────────────────
157
+
158
+ /**
159
+ * Wait for a devtools client to connect before proceeding.
160
+ *
161
+ * Starts the devtools server if not already running, and blocks until a
162
+ * devtools client connects via WebSocket.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * import { waitForDevtoolsConnection } from "@alloy-js/core/devtools";
167
+ * import { render } from "@alloy-js/core";
168
+ *
169
+ * await waitForDevtoolsConnection();
170
+ * const tree = render(<MyComponent />);
171
+ * ```
172
+ */
173
+ export async function waitForDevtoolsConnection(): Promise<void> {
174
+ devtoolsExplicitlyEnabled = true;
175
+ const server = await ensureServer();
176
+ if (server.connected) return;
177
+ await server.ready;
178
+ }
179
+
180
+ /**
181
+ * Enable devtools and start the server, returning when the server is ready.
182
+ * Use this in tests to enable devtools before connecting a client.
183
+ *
184
+ * @returns Server info with port number
185
+ */
186
+ export async function enableDevtools(
187
+ options?: EnableDevtoolsOptions,
188
+ ): Promise<DevtoolsServerInfo> {
189
+ devtoolsExplicitlyEnabled = true;
190
+ devtoolsInitialized = true;
191
+ if (options?.port !== undefined) {
192
+ configuredPort = options.port;
193
+ }
194
+ const server = await ensureServer();
195
+ return { port: server.port, connected: server.connected };
196
+ }
197
+
198
+ /**
199
+ * Initialize devtools if ALLOY_DEBUG is set. Called lazily by render functions.
200
+ * Returns immediately if devtools are not enabled or already initialized.
201
+ */
202
+ export async function initDevtoolsIfEnabled(): Promise<void> {
203
+ if (devtoolsInitialized) return;
204
+ if (!isDevtoolsEnabled()) return;
205
+ devtoolsInitialized = true;
206
+ await waitForDevtoolsConnection();
207
+ }
208
+
209
+ /**
210
+ * Start the devtools server and wait for a client connection.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * const serverInfo = await enableDevtoolsAndConnect({ port: 0 });
215
+ * // ... run your test ...
216
+ * await resetDevtoolsServerForTests();
217
+ * ```
218
+ *
219
+ * @returns Server info once a client has connected
220
+ */
221
+ export async function enableDevtoolsAndConnect(
222
+ options?: EnableDevtoolsOptions,
223
+ ): Promise<DevtoolsServerInfo> {
224
+ const info = await enableDevtools(options);
225
+ if (!info.connected) {
226
+ await transportState!.ready;
227
+ }
228
+ return { port: transportState!.port, connected: true };
229
+ }
230
+
231
+ // ─────────────────────────────────────────────────────────────────────────────
232
+ // Messaging
233
+ // ─────────────────────────────────────────────────────────────────────────────
234
+
235
+ /** Broadcast a message to all connected devtools clients. */
236
+ export function broadcastDevtoolsMessage(message: DevtoolsMessage) {
237
+ if (!isDevtoolsEnabled()) return;
238
+ if (!transportState) return;
239
+ if (transportState.clients.size === 0) return;
240
+
241
+ try {
242
+ const payload = JSON.stringify(message);
243
+ for (const client of transportState.clients) {
244
+ if (client.readyState === client.OPEN) {
245
+ client.send(payload);
246
+ }
247
+ }
248
+ } catch (err) {
249
+ // eslint-disable-next-line no-console
250
+ console.error(
251
+ `Failed to send devtools message (type: ${message.type}):`,
252
+ err,
253
+ );
254
+ }
255
+ }
256
+
257
+ /** Register a handler for incoming devtools messages. Returns an unsubscribe function. */
258
+ export function registerDevtoolsMessageHandler(
259
+ handler: (message: DevtoolsIncomingMessage) => void,
260
+ ) {
261
+ messageHandlers.add(handler);
262
+ return () => messageHandlers.delete(handler);
263
+ }
264
+
265
+ /** Throw if devtools are enabled but no client is connected (for sync render). */
266
+ export function assertDevtoolsConnectedForSyncRender() {
267
+ if (!isDevtoolsEnabled()) return;
268
+ if (!transportState || !transportState.connected) {
269
+ throw new Error(
270
+ "ALLOY_DEBUG is set but devtools are not connected. Use renderAsync or wait for the devtools client before rendering.",
271
+ );
272
+ }
273
+ }
274
+
275
+ // ─────────────────────────────────────────────────────────────────────────────
276
+ // Test utilities
277
+ // ─────────────────────────────────────────────────────────────────────────────
278
+
279
+ /** Reset all devtools state. For use in tests only. */
280
+ export async function resetDevtoolsServerForTests() {
281
+ if (transportState) {
282
+ await transportState.close();
283
+ }
284
+ transportState = null;
285
+ transportPromise = null;
286
+ devtoolsExplicitlyEnabled = false;
287
+ devtoolsInitialized = false;
288
+ configuredPort = undefined;
289
+ loggedDevtoolsLinks = false;
290
+ }