solid-tag-runtime 0.0.7 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +113 -0
- package/README.md +118 -15
- package/html.d.ts +49 -0
- package/index.d.ts +42 -1
- package/package.json +1 -1
- package/src/events.js +63 -0
- package/src/html.js +299 -24
- package/src/runtime.js +198 -94
package/ARCHITECTURE.md
CHANGED
|
@@ -101,6 +101,7 @@ const runtime = createRuntime(options);
|
|
|
101
101
|
|
|
102
102
|
```ts
|
|
103
103
|
runtime.define(id, source, options?);
|
|
104
|
+
runtime.defineMany(definitions);
|
|
104
105
|
runtime.update(id, source, options?);
|
|
105
106
|
```
|
|
106
107
|
|
|
@@ -138,9 +139,18 @@ runtime.getModuleInfo(id);
|
|
|
138
139
|
|
|
139
140
|
```ts
|
|
140
141
|
runtime.invalidate(id);
|
|
142
|
+
runtime.remove(id, options?);
|
|
143
|
+
runtime.clear(options?);
|
|
144
|
+
|
|
145
|
+
runtime.subscribe(listener);
|
|
146
|
+
runtime.subscribe(type, listener);
|
|
147
|
+
runtime.subscribe(types, listener);
|
|
148
|
+
|
|
141
149
|
runtime.dispose();
|
|
142
150
|
```
|
|
143
151
|
|
|
152
|
+
Lifecycle subscriptions are synchronous observational notifications. They do not intercept or modify runtime behavior. Resolution behavior remains customizable through `resolve()`, compilation through the compiler adapter, and executable-module creation through `ModuleUrlBackend`.
|
|
153
|
+
|
|
144
154
|
## 6. Module kinds
|
|
145
155
|
|
|
146
156
|
The runtime currently has three module record kinds.
|
|
@@ -232,6 +242,10 @@ await html.observe({ registerExisting: false });
|
|
|
232
242
|
The controller exposes:
|
|
233
243
|
|
|
234
244
|
```ts
|
|
245
|
+
html.subscribe(listener);
|
|
246
|
+
html.subscribe(type, listener);
|
|
247
|
+
html.subscribe(types, listener);
|
|
248
|
+
|
|
235
249
|
html.register(options?);
|
|
236
250
|
html.observe(options?);
|
|
237
251
|
html.flush(options?);
|
|
@@ -1031,3 +1045,102 @@ Invariants:
|
|
|
1031
1045
|
8. `removeElement()` is the canonical operation for releasing shared WeakMap ownership.
|
|
1032
1046
|
|
|
1033
1047
|
Regression coverage: package tests cover batch definition and duplicate rejection, dependency removal/invalidation, clear-with-host-preservation, lifecycle event delivery/unsubscribe, owned element updates, identity-change rejection, ownership release, DOM removal, and preserving a runtime module while releasing its HTML element.
|
|
1048
|
+
|
|
1049
|
+
### 0.0.8 — selective lifecycle subscriptions and HTML observability
|
|
1050
|
+
|
|
1051
|
+
Decision: expand lifecycle observation into typed, independently removable subscriptions on both the core runtime and the HTML adapter. Keep lifecycle subscriptions observational and separate from behavioral hooks/interceptors.
|
|
1052
|
+
|
|
1053
|
+
Core subscription forms:
|
|
1054
|
+
|
|
1055
|
+
```ts
|
|
1056
|
+
runtime.subscribe(listener);
|
|
1057
|
+
runtime.subscribe("module-error", listener);
|
|
1058
|
+
runtime.subscribe(["module-evaluating", "module-evaluated"], listener);
|
|
1059
|
+
```
|
|
1060
|
+
|
|
1061
|
+
HTML controllers expose the same shape:
|
|
1062
|
+
|
|
1063
|
+
```ts
|
|
1064
|
+
html.subscribe(listener);
|
|
1065
|
+
html.subscribe("element-registered", listener);
|
|
1066
|
+
html.subscribe(["observer-batch", "html-error"], listener);
|
|
1067
|
+
```
|
|
1068
|
+
|
|
1069
|
+
Each call creates an independent subscription and returns its own disposer. Disposing one subscription never affects another registration of the same callback or subscriptions to other event groups. Subscriber exceptions are reported but cannot alter runtime/HTML operations.
|
|
1070
|
+
|
|
1071
|
+
Core event additions:
|
|
1072
|
+
|
|
1073
|
+
```text
|
|
1074
|
+
module-updated
|
|
1075
|
+
modules-defined
|
|
1076
|
+
module-resolving
|
|
1077
|
+
module-resolved
|
|
1078
|
+
module-linking
|
|
1079
|
+
module-linked
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
The evaluation pipeline is now observed in semantic order:
|
|
1083
|
+
|
|
1084
|
+
```text
|
|
1085
|
+
module-linking
|
|
1086
|
+
↓
|
|
1087
|
+
module-resolving / module-resolved
|
|
1088
|
+
↓
|
|
1089
|
+
module-linked
|
|
1090
|
+
↓
|
|
1091
|
+
module-compiled
|
|
1092
|
+
↓
|
|
1093
|
+
module-evaluating
|
|
1094
|
+
↓
|
|
1095
|
+
module-evaluated
|
|
1096
|
+
```
|
|
1097
|
+
|
|
1098
|
+
`module-resolved` exposes the logical resolution result and resolution kind, while `module-linked` exposes source specifier → resolved module-ID dependencies without exposing Blob/data URL implementation details. `modules-defined` marks the completion of a `defineMany()` batch after buffered per-module events become observable. `module-updated` supplements the backward-compatible `module-defined { operation: "update" }` event with an explicit semantic update notification.
|
|
1099
|
+
|
|
1100
|
+
`module-error` remains one event with a structured pipeline phase instead of creating separate error event types. Supported phases are `resolve`, `analyze`, `compile`, `link`, `url-create`, `evaluate`, and `host-bridge`.
|
|
1101
|
+
|
|
1102
|
+
HTML controller event additions:
|
|
1103
|
+
|
|
1104
|
+
```text
|
|
1105
|
+
element-discovered
|
|
1106
|
+
element-claimed
|
|
1107
|
+
element-loading
|
|
1108
|
+
element-loaded
|
|
1109
|
+
element-registered
|
|
1110
|
+
element-updating
|
|
1111
|
+
element-updated
|
|
1112
|
+
element-removing
|
|
1113
|
+
element-released
|
|
1114
|
+
element-removed
|
|
1115
|
+
observer-connected
|
|
1116
|
+
observer-disconnected
|
|
1117
|
+
observer-batch
|
|
1118
|
+
root-changing
|
|
1119
|
+
root-changed
|
|
1120
|
+
append-target-changed
|
|
1121
|
+
entry-executing
|
|
1122
|
+
entry-executed
|
|
1123
|
+
html-error
|
|
1124
|
+
```
|
|
1125
|
+
|
|
1126
|
+
HTML ownership events include an origin describing the ingestion path (`initial-scan`, `observer`, `register-element`, `append`, `add-module`, etc.). The observer emits summarized `observer-batch` events instead of exposing raw `MutationRecord` values. Root/append-target events belong only to the HTML controller and are deliberately not mixed into core runtime events.
|
|
1127
|
+
|
|
1128
|
+
Architectural boundary:
|
|
1129
|
+
|
|
1130
|
+
```text
|
|
1131
|
+
Observation
|
|
1132
|
+
runtime.subscribe()
|
|
1133
|
+
html.subscribe()
|
|
1134
|
+
|
|
1135
|
+
Behavior customization
|
|
1136
|
+
resolve()
|
|
1137
|
+
compiler adapter
|
|
1138
|
+
ModuleUrlBackend
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
Lifecycle listeners are not interceptors: they cannot cancel evaluation, rewrite source, change resolution, or alter cache behavior. If source/evaluation interception is needed later, it must be designed as a separate hook contract with explicit ordering, async, cancellation, and caching semantics.
|
|
1142
|
+
|
|
1143
|
+
Implementation note: core and HTML event streams share a small internal dispatcher so all/selective subscription behavior, independent disposers, and listener-error isolation have identical semantics while keeping separate event unions.
|
|
1144
|
+
|
|
1145
|
+
Regression coverage: package tests cover catch-all, single-type, and multi-type subscriptions; independent unsubscribe; listener exception isolation; update/batch events; resolution/link/evaluation ordering and payloads; structured resolution errors; HTML ownership origins; observer connect/disconnect/batch events; root and append-target events; external source loading; entry execution; update/removal events; HTML error reporting; and HTML subscriber exception isolation.
|
|
1146
|
+
|
package/README.md
CHANGED
|
@@ -107,8 +107,8 @@ Browser import maps must map the subpath explicitly as well as the package root:
|
|
|
107
107
|
```json
|
|
108
108
|
{
|
|
109
109
|
"imports": {
|
|
110
|
-
"solid-tag-runtime": "https://esm.sh/solid-tag-runtime@0.0.
|
|
111
|
-
"solid-tag-runtime/html": "https://esm.sh/solid-tag-runtime@0.0.
|
|
110
|
+
"solid-tag-runtime": "https://esm.sh/solid-tag-runtime@0.0.8",
|
|
111
|
+
"solid-tag-runtime/html": "https://esm.sh/solid-tag-runtime@0.0.8/html"
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
```
|
|
@@ -572,28 +572,131 @@ removes everything. The returned array contains the IDs that were removed.
|
|
|
572
572
|
|
|
573
573
|
### Lifecycle events
|
|
574
574
|
|
|
575
|
+
`0.0.8` expands lifecycle subscriptions into a typed event stream with independent join/leave semantics.
|
|
576
|
+
|
|
577
|
+
Subscribe to everything:
|
|
578
|
+
|
|
575
579
|
```ts
|
|
576
580
|
const unsubscribe = runtime.subscribe(event => {
|
|
577
581
|
console.log(event.type, event);
|
|
578
582
|
});
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
Subscribe to one event type:
|
|
586
|
+
|
|
587
|
+
```ts
|
|
588
|
+
const leaveErrors = runtime.subscribe(
|
|
589
|
+
"module-error",
|
|
590
|
+
event => {
|
|
591
|
+
console.error(event.phase, event.error);
|
|
592
|
+
},
|
|
593
|
+
);
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
Subscribe to several event types:
|
|
597
|
+
|
|
598
|
+
```ts
|
|
599
|
+
const leaveEvaluation = runtime.subscribe(
|
|
600
|
+
["module-evaluating", "module-evaluated"],
|
|
601
|
+
event => {
|
|
602
|
+
console.log(event.type, event.id);
|
|
603
|
+
},
|
|
604
|
+
);
|
|
605
|
+
```
|
|
606
|
+
|
|
607
|
+
Each call owns an independent subscription:
|
|
608
|
+
|
|
609
|
+
```ts
|
|
610
|
+
leaveEvaluation();
|
|
611
|
+
// the error subscription remains active
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
Core events include:
|
|
615
|
+
|
|
616
|
+
```text
|
|
617
|
+
module-defined
|
|
618
|
+
module-updated
|
|
619
|
+
modules-defined
|
|
620
|
+
|
|
621
|
+
module-resolving
|
|
622
|
+
module-resolved
|
|
623
|
+
|
|
624
|
+
module-linking
|
|
625
|
+
module-linked
|
|
626
|
+
|
|
627
|
+
module-invalidated
|
|
628
|
+
module-compiled
|
|
629
|
+
module-evaluating
|
|
630
|
+
module-evaluated
|
|
631
|
+
|
|
632
|
+
module-removed
|
|
633
|
+
module-error
|
|
634
|
+
|
|
635
|
+
runtime-cleared
|
|
636
|
+
runtime-disposed
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
`module-resolved` reports how a specifier was resolved (`relative`, `registered`, `custom`, `native`, and so on). `module-linked` exposes the logical dependency mapping used to link a source module. `modules-defined` marks the completion of a `defineMany()` batch after all definitions have been installed.
|
|
640
|
+
|
|
641
|
+
`module-error.phase` is one of the runtime pipeline phases such as `resolve`, `analyze`, `compile`, `link`, `url-create`, `evaluate`, or `host-bridge`.
|
|
642
|
+
|
|
643
|
+
Subscribers are observational only: they cannot cancel or modify runtime operations, and subscriber exceptions are isolated from runtime execution. Behavioral extension remains separate through the resolver, compiler adapter, and module URL backend.
|
|
644
|
+
|
|
645
|
+
### HTML lifecycle events
|
|
646
|
+
|
|
647
|
+
The HTML controller has its own event stream because DOM ownership/observation is intentionally separate from the core module engine:
|
|
648
|
+
|
|
649
|
+
```ts
|
|
650
|
+
const leaveHTML = html.subscribe(event => {
|
|
651
|
+
console.log(event.type, event);
|
|
652
|
+
});
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
The same selective forms are supported:
|
|
656
|
+
|
|
657
|
+
```ts
|
|
658
|
+
const leaveOwnership = html.subscribe(
|
|
659
|
+
["element-claimed", "element-registered", "element-removed"],
|
|
660
|
+
event => {
|
|
661
|
+
console.log(event.type, event.moduleId);
|
|
662
|
+
},
|
|
663
|
+
);
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
HTML events include:
|
|
667
|
+
|
|
668
|
+
```text
|
|
669
|
+
element-discovered
|
|
670
|
+
element-claimed
|
|
671
|
+
element-loading
|
|
672
|
+
element-loaded
|
|
673
|
+
element-registered
|
|
674
|
+
|
|
675
|
+
element-updating
|
|
676
|
+
element-updated
|
|
677
|
+
element-removing
|
|
678
|
+
element-released
|
|
679
|
+
element-removed
|
|
680
|
+
|
|
681
|
+
observer-connected
|
|
682
|
+
observer-disconnected
|
|
683
|
+
observer-batch
|
|
684
|
+
|
|
685
|
+
root-changing
|
|
686
|
+
root-changed
|
|
687
|
+
append-target-changed
|
|
688
|
+
|
|
689
|
+
entry-executing
|
|
690
|
+
entry-executed
|
|
579
691
|
|
|
580
|
-
|
|
581
|
-
unsubscribe();
|
|
692
|
+
html-error
|
|
582
693
|
```
|
|
583
694
|
|
|
584
|
-
|
|
695
|
+
Ownership-related events include an `origin` describing how the element entered the controller (`observer`, `append`, `register-element`, `add-module`, and related internal scan origins). This is useful for tracing observer/manual-registration races and proving that an explicit `append()` was not processed a second time by the observer.
|
|
585
696
|
|
|
586
|
-
- `
|
|
587
|
-
- `module-invalidated`
|
|
588
|
-
- `module-compiled`
|
|
589
|
-
- `module-evaluating`
|
|
590
|
-
- `module-evaluated`
|
|
591
|
-
- `module-removed`
|
|
592
|
-
- `module-error`
|
|
593
|
-
- `runtime-cleared`
|
|
594
|
-
- `runtime-disposed`
|
|
697
|
+
`observer-batch` summarizes a DOM discovery pass instead of exposing noisy raw `MutationRecord` objects. `element-loading` / `element-loaded` are emitted for `src`-backed modules, and entry events distinguish evaluation caused by an HTML `entry` declaration from an ordinary `runtime.import()`.
|
|
595
698
|
|
|
596
|
-
|
|
699
|
+
Like core runtime subscribers, HTML subscribers are observational and exception-isolated.
|
|
597
700
|
|
|
598
701
|
## HTML-owned module updates and removal
|
|
599
702
|
|
package/html.d.ts
CHANGED
|
@@ -107,6 +107,45 @@ export interface RegisterHTMLResult {
|
|
|
107
107
|
}>;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
export type HTMLRegistrationOrigin =
|
|
111
|
+
| "initial-scan"
|
|
112
|
+
| "observer"
|
|
113
|
+
| "observer-initial"
|
|
114
|
+
| "observer-root-change"
|
|
115
|
+
| "root-change-scan"
|
|
116
|
+
| "define-element"
|
|
117
|
+
| "register-element"
|
|
118
|
+
| "append"
|
|
119
|
+
| "add-module"
|
|
120
|
+
| "update-element"
|
|
121
|
+
| "remove-element"
|
|
122
|
+
| string;
|
|
123
|
+
|
|
124
|
+
export type HTMLRuntimeEvent =
|
|
125
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-discovered"; element: HTMLModuleScriptElement; moduleId?: string; origin: HTMLRegistrationOrigin; accepted: boolean }
|
|
126
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-claimed"; element: HTMLModuleScriptElement; moduleId: string; format: ModuleFormat; entry: boolean; sourceUrl?: string; origin: HTMLRegistrationOrigin }
|
|
127
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-loading"; element: HTMLModuleScriptElement; moduleId: string; sourceUrl: string; origin: HTMLRegistrationOrigin }
|
|
128
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-loaded"; element: HTMLModuleScriptElement; moduleId: string; sourceUrl: string; origin: HTMLRegistrationOrigin; bytes: number; durationMs: number }
|
|
129
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-registered"; element: HTMLModuleScriptElement; moduleId: string; definition: HTMLModuleDefinition; origin: HTMLRegistrationOrigin }
|
|
130
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-updating"; element: HTMLModuleScriptElement; moduleId: string; origin: HTMLRegistrationOrigin }
|
|
131
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-updated"; element: HTMLModuleScriptElement; moduleId: string; definition: HTMLModuleDefinition; origin: HTMLRegistrationOrigin }
|
|
132
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-removing"; element: HTMLModuleScriptElement; moduleId: string; origin: HTMLRegistrationOrigin; removeModule: boolean; removeFromDOM: boolean }
|
|
133
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-released"; element: HTMLModuleScriptElement; moduleId: string; origin: HTMLRegistrationOrigin }
|
|
134
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "element-removed"; element: HTMLModuleScriptElement; moduleId: string; origin: HTMLRegistrationOrigin; moduleRemoved: boolean; elementRemoved: boolean }
|
|
135
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "observer-connected"; root: HTMLModuleRoot; subtree: boolean; registerExisting: boolean; reason: string }
|
|
136
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "observer-disconnected"; root?: HTMLModuleRoot; reason: string }
|
|
137
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "observer-batch"; root: HTMLModuleRoot; origin: HTMLRegistrationOrigin; discovered: number; matched: number; claimed: number; ignored: number; modules: string[] }
|
|
138
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "root-changing"; previousRoot?: HTMLModuleRoot; root: HTMLModuleRoot; connected: boolean; registerExisting: boolean }
|
|
139
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "root-changed"; previousRoot?: HTMLModuleRoot; root: HTMLModuleRoot; connected: boolean; registerExisting: boolean }
|
|
140
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "append-target-changed"; previousTarget?: HTMLAppendTarget; target: HTMLAppendTarget }
|
|
141
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "entry-executing"; element: HTMLModuleScriptElement; moduleId: string; origin: HTMLRegistrationOrigin }
|
|
142
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "entry-executed"; element: HTMLModuleScriptElement; moduleId: string; namespace: ModuleNamespaceLike; origin: HTMLRegistrationOrigin }
|
|
143
|
+
| { htmlRuntimeId: string; scope?: string; timestamp: number; type: "html-error"; operation: "discover" | "claim" | "fetch" | "register" | "update" | "remove" | "entry" | "root-change" | "observer" | string; error: unknown; element?: HTMLModuleScriptElement; moduleId?: string; origin?: HTMLRegistrationOrigin };
|
|
144
|
+
|
|
145
|
+
export type HTMLRuntimeEventType = HTMLRuntimeEvent["type"];
|
|
146
|
+
export type HTMLRuntimeEventOfType<T extends HTMLRuntimeEventType> =
|
|
147
|
+
Extract<HTMLRuntimeEvent, { type: T }>;
|
|
148
|
+
|
|
110
149
|
export interface ObserveHTMLOptions extends RegisterHTMLOptions {
|
|
111
150
|
/** Register scripts already present when observation starts. Default: true. */
|
|
112
151
|
registerExisting?: boolean;
|
|
@@ -158,6 +197,16 @@ export interface HTMLRuntimeController {
|
|
|
158
197
|
/** Result of the observer's initial scan. */
|
|
159
198
|
readonly initial: RegisterHTMLResult;
|
|
160
199
|
|
|
200
|
+
subscribe(listener: (event: HTMLRuntimeEvent) => void): () => boolean;
|
|
201
|
+
subscribe<T extends HTMLRuntimeEventType>(
|
|
202
|
+
type: T,
|
|
203
|
+
listener: (event: HTMLRuntimeEventOfType<T>) => void,
|
|
204
|
+
): () => boolean;
|
|
205
|
+
subscribe<const T extends readonly HTMLRuntimeEventType[]>(
|
|
206
|
+
types: T,
|
|
207
|
+
listener: (event: HTMLRuntimeEventOfType<T[number]>) => void,
|
|
208
|
+
): () => boolean;
|
|
209
|
+
|
|
161
210
|
/** One-shot scan of matching scripts under the configured/root override. */
|
|
162
211
|
register(options?: RegisterHTMLOptions): Promise<RegisterHTMLResult>;
|
|
163
212
|
|
package/index.d.ts
CHANGED
|
@@ -91,17 +91,50 @@ export interface ClearRuntimeOptions {
|
|
|
91
91
|
preserveHostModules?: boolean;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
export type ModuleResolutionKind =
|
|
95
|
+
| "custom"
|
|
96
|
+
| "registered"
|
|
97
|
+
| "url"
|
|
98
|
+
| "absolute"
|
|
99
|
+
| "relative"
|
|
100
|
+
| "native";
|
|
101
|
+
|
|
102
|
+
export type ModuleErrorPhase =
|
|
103
|
+
| "resolve"
|
|
104
|
+
| "analyze"
|
|
105
|
+
| "compile"
|
|
106
|
+
| "link"
|
|
107
|
+
| "url-create"
|
|
108
|
+
| "evaluate"
|
|
109
|
+
| "host-bridge";
|
|
110
|
+
|
|
111
|
+
export interface LinkedDependency {
|
|
112
|
+
specifier: string;
|
|
113
|
+
resolvedId: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
94
116
|
export type RuntimeLifecycleEvent =
|
|
95
117
|
| { runtimeId: string; timestamp: number; type: "module-defined"; id: string; kind: ModuleInfo["kind"]; version: number; operation: "define" | "defineMany" | "update" | "defineModule" | "defineUrl"; replaced: boolean; module: ModuleInfo }
|
|
118
|
+
| { runtimeId: string; timestamp: number; type: "module-updated"; id: string; kind: ModuleInfo["kind"]; previousVersion: number; version: number; format?: ModuleFormat; module: ModuleInfo }
|
|
119
|
+
| { runtimeId: string; timestamp: number; type: "modules-defined"; ids: string[]; modules: ModuleInfo[] }
|
|
120
|
+
| { runtimeId: string; timestamp: number; type: "module-resolving"; specifier: string; importer: string | null }
|
|
121
|
+
| { runtimeId: string; timestamp: number; type: "module-resolved"; specifier: string; importer: string | null; resolvedId: string; resolutionKind: ModuleResolutionKind }
|
|
122
|
+
| { runtimeId: string; timestamp: number; type: "module-linking"; id: string; kind: ModuleInfo["kind"]; version: number }
|
|
123
|
+
| { runtimeId: string; timestamp: number; type: "module-linked"; id: string; kind: ModuleInfo["kind"]; version: number; dependencies: LinkedDependency[]; module: ModuleInfo }
|
|
96
124
|
| { runtimeId: string; timestamp: number; type: "module-invalidated"; id: string; kind: ModuleInfo["kind"]; version: number; reason: string }
|
|
97
125
|
| { runtimeId: string; timestamp: number; type: "module-compiled"; id: string; kind: ModuleInfo["kind"]; version: number; module: ModuleInfo }
|
|
98
126
|
| { runtimeId: string; timestamp: number; type: "module-evaluating"; id: string; kind: ModuleInfo["kind"]; version: number }
|
|
99
127
|
| { runtimeId: string; timestamp: number; type: "module-evaluated"; id: string; kind: ModuleInfo["kind"]; version: number; module: ModuleInfo }
|
|
100
128
|
| { runtimeId: string; timestamp: number; type: "module-removed"; id: string; kind: ModuleInfo["kind"]; version: number; invalidateDependents: boolean }
|
|
101
|
-
| { runtimeId: string; timestamp: number; type: "module-error"; id?: string; kind?: ModuleInfo["kind"]; version?: number; phase:
|
|
129
|
+
| { runtimeId: string; timestamp: number; type: "module-error"; id?: string; kind?: ModuleInfo["kind"]; version?: number; phase: ModuleErrorPhase; error: unknown }
|
|
102
130
|
| { runtimeId: string; timestamp: number; type: "runtime-cleared"; ids: string[]; preserveHostModules: boolean }
|
|
103
131
|
| { runtimeId: string; timestamp: number; type: "runtime-disposed" };
|
|
104
132
|
|
|
133
|
+
export type RuntimeLifecycleEventType = RuntimeLifecycleEvent["type"];
|
|
134
|
+
export type RuntimeLifecycleEventOfType<T extends RuntimeLifecycleEventType> =
|
|
135
|
+
Extract<RuntimeLifecycleEvent, { type: T }>;
|
|
136
|
+
|
|
137
|
+
|
|
105
138
|
export interface SolidTagRuntime {
|
|
106
139
|
define(id: string, source: string, options?: DefineOptions): string;
|
|
107
140
|
defineMany(definitions: SourceModuleDefinition[]): string[];
|
|
@@ -117,6 +150,14 @@ export interface SolidTagRuntime {
|
|
|
117
150
|
remove(id: string, options?: RemoveModuleOptions): boolean;
|
|
118
151
|
clear(options?: ClearRuntimeOptions): string[];
|
|
119
152
|
subscribe(listener: (event: RuntimeLifecycleEvent) => void): () => boolean;
|
|
153
|
+
subscribe<T extends RuntimeLifecycleEventType>(
|
|
154
|
+
type: T,
|
|
155
|
+
listener: (event: RuntimeLifecycleEventOfType<T>) => void,
|
|
156
|
+
): () => boolean;
|
|
157
|
+
subscribe<const T extends readonly RuntimeLifecycleEventType[]>(
|
|
158
|
+
types: T,
|
|
159
|
+
listener: (event: RuntimeLifecycleEventOfType<T[number]>) => void,
|
|
160
|
+
): () => boolean;
|
|
120
161
|
modules(): ModuleInfo[];
|
|
121
162
|
dependencies(id: string): string[];
|
|
122
163
|
dependents(id: string): string[];
|
package/package.json
CHANGED
package/src/events.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export function createEventDispatcher(options = {}) {
|
|
2
|
+
const subscriptions = new Set();
|
|
3
|
+
const onListenerError = options.onListenerError;
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
subscribe,
|
|
7
|
+
emit,
|
|
8
|
+
clear,
|
|
9
|
+
get size() {
|
|
10
|
+
return subscriptions.size;
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function subscribe(typesOrListener, maybeListener) {
|
|
15
|
+
let types;
|
|
16
|
+
let listener;
|
|
17
|
+
|
|
18
|
+
if (typeof typesOrListener === "function") {
|
|
19
|
+
listener = typesOrListener;
|
|
20
|
+
types = undefined;
|
|
21
|
+
} else {
|
|
22
|
+
listener = maybeListener;
|
|
23
|
+
if (typeof typesOrListener === "string") {
|
|
24
|
+
types = new Set([typesOrListener]);
|
|
25
|
+
} else if (Array.isArray(typesOrListener)) {
|
|
26
|
+
if (typesOrListener.length === 0 || typesOrListener.some(type => typeof type !== "string" || !type)) {
|
|
27
|
+
throw new TypeError("subscribe(types, listener) expects a non-empty event type or event type array.");
|
|
28
|
+
}
|
|
29
|
+
types = new Set(typesOrListener);
|
|
30
|
+
} else {
|
|
31
|
+
throw new TypeError("subscribe() expects a listener, event type + listener, or event type array + listener.");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (typeof listener !== "function") {
|
|
36
|
+
throw new TypeError("subscribe() expects a listener function.");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const subscription = { types, listener };
|
|
40
|
+
subscriptions.add(subscription);
|
|
41
|
+
|
|
42
|
+
return () => subscriptions.delete(subscription);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function emit(event) {
|
|
46
|
+
for (const subscription of [...subscriptions]) {
|
|
47
|
+
if (subscription.types && !subscription.types.has(event.type)) continue;
|
|
48
|
+
try {
|
|
49
|
+
subscription.listener(event);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
try {
|
|
52
|
+
onListenerError?.(error, event);
|
|
53
|
+
} catch {
|
|
54
|
+
// Listener error reporting must never break the emitter.
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function clear() {
|
|
61
|
+
subscriptions.clear();
|
|
62
|
+
}
|
|
63
|
+
}
|