solid-tag-runtime 0.0.2 → 0.0.4

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 CHANGED
@@ -195,50 +195,209 @@ This permits ordinary JavaScript and JSX modules to coexist in one graph.
195
195
 
196
196
  ## 8. HTML/browser adapter
197
197
 
198
- `0.0.2` adds `solid-tag-runtime/html` as an opt-in browser-facing adapter.
198
+ `solid-tag-runtime/html` is an opt-in browser-facing adapter over the core module runtime.
199
+
200
+ `0.0.3` made the adapter runtime-aware rather than treating document scripts as a single global pool.
199
201
 
200
202
  Important architectural boundary:
201
203
 
202
204
  ```text
203
205
  DOM / HTML document
204
206
  ↓
205
- solid-tag-runtime/html
207
+ HTML runtime controller
206
208
  ↓
207
209
  runtime.define(...)
208
210
  ↓
209
211
  core module graph
210
212
  ```
211
213
 
212
- The core runtime remains DOM-independent. It does not scan documents, fetch `<script>` elements, or know about HTML attributes.
214
+ The core runtime remains DOM-independent. It does not scan documents, own HTML elements, run `MutationObserver`, or know about HTML attributes.
213
215
 
214
216
  ### Public HTML API
215
217
 
218
+ The preferred API for non-trivial usage is a persistent controller:
219
+
220
+ ```ts
221
+ const html = createHTMLRuntime(runtime, {
222
+ scope: "preview",
223
+ root: document,
224
+ });
225
+
226
+ await html.register();
227
+ await html.observe({ registerExisting: false });
228
+ ```
229
+
230
+ The controller exposes:
231
+
232
+ ```ts
233
+ html.register(options?);
234
+ html.observe(options?);
235
+ html.flush(options?);
236
+ html.disconnect();
237
+
238
+ html.defineElement(element, options?);
239
+ html.registerElement(element, options?);
240
+ html.append(element, options?);
241
+ html.addModule(options);
242
+
243
+ html.owns(element);
244
+ html.getModuleId(element);
245
+ html.getElement(moduleId);
246
+ ```
247
+
248
+ The original convenience functions remain supported and are implemented on top of a cached default controller for each runtime:
249
+
216
250
  ```ts
217
251
  await registerHTML(runtime, options?);
218
252
  await defineScript(runtime, element, options?);
219
253
  const observer = await observeHTML(runtime, options?);
220
254
  ```
221
255
 
222
- `registerHTML()` discovers matching script elements, defines the complete discovered graph, and only then executes modules marked `entry` unless `executeEntries: false` is supplied.
256
+ This keeps the simple single-runtime API while giving multi-runtime applications an explicit ownership object.
257
+
258
+ ### Element ownership model
259
+
260
+ A module-level `WeakMap` is the authoritative in-memory ownership registry for runtime script elements.
261
+
262
+ Conceptually:
263
+
264
+ ```ts
265
+ WeakMap<HTMLScriptElement, ElementRecord>
266
+ ```
267
+
268
+ An element record stores at least:
269
+
270
+ ```text
271
+ owner controller
272
+ module ID
273
+ format
274
+ entry flag
275
+ source URL
276
+ registration state
277
+ pending registration promise
278
+ result/error
279
+ ```
280
+
281
+ This registry is shared by all HTML runtime controllers created by this package instance.
282
+
283
+ Important invariants:
284
+
285
+ 1. A runtime script element has at most one HTML-runtime owner.
286
+ 2. Ownership is claimed synchronously before asynchronous fetch/compile work.
287
+ 3. `append()` claims ownership before inserting the node into the DOM.
288
+ 4. Observer discovery, scans, explicit registration, and append/add helpers all use the same ownership record.
289
+ 5. Re-registering an element through the same controller is idempotent and waits on the same pending registration work.
290
+ 6. A different controller attempting to claim an owned element receives `HTMLModuleOwnershipError`.
291
+ 7. The observer must never redefine a module already being handled through `append()` or `registerElement()`.
292
+ 8. Distinct HTML elements cannot silently claim the same module ID in one HTML controller.
293
+ 9. Existing non-HTML runtime modules are not silently replaced by HTML registration.
294
+ 10. DOM removal does not implicitly delete a runtime module.
295
+
296
+ A `WeakSet` alone is insufficient because the adapter needs to distinguish ownership, pending work, success, and failure. The shared `WeakMap` also avoids retaining detached elements after all external references disappear.
297
+
298
+ ### Controller scope and multiple runtimes
299
+
300
+ A controller may declare a scope:
301
+
302
+ ```ts
303
+ const previewHTML = createHTMLRuntime(previewRuntime, {
304
+ scope: "preview",
305
+ });
306
+ ```
307
+
308
+ Owned elements are marked declaratively:
309
+
310
+ ```html
311
+ <script
312
+ type="solid-jsx"
313
+ data-solid-runtime="preview"
314
+ module="/App.jsx">
315
+ </script>
316
+ ```
317
+
318
+ `data-solid-runtime` is useful for declarative selection and DevTools visibility. It is not the authoritative ownership record; the `WeakMap` points to the actual controller object and prevents two controllers with the same string scope from owning the same element.
319
+
320
+ A scoped controller accepts matching scripts. It may also claim unscoped scripts when `acceptUnscoped` is enabled (default `true`). Setting `acceptUnscoped: false` is recommended when multiple scoped runtimes observe the same DOM root.
321
+
322
+ An unscoped controller does not silently claim a script carrying `data-solid-runtime` for another runtime.
323
+
324
+ ### User-created script elements
325
+
326
+ Applications may create the element themselves and explicitly associate it with one runtime:
327
+
328
+ ```ts
329
+ const script = document.createElement("script");
330
+ script.type = "solid-jsx";
331
+ script.setAttribute("module", "/Preview.jsx");
332
+ script.textContent = source;
333
+
334
+ await previewHTML.append(script);
335
+ ```
336
+
337
+ `append()` performs this ordering:
223
338
 
