@uistate/core 5.2.0 → 5.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/package.json +5 -5
  2. package/queryClient.js +55 -0
  3. package/examples/001-counter/README.md +0 -44
  4. package/examples/001-counter/index.html +0 -33
  5. package/examples/002-counter-improved/README.md +0 -44
  6. package/examples/002-counter-improved/index.html +0 -47
  7. package/examples/003-input-reactive/README.md +0 -44
  8. package/examples/003-input-reactive/index.html +0 -33
  9. package/examples/004-computed-state/README.md +0 -45
  10. package/examples/004-computed-state/index.html +0 -65
  11. package/examples/005-conditional-rendering/README.md +0 -42
  12. package/examples/005-conditional-rendering/index.html +0 -39
  13. package/examples/006-list-rendering/README.md +0 -49
  14. package/examples/006-list-rendering/index.html +0 -63
  15. package/examples/007-form-validation/README.md +0 -52
  16. package/examples/007-form-validation/index.html +0 -102
  17. package/examples/008-undo-redo/README.md +0 -70
  18. package/examples/008-undo-redo/index.html +0 -108
  19. package/examples/009-localStorage-side-effects/README.md +0 -72
  20. package/examples/009-localStorage-side-effects/index.html +0 -57
  21. package/examples/010-decoupled-components/README.md +0 -74
  22. package/examples/010-decoupled-components/index.html +0 -93
  23. package/examples/011-async-patterns/README.md +0 -98
  24. package/examples/011-async-patterns/index.html +0 -132
  25. package/examples/028-counter-improved-eventTest/LICENSE +0 -55
  26. package/examples/028-counter-improved-eventTest/README.md +0 -131
  27. package/examples/028-counter-improved-eventTest/app/store.js +0 -9
  28. package/examples/028-counter-improved-eventTest/index.html +0 -49
  29. package/examples/028-counter-improved-eventTest/runtime/core/behaviors.runtime.js +0 -282
  30. package/examples/028-counter-improved-eventTest/runtime/core/eventState.js +0 -100
  31. package/examples/028-counter-improved-eventTest/runtime/core/eventStateNew.js +0 -149
  32. package/examples/028-counter-improved-eventTest/runtime/core/helpers.js +0 -212
  33. package/examples/028-counter-improved-eventTest/runtime/core/router.js +0 -271
  34. package/examples/028-counter-improved-eventTest/store.d.ts +0 -8
  35. package/examples/028-counter-improved-eventTest/style.css +0 -170
  36. package/examples/028-counter-improved-eventTest/tests/README.md +0 -208
  37. package/examples/028-counter-improved-eventTest/tests/counter.test.js +0 -116
  38. package/examples/028-counter-improved-eventTest/tests/eventTest.js +0 -176
  39. package/examples/028-counter-improved-eventTest/tests/generateTypes.js +0 -168
  40. package/examples/028-counter-improved-eventTest/tests/run.js +0 -20
  41. package/examples/030-todo-app-with-eventTest/LICENSE +0 -55
  42. package/examples/030-todo-app-with-eventTest/README.md +0 -121
  43. package/examples/030-todo-app-with-eventTest/app/router.js +0 -25
  44. package/examples/030-todo-app-with-eventTest/app/store.js +0 -16
  45. package/examples/030-todo-app-with-eventTest/app/views/home.js +0 -11
  46. package/examples/030-todo-app-with-eventTest/app/views/todoDemo.js +0 -88
  47. package/examples/030-todo-app-with-eventTest/index.html +0 -65
  48. package/examples/030-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  49. package/examples/030-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  50. package/examples/030-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  51. package/examples/030-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  52. package/examples/030-todo-app-with-eventTest/runtime/core/router.js +0 -271
  53. package/examples/030-todo-app-with-eventTest/store.d.ts +0 -18
  54. package/examples/030-todo-app-with-eventTest/style.css +0 -170
  55. package/examples/030-todo-app-with-eventTest/tests/README.md +0 -208
  56. package/examples/030-todo-app-with-eventTest/tests/eventTest.js +0 -176
  57. package/examples/030-todo-app-with-eventTest/tests/generateTypes.js +0 -189
  58. package/examples/030-todo-app-with-eventTest/tests/run.js +0 -20
  59. package/examples/030-todo-app-with-eventTest/tests/todos.test.js +0 -167
  60. package/examples/031-todo-app-with-eventTest/LICENSE +0 -55
  61. package/examples/031-todo-app-with-eventTest/README.md +0 -54
  62. package/examples/031-todo-app-with-eventTest/TUTORIAL.md +0 -390
  63. package/examples/031-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  64. package/examples/031-todo-app-with-eventTest/app/bridges.js +0 -113
  65. package/examples/031-todo-app-with-eventTest/app/router.js +0 -26
  66. package/examples/031-todo-app-with-eventTest/app/store.js +0 -15
  67. package/examples/031-todo-app-with-eventTest/app/views/home.js +0 -46
  68. package/examples/031-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  69. package/examples/031-todo-app-with-eventTest/devtools/dock.js +0 -41
  70. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  71. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  72. package/examples/031-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  73. package/examples/031-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  74. package/examples/031-todo-app-with-eventTest/index.html +0 -103
  75. package/examples/031-todo-app-with-eventTest/package-lock.json +0 -2184
  76. package/examples/031-todo-app-with-eventTest/package.json +0 -24
  77. package/examples/031-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  78. package/examples/031-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  79. package/examples/031-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  80. package/examples/031-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  81. package/examples/031-todo-app-with-eventTest/runtime/core/router.js +0 -271
  82. package/examples/031-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  83. package/examples/031-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  84. package/examples/031-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  85. package/examples/031-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  86. package/examples/031-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  87. package/examples/031-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  88. package/examples/031-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  89. package/examples/031-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  90. package/examples/031-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  91. package/examples/031-todo-app-with-eventTest/store.d.ts +0 -23
  92. package/examples/031-todo-app-with-eventTest/style.css +0 -170
  93. package/examples/031-todo-app-with-eventTest/tests/README.md +0 -208
  94. package/examples/031-todo-app-with-eventTest/tests/eventTest.js +0 -176
  95. package/examples/031-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  96. package/examples/031-todo-app-with-eventTest/tests/run.js +0 -20
  97. package/examples/031-todo-app-with-eventTest/tests/todos.test.js +0 -192
  98. package/examples/032-todo-app-with-eventTest/LICENSE +0 -55
  99. package/examples/032-todo-app-with-eventTest/README.md +0 -54
  100. package/examples/032-todo-app-with-eventTest/TUTORIAL.md +0 -390
  101. package/examples/032-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  102. package/examples/032-todo-app-with-eventTest/app/actions/index.js +0 -153
  103. package/examples/032-todo-app-with-eventTest/app/bridges.js +0 -113
  104. package/examples/032-todo-app-with-eventTest/app/router.js +0 -26
  105. package/examples/032-todo-app-with-eventTest/app/store.js +0 -15
  106. package/examples/032-todo-app-with-eventTest/app/views/home.js +0 -46
  107. package/examples/032-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  108. package/examples/032-todo-app-with-eventTest/devtools/dock.js +0 -41
  109. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  110. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  111. package/examples/032-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  112. package/examples/032-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  113. package/examples/032-todo-app-with-eventTest/index.html +0 -87
  114. package/examples/032-todo-app-with-eventTest/package-lock.json +0 -2184
  115. package/examples/032-todo-app-with-eventTest/package.json +0 -24
  116. package/examples/032-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  117. package/examples/032-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  118. package/examples/032-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  119. package/examples/032-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  120. package/examples/032-todo-app-with-eventTest/runtime/core/router.js +0 -271
  121. package/examples/032-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  122. package/examples/032-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  123. package/examples/032-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  124. package/examples/032-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  125. package/examples/032-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  126. package/examples/032-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  127. package/examples/032-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  128. package/examples/032-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  129. package/examples/032-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  130. package/examples/032-todo-app-with-eventTest/store.d.ts +0 -23
  131. package/examples/032-todo-app-with-eventTest/style.css +0 -170
  132. package/examples/032-todo-app-with-eventTest/tests/README.md +0 -208
  133. package/examples/032-todo-app-with-eventTest/tests/eventTest.js +0 -176
  134. package/examples/032-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  135. package/examples/032-todo-app-with-eventTest/tests/run.js +0 -20
  136. package/examples/032-todo-app-with-eventTest/tests/todos.test.js +0 -192
  137. package/playground/exercise001.html +0 -38
  138. package/playground/exercise002.html +0 -49
