@uistate/core 5.2.0 → 5.4.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 (142) hide show
  1. package/index.js +2 -9
  2. package/package.json +4 -10
  3. package/queryClient.js +55 -0
  4. package/cssState.js +0 -212
  5. package/examples/001-counter/README.md +0 -44
  6. package/examples/001-counter/index.html +0 -33
  7. package/examples/002-counter-improved/README.md +0 -44
  8. package/examples/002-counter-improved/index.html +0 -47
  9. package/examples/003-input-reactive/README.md +0 -44
  10. package/examples/003-input-reactive/index.html +0 -33
  11. package/examples/004-computed-state/README.md +0 -45
  12. package/examples/004-computed-state/index.html +0 -65
  13. package/examples/005-conditional-rendering/README.md +0 -42
  14. package/examples/005-conditional-rendering/index.html +0 -39
  15. package/examples/006-list-rendering/README.md +0 -49
  16. package/examples/006-list-rendering/index.html +0 -63
  17. package/examples/007-form-validation/README.md +0 -52
  18. package/examples/007-form-validation/index.html +0 -102
  19. package/examples/008-undo-redo/README.md +0 -70
  20. package/examples/008-undo-redo/index.html +0 -108
  21. package/examples/009-localStorage-side-effects/README.md +0 -72
  22. package/examples/009-localStorage-side-effects/index.html +0 -57
  23. package/examples/010-decoupled-components/README.md +0 -74
  24. package/examples/010-decoupled-components/index.html +0 -93
  25. package/examples/011-async-patterns/README.md +0 -98
  26. package/examples/011-async-patterns/index.html +0 -132
  27. package/examples/028-counter-improved-eventTest/LICENSE +0 -55
  28. package/examples/028-counter-improved-eventTest/README.md +0 -131
  29. package/examples/028-counter-improved-eventTest/app/store.js +0 -9
  30. package/examples/028-counter-improved-eventTest/index.html +0 -49
  31. package/examples/028-counter-improved-eventTest/runtime/core/behaviors.runtime.js +0 -282
  32. package/examples/028-counter-improved-eventTest/runtime/core/eventState.js +0 -100
  33. package/examples/028-counter-improved-eventTest/runtime/core/eventStateNew.js +0 -149
  34. package/examples/028-counter-improved-eventTest/runtime/core/helpers.js +0 -212
  35. package/examples/028-counter-improved-eventTest/runtime/core/router.js +0 -271
  36. package/examples/028-counter-improved-eventTest/store.d.ts +0 -8
  37. package/examples/028-counter-improved-eventTest/style.css +0 -170
  38. package/examples/028-counter-improved-eventTest/tests/README.md +0 -208
  39. package/examples/028-counter-improved-eventTest/tests/counter.test.js +0 -116
  40. package/examples/028-counter-improved-eventTest/tests/eventTest.js +0 -176
  41. package/examples/028-counter-improved-eventTest/tests/generateTypes.js +0 -168
  42. package/examples/028-counter-improved-eventTest/tests/run.js +0 -20
  43. package/examples/030-todo-app-with-eventTest/LICENSE +0 -55
  44. package/examples/030-todo-app-with-eventTest/README.md +0 -121
  45. package/examples/030-todo-app-with-eventTest/app/router.js +0 -25
  46. package/examples/030-todo-app-with-eventTest/app/store.js +0 -16
  47. package/examples/030-todo-app-with-eventTest/app/views/home.js +0 -11
  48. package/examples/030-todo-app-with-eventTest/app/views/todoDemo.js +0 -88
  49. package/examples/030-todo-app-with-eventTest/index.html +0 -65
  50. package/examples/030-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  51. package/examples/030-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  52. package/examples/030-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  53. package/examples/030-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  54. package/examples/030-todo-app-with-eventTest/runtime/core/router.js +0 -271
  55. package/examples/030-todo-app-with-eventTest/store.d.ts +0 -18
  56. package/examples/030-todo-app-with-eventTest/style.css +0 -170
  57. package/examples/030-todo-app-with-eventTest/tests/README.md +0 -208
  58. package/examples/030-todo-app-with-eventTest/tests/eventTest.js +0 -176
  59. package/examples/030-todo-app-with-eventTest/tests/generateTypes.js +0 -189
  60. package/examples/030-todo-app-with-eventTest/tests/run.js +0 -20
  61. package/examples/030-todo-app-with-eventTest/tests/todos.test.js +0 -167
  62. package/examples/031-todo-app-with-eventTest/LICENSE +0 -55
  63. package/examples/031-todo-app-with-eventTest/README.md +0 -54
  64. package/examples/031-todo-app-with-eventTest/TUTORIAL.md +0 -390
  65. package/examples/031-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  66. package/examples/031-todo-app-with-eventTest/app/bridges.js +0 -113
  67. package/examples/031-todo-app-with-eventTest/app/router.js +0 -26
  68. package/examples/031-todo-app-with-eventTest/app/store.js +0 -15
  69. package/examples/031-todo-app-with-eventTest/app/views/home.js +0 -46
  70. package/examples/031-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  71. package/examples/031-todo-app-with-eventTest/devtools/dock.js +0 -41
  72. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  73. package/examples/031-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  74. package/examples/031-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  75. package/examples/031-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  76. package/examples/031-todo-app-with-eventTest/index.html +0 -103
  77. package/examples/031-todo-app-with-eventTest/package-lock.json +0 -2184
  78. package/examples/031-todo-app-with-eventTest/package.json +0 -24
  79. package/examples/031-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  80. package/examples/031-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  81. package/examples/031-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  82. package/examples/031-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  83. package/examples/031-todo-app-with-eventTest/runtime/core/router.js +0 -271
  84. package/examples/031-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  85. package/examples/031-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  86. package/examples/031-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  87. package/examples/031-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  88. package/examples/031-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  89. package/examples/031-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  90. package/examples/031-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  91. package/examples/031-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  92. package/examples/031-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  93. package/examples/031-todo-app-with-eventTest/store.d.ts +0 -23
  94. package/examples/031-todo-app-with-eventTest/style.css +0 -170
  95. package/examples/031-todo-app-with-eventTest/tests/README.md +0 -208
  96. package/examples/031-todo-app-with-eventTest/tests/eventTest.js +0 -176
  97. package/examples/031-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  98. package/examples/031-todo-app-with-eventTest/tests/run.js +0 -20
  99. package/examples/031-todo-app-with-eventTest/tests/todos.test.js +0 -192
  100. package/examples/032-todo-app-with-eventTest/LICENSE +0 -55
  101. package/examples/032-todo-app-with-eventTest/README.md +0 -54
  102. package/examples/032-todo-app-with-eventTest/TUTORIAL.md +0 -390
  103. package/examples/032-todo-app-with-eventTest/WHY_EVENTSTATE.md +0 -777
  104. package/examples/032-todo-app-with-eventTest/app/actions/index.js +0 -153
  105. package/examples/032-todo-app-with-eventTest/app/bridges.js +0 -113
  106. package/examples/032-todo-app-with-eventTest/app/router.js +0 -26
  107. package/examples/032-todo-app-with-eventTest/app/store.js +0 -15
  108. package/examples/032-todo-app-with-eventTest/app/views/home.js +0 -46
  109. package/examples/032-todo-app-with-eventTest/app/views/todoDemo.js +0 -69
  110. package/examples/032-todo-app-with-eventTest/devtools/dock.js +0 -41
  111. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.dock.js +0 -10
  112. package/examples/032-todo-app-with-eventTest/devtools/stateTracker.js +0 -246
  113. package/examples/032-todo-app-with-eventTest/devtools/telemetry.js +0 -104
  114. package/examples/032-todo-app-with-eventTest/devtools/typeGenerator.js +0 -339
  115. package/examples/032-todo-app-with-eventTest/index.html +0 -87
  116. package/examples/032-todo-app-with-eventTest/package-lock.json +0 -2184
  117. package/examples/032-todo-app-with-eventTest/package.json +0 -24
  118. package/examples/032-todo-app-with-eventTest/runtime/core/behaviors.runtime.js +0 -282
  119. package/examples/032-todo-app-with-eventTest/runtime/core/eventState.js +0 -100
  120. package/examples/032-todo-app-with-eventTest/runtime/core/eventStateNew.js +0 -149
  121. package/examples/032-todo-app-with-eventTest/runtime/core/helpers.js +0 -212
  122. package/examples/032-todo-app-with-eventTest/runtime/core/router.js +0 -271
  123. package/examples/032-todo-app-with-eventTest/runtime/extensions/boundary.js +0 -36
  124. package/examples/032-todo-app-with-eventTest/runtime/extensions/converge.js +0 -63
  125. package/examples/032-todo-app-with-eventTest/runtime/extensions/eventState.plus.js +0 -210
  126. package/examples/032-todo-app-with-eventTest/runtime/extensions/hydrate.js +0 -157
  127. package/examples/032-todo-app-with-eventTest/runtime/extensions/queryBinding.js +0 -69
  128. package/examples/032-todo-app-with-eventTest/runtime/forms/computed.js +0 -78
  129. package/examples/032-todo-app-with-eventTest/runtime/forms/meta.js +0 -51
  130. package/examples/032-todo-app-with-eventTest/runtime/forms/submitWithBoundary.js +0 -28
  131. package/examples/032-todo-app-with-eventTest/runtime/forms/validators.js +0 -55
  132. package/examples/032-todo-app-with-eventTest/store.d.ts +0 -23
  133. package/examples/032-todo-app-with-eventTest/style.css +0 -170
  134. package/examples/032-todo-app-with-eventTest/tests/README.md +0 -208
  135. package/examples/032-todo-app-with-eventTest/tests/eventTest.js +0 -176
  136. package/examples/032-todo-app-with-eventTest/tests/generateTypes.js +0 -191
  137. package/examples/032-todo-app-with-eventTest/tests/run.js +0 -20
  138. package/examples/032-todo-app-with-eventTest/tests/todos.test.js +0 -192
  139. package/playground/exercise001.html +0 -38
  140. package/playground/exercise002.html +0 -49
  141. package/stateSerializer.js +0 -267
  142. package/templateManager.js +0 -216
@@ -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>