224
- `observeHTML()` is the live-discovery adapter. It uses `MutationObserver` to discover scripts added after registration. Existing scripts are registered by default; `registerExisting: false` supports the pattern where `registerHTML()` already performed the initial scan.
339
+ ```text
340
+ claim element
341
+ ↓
342
+ stamp data-solid-runtime (when scoped)
343
+ ↓
344
+ append to DOM
345
+ ↓
346
+ load/define module directly
347
+ ↓
348
+ observer later sees mutation and skips duplicate work
349
+ ```
225
350
 
226
- Every observer scan preserves the same graph invariant as `registerHTML()`: all newly discovered modules in that batch are defined before any newly discovered entry is executed. The observer tracks element identity so an already-seen element is not repeatedly redefined on unrelated DOM mutations.
351
+ This is deliberately not implemented as “append and wait for MutationObserver”. Explicit APIs are deterministic even when observation is disabled.
227
352
 
228
- The returned controller exposes:
353
+ For an element already in the DOM:
229
354
 
230
355
  ```ts
231
- observer.initial;
232
- observer.connected;
233
- await observer.flush();
234
- observer.disconnect();
356
+ await previewHTML.registerElement(script);
235
357
  ```
236
358
 
237
- `flush()` waits for queued observer work and performs another scan, making it useful to synchronize application code with asynchronous `src` fetching and module evaluation. Background observer failures may be handled with `onError`.
359
+ ### Controller-created script elements
360
+
361
+ `addModule()` creates and owns the script element for the caller:
238
362
 
239
- Observation in `0.0.2` is intentionally addition-only: changes to attributes/text of an already registered script and removal of that script do not implicitly update or remove its runtime module. Those semantics require explicit runtime updates today and may become a separate future feature.
363
+ ```ts
364
+ await previewHTML.addModule({
365
+ id: "/dynamic/Greeting.jsx",
366
+ source: `
367
+ export function Greeting(props) {
368
+ return <p>Hello {props.name}</p>;
369
+ }
370
+ `,
371
+ });
372
+ ```
240
373
 
241
- This ordering is an invariant: document order must not require dependencies to appear before entries.
374
+ It uses the same claim-before-append pipeline as `append()`.
375
+
376
+ ### One-shot registration and live observation
377
+
378
+ `register()` / `registerHTML()` perform one-shot discovery.
379
+
380
+ `observe()` / `observeHTML()` use `MutationObserver` for newly added scripts. Existing scripts are registered by default; `registerExisting: false` supports the pattern where a one-shot registration already ran.
381
+
382
+ Every discovered batch preserves the graph invariant:
383
+
384
+ ```text
385
+ discover complete batch
386
+ ↓
387
+ claim applicable elements
388
+ ↓
389
+ load all source
390
+ ↓
391
+ define all modules
392
+ ↓
393
+ execute newly discovered entries
394
+ ```
395
+
396
+ An entry may therefore import a dependency that appears later in the same discovery batch.
397
+
398
+ `flush()` waits for queued observer work and scans again, providing a deterministic synchronization point after external DOM mutations.
399
+
400
+ Observation remains addition-only: changing attributes/text of an already owned script or removing it does not implicitly update/remove the runtime module. Module replacement remains explicit through the core runtime update/invalidation APIs.
242
401
 
