sygnal 5.3.6 → 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 (226) hide show
  1. package/README.md +53 -38
  2. package/dist/astro/client.cjs.js +18 -8106
  3. package/dist/astro/client.cjs.js.map +1 -0
  4. package/dist/astro/client.mjs +17 -8105
  5. package/dist/astro/client.mjs.map +1 -0
  6. package/dist/astro/index.cjs.js +768 -9
  7. package/dist/astro/index.cjs.js.map +1 -0
  8. package/dist/astro/index.mjs +768 -9
  9. package/dist/astro/index.mjs.map +1 -0
  10. package/dist/astro/server.cjs.js +4 -1
  11. package/dist/astro/server.cjs.js.map +1 -0
  12. package/dist/astro/server.mjs +4 -1
  13. package/dist/astro/server.mjs.map +1 -0
  14. package/dist/diagnostics.cjs.js +1297 -0
  15. package/dist/diagnostics.cjs.js.map +1 -0
  16. package/dist/diagnostics.esm.js +1267 -0
  17. package/dist/diagnostics.esm.js.map +1 -0
  18. package/dist/index.cjs.js +2981 -1386
  19. package/dist/index.cjs.js.map +1 -0
  20. package/dist/index.d.ts +848 -111
  21. package/dist/index.esm.js +2997 -1411
  22. package/dist/index.esm.js.map +1 -0
  23. package/dist/jsx-dev-runtime.cjs.js +15 -9
  24. package/dist/jsx-dev-runtime.cjs.js.map +1 -0
  25. package/dist/jsx-dev-runtime.esm.js +15 -9
  26. package/dist/jsx-dev-runtime.esm.js.map +1 -0
  27. package/dist/jsx-runtime.cjs.js +15 -9
  28. package/dist/jsx-runtime.cjs.js.map +1 -0
  29. package/dist/jsx-runtime.esm.js +15 -9
  30. package/dist/jsx-runtime.esm.js.map +1 -0
  31. package/dist/jsx.cjs.js +15 -9
  32. package/dist/jsx.cjs.js.map +1 -0
  33. package/dist/jsx.esm.js +15 -9
  34. package/dist/jsx.esm.js.map +1 -0
  35. package/dist/sygnal.min.js +2 -1
  36. package/dist/sygnal.min.js.map +1 -0
  37. package/dist/vike/+config.cjs.js +1 -0
  38. package/dist/vike/+config.cjs.js.map +1 -0
  39. package/dist/vike/+config.js +1 -0
  40. package/dist/vike/+config.js.map +1 -0
  41. package/dist/vike/ClientOnly.cjs.js +1 -0
  42. package/dist/vike/ClientOnly.cjs.js.map +1 -0
  43. package/dist/vike/ClientOnly.mjs +1 -0
  44. package/dist/vike/ClientOnly.mjs.map +1 -0
  45. package/dist/vike/onRenderClient.cjs.js +1 -0
  46. package/dist/vike/onRenderClient.cjs.js.map +1 -0
  47. package/dist/vike/onRenderClient.mjs +1 -0
  48. package/dist/vike/onRenderClient.mjs.map +1 -0
  49. package/dist/vike/onRenderHtml.cjs.js +1 -0
  50. package/dist/vike/onRenderHtml.cjs.js.map +1 -0
  51. package/dist/vike/onRenderHtml.mjs +1 -0
  52. package/dist/vike/onRenderHtml.mjs.map +1 -0
  53. package/dist/vite/plugin.cjs.js +680 -47
  54. package/dist/vite/plugin.cjs.js.map +1 -0
  55. package/dist/vite/plugin.mjs +680 -47
  56. package/dist/vite/plugin.mjs.map +1 -0
  57. package/llms.txt +250 -0
  58. package/package.json +15 -6
  59. package/src/astro/client.ts +13 -2
  60. package/src/astro/index.d.ts +24 -1
  61. package/src/astro/index.ts +40 -9
  62. package/src/astro/server.ts +3 -1
  63. package/src/collection.ts +5 -2
  64. package/src/component.ts +375 -330
  65. package/src/cycle/dom/MainDOMSource.ts +4 -0
  66. package/src/cycle/dom/classNameModule.ts +74 -0
  67. package/src/cycle/dom/controlledInputModule.ts +33 -0
  68. package/src/cycle/dom/enrichEventStream.ts +9 -3
  69. package/src/cycle/dom/makeDOMDriver.ts +1 -2
  70. package/src/cycle/dom/mockDOMSource.ts +62 -8
  71. package/src/cycle/dom/modules.ts +5 -1
  72. package/src/cycle/state/Collection.ts +13 -3
  73. package/src/cycle/state/StateSource.ts +1 -1
  74. package/src/cycle/state/pickCombine.ts +35 -1
  75. package/src/cycle/state/withState.ts +1 -1
  76. package/src/extra/devtools.ts +8 -0
  77. package/src/extra/diagnostics/checks/collections.ts +67 -0
  78. package/src/extra/diagnostics/checks/dom.ts +241 -0
  79. package/src/extra/diagnostics/checks/events.ts +68 -0
  80. package/src/extra/diagnostics/checks/index.ts +109 -0
  81. package/src/extra/diagnostics/checks/inspect.ts +319 -0
  82. package/src/extra/diagnostics/checks/props.ts +51 -0
  83. package/src/extra/diagnostics/checks/public.d.ts +211 -0
  84. package/src/extra/diagnostics/checks/rxjsHints.ts +88 -0
  85. package/src/extra/diagnostics/checks/shared.ts +119 -0
  86. package/src/extra/diagnostics/checks/state.ts +55 -0
  87. package/src/extra/diagnostics/checks/strict.ts +112 -0
  88. package/src/extra/diagnostics/checks/wiring.ts +65 -0
  89. package/src/extra/diagnostics/codes.ts +232 -0
  90. package/src/extra/diagnostics/index.ts +328 -0
  91. package/src/extra/diagnostics/legacy.ts +59 -0
  92. package/src/extra/driverFactories.ts +106 -58
  93. package/src/extra/eventDriver.ts +4 -0
  94. package/src/extra/flatten.ts +75 -0
  95. package/src/extra/reducers.ts +12 -5
  96. package/src/extra/run.ts +11 -0
  97. package/src/extra/testing.ts +890 -180
  98. package/src/extra/xstreamExtras.ts +269 -0
  99. package/src/index.d.ts +428 -17
  100. package/src/index.ts +7 -6
  101. package/src/pragma/index.ts +14 -9
  102. package/src/switchable.ts +10 -8
  103. package/src/vike/types.ts +21 -4
  104. package/src/vite/plugin.d.ts +95 -2
  105. package/src/vite/plugin.ts +730 -55
  106. package/dist/astro/astro/client.d.ts +0 -5
  107. package/dist/astro/astro/index.d.ts +0 -16
  108. package/dist/astro/astro/server.d.ts +0 -12
  109. package/dist/astro/client.d.ts +0 -5
  110. package/dist/astro/client.esm.js +0 -4665
  111. package/dist/astro/collection.d.ts +0 -12
  112. package/dist/astro/component.d.ts +0 -22
  113. package/dist/astro/cycle/dom/BodyDOMSource.d.ts +0 -10
  114. package/dist/astro/cycle/dom/DOMSource.d.ts +0 -11
  115. package/dist/astro/cycle/dom/DocumentDOMSource.d.ts +0 -12
  116. package/dist/astro/cycle/dom/ElementFinder.d.ts +0 -8
  117. package/dist/astro/cycle/dom/EventDelegator.d.ts +0 -34
  118. package/dist/astro/cycle/dom/IsolateModule.d.ts +0 -23
  119. package/dist/astro/cycle/dom/MainDOMSource.d.ts +0 -32
  120. package/dist/astro/cycle/dom/PriorityQueue.d.ts +0 -7
  121. package/dist/astro/cycle/dom/ScopeChecker.d.ts +0 -9
  122. package/dist/astro/cycle/dom/SymbolTree.d.ts +0 -9
  123. package/dist/astro/cycle/dom/VNodeWrapper.d.ts +0 -8
  124. package/dist/astro/cycle/dom/enrichEventStream.d.ts +0 -24
  125. package/dist/astro/cycle/dom/fromEvent.d.ts +0 -6
  126. package/dist/astro/cycle/dom/index.d.ts +0 -8
  127. package/dist/astro/cycle/dom/isolate.d.ts +0 -9
  128. package/dist/astro/cycle/dom/makeDOMDriver.d.ts +0 -11
  129. package/dist/astro/cycle/dom/mockDOMSource.d.ts +0 -17
  130. package/dist/astro/cycle/dom/modules.d.ts +0 -5
  131. package/dist/astro/cycle/dom/snabbdom.d.ts +0 -22
  132. package/dist/astro/cycle/dom/styleModule.d.ts +0 -13
  133. package/dist/astro/cycle/dom/thunk.d.ts +0 -11
  134. package/dist/astro/cycle/dom/utils.d.ts +0 -8
  135. package/dist/astro/cycle/isolate/index.d.ts +0 -42
  136. package/dist/astro/cycle/run/adapt.d.ts +0 -6
  137. package/dist/astro/cycle/run/index.d.ts +0 -36
  138. package/dist/astro/cycle/run/internals.d.ts +0 -8
  139. package/dist/astro/cycle/run/types.d.ts +0 -49
  140. package/dist/astro/cycle/state/Collection.d.ts +0 -29
  141. package/dist/astro/cycle/state/StateSource.d.ts +0 -20
  142. package/dist/astro/cycle/state/index.d.ts +0 -5
  143. package/dist/astro/cycle/state/pickCombine.d.ts +0 -3
  144. package/dist/astro/cycle/state/pickMerge.d.ts +0 -3
  145. package/dist/astro/cycle/state/types.d.ts +0 -18
  146. package/dist/astro/cycle/state/withState.d.ts +0 -17
  147. package/dist/astro/extra/classes.d.ts +0 -7
  148. package/dist/astro/extra/devtools.d.ts +0 -78
  149. package/dist/astro/extra/dragDriver.d.ts +0 -20
  150. package/dist/astro/extra/driverFactories.d.ts +0 -12
  151. package/dist/astro/extra/eventDriver.d.ts +0 -9
  152. package/dist/astro/extra/exactState.d.ts +0 -1
  153. package/dist/astro/extra/hmr.d.ts +0 -17
  154. package/dist/astro/extra/logDriver.d.ts +0 -2
  155. package/dist/astro/extra/processDrag.d.ts +0 -19
  156. package/dist/astro/extra/processForm.d.ts +0 -15
  157. package/dist/astro/extra/run.d.ts +0 -13
  158. package/dist/astro/extra/xstreamCompat.d.ts +0 -5
  159. package/dist/astro/index.d.ts +0 -19
  160. package/dist/astro/index.esm.js +0 -27
  161. package/dist/astro/jsx-dev-runtime.d.ts +0 -1
  162. package/dist/astro/jsx-runtime.d.ts +0 -4
  163. package/dist/astro/jsx.d.ts +0 -2
  164. package/dist/astro/pragma/fn.d.ts +0 -7
  165. package/dist/astro/pragma/index.d.ts +0 -7
  166. package/dist/astro/pragma/is.d.ts +0 -10
  167. package/dist/astro/server.d.ts +0 -12
  168. package/dist/astro/server.esm.js +0 -25
  169. package/dist/astro/switchable.d.ts +0 -7
  170. package/dist/collection.d.ts +0 -12
  171. package/dist/component.d.ts +0 -22
  172. package/dist/cycle/dom/BodyDOMSource.d.ts +0 -10
  173. package/dist/cycle/dom/DOMSource.d.ts +0 -11
  174. package/dist/cycle/dom/DocumentDOMSource.d.ts +0 -12
  175. package/dist/cycle/dom/ElementFinder.d.ts +0 -8
  176. package/dist/cycle/dom/EventDelegator.d.ts +0 -34
  177. package/dist/cycle/dom/IsolateModule.d.ts +0 -23
  178. package/dist/cycle/dom/MainDOMSource.d.ts +0 -32
  179. package/dist/cycle/dom/PriorityQueue.d.ts +0 -7
  180. package/dist/cycle/dom/ScopeChecker.d.ts +0 -9
  181. package/dist/cycle/dom/SymbolTree.d.ts +0 -9
  182. package/dist/cycle/dom/VNodeWrapper.d.ts +0 -8
  183. package/dist/cycle/dom/enrichEventStream.d.ts +0 -24
  184. package/dist/cycle/dom/fromEvent.d.ts +0 -6
  185. package/dist/cycle/dom/index.d.ts +0 -8
  186. package/dist/cycle/dom/isolate.d.ts +0 -9
  187. package/dist/cycle/dom/makeDOMDriver.d.ts +0 -11
  188. package/dist/cycle/dom/mockDOMSource.d.ts +0 -17
  189. package/dist/cycle/dom/modules.d.ts +0 -5
  190. package/dist/cycle/dom/snabbdom.d.ts +0 -22
  191. package/dist/cycle/dom/styleModule.d.ts +0 -13
  192. package/dist/cycle/dom/thunk.d.ts +0 -11
  193. package/dist/cycle/dom/utils.d.ts +0 -8
  194. package/dist/cycle/isolate/index.d.ts +0 -42
  195. package/dist/cycle/run/adapt.d.ts +0 -6
  196. package/dist/cycle/run/index.d.ts +0 -36
  197. package/dist/cycle/run/internals.d.ts +0 -8
  198. package/dist/cycle/run/types.d.ts +0 -49
  199. package/dist/cycle/state/Collection.d.ts +0 -29
  200. package/dist/cycle/state/StateSource.d.ts +0 -20
  201. package/dist/cycle/state/index.d.ts +0 -5
  202. package/dist/cycle/state/pickCombine.d.ts +0 -3
  203. package/dist/cycle/state/pickMerge.d.ts +0 -3
  204. package/dist/cycle/state/types.d.ts +0 -18
  205. package/dist/cycle/state/withState.d.ts +0 -17
  206. package/dist/extra/classes.d.ts +0 -7
  207. package/dist/extra/devtools.d.ts +0 -78
  208. package/dist/extra/dragDriver.d.ts +0 -20
  209. package/dist/extra/driverFactories.d.ts +0 -12
  210. package/dist/extra/eventDriver.d.ts +0 -9
  211. package/dist/extra/exactState.d.ts +0 -1
  212. package/dist/extra/hmr.d.ts +0 -17
  213. package/dist/extra/logDriver.d.ts +0 -2
  214. package/dist/extra/processDrag.d.ts +0 -19
  215. package/dist/extra/processForm.d.ts +0 -15
  216. package/dist/extra/run.d.ts +0 -13
  217. package/dist/extra/xstreamCompat.d.ts +0 -5
  218. package/dist/jsx-dev-runtime.d.ts +0 -1
  219. package/dist/jsx-dev-runtime.js +0 -224
  220. package/dist/jsx-runtime.d.ts +0 -4
  221. package/dist/jsx-runtime.js +0 -224
  222. package/dist/jsx.d.ts +0 -2
  223. package/dist/pragma/fn.d.ts +0 -7
  224. package/dist/pragma/index.d.ts +0 -7
  225. package/dist/pragma/is.d.ts +0 -10
  226. package/dist/switchable.d.ts +0 -7
