solid-tag-runtime 0.0.8 → 0.0.11
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 +92 -1
- package/README.md +187 -5
- package/html.d.ts +120 -65
- package/package.json +1 -1
- package/src/html.js +872 -65
- package/src/render.js +205 -0
- package/src/runtime.js +8 -0
package/ARCHITECTURE.md
CHANGED
|
@@ -42,7 +42,9 @@ The runtime should allow applications to:
|
|
|
42
42
|
9. observe runtime lifecycle transitions for tooling/tracing
|
|
43
43
|
10. inspect dependencies and compiled source
|
|
44
44
|
11. support normal JavaScript modules in the same graph
|
|
45
|
-
12.
|
|
45
|
+
12. declaratively mount runtime component exports through the HTML adapter
|
|
46
|
+
13. reuse existing runtime modules through a light-DOM `solid-render` custom element
|
|
47
|
+
14. keep the JSX compiler replaceable behind a narrow adapter
|
|
46
48
|
|
|
47
49
|
## 3. Current non-goals
|
|
48
50
|
|
|
@@ -1120,6 +1122,7 @@ root-changed
|
|
|
1120
1122
|
append-target-changed
|
|
1121
1123
|
entry-executing
|
|
1122
1124
|
entry-executed
|
|
1125
|
+
html-warning
|
|
1123
1126
|
html-error
|
|
1124
1127
|
```
|
|
1125
1128
|
|
|
@@ -1144,3 +1147,91 @@ Implementation note: core and HTML event streams share a small internal dispatch
|
|
|
1144
1147
|
|
|
1145
1148
|
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
1149
|
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
### 0.0.9 — shared declarative rendering and `solid-render`
|
|
1153
|
+
|
|
1154
|
+
Decision: rendering remains entirely inside `solid-tag-runtime/html`. The core runtime still owns module identity, resolution, linking, execution, caching, invalidation, and host-module injection; it has no DOM or component-mounting responsibility.
|
|
1155
|
+
|
|
1156
|
+
Two public rendering forms now share one internal rendering core:
|
|
1157
|
+
|
|
1158
|
+
```text
|
|
1159
|
+
<script module render>
|
|
1160
|
+
define source + mount one component instance
|
|
1161
|
+
|
|
1162
|
+
<solid-render module>
|
|
1163
|
+
reference an existing module + mount one component instance
|
|
1164
|
+
```
|
|
1165
|
+
|
|
1166
|
+
Declarative script rendering follows these invariants:
|
|
1167
|
+
|
|
1168
|
+
- `render="#selector"` imports the module, selects `default` unless `component="Name"` is present, and uses normal Solid container rendering.
|
|
1169
|
+
- bare `render` replaces the declaration with start/end comment markers and mounts with positional insertion before the end marker; no wrapper element is introduced.
|
|
1170
|
+
- every discovered module in a batch is defined before any `entry` or render action executes.
|
|
1171
|
+
- `entry` and `render` on the same declaration are rejected as ambiguous.
|
|
1172
|
+
- anonymous `render` declarations receive internal runtime IDs just like anonymous entries.
|
|
1173
|
+
- render ownership/disposal is stored on the HTML declaration record and remains separate from module lifetime.
|
|
1174
|
+
- `updateElement()` remounts a rendered declaration after source/component/render metadata changes while preserving the same logical module identity.
|
|
1175
|
+
- `removeElement()` disposes mounted UI before releasing declaration/module ownership.
|
|
1176
|
+
- observer-discovered render declarations use the same batch/ownership pipeline as ordinary declarations.
|
|
1177
|
+
|
|
1178
|
+
The shared render adapter lazily resolves the host application's own `solid-js` and `@solidjs/web` modules through the runtime (with `solid-js/web` as a compatibility fallback). This preserves the no-duplicate-Solid invariant and keeps the HTML package free of a direct Solid dependency. Tests/special hosts may inject a render adapter.
|
|
1179
|
+
|
|
1180
|
+
`solid-render` invariants:
|
|
1181
|
+
|
|
1182
|
+
1. It references an existing runtime module; it never defines source.
|
|
1183
|
+
2. Missing `component` means `namespace.default`; `component="Name"` selects a named export.
|
|
1184
|
+
3. `data-solid-runtime` selects a matching HTML controller whose configured root contains the element. Without the attribute, controller selection follows the same rule as unscoped script discovery: a containing scoped controller may participate when `acceptUnscoped:true`, while an unscoped controller naturally accepts it. Equally specific matches are ambiguous and require explicit scope. A controller outside the element's root is never selected merely because it is the only candidate.
|
|
1185
|
+
4. The element remains in the DOM and is the light-DOM mount container. Wrapperless rendering belongs to bare `<script render>`.
|
|
1186
|
+
5. Renderer configuration (`module`, `component`, `data-solid-runtime`) is never forwarded as component props.
|
|
1187
|
+
6. Declarative props use `prop:*`; kebab names normalize to camelCase. Empty/presence values are boolean `true`, other values remain strings.
|
|
1188
|
+
7. `.props` carries arbitrary JavaScript references and overrides declarative props.
|
|
1189
|
+
8. Prop changes update a reactive prop facade and do not remount the component, preserving local state.
|
|
1190
|
+
9. Module/component/runtime identity changes increment a generation token, dispose the current owner, and remount. Stale async import successes and failures are ignored; they cannot mount or report an error against a newer identity.
|
|
1191
|
+
10. Initial light-DOM child nodes are captured once and exposed as reusable `props.children`; named slots and dynamic child recapture are not part of this phase.
|
|
1192
|
+
11. Multiple elements may share one evaluated module namespace while owning independent Solid component roots.
|
|
1193
|
+
12. Disconnect disposes the mounted root; reconnect mounts a fresh component instance from the retained declaration inputs.
|
|
1194
|
+
13. Custom-element registration is global/idempotent per `CustomElementRegistry`. `createHTMLRuntime()` registers it after installing the controller in the shared registry; registration/observation paths remain idempotent. `registerSolidRenderElement()` remains available for explicit/custom-registry use.
|
|
1195
|
+
14. Runtime/controller disposal tears down both script-owned mounts and connected `solid-render` instances so no Solid owners are orphaned.
|
|
1196
|
+
|
|
1197
|
+
Rendering lifecycle joins the existing HTML event stream through `render-mounting`, `render-mounted`, `render-disposing`, and `render-disposed`; failures are also reported through `html-error` with `render`/`solid-render` operations. Lifecycle subscriptions remain observational and cannot alter rendering.
|
|
1198
|
+
|
|
1199
|
+
The first `solid-render` phase intentionally excludes named slots, Shadow DOM, automatic numeric/JSON coercion, arbitrary unprefixed prop forwarding, loading/fallback templates, and expression evaluation inside attributes.
|
|
1200
|
+
|
|
1201
|
+
### 0.0.10 — unresolved scoped render diagnostics
|
|
1202
|
+
|
|
1203
|
+
Decision: a declarative `<script render>` with an explicit `data-solid-runtime` scope must not disappear silently when no registered HTML controller can perform that immediate render action.
|
|
1204
|
+
|
|
1205
|
+
The diagnostic remains an HTML-adapter concern. Core runtime resolution and module semantics are unchanged.
|
|
1206
|
+
|
|
1207
|
+
Rules:
|
|
1208
|
+
|
|
1209
|
+
1. Plain scoped module declarations remain quiet when seen by a non-matching controller; scope filtering is still normal routing behavior.
|
|
1210
|
+
2. An active render declaration (`render` present and `executeRenders !== false`) is immediate work. If no live controller with the requested scope has a root containing that declaration, discovery emits one warning.
|
|
1211
|
+
3. The warning is deduplicated per element + requested scope across overlapping controller scans. Repeated `register()` / observer passes must not spam the console.
|
|
1212
|
+
4. If a matching scoped controller is already registered and can cover the element's root, other controllers silently ignore the declaration and no warning is emitted.
|
|
1213
|
+
5. `executeRenders:false` intentionally disables render execution and therefore suppresses the missing-scope warning.
|
|
1214
|
+
6. The diagnostic is observable as `html-warning` with `code: "unresolved-runtime-scope"`, and is also surfaced through `console.warn` for developers who have not installed lifecycle tooling.
|
|
1215
|
+
7. `<solid-render>` remains stricter: a connected custom element that cannot resolve its runtime reports a render error because it is itself the active renderer.
|
|
1216
|
+
|
|
1217
|
+
The warning belongs at the shared controller-registry/discovery boundary rather than being treated as an ownership or module-resolution error. This preserves the distinction between ordinary cross-scope filtering and an unfulfilled immediate render request.
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
### 0.0.11 — `solid-render` routing parity and virtual top-level import safety
|
|
1222
|
+
|
|
1223
|
+
Decision: `<solid-render>` controller selection must use the same scope/`acceptUnscoped`/root-boundary semantics as declarative script discovery.
|
|
1224
|
+
|
|
1225
|
+
The 0.0.10 custom-element resolver treated an unscoped `<solid-render>` differently from an unscoped `<script>` declaration: it preferred controllers whose own scope was empty and could fall back to a sole candidate even when that controller's root did not contain the element. In pages/playgrounds with multiple active controllers this could select the wrong runtime. A registered virtual module such as `/ui/Button.jsx` would then appear missing and `runtime.import()` could fall through to native ESM loading, producing misleading network URLs such as an esm.sh-relative path.
|
|
1226
|
+
|
|
1227
|
+
Rules now enforced:
|
|
1228
|
+
|
|
1229
|
+
1. Explicit `data-solid-runtime="name"` considers only live controllers with that scope and whose root contains the element.
|
|
1230
|
+
2. An unscoped `<solid-render>` considers every containing controller that would accept an unscoped declaration: unscoped controllers plus scoped controllers with `acceptUnscoped:true`.
|
|
1231
|
+
3. When multiple containing controllers match, the most-specific root wins when one root is strictly nested inside the others; otherwise the selection is ambiguous and reports a render error.
|
|
1232
|
+
4. A controller outside the element's DOM root is never used as a fallback.
|
|
1233
|
+
5. Top-level `runtime.import()` now mirrors static-link resolution for virtual paths: unresolved relative (`./x`) and absolute virtual (`/x`) specifiers throw `ModuleResolutionError` even when `allowNativeImports:true`.
|
|
1234
|
+
6. Native fallback remains available for unresolved bare specifiers when `allowNativeImports:true`, and real absolute URLs remain native-loadable.
|
|
1235
|
+
7. `/ui/Button.jsx` and `./ui/Button.jsx` both resolve to the same registered virtual ID `/ui/Button.jsx` when imported at top level from the correct runtime.
|
|
1236
|
+
|
|
1237
|
+
This keeps DOM routing and module routing failures separate and produces actionable errors instead of accidental browser network requests.
|
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.11",
|
|
111
|
+
"solid-tag-runtime/html": "https://esm.sh/solid-tag-runtime@0.0.11/html"
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
```
|
|
@@ -138,6 +138,166 @@ await html.register();
|
|
|
138
138
|
await html.observe({ registerExisting: false });
|
|
139
139
|
```
|
|
140
140
|
|
|
141
|
+
|
|
142
|
+
## Render runtime UI
|
|
143
|
+
|
|
144
|
+
`solid-tag-runtime/html` can now mount component exports as an HTML-adapter concern while the core runtime remains DOM-independent.
|
|
145
|
+
|
|
146
|
+
There are two complementary forms:
|
|
147
|
+
|
|
148
|
+
```text
|
|
149
|
+
<script module>
|
|
150
|
+
define a runtime module
|
|
151
|
+
|
|
152
|
+
<script module render>
|
|
153
|
+
define a module + mount one instance
|
|
154
|
+
|
|
155
|
+
<solid-render module>
|
|
156
|
+
reference an existing module + mount one instance
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Define and render in one declaration
|
|
160
|
+
|
|
161
|
+
Render the default export into a normal Solid container:
|
|
162
|
+
|
|
163
|
+
```html
|
|
164
|
+
<div id="app"></div>
|
|
165
|
+
|
|
166
|
+
<script
|
|
167
|
+
type="solid-jsx"
|
|
168
|
+
data-solid-runtime="main"
|
|
169
|
+
module="/App.jsx"
|
|
170
|
+
render="#app"
|
|
171
|
+
>
|
|
172
|
+
export default function App() {
|
|
173
|
+
return <h1>Hello from runtime JSX</h1>;
|
|
174
|
+
}
|
|
175
|
+
</script>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
`render` defaults to `module.default`. Select a named export with `component`:
|
|
179
|
+
|
|
180
|
+
```html
|
|
181
|
+
<script
|
|
182
|
+
type="solid-jsx"
|
|
183
|
+
module="/widgets.jsx"
|
|
184
|
+
render="#app"
|
|
185
|
+
component="Counter"
|
|
186
|
+
>
|
|
187
|
+
export function Counter() {
|
|
188
|
+
return <button>Counter</button>;
|
|
189
|
+
}
|
|
190
|
+
</script>
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Bare `render` mounts at the declaration's exact sibling position without adding a wrapper:
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<p>Before</p>
|
|
197
|
+
|
|
198
|
+
<script type="solid-jsx" module="/Message.jsx" render>
|
|
199
|
+
export default function Message() {
|
|
200
|
+
return <strong>Hello</strong>;
|
|
201
|
+
}
|
|
202
|
+
</script>
|
|
203
|
+
|
|
204
|
+
<p>After</p>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
The adapter replaces the declaration with an owned start/end marker range and inserts the component between the markers. The module definition and mount lifecycle remain separate: removing the declaration through `html.removeElement()` disposes the Solid owner while module removal follows the existing lifecycle options.
|
|
208
|
+
|
|
209
|
+
`entry` and `render` are intentionally mutually exclusive on one declaration. Use separate declarations when a side-effect entry and a mounted component are both needed.
|
|
210
|
+
|
|
211
|
+
All matching modules in one scan/observer batch are defined before any `entry` or `render` action executes, so a render declaration may import a dependency declared later in the same batch.
|
|
212
|
+
|
|
213
|
+
### Reuse an existing module with `<solid-render>`
|
|
214
|
+
|
|
215
|
+
`<solid-render>` references an already-defined module and remains as the light-DOM mount container:
|
|
216
|
+
|
|
217
|
+
```html
|
|
218
|
+
<solid-render
|
|
219
|
+
data-solid-runtime="main"
|
|
220
|
+
module="/Counter.jsx"
|
|
221
|
+
></solid-render>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Named export:
|
|
225
|
+
|
|
226
|
+
```html
|
|
227
|
+
<solid-render
|
|
228
|
+
data-solid-runtime="main"
|
|
229
|
+
module="/widgets.jsx"
|
|
230
|
+
component="Counter"
|
|
231
|
+
></solid-render>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Component props use an explicit namespace so renderer configuration can never collide with component prop names:
|
|
235
|
+
|
|
236
|
+
```html
|
|
237
|
+
<solid-render
|
|
238
|
+
module="/UserCard.jsx"
|
|
239
|
+
prop:name="Alice"
|
|
240
|
+
prop:module="billing"
|
|
241
|
+
prop:compact
|
|
242
|
+
></solid-render>
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Declarative values are conservative:
|
|
246
|
+
|
|
247
|
+
```text
|
|
248
|
+
prop:name="Alice" → "Alice"
|
|
249
|
+
prop:compact → true
|
|
250
|
+
prop:count="42" → "42"
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Kebab-case prop names normalize to camelCase (`prop:user-id` → `userId`). Arbitrary JavaScript references use the `.props` property:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
const renderer = document.querySelector("solid-render");
|
|
257
|
+
|
|
258
|
+
renderer.props = {
|
|
259
|
+
user,
|
|
260
|
+
onSave,
|
|
261
|
+
service,
|
|
262
|
+
};
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Programmatic props override `prop:*` attributes. Prop changes update the existing component instance reactively and preserve local Solid state. Changes to `module`, `component`, or `data-solid-runtime` dispose the current component and mount a new identity.
|
|
266
|
+
|
|
267
|
+
Initial light-DOM children become `props.children`:
|
|
268
|
+
|
|
269
|
+
```html
|
|
270
|
+
<solid-render module="/Card.jsx" prop:title="Profile">
|
|
271
|
+
<p>Hello from HTML.</p>
|
|
272
|
+
<solid-render module="/SaveButton.jsx"></solid-render>
|
|
273
|
+
</solid-render>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
The first implementation deliberately has no named-slot system and no Shadow DOM. Nested `<solid-render>` elements work through normal custom-element connection when captured children are instantiated.
|
|
277
|
+
|
|
278
|
+
`createHTMLRuntime()` ensures the custom element is registered globally once after the controller has entered the shared runtime registry. `registerHTML()` / `observeHTML()` keep the same idempotent guarantee. Most applications therefore do not need to call a registration helper directly.
|
|
279
|
+
|
|
280
|
+
For custom registries, tests, or explicit registration, the helper remains available:
|
|
281
|
+
|
|
282
|
+
```ts
|
|
283
|
+
import { registerSolidRenderElement } from "solid-tag-runtime/html";
|
|
284
|
+
|
|
285
|
+
registerSolidRenderElement();
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Multiple `<solid-render>` elements may share one cached runtime module namespace while each mounted component owns independent Solid state. Async module changes are generation-guarded so a stale import can never replace a newer `module`/`component`/runtime selection.
|
|
289
|
+
|
|
290
|
+
`<solid-render>` uses the same runtime-routing rules as declarative scripts. An explicit `data-solid-runtime` selects a controller with that scope **whose root contains the element**. Without an explicit scope, any containing controller that accepts unscoped declarations (`acceptUnscoped: true`) may handle the element. If more than one equally specific controller can handle it, add `data-solid-runtime` to disambiguate. Controllers outside the element's DOM root are never selected as a fallback.
|
|
291
|
+
|
|
292
|
+
Both of these reference the same registered virtual module when used with the correct runtime:
|
|
293
|
+
|
|
294
|
+
```html
|
|
295
|
+
<solid-render module="/ui/Button.jsx"></solid-render>
|
|
296
|
+
<solid-render module="./ui/Button.jsx"></solid-render>
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Top-level relative module references are normalized as virtual paths; they are not browser URL fetches.
|
|
300
|
+
|
|
141
301
|
A scope is written to owned script elements as:
|
|
142
302
|
|
|
143
303
|
```html
|
|
@@ -146,6 +306,18 @@ A scope is written to owned script elements as:
|
|
|
146
306
|
|
|
147
307
|
When multiple runtimes observe the same document, give each one a unique scope and normally set `acceptUnscoped: false`.
|
|
148
308
|
|
|
309
|
+
A scoped declaration that only defines a module may be ignored by non-matching controllers without noise. A scoped declaration with active `render` semantics is different: rendering requests immediate UI work. If no registered HTML runtime with that scope can handle the declaration's DOM root, the adapter emits one deduplicated console warning and an `html-warning` lifecycle event with `code: "unresolved-runtime-scope"`. `executeRenders: false` suppresses this diagnostic because rendering was explicitly disabled.
|
|
310
|
+
|
|
311
|
+
```ts
|
|
312
|
+
html.subscribe("html-warning", event => {
|
|
313
|
+
if (event.code === "unresolved-runtime-scope") {
|
|
314
|
+
console.warn(event.requestedScope, event.moduleId);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
`<solid-render>` keeps stronger semantics: when it actively connects and cannot resolve its selected runtime, that is a render error rather than only a warning.
|
|
320
|
+
|
|
149
321
|
### Declarative modules
|
|
150
322
|
|
|
151
323
|
```html
|
|
@@ -689,12 +861,20 @@ append-target-changed
|
|
|
689
861
|
entry-executing
|
|
690
862
|
entry-executed
|
|
691
863
|
|
|
864
|
+
render-mounting
|
|
865
|
+
render-mounted
|
|
866
|
+
render-disposing
|
|
867
|
+
render-disposed
|
|
868
|
+
|
|
869
|
+
html-warning
|
|
692
870
|
html-error
|
|
693
871
|
```
|
|
694
872
|
|
|
695
873
|
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.
|
|
696
874
|
|
|
697
|
-
`
|
|
875
|
+
`html-warning` currently reports non-fatal adapter diagnostics. `unresolved-runtime-scope` is emitted once per render declaration/scope when `data-solid-runtime` requests immediate rendering but no registered controller can handle that scoped declaration. The event includes `requestedScope`, `registeredScopes`, `moduleId` when available, and whether a matching scope exists outside the declaration's root.
|
|
876
|
+
|
|
877
|
+
`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()`. Render events cover both `<script render>` and `<solid-render>`; `source` identifies `script-render` versus `solid-render`, and `mode` identifies selector, in-place, or container mounting.
|
|
698
878
|
|
|
699
879
|
Like core runtime subscribers, HTML subscribers are observational and exception-isolated.
|
|
700
880
|
|
|
@@ -762,7 +942,7 @@ Default runtime resolution supports:
|
|
|
762
942
|
|
|
763
943
|
`allowNativeImports` defaults to `true`.
|
|
764
944
|
|
|
765
|
-
This means an unresolved bare import can be left for the browser's native module resolver/import map:
|
|
945
|
+
This means an unresolved **bare** import can be left for the browser's native module resolver/import map:
|
|
766
946
|
|
|
767
947
|
```ts
|
|
768
948
|
const runtime = createRuntime({
|
|
@@ -770,7 +950,9 @@ const runtime = createRuntime({
|
|
|
770
950
|
});
|
|
771
951
|
```
|
|
772
952
|
|
|
773
|
-
|
|
953
|
+
Relative and absolute virtual paths are different. If `/ui/Button.jsx` or `./ui/Button.jsx` does not resolve to a registered runtime module, `runtime.import()` throws `ModuleResolutionError`; it does not turn the path into a browser/native network import. Use `defineUrl()` or an actual absolute URL when native URL loading is intended.
|
|
954
|
+
|
|
955
|
+
Set `allowNativeImports` to `false` when even unresolved bare imports must be explicitly registered with the runtime.
|
|
774
956
|
|
|
775
957
|
## Runtime lifecycle
|
|
776
958
|
|