243
402
  ### Supported script declarations
244
403
 
@@ -278,9 +437,7 @@ Example:
278
437
 
279
438
  The source may move without changing imports of `/ui/Button.jsx`.
280
439
 
281
- If a `src` script omits `module`, its resolved source URL becomes the module ID. This allows multiple URL-backed source scripts to use normal relative imports.
282
-
283
- Inline non-entry scripts require an explicit `module` identity. Inline entries may omit it and receive an anonymous runtime ID.
440
+ If a `src` script omits `module`, its resolved source URL becomes the module ID. Inline non-entry scripts require an explicit `module` identity. Inline entries may omit it and receive an anonymous runtime ID.
284
441
 
285
442
  ### Entry execution
286
443
 
@@ -290,13 +447,7 @@ Inline non-entry scripts require an explicit `module` identity. Inline entries m
290
447
  <script type="solid-jsx" module="/App.jsx" entry>...</script>
291
448
  ```
292
449
 
293
- After all discovered modules are defined, the adapter performs:
294
-
295
- ```ts
296
- await runtime.import("/App.jsx");
297
- ```
298
-
299
- The entry module is expected to perform whatever side effect starts the application, such as calling `render()`.
450
+ After all newly discovered modules in the batch are defined, the adapter imports each entry unless `executeEntries: false` is supplied.
300
451
 
301
452
  ### Explicitly not HTML-as-JSX
302
453
 
@@ -737,3 +888,31 @@ Decision: add `observeHTML()` to the existing `solid-tag-runtime/html` subpath i
737
888
 
738
889
  Reason: applications that dynamically insert runtime modules should not need to manually rescan the document, while keeping DOM observation separate from the core runtime module engine. Addition-only semantics avoid silently redefining modules because of text/attribute churn or trying to infer deletion semantics before the runtime has an explicit module-removal API.
739
890
 
891
+ ### 2026-10-02 — Persistent HTML runtime controllers own DOM/module bindings
892
+
893
+ Decision: `0.0.3` added `createHTMLRuntime(runtime, options)` as the preferred advanced HTML API while keeping `registerHTML()`, `observeHTML()`, and `defineScript()` as compatibility conveniences.
894
+
895
+ Reason: once multiple runtimes, explicit append/register helpers, and observers coexist, ownership must be represented by a persistent object instead of implicit document-wide behavior.
896
+
897
+ ### 2026-10-02 — Runtime script ownership is coordinated through a shared WeakMap
898
+
899
+ Decision: all HTML ingestion paths use one module-level `WeakMap` from script element to ownership/registration record. Per-controller module-ID maps supplement element ownership.
900
+
901
+ Reason: a simple observer-local `WeakSet` cannot prevent races between manual registration and MutationObserver, distinguish different owners, retain a pending registration promise, or reject cross-runtime claims deterministically.
902
+
903
+ ### 2026-10-02 — Explicit append claims before DOM insertion
904
+
905
+ Decision: `html.append(element)` and `html.addModule()` claim ownership before mutating the DOM and register directly rather than relying on the observer callback.
906
+
907
+ Reason: ownership-before-insertion guarantees the observer can only observe already-owned work, eliminating duplicate compilation and making explicit APIs deterministic even when no observer is active.
908
+
909
+ ### 2026-10-02 — HTML runtime scope is declarative metadata, not ownership authority
910
+
911
+ Decision: scoped controllers stamp/use `data-solid-runtime="<scope>"` for discovery and debugging, while the in-memory WeakMap remains authoritative.
912
+
913
+ Reason: attributes are useful across declarative HTML and DevTools but cannot uniquely identify a controller instance or safely coordinate concurrent registration work.
914
+
915
+
916
+ ### 0.0.4 — typing/test/documentation hardening
917
+
918
+ Decision: publish the next package as `0.0.4` because `0.0.3` has already been published. `0.0.4` preserves the `0.0.3` runtime/HTML semantics while shipping the DOM-compatible HTML adapter declaration fixes, broader regression coverage, and updated feature documentation. No module-resolution, ownership, execution-backend, or cache-invalidation semantics change in this release.
package/README.md CHANGED
@@ -100,18 +100,48 @@ The runtime compiles and links the dependency graph automatically.
100
100
 
101
101
  ## Declarative HTML modules
102
102
 
103
- `0.0.2` adds a browser adapter at `solid-tag-runtime/html`. The core runtime remains DOM-independent; the HTML adapter only discovers source modules and feeds them into the same runtime module graph.
103
+ `solid-tag-runtime/html` is the browser/DOM adapter. The core runtime remains DOM-independent.
104
+
105
+ For simple single-runtime use, the original helpers remain available:
104
106
 
105
107
  ```ts