package/dist/index.d.ts CHANGED
@@ -1,25 +1,370 @@
1
- import type { MainDOMSource } from './cycle/dom/MainDOMSource'
2
- import type { EnrichedEventStream } from './cycle/dom/enrichEventStream'
3
- import type { StateSource } from './cycle/state/index'
4
- import xsDefault from 'xstream'
5
- import type { MemoryStream, Stream } from 'xstream'
1
+ import xsDefault, { Stream, MemoryStream } from 'xstream';
2
+ export { MemoryStream, Stream } from 'xstream';
3
+ import { VNode, VNodeData } from 'snabbdom/build/vnode.js';
4
+ export { VNode, VNodeData } from 'snabbdom/build/vnode.js';
5
+ export { default as debounce } from 'xstream/extra/debounce.js';
6
+ export { default as throttle } from 'xstream/extra/throttle.js';
7
+ export { default as delay } from 'xstream/extra/delay.js';
8
+ export { default as dropRepeats } from 'xstream/extra/dropRepeats.js';
9
+ export { default as sampleCombine } from 'xstream/extra/sampleCombine.js';
10
+ export { default as flattenConcurrently } from 'xstream/extra/flattenConcurrently.js';
11
+ export { default as flattenSequentially } from 'xstream/extra/flattenSequentially.js';
12
+ export { default as concat } from 'xstream/extra/concat.js';
13
+ export { h } from 'snabbdom/build/h.js';
14
+ import { Options } from 'snabbdom/build/init.js';
15
+ import { Module } from 'snabbdom/build/modules/module.js';
16
+
17
+ type Predicate = (ev: Event) => boolean;
18
+ type Comparator = Record<string, unknown>;
19
+ type PreventDefaultOpt = boolean | Predicate | Comparator;
20
+
21
+ interface EnrichedEventStream<T = Event> extends Stream<T> {
22
+ value(): EnrichedEventStream<string>;
23
+ value<R>(fn: (val: string) => R): EnrichedEventStream<R>;
24
+ checked(): EnrichedEventStream<boolean>;
25
+ checked<R>(fn: (val: boolean) => R): EnrichedEventStream<R>;
26
+ data(name: string): EnrichedEventStream<string | undefined>;
27
+ data<R>(name: string, fn: (val: string | undefined) => R): EnrichedEventStream<R>;
28
+ target(): EnrichedEventStream<EventTarget | null>;
29
+ target<R>(fn: (el: EventTarget | null) => R): EnrichedEventStream<R>;
30
+ key(): EnrichedEventStream<string>;
31
+ key<R>(fn: (key: string) => R): EnrichedEventStream<R>;
32
+ }
33
+
34
+ declare class DocumentDOMSource {
35
+ private _name;
36
+ private _selector;
37
+ constructor(_name: string, selector?: string);
38
+ select(selector: string): DocumentDOMSource;
39
+ elements(): MemoryStream<Array<Document | Element>>;
40
+ element(): MemoryStream<Document | Element | null>;
41
+ events<K extends keyof DocumentEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): EnrichedEventStream<DocumentEventMap[K]>;
42
+ }
43
+
44
+ declare class BodyDOMSource {
45
+ private _name;
46
+ constructor(_name: string);
47
+ select(selector: string): BodyDOMSource;
48
+ elements(): MemoryStream<Array<HTMLBodyElement>>;
49
+ element(): MemoryStream<HTMLBodyElement>;
50
+ events<K extends keyof HTMLBodyElementEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): Stream<HTMLBodyElementEventMap[K]>;
51
+ }
52
+
53
+ interface EventsFnOptions {
54
+ useCapture?: boolean;
55
+ passive?: boolean;
56
+ bubbles?: boolean;
57
+ preventDefault?: PreventDefaultOpt;
58
+ }
59
+ type DOMSource = MainDOMSource | DocumentDOMSource | BodyDOMSource;
60
+
61
+ interface Scope$1 {
62
+ type: 'sibling' | 'total' | 'selector';
63
+ scope: string;
64
+ }
65
+ type IsolateSink<T extends VNode> = (s: Stream<T>, scope: string) => Stream<T>;
66
+
67
+ interface CycleDOMEvent extends Event {
68
+ propagationHasBeenStopped: boolean;
69
+ ownerTarget: Element;
70
+ }
71
+ declare class EventDelegator {
72
+ private rootElement$;
73
+ isolateModule: IsolateModule;
74
+ private virtualListeners;
75
+ private origin;
76
+ private domListeners;
77
+ private nonBubblingListeners;
78
+ private domListenersToAdd;
79
+ private nonBubblingListenersToAdd;
80
+ private virtualNonBubblingListener;
81
+ constructor(rootElement$: Stream<Element>, isolateModule: IsolateModule);
82
+ addEventListener(eventType: string, namespace: Array<Scope$1>, options: EventsFnOptions, bubbles?: boolean): Stream<Event>;
83
+ removeElement(element: Element, namespace?: Array<Scope$1>): void;
84
+ private insertListener;
85
+ private getVirtualListeners;
86
+ private setupDOMListener;
87
+ private setupNonBubblingListener;
88
+ private resetEventListeners;
89
+ private putNonBubblingListener;
90
+ private onEvent;
91
+ private bubble;
92
+ private doBubbleStep;
93
+ private patchEvent;
94
+ private mutateEventCurrentTarget;
95
+ }
96
+
97
+ declare class IsolateModule {
98
+ private namespaceTree;
99
+ private namespaceByElement;
100
+ private eventDelegator;
101
+ private vnodesBeingRemoved;
102
+ constructor();
103
+ setEventDelegator(del: EventDelegator): void;
104
+ private insertElement;
105
+ private removeElement;
106
+ getElement(namespace: Array<Scope$1>, max?: number): Element | undefined;
107
+ getRootElement(elm: Element): Element | undefined;
108
+ getNamespace(elm: Element): Array<Scope$1> | undefined;
109
+ createModule(): {
110
+ create(emptyVNode: VNode, vNode: VNode): void;
111
+ update(oldVNode: VNode, vNode: VNode): void;
112
+ destroy(vNode: VNode): void;
113
+ remove(vNode: VNode, cb: Function): void;
114
+ post(): void;
115
+ };
116
+ }
117
+
118
+ interface SpecialSelector {
119
+ body: BodyDOMSource;
120
+ document: DocumentDOMSource;
121
+ }
122
+ declare class MainDOMSource {
123
+ private _rootElement$;
124
+ private _sanitation$;
125
+ private _namespace;
126
+ _isolateModule: IsolateModule;
127
+ private _eventDelegator;
128
+ private _name;
129
+ constructor(_rootElement$: Stream<Element>, _sanitation$: Stream<null>, _namespace: Array<Scope$1>, _isolateModule: IsolateModule, _eventDelegator: EventDelegator, _name: string);
130
+ private _elements;
131
+ elements(): MemoryStream<Array<Element>>;
132
+ element(): MemoryStream<Element>;
133
+ get namespace(): Array<Scope$1>;
134
+ select<T extends keyof SpecialSelector>(selector: T): SpecialSelector[T];
135
+ select(selector: string): MainDOMSource;
136
+ events<K extends keyof HTMLElementEventMap>(eventType: K, options?: EventsFnOptions, bubbles?: boolean): EnrichedEventStream<HTMLElementEventMap[K]>;
137
+ dispose(): void;
138
+ isolateSource: (source: MainDOMSource, scope: string) => MainDOMSource;
139
+ isolateSink: IsolateSink<VNode>;
140
+ }
141
+
142
+ type Reducer$1<T> = (state: T | undefined) => T | undefined;
143
+ type Getter<T, R> = (state: T | undefined) => R | undefined;
144
+ type Setter<T, R> = (state: T | undefined, childState: R | undefined) => T | undefined;
145
+ type Lens$1<T, R> = {
146
+ get: Getter<T, R>;
147
+ set: Setter<T, R>;
148
+ };
149
+ type Scope<T, R> = string | number | Lens$1<T, R>;
150
+
151
+ declare function isolateSource<T, R>(source: StateSource<T>, scope: Scope<T, R>): StateSource<R>;
152
+ declare function isolateSink<T, R>(innerReducer$: Stream<Reducer$1<R>>, scope: Scope<T, R>): Stream<Reducer$1<T>>;
153
+ /**
154
+ * Represents a piece of application state dynamically changing over time.
155
+ */
156
+ declare class StateSource<S> {
157
+ stream: MemoryStream<S>;
158
+ private _stream;
159
+ private _name;
160
+ constructor(stream: Stream<S>, name: string);
161
+ /**
162
+ * Selects a part (or scope) of the state object and returns a new StateSource
163
+ * dynamically representing that selected part of the state.
164
+ */
165
+ select<R>(scope: Scope<S, R>): StateSource<R>;
166
+ isolateSource: typeof isolateSource;
167
+ isolateSink: typeof isolateSink;
168
+ }
169
+
170
+ /**
171
+ * Types for the 'sygnal/diagnostics' entry (runtime consistency checks).
172
+ *
173
+ * import 'sygnal/diagnostics' // registers all checks (side effect)
174
+ *
175
+ * Checks only run while diagnostics are on: run(App, drivers, { diagnostics: 'warn' }),
176
+ * or globalThis.__SYGNAL_DEV__ (set by the Vite plugin in dev).
177
+ */
178
+
179
+ type DiagnosticSeverity$1 = 'error' | 'warn' | 'info'
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // inspect (PLAN-1 workstream 2B): a machine-readable app graph. The same shape
183
+ // is produced at runtime (inspect(), getDevTools().inspect(), renderComponent's
184
+ // t.inspect()) and statically (`sygnal-check --graph --json`); JSON Schema:
185
+ // sygnal-check/schema/inspect.schema.json. Fields one side cannot know are
186
+ // null (or omitted).
187
+ // ---------------------------------------------------------------------------
188
+
189
+ /** How an action is dispatched. */
190
+ type InspectActionTrigger = 'intent' | 'next' | 'builtin' | 'unknown'
191
+
192
+ interface InspectAction {
193
+ name: string
194
+ /**
195
+ * 'intent': returned by the component's intent. 'builtin': BOOTSTRAP,
196
+ * INITIALIZE, HYDRATE, DISPOSE or READY. 'next': dispatched with next()
197
+ * (statically: a next('NAME') literal; at runtime: a model-only action whose
198
+ * STATE reducer was seen running). 'unknown': none of these is known.
199
+ */
200
+ trigger: InspectActionTrigger
201
+ /** sinks of the model entry (STATE, EVENTS, EFFECT, PARENT, custom drivers); [] without a model entry */
202
+ sinks: string[]
203
+ }
204
+
205
+ interface InspectChild {
206
+ name: string
207
+ via: 'tag' | 'collection' | 'switchable' | 'slot'
208
+ /** Collection: the `from` state field, when known */
209
+ from?: string | null
210
+ /** runtime: number of live instances behind this entry (e.g. Collection items) */
211
+ count?: number
212
+ }
213
+
214
+ interface InspectSelector {
215
+ /** CSS selector passed to DOM.select() (chained selects joined with a space) */
216
+ selector: string
217
+ /** event types listened to; null when unknown (runtime, real DOM) */
218
+ events: string[] | null
219
+ /**
220
+ * whether it matches an element the component itself renders; null when unknown.
221
+ * static: the class/id is in the view source. renderComponent: an element of the latest
222
+ * render matches (a conditionally rendered element that is hidden right now gives false).
223
+ * real DOM: true once a DOM check saw it match, false after SYG103/SYG104, else null.
224
+ */
225
+ matched: boolean | null
226
+ /** the child component whose (isolated) elements it matches instead, if any */
227
+ isolationHit: string | null
228
+ }
229
+
230
+ interface InspectDiagnostic {
231
+ code: string
232
+ severity: DiagnosticSeverity$1
233
+ component?: string
234
+ message: string
235
+ fix?: string
236
+ docsUrl?: string
237
+ data?: any
238
+ /** static only */
239
+ file?: string
240
+ line?: number
241
+ column?: number
242
+ }
243
+
244
+ interface InspectComponent {
245
+ name: string
246
+ /** runtime: instance number (as a string); static: 'file:line' of the definition */
247
+ id: string
248
+ /** runtime: the parent instance's id; static: null (see the parents' `children`) */
249
+ parentId: string | null
250
+ /** static only: source file, relative to the working directory */
251
+ file?: string
252
+ /**
253
+ * runtime: how the instance was created; static: 'root' when no scanned
254
+ * component renders it, else how it is first rendered
255
+ */
256
+ kind: 'root' | 'child' | 'collection-item' | 'switchable'
257
+ actions: InspectAction[]
258
+ /** state keys (runtime: current state; static: initialState) */
259
+ stateKeys: string[]
260
+ /** calculated field names */
261
+ calculated: string[]
262
+ /** context fields this component provides (Component.context) */
263
+ contextProvides: string[]
264
+ /** context fields its view reads (static only; null at runtime) */
265
+ contextConsumes?: string[] | null
266
+ /** EVENTS types this component emits */
267
+ eventsEmitted: string[]
268
+ /** EVENTS types this component selects ('*' = EVENTS.select() without a type) */
269
+ eventsSelected: string[]
270
+ children: InspectChild[]
271
+ selectors: InspectSelector[]
272
+ diagnostics: InspectDiagnostic[]
273
+ }
6
274
 