@@ -1,339 +0,0 @@
1
- // typeGenerator.js — Generate TypeScript definitions from telemetry
2
- // Analyzes runtime telemetry to extract state shape and generate .d.ts files
3
-
4
- import store from '../app/store.js';
5
-
6
- class TypeGenerator {
7
- constructor() {
8
- this.pathTypes = new Map(); // path → type info
9
- this.pathSamples = new Map(); // path → sample values
10
- }
11
-
12
- /**
13
- * Observe a state change and infer its type
14
- */
15
- observe(path, value) {
16
- const type = this.inferType(value);
17
-
18
- // Store sample for complex types
19
- if (typeof value === 'object' && value !== null) {
20
- if (!this.pathSamples.has(path)) {
21
- this.pathSamples.set(path, []);
22
- }
23
- const samples = this.pathSamples.get(path);
24
- if (samples.length < 10) {
25
- samples.push(value);
26
- }
27
- }
28
-
29
- // Merge with existing type info
30
- if (this.pathTypes.has(path)) {
31
- const existing = this.pathTypes.get(path);
32
- this.pathTypes.set(path, this.mergeTypes(existing, type));
33
- } else {
34
- this.pathTypes.set(path, type);
35
- }
36
- }
37
-
38
- /**
39
- * Infer TypeScript type from a value
40
- */
41
- inferType(value) {
42
- if (value === null) return 'null';
43
- if (value === undefined) return 'undefined';
44
-
45
- if (Array.isArray(value)) {
46
- if (value.length === 0) return 'Array<unknown>';
47
-
48
- // Sample first few elements and merge their types
49
- const samples = value.slice(0, 10);
50
- let mergedElementType = null;
51
-
52
- for (const sample of samples) {
53
- const elementType = this.inferType(sample);
54
- if (mergedElementType === null) {
55
- mergedElementType = elementType;
56
- } else {
57
- mergedElementType = this.mergeTypes(mergedElementType, elementType);
58
- }
59
- }
60
-
61
- return `Array<${this.typeToString(mergedElementType)}>`;
62
- }
63
-
64
- if (typeof value === 'object') {
65
- // Infer object shape
66
- const shape = {};
67
- for (const [key, val] of Object.entries(value)) {
68
- shape[key] = this.inferType(val);
69
- }
70
- return shape;
71
- }
72
-
73
- // Primitives
74
- if (typeof value === 'string') return 'string';
75
- if (typeof value === 'number') return 'number';
76
- if (typeof value === 'boolean') return 'boolean';
77
-
78
- return 'unknown';
79
- }
80
-
81
- /**
82
- * Convert type representation to string
83
- */
84
- typeToString(type) {
85
- if (typeof type === 'string') return type;
86
-
87
- if (typeof type === 'object' && !Array.isArray(type)) {
88
- const props = Object.entries(type)
89
- .map(([k, v]) => `${k}: ${this.typeToString(v)}`)
90
- .join('; ');
91
- return `{ ${props} }`;
92
- }
93
-
94
- return 'unknown';
95
- }
96
-
97
- /**
98
- * Merge two type definitions (for union types)
99
- */
100
- mergeTypes(type1, type2) {
101
- // Normalize for comparison
102
- const str1 = this.normalizeType(type1);
103
- const str2 = this.normalizeType(type2);
104
-
105
- if (str1 === str2) return type1;
106
-
107
- // Handle string types
108
- if (typeof type1 === 'string' && typeof type2 === 'string') {
109
- if (type1 === type2) return type1;
110
- // Avoid duplicate unions
111
- if (type1.includes(type2)) return type1;
112
- if (type2.includes(type1)) return type2;
113
- return `${type1} | ${type2}`;
114
- }
115
-
116
- // Handle object merging (merge properties, not create union)
117
- if (typeof type1 === 'object' && typeof type2 === 'object' &&
118
- !Array.isArray(type1) && !Array.isArray(type2)) {
119
- const merged = { ...type1 };
120
- for (const [key, val] of Object.entries(type2)) {
121
- if (key in merged) {
122
- merged[key] = this.mergeTypes(merged[key], val);
123
- } else {
124
- merged[key] = val;
125
- }
126
- }
127
- return merged;
128
- }
129
-
130
- // Mixed types: create union
131
- if (typeof type1 === 'string' && typeof type2 === 'object') {
132
- return `${type1} | ${this.typeToString(type2)}`;
133
- }
134
- if (typeof type1 === 'object' && typeof type2 === 'string') {
135
- return `${this.typeToString(type1)} | ${type2}`;
136
- }
137
-
138
- return type1; // Default: keep first type
139
- }
140
-
141
- /**
142
- * Normalize type for comparison
143
- */
144
- normalizeType(type) {
145
- if (typeof type === 'string') return type;
146
- return JSON.stringify(type, Object.keys(type).sort());
147
- }
148
-
149
- /**
150
- * Build hierarchical tree from flat paths
151
- */
152
- buildTree() {
153
- const tree = {};
154
-
155
- for (const [path, type] of this.pathTypes) {
156
- const parts = path.split('.');
157
- let current = tree;
158
-
159
- for (let i = 0; i < parts.length; i++) {
160
- const part = parts[i];
161
-
162
- if (i === parts.length - 1) {
163
- // Leaf node
164
- current[part] = { __type: type };
165
- } else {
166
- // Branch node
167
- if (!current[part]) {
168
- current[part] = {};
169
- }
170
- current = current[part];
171
- }
172
- }
173
- }
174
-
175
- return tree;
176
- }
177
-
178
- /**
179
- * Generate TypeScript interface from type info
180
- */
181
- generateInterface(obj, indent = 0) {
182
- const lines = [];
183
- const spaces = ' '.repeat(indent);
184
-
185
- for (const [key, value] of Object.entries(obj)) {
186
- if (value.__type !== undefined) {
187
- // Leaf node with type
188
- const type = this.formatType(value.__type);
189
- lines.push(`${spaces}${key}: ${type};`);
190
- } else {
191
- // Nested object
192
- lines.push(`${spaces}${key}: {`);
193
- lines.push(this.generateInterface(value, indent + 1));
194
- lines.push(`${spaces}};`);
195
- }
196
- }
197
-
198
- return lines.join('\n');
199
- }
200
-
201
- /**
202
- * Format type for TypeScript output
203
- */
204
- formatType(type) {
205
- if (typeof type === 'string') {
206
- return type;
207
- }
208
-
209
- if (typeof type === 'object' && !Array.isArray(type)) {
210
- // Inline object type
211
- const props = Object.entries(type)
212
- .map(([k, v]) => `${k}: ${this.formatType(v)}`)
213
- .join('; ');
214
- return `{ ${props} }`;
215
- }
216
-
217
- return 'unknown';
218
- }
219
-
220
- /**
221
- * Generate complete .d.ts file
222
- */
223
- generateDTS() {
224
- const lines = [
225
- '// Auto-generated from runtime telemetry',
226
- '// DO NOT EDIT - regenerate by using the app and clicking "Generate Types"',
227
- '',
228
- 'export interface StoreState {',
229
- ];
230
-
231
- const tree = this.buildTree();
232
- lines.push(this.generateInterface(tree, 1));
233
- lines.push('}');
234
- lines.push('');
235
- lines.push('export default StoreState;');
236
- lines.push('');
237
-
238
- return lines.join('\n');
239
- }
240
-
241
- /**
242
- * Parse telemetry buffer and extract types
243
- */
244
- parseBuffer(buffer) {
245
- for (const entry of buffer) {
246
- if (entry.level !== 'log') continue;
247
-
248
- const args = entry.args;
249
- if (!args || args.length < 2) continue;
250
-
251
- const tag = args[0];
252
-
253
- // Parse [state] entries
254
- if (typeof tag === 'string' && tag.startsWith('[state]')) {
255
- const path = tag.replace('[state] ', '');
256
- const value = args[1];
257
- this.observe(path, value);
258
- }
259
-
260
- // Parse [intent] entries
261
- if (typeof tag === 'string' && tag.startsWith('[intent]')) {
262
- const intentName = tag.replace('[intent] ', '');
263
- const path = `intent.${intentName}`;
264
- const value = args[1];
265
- this.observe(path, value);
266
- }
267
- }
268
- }
269
-
270
- /**
271
- * Parse test assertions and extract types
272
- */
273
- parseTestAssertions(assertions) {
274
- for (const assertion of assertions) {
275
- const { path, type, elementShape, shape } = assertion;
276
-
277
- if (type === 'array' && elementShape) {
278
- // Array type with element shape
279
- this.pathTypes.set(path, `Array<${this.typeToString(elementShape)}>`);
280
- } else if (type === 'object' && shape) {
281
- // Object type with shape
282
- this.pathTypes.set(path, shape);
283
- } else if (type) {
284
- // Primitive type
285
- this.pathTypes.set(path, type);
286
- }
287
- }
288
- }
289
-
290
- /**
291
- * Save .d.ts file (browser download)
292
- */
293
- save(filename = 'store.d.ts') {
294
- const dts = this.generateDTS();
295
- const blob = new Blob([dts], { type: 'text/plain' });
296
- const url = URL.createObjectURL(blob);
297
- const a = document.createElement('a');
298
- a.href = url;
299
- a.download = filename;
300
- a.click();
301
- URL.revokeObjectURL(url);
302
- }
303
- }
304
-
305
- // Create and expose type generator
306
- const typeGenerator = new TypeGenerator();
307
- window.__typeGenerator = typeGenerator;
308
-
309
- // Subscribe to all state changes for live type inference
310
- if (store && store.subscribe) {
311
- store.subscribe('*', (detail) => {
312
- const { path, value } = detail;
313
- typeGenerator.observe(path, value);
314
- });
315
-
316
- console.info('[typeGenerator] Live type inference enabled');
317
- }
318
-
319
- // Register with dev dock
320
- if (window.__devdock && typeof window.__devdock.register === 'function') {
321
- window.__devdock.register({
322
- id: 'generate-types',
323
- label: 'Types',
324
- title: 'Generate TypeScript definitions',
325
- onClick: () => {
326
- // Also parse telemetry buffer for historical data
327
- if (window.__telemetry) {
328
- const buffer = window.__telemetry.get();
329
- typeGenerator.parseBuffer(buffer);
330
- }
331
-
332
- typeGenerator.save('store.d.ts');
333
- console.info('[typeGenerator] Generated store.d.ts');
334
- }
335
- });
336
- }
337
-
338
- export default typeGenerator;
339
- export { TypeGenerator };
@@ -1,103 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>009 Todo App with eventTest</title>
7
- <link rel="stylesheet" href="style.css">
8
- </head>
9
- <body data-theme="dark" data-bind="data-theme: ui.theme">
10
- <nav style="display:flex; gap:10px; align-items:center; padding:10px 12px;">
11
- <a href="/" data-link>Home</a>
12
- <a href="/todo-demo" data-link>Todo app demo</a>
13
- <span class="loading-badge" aria-live="polite">Loading…</span>
14
- <span style="flex:1"></span>
15
- <button class="btn" title="Toggle theme" data-on="click: toggleTheme() | log('toggle theme') | logPath('ui.theme')">Theme</button>
16
- </nav>
17
- <div data-route-root></div>
18
-
19
- <script type="module" src="./app/router.js"></script>
20
- <!-- Expose the store globally so stateTracker (optional) can bind without tight coupling -->
21
- <script type="module">
22
- import store from './app/store.js';
23
- window.stateTrackerStore = store;
24
-
25
- // Bind loading badge to route transitioning state (after DOM ready)
26
- requestAnimationFrame(() => {
27
- const badge = document.querySelector('.loading-badge');
28
- if (badge) {
29
- store.subscribe('ui.route.transitioning', (isTransitioning) => {
30
- badge.style.display = isTransitioning ? 'inline' : 'none';
31
- });
32
- // Set initial state (default hidden in CSS)
33
- badge.style.display = store.get('ui.route.transitioning') ? 'inline' : 'none';
34
- }
35
- });
36
- </script>
37
- <!-- Install behaviors runtime with inline actions (no separate registry file) -->
38
- <script type="module">
39
- import store from './app/store.js';
40
- import { installBehaviors } from './runtime/core/behaviors.runtime.js';
41
-
42
- // Inline action registry - just the actions used in this example
43
- const registry = {
44
- toggleTheme(ctx) {
45
- const cur = ctx.get('ui.theme');
46
- const next = (cur === 'dark') ? 'light' : 'dark';
47
- ctx.set('ui.theme', next);
48
- console.log('[action] theme ->', next);
49
- },
50
- log(ctx, ...args) {
51
- console.log('[action]', ...args);
52
- },
53
- logPath(ctx, path) {
54
- console.log('[action]', String(path), ctx.get(String(path)));
55
- }
56
- };
57
-
58
- window.behaviorsWhitelistDefault = ['ui.counter', 'ui.name', 'ui.items', 'ui.newItem', 'ui.itemsCount', 'ui.guard.whitelist', 'ui.theme', 'intent.**'];
59
- window.behaviorsWhitelist = [...window.behaviorsWhitelistDefault];
60
- const recUn = window.__recorder?.install?.(store);
61
- window.behaviorsUninstall = installBehaviors(store, {
62
- registry,
63
- root: document,
64
- writablePrefixes: ['ui.','intent.'],
65
- writableWhitelist: window.behaviorsWhitelist,
66
- debug: true,
67
- onStep: (e) => {
68
- try { window.__recorder?.onStep?.(e); } catch{}
69
- // Log all behavior steps to telemetry
70
- try {
71
- if (e.phase === 'started') {
72
- console.log(`[action] ${e.name}(${e.args?.join(', ') || ''})`, { event: e.event?.type, element: e.el?.tagName });
73
- }
74
- if (e.phase === 'applied' && e.write) {
75
- console.log(`[write] ${e.write}`, store.get(e.write));
76
- }
77
- if (e.phase === 'blocked') {
78
- console.warn(`[blocked] ${e.name} tried to write ${e.write}`, e.reason);
79
- }
80
- } catch{}
81
- },
82
- });
83
- try { store.set('ui.guard.whitelist', [...window.behaviorsWhitelist]); } catch {}
84
- try {
85
- const cur = store.get('ui.theme');
86
- if (!cur) {
87
- const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
88
- store.set('ui.theme', prefersDark ? 'dark' : 'light');
89
- }
90
- try { store.subscribe && store.subscribe('ui.theme', () => { try { localStorage.setItem('ui.theme', store.get('ui.theme')); } catch {} }); } catch {}
91
- } catch {}
92
- </script>
93
- <script type="module" src="./devtools/stateTracker.js"></script>
94
- <!-- Dev dock MUST load first so __devdock is available -->
95
- <script type="module" src="./devtools/dock.js"></script>
96
- <!-- Now load tools that register with the dock -->
97
- <script type="module" src="./devtools/telemetry.js"></script>
98
- <script type="module" src="./devtools/typeGenerator.js"></script>
99
- <script type="module" src="./devtools/stateTracker.dock.js"></script>
100
- <!-- App bridges: intent→domain and derived wildcards -->
101
- <script type="module" src="./app/bridges.js"></script>
102
- </body>
103
- </html>