106
- import { registerHTML, observeHTML } from "solid-tag-runtime/html";
108
+ import {
109
+ registerHTML,
110
+ observeHTML,
111
+ } from "solid-tag-runtime/html";
107
112
 
108
113
  await registerHTML(runtime);
109
114
  ```
110
115
 
111
- The adapter recognizes runtime script modules such as:
116
+ For applications that may have multiple runtimes or that create runtime scripts programmatically, `0.0.3` added a persistent HTML runtime controller:
117
+
118
+ ```ts
119
+ import { createHTMLRuntime } from "solid-tag-runtime/html";
120
+
121
+ const html = createHTMLRuntime(runtime, {
122
+ scope: "main",
123
+ root: document,
124
+ });
125
+
126
+ await html.register();
127
+ await html.observe({ registerExisting: false });
128
+ ```
129
+
130
+ A scope is written to owned script elements as:
131
+
132
+ ```html
133
+ <script data-solid-runtime="main" ...></script>
134
+ ```
135
+
136
+ When multiple runtimes observe the same document, give each one a unique scope and normally set `acceptUnscoped: false`.
137
+
138
+ ### Declarative modules
112
139
 
113
140
  ```html
114
- <script type="solid-jsx" module="/ui/Button.jsx">
141
+ <script
142
+ type="solid-jsx"
143
+ data-solid-runtime="main"
144
+ module="/ui/Button.jsx">
115
145
  export function Button(props) {
116
146
  return (
117
147
  <button onClick={props.onClick}>
@@ -120,126 +150,133 @@ The adapter recognizes runtime script modules such as:
120
150
  );
121
151
  }
122
152
  </script>
153
+ ```
123
154
 
124
- <script type="solid-jsx" module="/App.jsx" entry>
125
- import { render } from "@solidjs/web";
126
- import { Button } from "./ui/Button.jsx";
127
-
128
- function App() {
129
- return <Button>Hello from runtime JSX</Button>;
130
- }
155
+ Runtime modules import one another normally:
131
156
 
132
- render(() => <App />, document.getElementById("app"));
133
- </script>
157
+ ```tsx
158
+ import { Button } from "./ui/Button.jsx";
134
159
  ```
135
160
 
136
- All matching scripts are **defined before any `entry` module is executed**. This means an entry may import a module that appears later in the HTML document.
161
+ All newly discovered scripts in one batch are defined before any newly discovered `entry` module executes, so HTML document order does not require dependencies to appear first.
137
162
 
138
- External source is supported as well:
163
+ ### External source
139
164
 
140
165
  ```html
141
166
  <script
142
167
  type="solid-jsx"
168
+ data-solid-runtime="main"
143
169
  module="/ui/Button.jsx"
144
170
  src="./components/Button.jsx">
145
171
  </script>
146
-
147
- <script
148
- type="solid-jsx"
149
- module="/App.jsx"
150
- src="./App.jsx"
151
- entry>
152
- </script>
153
172
  ```
154
173
 
155
- `src` answers **where the source is fetched from** while `module` answers **what its identity is in the runtime graph**. They are intentionally separate.
174
+ `src` answers **where source is loaded from**. `module` answers **what identity the source has in the runtime graph**.
156
175
 
157
- If `module` is omitted for a `src` script, the resolved source URL becomes the module ID. This makes relative imports between externally loaded modules work naturally. Inline non-entry scripts require a `module` attribute; an inline `entry` may omit it and receives an anonymous runtime module ID.
176
+ ### User-created script elements
158
177
 
159
- ### HTML script formats
178
+ If application code creates a script itself, use the controller to associate it with the correct runtime:
160
179
 
161
- Explicit script types:
180
+ ```ts
181
+ const script = document.createElement("script");
182
+ script.type = "solid-jsx";
183
+ script.setAttribute("module", "/dynamic/Greeting.jsx");
184
+ script.textContent = `
185
+ export function Greeting(props) {
186
+ return <p>Hello {props.name}</p>;
187
+ }
188
+ `;
162
189
 