7
- export declare const ABORT: unique symbol
8
- export type ABORT = typeof ABORT
275
+ interface InspectGraph {
276
+ version: 1
277
+ /** which implementation produced the graph */
278
+ source?: 'runtime' | 'static'
279
+ components: InspectComponent[]
280
+ /** EVENTS bus: type -> names of the components that emit / select it */
281
+ events: Record<string, { emitters: string[]; selectors: string[] }>
282
+ /** diagnostics not tied to a listed component */
283
+ diagnostics: InspectDiagnostic[]
284
+ }
9
285
 
10
- export type DriverSpec<SOURCE = any, SINK = any> = {
286
+ interface ThunkData extends VNodeData {
287
+ fn(): VNode;
288
+ args: Array<any>;
289
+ }
290
+ interface Thunk extends VNode {
291
+ data: ThunkData;
292
+ }
293
+ declare function thunk(sel: string, fn: Function, args: Array<any>): Thunk;
294
+ declare function thunk(sel: string, key: any, fn: Function, args: Array<any>): Thunk;
295
+
296
+ type FantasyObserver<T> = {
297
+ next(x: T): void;
298
+ error(err: any): void;
299
+ complete(c?: any): void;
300
+ };
301
+ type FantasySubscription = {
302
+ unsubscribe(): void;
303
+ };
304
+ type FantasyObservable<T> = {
305
+ subscribe(observer: FantasyObserver<T>): FantasySubscription;
306
+ };
307
+ type Driver<Si, So> = Si extends void ? (() => So) : ((stream: Si) => So);
308
+
309
+ interface DOMDriverOptions {
310
+ modules?: Array<Partial<Module>>;
311
+ reportSnabbdomError?(err: unknown): void;
312
+ snabbdomOptions?: Options;
313
+ }
314
+ declare function makeDOMDriver(container: string | Element | DocumentFragment, options?: DOMDriverOptions): Driver<Stream<VNode>, MainDOMSource>;
315
+
316
+ /**
317
+ * Optional simulated-event hub (used by renderComponent's simulateEvent): a
318
+ * stream of `{type, event, match(path)}`; each source's events(type) also emits
319
+ * the hub events whose `match` accepts its selector path (isolation scopes
320
+ * included as '.___scope' segments).
321
+ */
322
+ type MockEventHub = Stream<{
323
+ type: string;
324
+ event: any;
325
+ match: (path: string[]) => boolean;
326
+ }>;
327
+ /**
328
+ * Optional listener callback (renderComponent): called with `live` undefined when events() is
329
+ * called (SYG103/104 checks), then with true / false when that hub listener is subscribed /
330
+ * unsubscribed (simulateEvent waits for a just-mounted child's listeners, G-039).
331
+ */
332
+ type MockOnEvents = (path: string[], eventType: string, live?: boolean) => void;
333
+ type MockConfig = {
334
+ [name: string]: FantasyObservable<any> | MockConfig;
335
+ };
336
+ declare class MockedDOMSource {
337
+ private _mockConfig;
338
+ private _hub?;
339
+ _path: string[];
340
+ private _onEvents?;
341
+ private _elements;
342
+ constructor(_mockConfig: MockConfig, _hub?: MockEventHub | undefined, _path?: string[], _onEvents?: MockOnEvents | undefined);
343
+ elements(): any;
344
+ element(): any;
345
+ events(eventType: string, options?: EventsFnOptions, bubbles?: boolean): any;
346
+ select(selector: string): MockedDOMSource;
347
+ isolateSource(source: MockedDOMSource, scope: string): MockedDOMSource;
348
+ isolateSink(sink: any, scope: string): any;
349
+ }
350
+ declare function mockDOMSource(mockConfig: MockConfig, hub?: MockEventHub, onEvents?: MockOnEvents): MockedDOMSource;
351
+
352
+ declare const ABORT: unique symbol
353
+ type ABORT = typeof ABORT
354
+
355
+ type DriverSpec<SOURCE = any, SINK = any> = {
11
356
  source: SOURCE;
12
357
  sink: SINK;
13
358
  }
14
359
 
15
- export type DriverSpecs = Record<string, DriverSpec<any, any>>
360
+ type DriverSpecs = Record<string, DriverSpec<any, any>>
16
361
 
17
- export type CycleDriver<SINK = any, SOURCE = any> =
362
+ type CycleDriver<SINK = any, SOURCE = any> =
18
363
  SINK extends void
19
364
  ? (() => SOURCE)
20
365
  : ((sink$: Stream<SINK>) => SOURCE)
21
366
 
22
- export type DriverFactories<DRIVERS extends DriverSpecs = DriverSpecs> = {
367
+ type DriverFactories<DRIVERS extends DriverSpecs = DriverSpecs> = {
23
368
  [DRIVER_KEY in keyof DRIVERS]: CycleDriver<DRIVERS[DRIVER_KEY]['sink'], DRIVERS[DRIVER_KEY]['source']>
24
369
  }
25
370
 
@@ -51,23 +396,89 @@ type Reducer<STATE, PROPS, ACTIONS = any, DATA = any, RETURN = any, CONTEXT = {}
51
396
  props: ReducerExtras<PROPS, CONTEXT>
52
397
  ) => RETURN | ABORT | undefined
53
398
 
54
- export type ExactShape<EXPECTED, ACTUAL extends EXPECTED> = ACTUAL &
399
+ type ExactShape<EXPECTED, ACTUAL extends EXPECTED> = ACTUAL &
55
400
  Record<Exclude<keyof ACTUAL, keyof EXPECTED>, never>
56
401
 
57
402
  type StateOnlyReducer<STATE, RETURN = any> = (
58
403
  state: STATE
59
404
  ) => RETURN | ABORT
60
405
 
61
- export type Event<DATA = any> = { type: string; data: DATA }
406
+ type Event$1<DATA = any> = { type: string; data: DATA }
407
+
408
+ // ── EVENTS registry ────────────────────────────────────────────────
409
+
410
+ /**
411
+ * Registry of global EVENTS bus event names and their payload types.
412
+ *
413
+ * Empty by default, which keeps the EVENTS bus untyped (`any`). Augment it to
414
+ * type-check `EVENTS.select()`, `event()`, `emit()` and raw EVENTS sink returns:
415
+ *
416
+ * declare module 'sygnal' {
417
+ * interface SygnalEvents {
418
+ * DELETE_LANE: { laneId: string }
419
+ * RESET: void // no payload: event('RESET')
420
+ * }
421
+ * }
422
+ *
423
+ * Once the registry has at least one entry, unregistered event names are type errors.
424
+ * The augmenting file must be a module (have at least one import or export).
425
+ */
426
+ interface SygnalEvents {}
427
+
428
+ /** Valid event names: `string` while the registry is empty, otherwise the registered names. */
429
+ type EventName = keyof SygnalEvents extends never ? string : keyof SygnalEvents & string
430
+
431
+ /** Payload type of a registered event (`any` while the registry is empty). */
432
+ type EventPayload<TYPE extends string = string> = keyof SygnalEvents extends never
433
+ ? any
434
+ : TYPE extends keyof SygnalEvents ? SygnalEvents[TYPE] : never
435
+
436
+ /**
437
+ * An event object as put on the EVENTS bus. While the registry is empty this is `Event<any>`;
438
+ * otherwise it is the union of `{ type, data }` for every registered event.
439
+ */
440
+ type RegisteredEvent = keyof SygnalEvents extends never
441
+ ? Event$1<any>
442
+ : { [TYPE in keyof SygnalEvents & string]: { type: TYPE; data: SygnalEvents[TYPE] } }[keyof SygnalEvents & string]
62
443
 
63
- export type NonStateSinkReturns = {
444
+ /** The `{ type, data }` object produced by `event(type, ...)` / `emit(type, ...)`. */
445
+ type EmittedEvent<TYPE extends string = string> = keyof SygnalEvents extends never
446
+ ? { type: TYPE; data: any }
447
+ : { type: TYPE; data: EventPayload<TYPE> }
448
+
449
+ /** The `next()` function as seen by an event payload function. */
450
+ type EventNextFunction = (action: string, data?: any, delay?: number) => void
451
+
452
+ /** Payload function for `event()` / `emit()`: receives the reducer arguments, returns the event data. */
453
+ type EventPayloadFunction<TYPE extends string = string, STATE = any, DATA = any> =
454
+ (state: STATE, data: DATA, next: EventNextFunction, props: any) => EventPayload<TYPE>
455
+
456
+ /**
457
+ * Remaining arguments of `event()` / `emit()` when the payload is a static value.
458
+ * The payload may be omitted when the registry is empty or the event's payload
459
+ * type accepts `undefined` (e.g. `void`).
460
+ */
461
+ type StaticEventArgs<TYPE extends string> = keyof SygnalEvents extends never
462
+ ? [payload?: any]
463
+ : undefined extends EventPayload<TYPE>
464
+ ? [payload?: EventPayload<TYPE>]
465
+ : [payload: EventPayload<TYPE>]
466
+
467
+ /**
468
+ * The sink function returned by `event()`. Use it as the value of an `EVENTS` key in a
469
+ * model entry: `ACTION: { STATE: ..., EVENTS: event('TYPE', fn) }`.
470
+ */
471
+ type EventSink<TYPE extends string = string, STATE = any, DATA = any> =
472
+ (state: STATE, data: DATA, next: any, props: any) => EmittedEvent<TYPE>
473
+
474
+ type NonStateSinkReturns = {
64
475
  EVENTS?: unknown;
65
476
  LOG?: unknown;
66
477
  PARENT?: unknown;
67
478
  }
68
479
 
69
480
  type ResolvedNonStateSinkReturns<SINK_RETURNS extends NonStateSinkReturns = {}> = {
70
- EVENTS: SINK_RETURNS extends { EVENTS: infer EVENTS_RETURN } ? EVENTS_RETURN : Event<any>;
481
+ EVENTS: SINK_RETURNS extends { EVENTS: infer EVENTS_RETURN } ? EVENTS_RETURN : RegisteredEvent;
71
482
  LOG: SINK_RETURNS extends { LOG: infer LOG_RETURN } ? LOG_RETURN : any;
72
483
  PARENT: SINK_RETURNS extends { PARENT: infer PARENT_RETURN } ? PARENT_RETURN : any;
73
484
  }
@@ -149,20 +560,58 @@ type ComponentModel<STATE, PROPS, DRIVERS, ACTIONS, CALCULATED, SINK_RETURNS ext
149
560
  >
150
561
  }
151
562
 
563
+ type TrimSpaces<S extends string> =
564
+ S extends ` ${infer REST}` ? TrimSpaces<REST>
565
+ : S extends `${infer REST} ` ? TrimSpaces<REST>
566
+ : S
567
+
568
+ /** Value type produced by a PARENT sink value (a reducer's return, minus ABORT/undefined). */
569
+ type ParentSinkValueReturn<VALUE> =
570
+ VALUE extends (...args: any[]) => infer RETURN ? Exclude<RETURN, ABORT | undefined | void> : never
571
+
572
+ type ParentPayloadFromEntry<ENTRY> =
573
+ ENTRY extends (...args: any[]) => any ? never
574
+ : ENTRY extends object
575
+ ? 'PARENT' extends keyof ENTRY ? ParentSinkValueReturn<NonNullable<ENTRY['PARENT']>> : never
576
+ : never
577
+
578
+ type ParentPayloadsOfModel<MODEL> = {
579
+ [ACTION_KEY in keyof MODEL]-?: ACTION_KEY extends `${string}|${infer SINK}`
580
+ ? TrimSpaces<SINK> extends 'PARENT' ? ParentSinkValueReturn<NonNullable<MODEL[ACTION_KEY]>> : never
581
+ : ParentPayloadFromEntry<NonNullable<MODEL[ACTION_KEY]>>
582
+ }[keyof MODEL]
583
+
584
+ type AnyIfNever<T> = [T] extends [never] ? any : T
585
+
586
+ /**
587
+ * The value type a component sends to its parent through the `PARENT` sink, inferred from the
588
+ * component's `model` (object-form `{ PARENT: fn }` entries and `'ACTION | PARENT'` shorthand).
589
+ * Falls back to `any` when it can't be inferred (no model, a `Component<...>` annotation without
590
+ * a `PARENT` entry in its `SINK_RETURNS`, or `PARENT: true` pass-through entries only).
591
+ */
592
+ type ParentPayloadOf<COMPONENT> =
593
+ COMPONENT extends { model?: infer MODEL }
594
+ ? 0 extends (1 & MODEL) ? any : AnyIfNever<ParentPayloadsOfModel<NonNullable<MODEL>>>
595
+ : any
596
+
152
597
  type ChildSource = {
598
+ /** Typed: the stream type is inferred from the child's PARENT sink (falls back to `any`). */
599
+ select<COMPONENT extends (...args: any[]) => any>(component: COMPONENT): Stream<ParentPayloadOf<COMPONENT>>;
153
600
  select<T = any>(component: (...args: any[]) => any): Stream<T>;
154
601
  select<T = any>(name: string): Stream<T>;
155
602
  }
156
603
 
157
- export type SygnalDOMSource = MainDOMSource & {
604
+ type SygnalDOMSource = MainDOMSource & {
158
605
  [eventName: string]: (selector: string) => EnrichedEventStream<globalThis.Event>
159
606
  }
160
607
 
161
- export type EventsSource<EVENTS = any> = Stream<Event<EVENTS>> & {
162
- select<T = any>(type: string): Stream<T>;
163
- }
608
+ type EventsSelect = keyof SygnalEvents extends never
609
+ ? { select<T = any>(type: string): Stream<T>; }
610
+ : { select<TYPE extends keyof SygnalEvents & string>(type: TYPE): Stream<SygnalEvents[TYPE]>; }
164
611
 
165
- export type DefaultDrivers<STATE, EVENTS = any> = {
612
+ type EventsSource<EVENTS = any> = Stream<Event$1<EVENTS>> & EventsSelect
613
+
614
+ type DefaultDrivers<STATE, EVENTS = any> = {
166
615
  STATE: {
167
616
  source: StateSource<STATE>;
168
617
  sink: STATE;
@@ -204,7 +653,7 @@ type IntentActions<ACTIONS> = keyof ACTIONS extends never
204
653
  * Supports both `type` aliases and `interface` declarations (interfaces lack implicit index
205
654
  * signatures, so a structural fallback check is needed).
206
655
  */
207
- export type FixDrivers<DRIVERS> =
656
+ type FixDrivers<DRIVERS> =
208
657
  0 extends (1 & DRIVERS)
209
658
  ? {}
210
659
  : DRIVERS extends DriverSpecs
@@ -217,6 +666,42 @@ export type FixDrivers<DRIVERS> =
217
666
 
218
667
  type CombinedSources<STATE, DRIVERS> = Sources<DefaultDrivers<STATE> & DRIVERS> & { dispose$: Stream<boolean> }
219
668
 
669
+ /**
670
+ * The sources object an intent function receives (DOM, STATE, EVENTS, CHILD, dispose$, plus
671
+ * any custom drivers). Use it to annotate an intent declared before its component:
672
+ *
673
+ * const intent = ({ DOM }: IntentSources<State>) => ({ INC: DOM.click('.inc') })
674
+ */
675
+ type IntentSources<STATE = any, DRIVERS = {}> = CombinedSources<STATE, FixDrivers<DRIVERS>>
676
+
677
+ type StreamPayload<STREAM> = STREAM extends Stream<infer T> ? T : any
678
+
679
+ type IntentReturnToActions<RETURN> = {
680
+ [ACTION_KEY in keyof RETURN & string]-?: StreamPayload<Exclude<RETURN[ACTION_KEY], undefined>>
681
+ }
682
+
683
+ /**
684
+ * Derives the ACTIONS map (action name → payload type) from an intent function's type
685
+ * (or from its return object type): each key's `Stream<T>` becomes `T`.
686
+ *
687
+ * const intent = ({ DOM }: IntentSources<State>) => ({
688
+ * INC: DOM.click('.inc').mapTo(1), // Stream<number>
689
+ * NAME: DOM.input('.name').value(), // Stream<string>
690
+ * })
691
+ * const Counter: Component<State, {}, {}, ActionsOf<typeof intent>> = ...
692
+ * Counter.intent = intent
693
+ * Counter.model = { INC: (state, n) => ..., NAME: (state, name) => ... } // n: number, name: string
694
+ *
695
+ * With it, model keys not returned by the intent are type errors (the built-ins BOOTSTRAP,
696
+ * INITIALIZE, HYDRATE and DISPOSE stay allowed). Actions reached only through `next()` are
697
+ * added explicitly:
698
+ *
699
+ * type Actions = ActionsOf<typeof intent> & { SAVED: { id: string } }
700
+ */
701
+ type ActionsOf<INTENT> = INTENT extends (...args: any[]) => infer RETURN
702
+ ? IntentReturnToActions<RETURN>
703
+ : IntentReturnToActions<INTENT>
704
+
220
705
  interface ComponentIntent<STATE, DRIVERS, ACTIONS> {
221
706
  (args: CombinedSources<STATE, DRIVERS>): Partial<IntentActions<ACTIONS>>
222
707
  }
@@ -233,25 +718,25 @@ type Context<STATE, CONTEXT> = keyof CONTEXT extends never
233
718
  ? { [field: string]: boolean | StateOnlyReducer<STATE, any> }
234
719
  : { [CONTEXT_KEY in keyof CONTEXT]: boolean | StateOnlyReducer<STATE, CONTEXT[CONTEXT_KEY]> }
235
720
 
236
- export type Lense<PARENT_STATE = any, CHILD_STATE = any> = {
721
+ type Lense<PARENT_STATE = any, CHILD_STATE = any> = {
237
722
  get: (state: PARENT_STATE) => CHILD_STATE;
238
723
  set: (state: PARENT_STATE, childState: CHILD_STATE) => PARENT_STATE;
239
724
  }
240
725
 
241
- export type Lens<PARENT_STATE = any, CHILD_STATE = any> = Lense<PARENT_STATE, CHILD_STATE>
726
+ type Lens<PARENT_STATE = any, CHILD_STATE = any> = Lense<PARENT_STATE, CHILD_STATE>
242
727
 
243
- export type Filter<ITEM = any> = (item: ITEM) => boolean
728
+ type Filter<ITEM = any> = (item: ITEM) => boolean
244
729
 
245
- export type SortFunction<ITEM = any> = (a: ITEM, b: ITEM) => number
730
+ type SortFunction<ITEM = any> = (a: ITEM, b: ITEM) => number
246
731
 
247
- export type SortObject<ITEM = any> = {
732
+ type SortObject<ITEM = any> = {
248
733
  [field: string]: 'asc' | 'desc' | SortFunction<ITEM>
249
734
  }
250
735
 
251
736
  /**
252
737
  * Sygnal Component
253
738
  */
254
- export type Component<
739
+ type Component<
255
740
  STATE = any,
256
741
  PROPS = { [prop: string]: any },
257
742
  DRIVERS = {},
@@ -267,6 +752,12 @@ export type Component<
267
752
  model?: ComponentModel<STATE, PROPS, FixDrivers<DRIVERS>, ACTIONS, CALCULATED, SINK_RETURNS, CONTEXT>;
268
753
  intent?: ComponentIntent<STATE & CALCULATED, FixDrivers<DRIVERS>, ACTIONS>;
269
754
  initialState?: STATE;
755
+ /**
756
+ * Give a sub-component its own state instead of the slice its parent passes in.
757
+ * Required to use `initialState` on a sub-component (otherwise SYG405). Without a
758
+ * `state` prop the state is local to the instance and never written to the parent.
759
+ */
760
+ isolatedState?: boolean;
270
761
  calculated?: Calculated<STATE, CALCULATED>;
271
762
  storeCalculatedInState?: boolean;
272
763
  context?: Context<STATE & CALCULATED, CONTEXT>;
@@ -279,7 +770,7 @@ export type Component<
279
770
  /**
280
771
  * Sygnal Root Component
281
772
  */
282
- export type RootComponent<
773
+ type RootComponent<
283
774
  STATE = any,
284
775
  DRIVERS = {},
285
776
  ACTIONS = {},
@@ -294,68 +785,175 @@ export type RootComponent<
294
785
  */
295
786
  type AnyComponent = ((...args: any[]) => any) & Record<string, any>
296
787
 
297
- export type CollectionProps<PROPS = any> = {
788
+ /** Keys of STATE whose value is an array (optional/nullable arrays included). */
789
+ type ArrayKeysOf<STATE> = {
790
+ [KEY in keyof STATE]-?: NonNullable<STATE[KEY]> extends ReadonlyArray<any> ? KEY : never
791
+ }[keyof STATE] & string
792
+
793
+ /**
794
+ * Valid `from` values for a Collection: any string or Lense while the parent STATE is unknown
795
+ * (`any`); otherwise an array-valued key of STATE or a Lense over STATE.
796
+ */
797
+ type CollectionFrom<STATE = any> = 0 extends (1 & STATE)
798
+ ? string | Lense
799
+ : ArrayKeysOf<STATE> | Lense<STATE, any>
800
+
801
+ /**
802
+ * Collection props. Pass the parent component's state type as STATE to type-check `from`:
803
+ *
804
+ * const TaskCollection = Collection<{}, LaneState> // instantiation expression
805
+ * <TaskCollection of={TaskCard} from="tasks" /> // 'tasks' must be an array key of LaneState
806
+ */
807
+ type CollectionProps<PROPS = any, STATE = any> = {
298
808
  of: AnyComponent;
299
- from: string | Lense;
809
+ from: CollectionFrom<STATE>;
300
810
  filter?: Filter;
301
811
  sort?: string | SortFunction | SortObject;
302
- } & Omit<PROPS, 'of' | 'from' | 'filter' | 'sort'>
812
+ /**
813
+ * Item field used as the key that tracks each item (its component instance, isolation
814
+ * scope and DOM) across updates. Items are keyed by `id` by default; keys should be
815
+ * unique and stable (an item without the field is keyed by its index).
816
+ */
817
+ idfield?: string;
818
+ } & Omit<PROPS, 'of' | 'from' | 'filter' | 'sort' | 'idfield'>
303
819
 
304
- export type SwitchableProps<PROPS = any> = {
820
+ type SwitchableProps<PROPS = any> = {
305
821
  of: Record<string, AnyComponent>;
306
822
  current: string;
307
823
  state?: string | Lense;
308
824
  } & Omit<PROPS, 'of' | 'state' | 'current'>
309
825
 
310
- export type PortalProps = {
826
+ type PortalProps = {
311
827
  target: string;
312
828
  children?: any;
313
829
  }
314
830
 
315
- export type TransitionProps = {
831
+ type TransitionProps = {
316
832
  name?: string;
317
833
  duration?: number;
318
834
  appear?: boolean;
319
835
  children?: any;
320
836
  }
321
837
 
322
- export type SlotProps = {
838
+ type SuspenseProps = {
839
+ /**
840
+ * Shown (wrapped in `<div data-sygnal-suspense="pending">`) while any child is not ready:
841
+ * a `lazy()` component still loading, or a component with an explicit READY model entry
842
+ * that hasn't emitted true. A string renders as text. Without it the children render as-is.
843
+ */
844
+ fallback?: JSX.Element | string;
845
+ children?: any;
846
+ }
847
+
848
+ type SlotProps = {
323
849
  name?: string;
324
850
  children?: any;
325
851
  }
326
852
 
327
- export type ClassesType = (string | string[] | { [className: string]: boolean | undefined })[]
853
+ type ClassesType = (string | string[] | { [className: string]: boolean | undefined })[]
854
+
855
+ /**
856
+ * Diagnostics mode.
857
+ * - 'off' — no checks, no collection (default in production)
858
+ * - 'collect' — collect diagnostics silently (read with getDiagnostics())
859
+ * - 'warn' — collect and print warn/error diagnostics to the console (default in Vite dev)
860
+ * - 'error' — collect and throw on warn/error diagnostics
861
+ */
862
+ type DiagnosticsMode = 'off' | 'collect' | 'warn' | 'error'
863
+
864
+ /** Stable diagnostic code, e.g. 'SYG101'. See https://sygnal.js.org/reference/errors */
865
+ type DiagnosticCode = `SYG${number}`
866
+
867
+ type DiagnosticSeverity = 'error' | 'warn' | 'info'
868
+
869
+ type Diagnostic = {
870
+ code: DiagnosticCode;
871
+ severity: DiagnosticSeverity;
872
+ /** Name of the component the diagnostic is about */
873
+ component?: string;
874
+ /** What is wrong */
875
+ message: string;
876
+ /** How to fix it */
877
+ fix?: string;
878
+ /** Structured payload (check-specific) */
879
+ data?: any;
880
+ /** Link to the docs entry for this code */
881
+ docsUrl: string;
882
+ /** Fully formatted message: `[Sygnal SYG123] Component: message. fix docsUrl` */
883
+ text: string;
884
+ timestamp: number;
885
+ }
886
+
887
+ type DiagnosticsOptions = {
888
+ mode?: DiagnosticsMode;
889
+ /** Codes to ignore entirely */
890
+ ignore?: DiagnosticCode[];
891
+ }
328
892
 
329
- export type RunOptions = {
893
+ type RunOptions = {
330
894
  mountPoint?: string;
331
895
  fragments?: boolean;
332
896
  useDefaultDrivers?: boolean;
897
+ /**
898
+ * Runtime diagnostics. Takes precedence over `globalThis.__SYGNAL_DEV__`
899
+ * (set by the Sygnal Vite plugin in dev), which enables 'warn'. Default: 'off'.
900
+ */
901
+ diagnostics?: DiagnosticsMode | DiagnosticsOptions;
333
902
  }
334
903
 
335
- export type SygnalSinks<STATE = any, DRIVERS = {}> = {
904
+ /** All diagnostics collected so far (most recent last). */
905
+ declare function getDiagnostics(): Diagnostic[]
906
+
907
+ /** Clear the collected diagnostics. */
908
+ declare function clearDiagnostics(): void
909
+
910
+ /** Subscribe to diagnostics as they are reported. Returns an unsubscribe function. */
911
+ declare function onDiagnostic(callback: (diagnostic: Diagnostic) => void): () => void
912
+
913
+
914
+ /**
915
+ * The Sygnal DevTools bridge (also `window.__SYGNAL_DEVTOOLS__` once run() has
916
+ * initialized it in a browser). Only the stable, documented members are typed.
917
+ */
918
+ interface SygnalDevTools {
919
+ /** true while the browser extension is connected */
920
+ readonly connected: boolean
921
+ /** Diagnostics collected so far (same as getDiagnostics()) */
922
+ getDiagnostics(): Diagnostic[]
923
+ /**
924
+ * The machine-readable app graph of the live components. Present only when the
925
+ * 'sygnal/diagnostics' dev entry is loaded (it attaches this method); needs diagnostics on.
926
+ */
927
+ inspect?(): InspectGraph
928
+ }
929
+
930
+ /** The DevTools bridge singleton. */
931
+ declare function getDevTools(): SygnalDevTools | undefined
932
+
933
+ type SygnalSinks<STATE = any, DRIVERS = {}> = {
336
934
  [SINK_NAME in keyof (DefaultDrivers<STATE> & FixDrivers<DRIVERS>) | string]?: Stream<any>
337
935
  }
338
936
 
339
- export type AnyComponentModule<COMPONENT = any> =
937
+ type AnyComponentModule<COMPONENT = any> =
340
938
  | COMPONENT
341
939
  | { default: COMPONENT }
342
940
  | Array<COMPONENT | { default: COMPONENT } | null | undefined>
343
941
  | null
344
942
  | undefined
345
943
 
346
- export type SygnalApp<STATE = any, DRIVERS = {}> = {
944
+ type SygnalApp<STATE = any, DRIVERS = {}> = {
347
945
  sources: CombinedSources<STATE, FixDrivers<DRIVERS>>;
348
946
  sinks: SygnalSinks<STATE, DRIVERS>;
349
947
  dispose: () => void;
350
948
  hmr: (newComponent?: AnyComponentModule<RootComponent<STATE, DRIVERS>>, state?: STATE) => void;
351
949
  }
352
950
 
353
- export type HotModuleAPI = {
951
+ type HotModuleAPI = {
354
952
  accept: (...args: any[]) => any;
355
953
  dispose?: (callback: () => void) => void;
356
954
  }
357
955
 
358
- export function run<
956
+ declare function run<
359
957
  STATE = any,
360
958
  DRIVERS = {},
361
959
  ACTIONS = {},
@@ -367,21 +965,21 @@ export function run<
367
965
  options?: RunOptions
368
966
  ): SygnalApp<STATE & CALCULATED, FixDrivers<DRIVERS>>
369
967
 
370
- export function run(
968
+ declare function run(
371
969
  component: any,
372
970
  drivers?: Record<string, CycleDriver<any, any>>,
373
971
  options?: RunOptions
374
972
  ): SygnalApp<any, {}>
375
973
 
376
- export function enableHMR<STATE = any, DRIVERS = {}>(
974
+ declare function enableHMR<STATE = any, DRIVERS = {}>(
377
975
  app: SygnalApp<STATE, DRIVERS>,
378
976
  hot: HotModuleAPI,
379
977
  loadComponent?: () => Promise<AnyComponentModule<RootComponent<STATE, DRIVERS>>> | AnyComponentModule<RootComponent<STATE, DRIVERS>>,
380
978
  acceptDependencies?: string | string[]
381
979
  ): SygnalApp<STATE, DRIVERS>
382
980
 
383
- export function classes(...classes: ClassesType): string
384
- export function exactState<STATE>(): <ACTUAL extends STATE>(state: ExactShape<STATE, ACTUAL>) => STATE
981
+ declare function classes(...classes: ClassesType): string
982
+ declare function exactState<STATE>(): <ACTUAL extends STATE>(state: ExactShape<STATE, ACTUAL>) => STATE
385
983
 
386
984
  // ── Reducer helpers ────────────────────────────────────────────────
387
985
 
@@ -395,7 +993,7 @@ export function exactState<STATE>(): <ACTUAL extends STATE>(state: ExactShape<ST
395
993
  * returns the partial update to merge:
396
994
  * `set((state, title) => ({ title }))`
397
995
  */
398
- export function set<S = any>(
996
+ declare function set<S = any>(
399
997
  partial: Partial<S> | ((state: S, data: any, next: Function, props: any) => Partial<S>)
400
998
  ): (state: S, data: any, next: Function, props: any) => S
401
999
 
@@ -404,33 +1002,69 @@ export function set<S = any>(
404
1002
  *
405
1003
  * `toggle('showModal')`
406
1004
  */
407
- export function toggle<S = any>(field: keyof S & string): (state: S) => S
1005
+ declare function toggle<S = any>(field: keyof S & string): (state: S) => S
1006
+
1007
+ type EmitEntry<TYPE extends string> = keyof SygnalEvents extends never
1008
+ ? { EVENTS: (state: any, actionData: any, next: Function, props: any) => { type: string; data: any } }
1009
+ : { EVENTS: (state: any, actionData: any, next: Function, props: any) => EmittedEvent<TYPE> }
408
1010
 
409
1011
  /**
410
1012
  * Create a model entry that emits an EVENTS bus event.
1013
+ * Prefer `event()` inside the object form: `ACTION: { EVENTS: event('TYPE', fn) }`.
411
1014
  *
412
1015
  * `emit('DELETE_LANE', (state) => ({ laneId: state.id }))`
413
1016
  * `emit('REFRESH')`
1017
+ *
1018
+ * With a `SygnalEvents` registry, `type` and the payload are checked against it.
1019
+ */
1020
+ declare function emit<TYPE extends EventName>(
1021
+ type: TYPE,
1022
+ data: (state: any, actionData: any, next: Function, props: any) => EventPayload<TYPE>
1023
+ ): EmitEntry<TYPE>
1024
+ declare function emit<TYPE extends EventName>(
1025
+ type: TYPE,
1026
+ ...data: StaticEventArgs<TYPE>
1027
+ ): EmitEntry<TYPE>
1028
+
1029
+ /**
1030
+ * Create an EVENTS sink function that puts `{ type, data }` on the EVENTS bus.
1031
+ * Use it as the `EVENTS` value inside an object-form model entry:
1032
+ *
1033
+ * DELETE: {
1034
+ * STATE: (state) => ({ ...state, deleting: true }),
1035
+ * EVENTS: event('DELETE_LANE', (state) => ({ laneId: state.id })),
1036
+ * }
1037
+ *
1038
+ * The payload is either a function `(state, data, next, props) => payload` or a static value:
1039
+ * `event('RESET')`, `event('SET_MODE', 'dark')`.
1040
+ *
1041
+ * With a `SygnalEvents` registry, `type` must be a registered name and the payload must match
1042
+ * its type. When used inside a model, the payload function's `state` and `data` parameters are
1043
+ * typed from the component.
414
1044
  */
415
- export function emit(
416
- type: string,
417
- data?: any | ((state: any, actionData: any, next: Function, props: any) => any)
418
- ): { EVENTS: (state: any, actionData: any, next: Function, props: any) => { type: string; data: any } }
1045
+ declare function event<TYPE extends EventName, STATE = any, DATA = any>(
1046
+ type: TYPE,
1047
+ payload: EventPayloadFunction<TYPE, STATE, DATA>
1048
+ ): EventSink<TYPE, STATE, DATA>
1049
+ declare function event<TYPE extends EventName>(
1050
+ type: TYPE,
1051
+ ...payload: StaticEventArgs<TYPE>
1052
+ ): EventSink<TYPE>
419
1053
 
420
1054
  /**
421
1055
  * Any object with an events() method (e.g., DOM.select('form')).
422
1056
  * Uses permissive signature to be compatible with MainDOMSource's overloaded events().
423
1057
  */
424
- export type FormSource = {
1058
+ type FormSource = {
425
1059
  events(eventName: string, ...args: any[]): Stream<any>
426
1060
  }
427
1061
 
428
- export type FormData<FIELDS extends Record<string, string> = Record<string, string>> = FIELDS & {
1062
+ type FormData<FIELDS extends Record<string, string> = Record<string, string>> = FIELDS & {
429
1063
  event: globalThis.Event;
430
1064
  eventType: string;
431
1065
  }
432
1066
 
433
- export type ProcessFormOptions = {
1067
+ type ProcessFormOptions = {
434
1068
  events?: string | string[];
435
1069
  preventDefault?: boolean;
436
1070
  }
@@ -449,7 +1083,7 @@ export type ProcessFormOptions = {
449
1083
  * // form$ is Stream<FormData<{ username: string; email: string }>>
450
1084
  * // form$.username is typed as string ✓
451
1085
  */
452
- export function processForm<FIELDS extends Record<string, string> = Record<string, string>>(
1086
+ declare function processForm<FIELDS extends Record<string, string> = Record<string, string>>(
453
1087
  target: FormSource,
454
1088
  options?: ProcessFormOptions
455
1089
  ): Stream<FormData<FIELDS>>
@@ -458,11 +1092,11 @@ export function processForm<FIELDS extends Record<string, string> = Record<strin
458
1092
  * Any object with an events() method (e.g., DOM.select('.draggable')).
459
1093
  * Uses permissive signature to be compatible with MainDOMSource's overloaded events().
460
1094
  */
461
- export type DragSource = {
1095
+ type DragSource = {
462
1096
  events(eventName: string, ...args: any[]): Stream<any>
463
1097
  }
464
1098
 
465
- export function processDrag(
1099
+ declare function processDrag(
466
1100
  sources?: { draggable?: DragSource; dropZone?: DragSource },
467
1101
  options?: { effectAllowed?: string }
468
1102
  ): {
@@ -472,7 +1106,7 @@ export function processDrag(
472
1106
  drop$: Stream<DragEvent>
473
1107
  }
474
1108
 
475
- export type DragDriverRegistration = {
1109
+ type DragDriverRegistration = {
476
1110
  category: string;
477
1111
  draggable?: string;
478
1112
  dropZone?: string;
@@ -482,24 +1116,24 @@ export type DragDriverRegistration = {
482
1116
  dragImage?: string;
483
1117
  }
484
1118
 
485
- export type DragStartPayload = {
1119
+ type DragStartPayload = {
486
1120
  element: HTMLElement;
487
1121
  dataset: Record<string, string>;
488
1122
  }
489
1123
 
490
- export type DropPayload = {
1124
+ type DropPayload = {
491
1125
  dropZone: HTMLElement;
492
1126
  insertBefore: HTMLElement | null;
493
1127
  }
494
1128
 
495
- export type DragDriverCategory = {
1129
+ type DragDriverCategory = {
496
1130
  events(eventType: 'dragstart'): Stream<DragStartPayload>;
497
1131
  events(eventType: 'dragend'): Stream<null>;
498
1132
  events(eventType: 'drop'): Stream<DropPayload>;
499
1133
  events(eventType: string): Stream<any>;
500
1134
  }
501
1135
 
502
- export type DragDriverSource = {
1136
+ type DragDriverSource = {
503
1137
  select(category: string): DragDriverCategory;
504
1138
  dragstart(category: string): Stream<DragStartPayload>;
505
1139
  dragend(category: string): Stream<null>;
@@ -508,9 +1142,9 @@ export type DragDriverSource = {
508
1142
  dispose(): void;
509
1143
  }
510
1144
 
511
- export function makeDragDriver(): (sink$: Stream<DragDriverRegistration | DragDriverRegistration[]>) => DragDriverSource
1145
+ declare function makeDragDriver(): (sink$: Stream<DragDriverRegistration | DragDriverRegistration[]>) => DragDriverSource
512
1146
 
513
- export type ComponentFactoryOptions<
1147
+ type ComponentFactoryOptions<
514
1148
  STATE = any,
515
1149
  PROPS = any,
516
1150
  DRIVERS = {},
@@ -536,7 +1170,7 @@ export type ComponentFactoryOptions<
536
1170
  debug?: boolean;
537
1171
  }
538
1172
 
539
- export function component<
1173
+ declare function component<
540
1174
  STATE = any,
541
1175
  PROPS = any,
542
1176
  DRIVERS = {},
@@ -548,25 +1182,50 @@ export function component<
548
1182
  options: ComponentFactoryOptions<STATE, PROPS, DRIVERS, ACTIONS, CALCULATED, CONTEXT, SINK_RETURNS>
549
1183
  ): Component<STATE, PROPS, DRIVERS, ACTIONS, CALCULATED, CONTEXT, SINK_RETURNS>
550
1184
 
551
- export function collection(...args: any[]): any
552
- export function switchable(...args: any[]): any
553
- export function portal(...args: any[]): any
1185
+ declare function collection(...args: any[]): any
1186
+ declare function switchable(...args: any[]): any
1187
+ declare function portal(...args: any[]): any
554
1188
 
555
- export function Collection<PROPS extends { [prop: string]: any }>(props: CollectionProps<PROPS>): JSX.Element
556
- export function Switchable<PROPS extends { [prop: string]: any }>(props: SwitchableProps<PROPS>): JSX.Element
557
- export function Portal(props: PortalProps): JSX.Element
558
- export function Transition(props: TransitionProps): JSX.Element
559
- export function Slot(props: SlotProps): JSX.Element
1189
+ declare function Collection<PROPS extends { [prop: string]: any }, STATE = any>(props: CollectionProps<PROPS, STATE>): JSX.Element
1190
+ declare function Switchable<PROPS extends { [prop: string]: any }>(props: SwitchableProps<PROPS>): JSX.Element
1191
+ declare function Portal(props: PortalProps): JSX.Element
1192
+ declare function Transition(props: TransitionProps): JSX.Element
1193
+ declare function Suspense(props: SuspenseProps): JSX.Element
1194
+ declare function Slot(props: SlotProps): JSX.Element
1195
+
1196
+ /**
1197
+ * What `lazy()` returns: a sub-component used in JSX with its own props only
1198
+ * (`<Chart title="Sales" />`; `state` is optional, as for any sub-component), that
1199
+ * still carries the component statics (`model`, `intent`, …) once loaded.
1200
+ */
1201
+ type LazyComponent<PROPS = any> = ((
1202
+ props: PROPS & { state?: any; children?: JSX.Element | JSX.Element[] }
1203
+ ) => JSX.Element) & Omit<Component<any, PROPS>, never>
560
1204
 
561
- export function lazy<PROPS = any>(
1205
+ declare function lazy<PROPS = any>(
562
1206
  loadFn: () => Promise<{ default: Component<any, PROPS> } | Component<any, PROPS>>
563
- ): Component<any, PROPS>
1207
+ ): LazyComponent<PROPS>
1208
+
1209
+ /** Payload on `errors()` of a driverFromAsync source when a request fails */
1210
+ type AsyncDriverError<INCOMING = any> = {
1211
+ /** The rejection reason (or what `post` threw) */
1212
+ error: any;
1213
+ /** The request that failed */
1214
+ request: INCOMING;
1215
+ /** The request's selector property (default 'category') is copied here */
1216
+ [selectorProperty: string]: any;
1217
+ }
564
1218
 
565
- export type AsyncDriverFromFunction<INCOMING = any, OUTGOING = any> = {
1219
+ type AsyncDriverFromFunction<INCOMING = any, OUTGOING = any> = {
566
1220
  select: (selector?: string | ((value: OUTGOING) => boolean)) => Stream<OUTGOING>
1221
+ /**
1222
+ * Failed requests (rejected promise, rejected/throwing `post`). Filters like
1223
+ * `select()`. Failures are only console.error'd while nothing listens here.
1224
+ */
1225
+ errors: (selector?: string | ((error: AsyncDriverError<INCOMING>) => boolean)) => Stream<AsyncDriverError<INCOMING>>
567
1226
  }
568
1227
 
569
- export type DriverFromAsyncOptions<INCOMING = any, OUTGOING = any, RETURN = any> = {
1228
+ type DriverFromAsyncOptions<INCOMING = any, OUTGOING = any, RETURN = any> = {
570
1229
  selector?: string;
571
1230
  args?: string | string[] | ((incoming: INCOMING) => any | any[]);
572
1231
  return?: string | undefined;
@@ -574,71 +1233,101 @@ export type DriverFromAsyncOptions<INCOMING = any, OUTGOING = any, RETURN = any>
574
1233
  post?: (value: RETURN, incoming: INCOMING) => OUTGOING | Promise<OUTGOING>;
575
1234
  }
576
1235
 
577
- export function driverFromAsync<INCOMING = any, RETURN = any, OUTGOING = any>(
1236
+ declare function driverFromAsync<INCOMING = any, RETURN = any, OUTGOING = any>(
578
1237
  promiseReturningFunction: (...args: any[]) => Promise<RETURN>,
579
1238
  options?: DriverFromAsyncOptions<INCOMING, OUTGOING, RETURN>
580
1239
  ): (fromApp$: Stream<INCOMING>) => AsyncDriverFromFunction<INCOMING, OUTGOING>
581
1240
 
582
- export interface Ref<T = HTMLElement> {
1241
+ interface Ref<T = HTMLElement> {
583
1242
  current: T | null;
584
1243
  }
585
1244
 
586
- export interface Ref$<T = HTMLElement> extends Ref<T> {
1245
+ interface Ref$<T = HTMLElement> extends Ref<T> {
587
1246
  stream: MemoryStream<T | null>;
588
1247
  }
589
1248
 
590
- export function createRef<T = HTMLElement>(): Ref<T>
591
- export function createRef$<T = HTMLElement>(): Ref$<T>
1249
+ declare function createRef<T = HTMLElement>(): Ref<T>
1250
+ declare function createRef$<T = HTMLElement>(): Ref$<T>
592
1251
 
593
- export interface Command {
1252
+ interface Command {
594
1253
  send(type: string, data?: any): void;
595
1254
  }
596
1255
 
597
- export interface CommandSource {
1256
+ interface CommandSource {
598
1257
  select(type: string): Stream<any>;
599
1258
  }
600
1259
 
601
- export function createCommand(): Command
1260
+ declare function createCommand(): Command
602
1261
 
603
1262
  // ── PWA Helpers ──────────────────────────────────────────────
604
1263
 
605
- export interface ServiceWorkerSource {
1264
+ interface ServiceWorkerSource {
606
1265
  select(type?: 'installed' | 'activated' | 'waiting' | 'controlling' | 'error' | 'message' | string): Stream<any>;
607
1266
  }
608
1267
 
609
- export interface ServiceWorkerCommand {
1268
+ interface ServiceWorkerCommand {
610
1269
  action: 'skipWaiting' | 'postMessage' | 'unregister';
611
1270
  data?: any;
612
1271
  }
613
1272
 
614
- export interface ServiceWorkerOptions {
1273
+ interface ServiceWorkerOptions {
615
1274
  scope?: string;
616
1275
  }
617
1276
 
618
- export function makeServiceWorkerDriver(
1277
+ declare function makeServiceWorkerDriver(
619
1278
  scriptUrl: string,
620
1279
  options?: ServiceWorkerOptions
621
1280
  ): (sink$: Stream<ServiceWorkerCommand>) => ServiceWorkerSource
622
1281
 
623
- export const onlineStatus$: Stream<boolean>
1282
+ declare const onlineStatus$: Stream<boolean>
624
1283
 
625
- export interface InstallPrompt {
1284
+ interface InstallPrompt {
626
1285
  select(type: 'beforeinstallprompt' | 'appinstalled'): Stream<any>;
627
1286
  prompt(): Promise<any> | undefined;
628
1287
  }
629
1288
 
630
- export function createInstallPrompt(): InstallPrompt
1289
+ declare function createInstallPrompt(): InstallPrompt
1290
+
1291
+ interface SimulatedEventInit {
1292
+ /** Merged into `event.target` (value, checked, dataset, ...) */
1293
+ target?: Record<string, any>;
1294
+ /** Shorthand for target.value */
1295
+ value?: any;
1296
+ /** Shorthand for target.checked */
1297
+ checked?: boolean;
1298
+ /** Merged into target.dataset (values become strings, like the DOM) */
1299
+ dataset?: Record<string, any>;
1300
+ /** Alias for dataset */
1301
+ data?: Record<string, any>;
1302
+ /** Keyboard key (e.key) */
1303
+ key?: string;
1304
+ /**
1305
+ * Don't fail when the selector matches no rendered element: wait up to 300ms for it, then
1306
+ * drop the event with SYG103 (info). Not copied onto the event.
1307
+ */
1308
+ allowMissing?: boolean;
1309
+ /** Any other event properties are copied onto the event */
1310
+ [prop: string]: any;
1311
+ }
631
1312
 
632
- export interface RenderOptions {
1313
+ interface RenderOptions {
633
1314
  /** Override initial state (defaults to component's .initialState) */
634
1315
  initialState?: any;
635
1316
  /** Mock DOM configuration — maps selectors to event streams */
636
1317
  mockConfig?: Record<string, any>;
637
- /** Additional drivers beyond DOM, EVENTS, STATE, and LOG */
1318
+ /** Additional drivers beyond DOM, EVENTS, STATE, and LOG (model sinks without a driver get a no-op one) */
638
1319
  drivers?: Record<string, any>;
1320
+ /**
1321
+ * Diagnostics mode while rendered. Default: 'collect' (error-severity messages still print),
1322
+ * or the current mode when diagnostics are already on. Restored when the last instance is
1323
+ * disposed. Dev checks require `import 'sygnal/diagnostics'` (the Vite plugin adds it under Vitest).
1324
+ */
1325
+ diagnostics?: DiagnosticsMode;
1326
+ /** Enable strict (canonical-form) runtime checks while rendered (requires 'sygnal/diagnostics') */
1327
+ strict?: boolean;
639
1328
  }
640
1329
 
641
- export interface RenderResult {
1330
+ interface RenderResult {
642
1331
  /** Stream of state values */
643
1332
  state$: Stream<any>;
644
1333
  /** Stream of rendered VNode trees */
@@ -649,19 +1338,73 @@ export interface RenderResult {
649
1338
  sinks: Record<string, any>;
650
1339
  /** All source objects by driver name */
651
1340
  sources: Record<string, any>;
652
- /** Push an action directly into the intent→model pipeline */
1341
+ /** Push an action into the intent→model pipeline under its real name (all sinks of the entry run) */
653
1342
  simulateAction: (actionName: string, data?: any) => void;
654
- /** Wait for state to satisfy a predicate (resolves with the matching state) */
1343
+ /**
1344
+ * Dispatch a synthetic DOM event through the mock DOM source so the component's real intent
1345
+ * streams fire (DOM.click('.x'), DOM.select('.x').events('click'), .value(), .data()).
1346
+ * Targets the first rendered element matching `selector` and bubbles within its isolation scope.
1347
+ * Selectors match the rendered tree like the real DOM: tag, .class, #id, [attr], [attr="v"]
1348
+ * (^= $= *= ~=), :first-child, :last-child, :only-child, :nth-child(an+b|odd|even),
1349
+ * :nth-last-child(), :first/last/only/nth-of-type, :not(), descendant ' ' and child '>'
1350
+ * combinators, ',' lists. Other syntax (:has(), '+', '~', pseudo-elements...) throws.
1351
+ * If nothing matches yet, the event waits (up to 300ms, re-checked on every render) for a
1352
+ * matching element, then targets the first one. If none renders, the test fails with an
1353
+ * error naming the selector: it rejects the pending next()/waitForState()/settle(), or is
1354
+ * thrown by the next t.* call or dispose() (or by simulateEvent itself when nothing is
1355
+ * pending and the tree is quiet). Pass `{ allowMissing: true }` to drop the event with SYG103
1356
+ * instead. It is never sent to every listener with that selector string. It also waits until
1357
+ * the listeners it reaches are subscribed (a just-mounted child subscribes a few ms late).
1358
+ * `'document'` / `'body'` go to the DOM.select('document' | 'body') listeners.
1359
+ * simulateAction/simulateEvent calls are delivered in call order; a waiting event holds the
1360
+ * calls after it. Reports SYG104 (selector only matches inside a child component).
1361
+ */
1362
+ simulateEvent: (selector: string, eventType: string, eventInit?: SimulatedEventInit) => void;
1363
+ /** Resolves once the component is subscribed (earlier simulate* calls are buffered and replayed) */
1364
+ ready: () => Promise<void>;
1365
+ /**
1366
+ * Wait for a state that satisfies the predicate. Matches the recorded HISTORY too: a state
1367
+ * from before the call resolves it (e.g. `count === 0` right after a reset resolves at once
1368
+ * with the initial state). Resolves with the matching state once the whole tree (children
1369
+ * included) has rendered it. Use `next()` to wait for a new state.
1370
+ */
655
1371
  waitForState: (predicate: (state: any) => boolean, timeoutMs?: number) => Promise<any>;
1372
+ /**
1373
+ * Wait for the next state emitted AFTER this call that satisfies the predicate (default: any
1374
+ * state). Resolves with it once the whole tree (children included) has rendered it; rejects
1375
+ * after timeoutMs (default 2000).
1376
+ */
1377
+ next: (predicate?: (state: any) => boolean, timeoutMs?: number) => Promise<any>;
1378
+ /**
1379
+ * Resolves once nothing is pending: the component is ready, no simulated input is waiting,
1380
+ * and nothing in the tree has rendered, reduced or changed state for 20ms (longer than
1381
+ * next()'s default delay). Rejects after timeoutMs (default 2000) if it never calms down.
1382
+ */
1383
+ settle: (timeoutMs?: number) => Promise<void>;
656
1384
  /** Collected state values — grows as new states are emitted */
657
1385
  states: any[];
658
- /** Tear down the component and clean up all listeners */
1386
+ /** Live array of values emitted on a sink (EVENTS as {type, data}, PARENT unwrapped, custom drivers) */
1387
+ sinkValues: (sinkName: string) => any[];
1388
+ /** Live array of EVENTS sink emissions ({type, data}) */
1389
+ emitted: Array<{ type: string; data: any }>;
1390
+ /** Live array of diagnostics reported while rendered */
1391
+ diagnostics: Diagnostic[];
1392
+ /** Throws (with the formatted texts) if any warn/error diagnostics were collected */
1393
+ expectNoDiagnostics: () => void;
1394
+ /** Latest rendered VNode serialized to HTML ('' before the first render) */
1395
+ html: () => string;
1396
+ /** Tear down the component, clean up listeners and restore the diagnostics mode */
659
1397
  dispose: () => void;
1398
+ /**
1399
+ * The app graph of the rendered tree (components, actions, selectors with the mock DOM's
1400
+ * match / isolation results, EVENTS, diagnostics). Throws unless 'sygnal/diagnostics' is loaded.
1401
+ */
1402
+ inspect: () => InspectGraph;
660
1403
  }
661
1404
 
662
- export function renderComponent(componentDef: any, options?: RenderOptions): RenderResult
1405
+ declare function renderComponent(componentDef: any, options?: RenderOptions): RenderResult
663
1406
 
664
- export interface RenderToStringOptions {
1407
+ interface RenderToStringOptions {
665
1408
  /** Initial state for the root component */
666
1409
  state?: any
667
1410
  /** Props to pass to the root component */
@@ -679,18 +1422,10 @@ export interface RenderToStringOptions {
679
1422
  /**
680
1423
  * Render a Sygnal component to an HTML string on the server.
681
1424
  */
682
- export function renderToString(componentDef: any, options?: RenderToStringOptions): string
1425
+ declare function renderToString(componentDef: any, options?: RenderToStringOptions): string
683
1426
 
684
- export const xs: typeof xsDefault
1427
+ declare const xs: typeof xsDefault
685
1428
 
686
- export { default as debounce } from 'xstream/extra/debounce.js'
687
- export { default as throttle } from 'xstream/extra/throttle.js'
688
- export { default as delay } from 'xstream/extra/delay.js'
689
- export { default as dropRepeats } from 'xstream/extra/dropRepeats.js'
690
- export { default as sampleCombine } from 'xstream/extra/sampleCombine.js'
691
-
692
- export * from './cycle/dom/index'
693
- export type { MemoryStream, Stream }
694
1429
 
695
1430
  /**
696
1431
  * JSX Types
@@ -717,3 +1452,5 @@ declare global {
717
1452
  }
718
1453
  }
719
1454
  }
1455
+
1456
+ export { ABORT, type ActionsOf, type AnyComponentModule, type ArrayKeysOf, type AsyncDriverError, type AsyncDriverFromFunction, type ClassesType, Collection, type CollectionFrom, type CollectionProps, type Command, type CommandSource, type Component, type ComponentFactoryOptions, type CycleDOMEvent, type CycleDriver, type DOMDriverOptions, type DOMSource, type DefaultDrivers, type Diagnostic, type DiagnosticCode, type DiagnosticSeverity, type DiagnosticsMode, type DiagnosticsOptions, type DragDriverCategory, type DragDriverRegistration, type DragDriverSource, type DragSource, type DragStartPayload, type DriverFactories, type DriverFromAsyncOptions, type DriverSpec, type DriverSpecs, type DropPayload, type EmittedEvent, type EnrichedEventStream, type Event$1 as Event, type EventName, type EventPayload, type EventPayloadFunction, type EventSink, type EventsFnOptions, type EventsSource, type ExactShape, type Filter, type FixDrivers, type FormData, type FormSource, type HotModuleAPI, type InspectAction, type InspectActionTrigger, type InspectChild, type InspectComponent, type InspectDiagnostic, type InspectGraph, type InspectSelector, type InstallPrompt, type IntentSources, type LazyComponent, type Lens, type Lense, MainDOMSource, type MockConfig, MockedDOMSource, type NonStateSinkReturns, type ParentPayloadOf, Portal, type PortalProps, type ProcessFormOptions, type Ref, type Ref$, type RegisteredEvent, type RenderOptions, type RenderResult, type RenderToStringOptions, type RootComponent, type RunOptions, type ServiceWorkerCommand, type ServiceWorkerOptions, type ServiceWorkerSource, type SimulatedEventInit, Slot, type SlotProps, type SortFunction, type SortObject, Suspense, type SuspenseProps, Switchable, type SwitchableProps, type SygnalApp, type SygnalDOMSource, type SygnalDevTools, type SygnalEvents, type SygnalSinks, type Thunk, type ThunkData, Transition, type TransitionProps, classes, clearDiagnostics, collection, component, createCommand, createInstallPrompt, createRef, createRef$, driverFromAsync, emit, enableHMR, event, exactState, getDevTools, getDiagnostics, lazy, makeDOMDriver, makeDragDriver, makeServiceWorkerDriver, mockDOMSource, onDiagnostic, onlineStatus$, portal, processDrag, processForm, renderComponent, renderToString, run, set, switchable, thunk, toggle, xs };