163
- ```text
164
- solid-jsx / text/solid-jsx → JSX transformation
165
- solid-js / text/solid-js → plain JavaScript module
166
- solid-module → infer from module/src extension
190
+ await html.append(script);
167
191
  ```
168
192
 
169
- For `solid-module`, `.js`/`.mjs` are treated as JavaScript and other extensions currently default to JSX. A `language="js"` or `language="jsx"` attribute can override inference.
193
+ `append()` claims the element **before** inserting it in the DOM, stamps the controller scope, then registers it directly. If a `MutationObserver` is active, the later mutation callback sees that the element is already owned and does not compile it twice.
170
194
 
171
- ### Register without executing entries
195
+ For an element that is already in the DOM:
172
196
 
173
197
  ```ts
174
- const registration = await registerHTML(runtime, {
175
- executeEntries: false,
176
- });
177
-
178
- console.log(registration.modules);
179
- console.log(registration.entries);
180
-
181
- await runtime.import(registration.entries[0]);
198
+ await html.registerElement(script);
182
199
  ```
183
200
 
184
- ### Register one script manually
201
+ Same-controller repeated registration is idempotent. Trying to register an element already owned by another HTML controller throws `HTMLModuleOwnershipError`.
185
202
 
186
- ```ts
187
- import { defineScript } from "solid-tag-runtime/html";
203
+ ### Let the controller create the script
188
204
 
189
- const definition = await defineScript(
190
- runtime,
191
- document.querySelector("#runtime-component"),
192
- );
193
-
194
- const namespace = await runtime.import(definition.id);
205
+ ```ts
206
+ await html.addModule({
207
+ id: "/dynamic/Badge.jsx",
208
+ source: `
209
+ export function Badge(props) {
210
+ return <span>{props.children}</span>;
211
+ }
212
+ `,
213
+ });
195
214
  ```
196
215
 
197
- ### Observe scripts added later
216
+ `addModule()` creates the `<script>` element, associates it with the controller, appends it, and registers it.
198
217
 
199
- `observeHTML()` uses `MutationObserver` to register runtime module scripts added after startup. It performs an initial scan by default and preserves the same batch invariant as `registerHTML()`: all newly discovered modules are defined before any newly discovered `entry` executes.
218
+ ### Observe scripts added by other code
200
219
 
201
220
  ```ts
202
- import { observeHTML } from "solid-tag-runtime/html";
203
-
204
- const observer = await observeHTML(runtime, {
221
+ await html.observe({
222
+ registerExisting: false,
205
223
  onError(error) {
206
- console.error("runtime module registration failed", error);
224
+ console.error(error);
207
225
  },
208
226
  });
209
227
 
210
- // Later, code may append a new runtime module script.
228
+ // Some unrelated code mutates the DOM directly.
211
229
  const script = document.createElement("script");
212
230
  script.type = "solid-jsx";
213
- script.setAttribute("module", "/dynamic/Greeting.jsx");
214
- script.textContent = `
215
- export function Greeting(props) {
216
- return <p>Hello {props.name}</p>;
217
- }
218
- `;
231
+ script.setAttribute("data-solid-runtime", "main");
232
+ script.setAttribute("module", "/observed/Thing.jsx");
233
+ script.textContent = `export const value = 42;`;
219
234
  document.body.append(script);
220
235
 
221
- // Normally MutationObserver handles this automatically. flush() is useful when
222
- // code needs to wait until queued observation work has completed.
223
- await observer.flush();
236
+ await html.flush();
237
+ const module = await runtime.import("/observed/Thing.jsx");
238
+ ```
224
239
 
225
- const { Greeting } = await runtime.import("/dynamic/Greeting.jsx");
240
+ The observer is for DOM changes that happen **outside** the controller API. Prefer `html.append()` / `html.addModule()` when your code controls insertion because those operations are deterministic and do not depend on observer timing.
226
241
 
227
- observer.disconnect();
228
- ```
242
+ ### Ownership and deduplication
243
+
244
+ All HTML controllers share an internal `WeakMap` of script element → ownership/registration record.
245
+
246
+ That controller model gives these guarantees:
229
247
 
230
- If existing scripts were already registered separately, start observation without re-registering them:
248
+ - one script element has at most one HTML-runtime owner;
249
+ - manual registration and observer registration cannot compile the same element twice;
250
+ - the same controller can register the same element repeatedly without redefining it;
251
+ - two distinct elements cannot silently define the same HTML-owned module ID;
252
+ - an HTML script cannot silently replace a module already defined outside that HTML controller;
253
+ - `data-solid-runtime` is declarative metadata while the in-memory owner record is authoritative.
254
+
255
+ The controller also exposes lightweight introspection:
231
256
 
232
257
  ```ts
233
- await registerHTML(runtime);
258
+ html.owns(script);
259
+ html.getModuleId(script);
260
+ html.getElement("/dynamic/Greeting.jsx");
261
+ ```
234
262
 
235
- const observer = await observeHTML(runtime, {
236
- registerExisting: false,
237
- });
263
+ ### Script formats
264
+
265
+ ```text
266
+ solid-jsx / text/solid-jsx → JSX transformation
267
+ solid-js / text/solid-js → plain JavaScript module
268
+ solid-module → infer from module/src extension
238
269
  ```
239
270
 
240
- In `0.0.2`, observation is intentionally **addition-only**. Editing attributes/text of an already registered script or removing that script does not automatically update/remove the corresponding runtime module. Use `runtime.update()` / `runtime.invalidate()` explicitly when needed.
271
+ `language="js"` or `language="jsx"` may override inference.
272
+
273
+ ### Addition-only observation
274
+
275
+ Observation remains addition-only in `0.0.4`.
276
+
277
+ Changing the source/attributes of an already owned script or removing it from the DOM does not implicitly update/delete the corresponding runtime module. Use `runtime.update()` / `runtime.invalidate()` for explicit module lifecycle changes.
241
278
 
242
- The HTML adapter does **not** reinterpret ordinary document HTML as JSX and does not currently add `<template>` component semantics. JSX remains source-code syntax inside runtime modules.
279
+ The HTML adapter does **not** reinterpret arbitrary document HTML as JSX and does not currently assign component semantics to `<template>`.
243
280
 
244
281
  ## `toModule()`
245
282
 
package/html.d.ts CHANGED
@@ -4,12 +4,28 @@ import type { ModuleFormat, ModuleNamespaceLike, SolidTagRuntime } from "./index
4
4
  export interface HTMLModuleScriptElement {
5
5
  textContent?: string | null;
6
6
  baseURI?: string;
7
+ ownerDocument?: HTMLDocumentLike | null;
7
8
  getAttribute(name: string): string | null;
8
9
  hasAttribute?(name: string): boolean;
10
+ setAttribute?(name: string, value: string): void;
11
+ }
12
+
13
+ export interface HTMLAppendTarget {
14
+ append?(...nodes: any[]): void;
15
+ appendChild?(element: any): unknown;
16
+ }
17
+
18
+ export interface HTMLDocumentLike extends HTMLModuleRoot, HTMLAppendTarget {
19
+ body?: HTMLAppendTarget;
20
+ documentElement?: HTMLAppendTarget;
21
+ createElement?(tagName: string): any;
9
22
  }
10
23
 
11
24
  export interface HTMLModuleRoot {
12
25
  baseURI?: string;
26
+ ownerDocument?: HTMLDocumentLike | null;
27
+ body?: HTMLAppendTarget;
28
+ documentElement?: HTMLAppendTarget;
13
29
  querySelectorAll(selector: string): Iterable<HTMLModuleScriptElement> | ArrayLike<HTMLModuleScriptElement>;
14
30
  }
15
31
 
@@ -44,6 +60,10 @@ export interface DefineScriptOptions {
44
60
  baseUrl?: string;
45
61
  format?: ModuleFormat | "javascript";
46
62
  fetch?: HTMLFetch;
63
+ /** Declarative ownership scope stored in data-solid-runtime. */
64
+ scope?: string;
65
+ /** Whether an HTML runtime may claim scripts without data-solid-runtime. Default: true. */
66
+ acceptUnscoped?: boolean;
47
67
  }
48
68
 
49
69
  export interface HTMLModuleDefinition {
@@ -80,22 +100,89 @@ export interface ObserveHTMLOptions extends RegisterHTMLOptions {
80
100
  onError?: (error: unknown) => void;
81
101
  }
82
102
 
83
- export interface HTMLObserverController {
84
- /** Result of the initial scan. Empty when registerExisting is false. */
85
- initial: RegisterHTMLResult;
103
+ export interface AddHTMLModuleOptions extends DefineScriptOptions {
104
+ id?: string;
105
+ module?: string;
106
+ source?: string;
107
+ src?: string;
108
+ entry?: boolean;
109
+ type?: string;
110
+ language?: string;
111
+ executeEntries?: boolean;
112
+ appendTo?: HTMLAppendTarget;
113
+ document?: HTMLDocumentLike;
114
+ createElement?: (tagName: string) => HTMLModuleScriptElement;
115
+ }
116
+
117
+ export interface HTMLRuntimeOptions extends ObserveHTMLOptions {
118
+ appendTo?: HTMLAppendTarget;
119
+ createElement?: (tagName: string) => HTMLModuleScriptElement;
120
+ }
121
+
122
+ export interface HTMLRuntimeController {
123
+ readonly runtime: SolidTagRuntime;
124
+ readonly scope?: string;
86
125
  readonly connected: boolean;
87
- /** Wait for queued observer work and synchronously scan for any unseen scripts. */
88
- flush(): Promise<RegisterHTMLResult>;
126
+ /** Result of the observer's initial scan. */
127
+ readonly initial: RegisterHTMLResult;
128
+
129
+ /** One-shot scan of matching scripts under the configured/root override. */
130
+ register(options?: RegisterHTMLOptions): Promise<RegisterHTMLResult>;
131
+
132
+ /** Start live addition observation. Returns this controller. */
133
+ observe(options?: ObserveHTMLOptions): Promise<HTMLRuntimeController>;
134
+
135
+ /** Wait for queued observer work and scan for newly discoverable scripts. */
136
+ flush(options?: RegisterHTMLOptions): Promise<RegisterHTMLResult>;
89
137
  disconnect(): void;
138
+
139
+ /** Define one element without auto-running an entry. */
140
+ defineElement(
141
+ element: HTMLModuleScriptElement,
142
+ options?: DefineScriptOptions,
143
+ ): Promise<HTMLModuleDefinition>;
144
+
145
+ /** Explicitly claim/register an existing element for this runtime. */
146
+ registerElement(
147
+ element: HTMLModuleScriptElement,
148
+ options?: RegisterHTMLOptions,
149
+ ): Promise<HTMLModuleDefinition>;
150
+
151
+ /** Claim first, append a user-created element, then register it directly. */
152
+ append(
153
+ element: HTMLModuleScriptElement,
154
+ options?: RegisterHTMLOptions & { appendTo?: HTMLAppendTarget },
155
+ ): Promise<HTMLModuleDefinition>;
156
+
157
+ /** Create a runtime script element and add it through the controller. */
158
+ addModule(options: AddHTMLModuleOptions): Promise<HTMLModuleDefinition>;
159
+
160
+ owns(element: HTMLModuleScriptElement): boolean;
161
+ getModuleId(element: HTMLModuleScriptElement): string | undefined;
162
+ getElement(id: string): HTMLModuleScriptElement | undefined;
90
163
  }
91
164
 
165
+ /** Legacy observer shape is now the full HTML runtime controller. */
166
+ export type HTMLObserverController = HTMLRuntimeController;
167
+
92
168
  export declare class HTMLModuleError extends SolidTagRuntimeError {
93
169
  element?: HTMLModuleScriptElement;
94
170
  moduleId?: string;
95
171
  sourceUrl?: string;
96
172
  }
97
173
 
174
+ export declare class HTMLModuleOwnershipError extends HTMLModuleError {
175
+ ownerScope?: string;
176
+ requestedScope?: string;
177
+ }
178
+
98
179
  export declare const htmlModuleSelector: string;
180
+ export declare const htmlRuntimeScopeAttribute: "data-solid-runtime";
181
+
182
+ export declare function createHTMLRuntime(
183
+ runtime: SolidTagRuntime,
184
+ options?: HTMLRuntimeOptions,
185
+ ): HTMLRuntimeController;
99
186
 
100
187
  export declare function defineScript(
101
188
  runtime: SolidTagRuntime,