@xmachines/play-vue 6.1.0 → 7.0.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.
- package/README.md +17 -15
- package/dist/ActorProvider.js.map +1 -1
- package/dist/ActorProvider.vue.d.ts +61 -0
- package/dist/ActorProvider.vue.d.ts.map +1 -0
- package/dist/ActorProvider.vue_vue_type_script_lang.js +40 -104
- package/dist/ActorProvider.vue_vue_type_script_lang.js.map +1 -1
- package/dist/PlayRenderer.js.map +1 -1
- package/dist/PlayRenderer.vue.d.ts +6 -0
- package/dist/PlayRenderer.vue.d.ts.map +1 -0
- package/dist/PlayUIProvider.js.map +1 -1
- package/dist/PlayUIProvider.vue.d.ts +85 -0
- package/dist/PlayUIProvider.vue.d.ts.map +1 -0
- package/dist/PlayUIProvider.vue_vue_type_script_lang.js.map +1 -1
- package/dist/define-registry.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +8 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +24 -23
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Vue 3 renderer for the XMachines Play Architecture. It observes the actor atoms and renders the UI through `@xmachines/json-render-vue`.
|
|
4
4
|
|
|
5
|
-
[](https://opensource.org/licenses/MIT) [](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/@xmachines/play-vue)
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -27,7 +27,7 @@ pnpm add @xmachines/play-vue
|
|
|
27
27
|
**Peer dependencies.** Install them with the package:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
pnpm add vue@^3.5.
|
|
30
|
+
pnpm add vue@^3.5.11 @xmachines/core @xmachines/play @xmachines/play-atom @xstate/store@^4.2.3 @xmachines/json-render-vue@0.21.0-xm.6 @xmachines/json-render-core@0.21.0-xm.6 @xmachines/json-render-xstate@0.21.0-xm.6
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
`@xstate/store` is the peer of [`@xmachines/play-atom`](../play-atom/README.md), and not of this
|
|
@@ -83,20 +83,20 @@ const registryResult = defineRegistry(myCatalog, {
|
|
|
83
83
|
|
|
84
84
|
The composite provider. It wraps `<ActorProvider>` and `JSONUIProvider` in one component. **Use it in most applications.**
|
|
85
85
|
|
|
86
|
-
| Prop | Type | Required | Description
|
|
87
|
-
| --------------------- | --------------------------------------------- | -------- |
|
|
88
|
-
| `actor` | `PlayActor & Viewable` | ✅ | The XMachines actor instance
|
|
89
|
-
| `registryResult` | `DefineRegistryResult` | ✅ | Result of `defineRegistry()`
|
|
90
|
-
| `store` | `StateStore` | — | External controlled state store (optional)
|
|
91
|
-
| `onRenderError` | `
|
|
92
|
-
| `onError` | `(error: unknown, reset: () => void) => void` | — | Error handler of the outer boundary; the second parameter is the reset
|
|
93
|
-
| `navigate` | `(path: string) => void` | — | Link navigation function
|
|
94
|
-
| `validationFunctions` | `Record<string, Function>` | — | Custom validation functions
|
|
95
|
-
| `functions` | `Record<string, Function>` | — | Named functions for `$computed` expressions
|
|
86
|
+
| Prop | Type | Required | Description |
|
|
87
|
+
| --------------------- | --------------------------------------------- | -------- | -------------------------------------------------------------------------- |
|
|
88
|
+
| `actor` | `PlayActor & Viewable` | ✅ | The XMachines actor instance |
|
|
89
|
+
| `registryResult` | `DefineRegistryResult` | ✅ | Result of `defineRegistry()` |
|
|
90
|
+
| `store` | `StateStore` | — | External controlled state store (optional) |
|
|
91
|
+
| `onRenderError` | `OnRenderError` | — | The `(error, name, info)` handler of each failure that json-render reports |
|
|
92
|
+
| `onError` | `(error: unknown, reset: () => void) => void` | — | Error handler of the outer boundary; the second parameter is the reset |
|
|
93
|
+
| `navigate` | `(path: string) => void` | — | Link navigation function |
|
|
94
|
+
| `validationFunctions` | `Record<string, Function>` | — | Custom validation functions |
|
|
95
|
+
| `functions` | `Record<string, Function>` | — | Named functions for `$computed` expressions |
|
|
96
96
|
|
|
97
97
|
**Slots:** `default` (the rendered content), `fallback` (the content while the actor view is `null`, and while the boundary holds an error)
|
|
98
98
|
|
|
99
|
-
The provider contains an error of the **render** of a descendant — the render function, the setup function, and a lifecycle hook — so that a subtree that throws cannot take the whole application down. It calls `onError`, and it renders the `fallback` slot instead of the children. The next view emission clears the error, so a view transition retries the render. A throw of a catalog component reaches the per-element boundary of `@xmachines/json-render-vue` first, and `onRenderError` reports it
|
|
99
|
+
The provider contains an error of the **render** of a descendant — the render function, the setup function, and a lifecycle hook — so that a subtree that throws cannot take the whole application down. It calls `onError`, and it renders the `fallback` slot instead of the children. The next view emission clears the error, so a view transition retries the render. A throw of a catalog component below the root reaches the per-element boundary of `@xmachines/json-render-vue` first, and `onRenderError` reports it. A failure of the root of the view — its component, a prop, or its `visible` condition — reaches no hook of the host, so the provider contains it as a failure of the view: it calls `onError` one time, it renders the `fallback` slot, and the next view renders again. `onRenderError` also receives it, with the kind `"root"`. This boundary is the outer net for everything else.
|
|
100
100
|
|
|
101
101
|
The boundary stops a render error, so `app.config.errorHandler` does not see it. Without an `onError` prop the provider therefore writes the error to `console.error`.
|
|
102
102
|
|
|
@@ -110,6 +110,8 @@ Vue reports such an error a **second** time where the application wires no `app.
|
|
|
110
110
|
|
|
111
111
|
**One case escapes that rule.** An ancestor `errorCaptured` hook that returns `false` stops Vue before the re-throw, so the record of the provider waits for a repeat that never comes. A second failure in the same flush can take that record. It must carry the same error value, and it must unwind out of the update job of a parent. Vue reports such a failure as a component update. The provider then holds the stale subtree on the screen, and `onError` stays silent.
|
|
112
112
|
|
|
113
|
+
An event handler of a catalog component below the `Renderer` of `@xmachines/json-render-vue` is different. That renderer throws the error of such a handler again in place, so the window gets it as an `error` event. Neither this provider nor `app.config.errorHandler` sees it.
|
|
114
|
+
|
|
113
115
|
#### `<PlayRenderer>`
|
|
114
116
|
|
|
115
117
|
The leaf component without props. It reads the current `spec` and `registry` from the nearest `<ActorProvider>` or `<PlayUIProvider>` context, then renders them with `<Renderer>`. Put it inside one of those providers.
|
|
@@ -129,7 +131,7 @@ The low-level provider for a custom provider composition. It owns the complete a
|
|
|
129
131
|
| `actor` | `PlayActor & Viewable` | ✅ | The XMachines actor instance |
|
|
130
132
|
| `registryResult` | `DefineRegistryResult` | ✅ | Result of `defineRegistry()` |
|
|
131
133
|
| `store` | `StateStore` | — | External controlled state store |
|
|
132
|
-
| `onRenderError` | `
|
|
134
|
+
| `onRenderError` | `OnRenderError` | — | Override render error handler |
|
|
133
135
|
|
|
134
136
|
---
|
|
135
137
|
|
|
@@ -139,7 +141,7 @@ The low-level provider for a custom provider composition. It owns the complete a
|
|
|
139
141
|
|
|
140
142
|
This function is the drop-in replacement for `defineRegistry` from `@xmachines/json-render-vue`. **Always import it from `@xmachines/play-vue`** when you work with a Vue SFC, not from `@xmachines/json-render-vue`. The wrapper finds each `.vue` SFC in the `components` map, and wraps it with `h()`. A Vue composable, and also a composable that uses `inject`, then works correctly inside `<script setup>`.
|
|
141
143
|
|
|
142
|
-
```typescript
|
|
144
|
+
```typescript fragment
|
|
143
145
|
import { defineRegistry } from "@xmachines/play-vue";
|
|
144
146
|
// NOT: import { defineRegistry } from "@xmachines/json-render-vue"
|
|
145
147
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActorProvider.js","names":[],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — the low-level provider of the XMachines Vue render architecture.\n *\n * It owns the complete actor lifecycle:\n * - the atom subscription (watchAtom), which connects the atoms to the Vue reactivity\n * - the StateStore lifecycle of each view, controlled and uncontrolled\n * - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider\n * - the ViewContextValue, which it provides through the ViewKey injection key\n * - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below\n * - the injection of onRenderError into the registry\n *\n * The author of a library who needs this control uses the component directly.\n * An end user takes <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - the Actor decides each state transition, with its guards\n * @invariant Passive Infrastructure - the component observes the atoms, and it sends the events\n * @invariant Atom-Only Reactivity - the state of the business logic is in the actor atoms\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\tonErrorCaptured,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n\tgetCurrentInstance,\n} from \"vue\";\nimport type { ComponentPublicInstance, PropType } from \"vue\";\nimport { createAtom, watchAtom } from \"@xmachines/play-atom\";\nimport { canRaiseAgain, failsTheRender, isComponentUpdate } from \"./error-source.js\";\nimport {\n\tattachRenderErrorHandler,\n\tcreateFailureLatch,\n\tcreateReportGuard,\n\tcreateViewStoreLifecycle,\n} from \"@xmachines/play-view\";\nimport type { Viewable, PlaySpec, ViewActor } from \"@xmachines/play-view\";\nimport type {\n\tDefineRegistryResult,\n\tSetState,\n\tRenderErrorHandler,\n} from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export the props type and the context accessors, for a consumer that imports from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { usePlayView } from \"./actor-provider-context.js\";\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — it renders inside StateProvider, so that it can call useStateStore()\n// It gives the ViewContextValue, the ActionProvider, and the VisibilityProvider to the Renderer below.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The code uses a shallowRef for the value of the view context, because a deep\n\t\t// reactivity costs too much. The Proxy below lets inject() always read the newest\n\t\t// value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Give the ViewContextValue through the inject and provide system of Vue.\n\t\t// The code calls provide synchronously in setup(), so that Vue registers the value on\n\t\t// the instance of the component. It uses a Proxy, so that each descendant always\n\t\t// receives the newest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() during setup(), which is synchronous and before the return.\n\t\t// A Vue composable that uses inject() must run during setup(), and not in a render\n\t\t// function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Build a SetState adapter, because the factory of the handlers expects the pattern\n\t\t// of an updater function. The code defines it one time, in setup(). It reads\n\t\t// stateStore.getSnapshot and stateStore.update at the moment of the call. Therefore\n\t\t// it always works on the live state of the store, and it needs no new definition when\n\t\t// the identity of stateStore changes between two renders.\n\t\tconst setStateAdapter: SetState = (updater) => {\n\t\t\tconst prev = stateStore.getSnapshot();\n\t\t\tstateStore.update(updater(prev));\n\t\t};\n\n\t\t// Keep the handlers, with the identity of the registryResult prop as the key. The\n\t\t// getter functions are stable closures, and they hold the stateStore of setup().\n\t\t// Therefore they cause no new computation. The code computes the handlers again only\n\t\t// after a change of the definition of the registry, and not on each render of a view\n\t\t// update.\n\t\tconst handlers = computed(() =>\n\t\t\tprops.registryResult.handlers(\n\t\t\t\t() => setStateAdapter,\n\t\t\t\t() => stateStore.getSnapshot(),\n\t\t\t),\n\t\t);\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap the children with an ActionProvider and a VisibilityProvider. The Renderer of\n\t\t\t// PlayRenderer therefore works also with ActorProvider alone, without PlayUIProvider\n\t\t\t// and without JSONUIProvider.\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonError: {\n\t\t\ttype: Function as PropType<(error: unknown, reset: () => void) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The error boundary. It contains an error of the RENDER of a descendant — the\n\t\t// render function, the setup function, and a lifecycle hook — so that a subtree\n\t\t// that throws cannot take the whole application down. `onErrorCaptured` notifies\n\t\t// `onError`, it sets the errored flag, and the render function below then returns\n\t\t// the `fallback` slot instead of the children.\n\t\t//\n\t\t// `onErrorCaptured` of Vue also fires for an error of an event handler, and of a\n\t\t// watcher callback, which no other renderer of this workspace sees: the boundary\n\t\t// of React, the ErrorBoundary of Solid, and `<svelte:boundary>` each catch a\n\t\t// failure of the render only. A click handler that throws must therefore NOT\n\t\t// replace the view with the fallback. This boundary leaves such an error\n\t\t// COMPLETELY alone: it calls `onError` never, and it returns undefined, so the\n\t\t// error continues to `app.config.errorHandler` exactly as it does without this\n\t\t// provider. A report here would give play-vue a wider `onError` contract than the\n\t\t// other four renderers, and it would reach a caller that wires both this prop and\n\t\t// the global handler two times for one click.\n\t\t//\n\t\t// RESET RULE: the next view emission clears the flag (see the callbacks of\n\t\t// watchAtom and the handler of the actor swap). A view transition therefore\n\t\t// retries the render. Without the rule the user sends a recovery event, the actor\n\t\t// moves to a healthy view, and the screen keeps the fallback.\n\t\t//\n\t\t// The per-element boundary of @json-render catches a throw of a catalog component\n\t\t// upstream, and reports it through `onRenderError`. This boundary is the outer net\n\t\t// for everything else.\n\t\t//\n\t\t// The return of false stops a render error HERE. Without `onError` that error\n\t\t// therefore reaches neither `app.config.errorHandler` nor the console, and a\n\t\t// consumer that gives no handler loses it in silence. Write it to `console.error`\n\t\t// in that case, in the same way as the inner renderer does for a component that\n\t\t// throws without an `onRenderError` handler.\n\t\tconst errored = ref(false);\n\t\t/**\n\t\t * The report-once rule, from @xmachines/play-actor.\n\t\t *\n\t\t * It holds the actor, the view and the store of the failure that it reported. A\n\t\t * latch that compared the identity of the ERROR held nothing: an accessor that\n\t\t * throws builds a new one at each read, which is the ordinary shape of a failing\n\t\t * projection. play-svelte and play-solid use the same latch.\n\t\t */\n\t\tconst failureLatch = createFailureLatch();\n\n\t\t// The report guard, from @xmachines/play-actor: it blocks a reset that the host\n\t\t// calls from INSIDE the report, and every callback once the provider is gone. The\n\t\t// five renderers share the one implementation.\n\t\t//\n\t\t// The re-entry rule matters more here than a stack suggests: a write of a ref\n\t\t// renders on the NEXT tick, so a host with a retry-once policy loops with no stack\n\t\t// at all, and a flag around the retry itself would catch nothing.\n\t\t//\n\t\t// It CONTAINS a handler of the host that throws. The flag below schedules a\n\t\t// RENDER, and a throw that leaves the hook stops that render and skips the\n\t\t// `return false`, so the subtree that threw stays on the screen AND the error\n\t\t// reaches `app.config.errorHandler`.\n\t\tconst guard = createReportGuard({\n\t\t\tnoHandler:\n\t\t\t\t\"[@xmachines/play-vue] ActorProvider contained an error of a descendant. \" +\n\t\t\t\t\"Give an onError prop to receive it.\",\n\t\t\thandlerThrew:\n\t\t\t\t\"[@xmachines/play-vue] the onError handler of the host threw. \" +\n\t\t\t\t\"ActorProvider contained the failure of the view all the same.\",\n\t\t});\n\t\t// The retry renders again through a nonce that the render function reads. Clearing\n\t\t// the flags alone renders nothing: `errored.value = false` writes the value that\n\t\t// the ref holds already on the path of a failed RESOLUTION, and Vue schedules\n\t\t// nothing for a write that changes no value.\n\t\tconst retryNonce = ref(0);\n\n\t\t/**\n\t\t * Clears the contained error and renders again.\n\t\t *\n\t\t * The render function reads `view.value`, so the retry resolves the view that the\n\t\t * actor holds NOW. A retry bound to the view that failed would take a host that\n\t\t * keeps the callback back onto the screen that threw.\n\t\t */\n\t\tconst retry = (): void => {\n\t\t\tif (guard.blocked()) return;\n\t\t\terrored.value = false;\n\t\t\tfailureLatch.clear();\n\t\t\tretryNonce.value++;\n\t\t};\n\n\t\t/** Sends a contained failure to `onError`, or to the console when none is given. */\n\t\tconst report = (err: unknown): void => {\n\t\t\tconst handler = props.onError;\n\t\t\tguard.report(err, handler ? () => handler(err, retry) : undefined);\n\t\t};\n\n\t\t// The configuration of the application, read one time. `canRaiseAgain` asks the two\n\t\t// fields that `handleError` of Vue reads on every error. It lives in error-source.ts,\n\t\t// because its production half answers a spelling that a mounted test reaches never.\n\t\tconst appConfig = getCurrentInstance()?.appContext.config;\n\n\t\t// The error that this boundary let through LAST, and that the NEXT raise can still\n\t\t// claim as a repeat.\n\t\t//\n\t\t// The second raise is SYNCHRONOUS and IMMEDIATE. `logError` of the development\n\t\t// bundle re-throws, and the throw unwinds straight back into `callWithErrorHandling`\n\t\t// of `flushJobs`, which reports the same value again. No other raise reaches this\n\t\t// hook in between, so ONE slot holds the complete window.\n\t\t//\n\t\t// EVERY raise that fails the render takes the slot, and not a component update\n\t\t// alone. A record that no raise takes can otherwise outlive its window.\n\t\t//\n\t\t// The record names the INSTANCE beside the error value. A repeat carries the\n\t\t// instance whose JOB ran when the error unwound, and that is the owner of the\n\t\t// watcher OR one of its ANCESTORS: a pre-flush watcher of a child runs inside the\n\t\t// update of the parent that passes it a prop, and `flushJobs` reports the throw\n\t\t// under the parent — or under the outermost ancestor whose update ran. The take\n\t\t// therefore walks the `$parent` chain of the recorded instance. A SIBLING stands on\n\t\t// that chain never, and a sibling that fails with the same cached error is one\n\t\t// loader with two consumers: that failure is a first incident, and the boundary\n\t\t// contains it.\n\t\t//\n\t\t// The microtask is the BACKSTOP, for a raise that neither a repeat nor another\n\t\t// raise follows. A record for the life of the provider would disarm the boundary\n\t\t// for that error for ever, and a descendant that keeps a failure and raises it\n\t\t// again from a LATER render is an ordinary shape.\n\t\t//\n\t\t// Each `remember` schedules a clear of ITS OWN record, and that clear takes no\n\t\t// other. A clear that removed whatever the slot holds could run after a take\n\t\t// emptied the slot and a later `remember` filled it again, and it would then\n\t\t// disarm the boundary for a repeat that is still to come.\n\t\tlet letThrough: { error: unknown; instance: ComponentPublicInstance | null } | null = null;\n\t\tconst remember = (error: unknown, instance: ComponentPublicInstance | null): void => {\n\t\t\tconst record = { error, instance };\n\t\t\tletThrough = record;\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (letThrough === record) letThrough = null;\n\t\t\t});\n\t\t};\n\t\t/**\n\t\t * Takes the record. It answers TRUE when the record names this error, and when the\n\t\t * instance that raises it is the recorded one or one of its ancestors.\n\t\t *\n\t\t * The comparison reads `$` on both sides, which is the INTERNAL instance. Vue hands\n\t\t * `onErrorCaptured` the `proxy` of a component, and `$parent` answers with the\n\t\t * `exposeProxy` of a parent that called `expose()` — which the compiler makes every\n\t\t * `<script setup>` component do. The two objects differ, so a walk that compared\n\t\t * them found an exposed ancestor never, and the boundary contained a watcher error\n\t\t * that it must let through. `$` resolves through both proxies and names one object.\n\t\t */\n\t\tconst takeRepeat = (error: unknown, instance: ComponentPublicInstance | null): boolean => {\n\t\t\tconst record = letThrough;\n\t\t\tletThrough = null;\n\t\t\tif (record === null || record.error !== error) return false;\n\t\t\tfor (let node = record.instance; node !== null; node = node.$parent) {\n\t\t\t\tif (node.$ === instance?.$) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t\tonErrorCaptured((err, instance, info) => {\n\t\t\t// An error that did NOT fail the render leaves this boundary untouched: the\n\t\t\t// screen keeps its view, `onError` stays silent, and the return of undefined\n\t\t\t// sends the error on to `app.config.errorHandler`. The boundary of React, the\n\t\t\t// ErrorBoundary of Solid, and `<svelte:boundary>` each see such an error never,\n\t\t\t// so a call of `onError` here would give play-vue a wider contract than the\n\t\t\t// other four, AND it would report the same failure twice to a caller that wires\n\t\t\t// both `onError` and the global handler of the application.\n\t\t\tif (!failsTheRender(info)) {\n\t\t\t\t// Arm the record only where Vue WILL raise this error a second time. A record\n\t\t\t\t// that no repeat claims stands until the microtask, and a genuine failure of\n\t\t\t\t// a render in the same flush — the same descendant, the same cached error —\n\t\t\t\t// would then take it: no fallback, no `onError`, and no screen.\n\t\t\t\t//\n\t\t\t\t// `handleError` of Vue calls `app.config.errorHandler` where one exists, and\n\t\t\t\t// it reaches `logError` never; the production bundle throws only where the\n\t\t\t\t// application asks for `throwUnhandledErrorInProduction`. The one case that\n\t\t\t\t// this line cannot see is an ANCESTOR `errorCaptured` that answers false,\n\t\t\t\t// which stops Vue before `logError` too. That case stays open, and the doc of\n\t\t\t\t// `onError` names it.\n\t\t\t\tif (canRaiseAgain(info, appConfig)) remember(err, instance);\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\t// Vue can raise the SAME error a SECOND time under another source. The\n\t\t\t// development bundle of `logError` re-throws an error that no\n\t\t\t// `app.config.errorHandler` took. A queued job then loses that throw to\n\t\t\t// `callWithErrorHandling(job, job.i, 15)` of `flushJobs` — a `watch` callback\n\t\t\t// with the default `pre` flush, for one — and `flushJobs` reports it again as\n\t\t\t// \"component update\". The classification above answers \"render failure\" for that\n\t\t\t// second spelling, so a watcher that threw would take the view off the screen\n\t\t\t// after all. One error is one incident: an error that this boundary let through\n\t\t\t// in this turn stays through.\n\t\t\t//\n\t\t\t// The gate asks for the SOURCE of the repeat as well. `flushJobs` reports a\n\t\t\t// job under \"component update\", and no other source can carry a second raise\n\t\t\t// to this hook, so a record of the turn can disarm the boundary for that one\n\t\t\t// spelling alone. Without the question a setup function or a render function\n\t\t\t// that throws the SAME error value in the same turn — a loader that caches its\n\t\t\t// rejection, for one — would reach no fallback, no `onError`, and no screen.\n\t\t\t//\n\t\t\t// It returns FALSE, and not undefined. The FIRST raise went on to\n\t\t\t// `app.config.errorHandler`, which is the contract of a non-render source, and\n\t\t\t// the development bundle re-threw it there — that throw IS this second report.\n\t\t\t// A second `undefined` sends it on one more time, so `logError` warns twice for\n\t\t\t// one incident and throws again, and that throw leaves `flushJobs`. The\n\t\t\t// `finally` of `flushJobs` runs `queue.length = 0`. `flushJobs` therefore drops\n\t\t\t// every job behind the one that failed, and a sibling of the descendant that\n\t\t\t// threw renders never. One incident reaches the caller ONE time, and the flush\n\t\t\t// of Vue finishes.\n\t\t\t// `takeRepeat` runs for EVERY raise that fails the render, and not inside the\n\t\t\t// condition below: a raise of another source ENDS the window of the repeat, so\n\t\t\t// the record can disarm the boundary for the one raise that follows it and for\n\t\t\t// no other.\n\t\t\tconst repeated = takeRepeat(err, instance);\n\t\t\tif (isComponentUpdate(info) && repeated) {\n\t\t\t\t// The value reaches no console without this line. `logError` of the\n\t\t\t\t// development bundle writes the SOURCE, and not the value. It then throws\n\t\t\t\t// the value, and that throw IS this second report, which the `return`\n\t\t\t\t// below stops. `report()` wrote such an error before this gate existed, so\n\t\t\t\t// a host with no `onError` prop could still debug a watcher or a loader\n\t\t\t\t// that failed. The production bundle writes the value on the FIRST raise,\n\t\t\t\t// and it throws instead where the application asks for\n\t\t\t\t// `throwUnhandledErrorInProduction` — that application gets the write here.\n\t\t\t\t// One incident reaches the console ONE time in both bundles.\n\t\t\t\t//\n\t\t\t\t// The line carries the name of this package, as every other console write\n\t\t\t\t// of this provider does. Without it a developer reads a bare error and\n\t\t\t\t// cannot tell that the provider wrote it, and not Vue.\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"[@xmachines/play-vue] ActorProvider stopped a second report of this \" +\n\t\t\t\t\t\t\"error. Vue raised it again under the source of a component update, \" +\n\t\t\t\t\t\t\"and it failed no render.\",\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// The SCREEN comes first, and the report second, as `contain()` of play-dom\n\t\t\t// states it. A reporter can throw — one that re-throws to escalate, or a\n\t\t\t// transport that fails — and here the order alone is not enough: the flag\n\t\t\t// schedules a RENDER, and a throw that leaves this hook stops that render and\n\t\t\t// skips the `return false`. The GUARD holds that half, for the four renderers\n\t\t\t// that need it: it carries a `handlerThrew` message, so it contains the throw\n\t\t\t// of the handler and writes it to `console.error`.\n\t\t\t//\n\t\t\t// The five renderers hold the one rule: a handler of the host never defeats the\n\t\t\t// containment, and a host that must escalate raises the failure from a task of\n\t\t\t// its own.\n\t\t\terrored.value = true;\n\t\t\treport(err);\n\t\t\treturn false;\n\t\t});\n\n\t\t// Take the actor out of the reactive proxy of Vue, to reach the raw Atom objects.\n\t\t// A shallowRef holds the actor. Therefore the injected value and the atom watcher\n\t\t// can follow `props.actor` when the prop changes after the mount.\n\t\tconst actorRef = shallowRef(toRaw(props.actor as ViewActor));\n\n\t\t// Take the registryResult out of the proxy, and mark each component as raw, because the reactivity of Vue costs too much here\n\t\tconst rawRegistry = Object.fromEntries(\n\t\t\tObject.entries(toRaw(props.registryResult).registry).map(([k, v]) => [\n\t\t\t\tk,\n\t\t\t\tmarkRaw(v as object),\n\t\t\t]),\n\t\t) as DefineRegistryResult[\"registry\"];\n\n\t\t// Put the onRenderError prop into the registry. The property is not enumerable, and\n\t\t// it replaces the handler of the defineRegistry level. attachRenderErrorHandler makes\n\t\t// a copy, and it changes the registry of the caller never.\n\t\t// The code must call markRaw on the copy again, because a copy does not carry the\n\t\t// non-enumerable flag of markRaw.\n\t\tconst rawRegistryResult: DefineRegistryResult = {\n\t\t\t...toRaw(props.registryResult),\n\t\t\tregistry: markRaw(\n\t\t\t\tprops.onRenderError\n\t\t\t\t\t? attachRenderErrorHandler(rawRegistry, props.onRenderError)\n\t\t\t\t\t: rawRegistry,\n\t\t\t),\n\t\t};\n\n\t\t// Give the actor to each descendant, through the provide and inject mechanism of Vue.\n\t\t//\n\t\t// The code gives a stable Proxy, and not the raw actor. The pattern is the same as\n\t\t// the ViewKey proxy of ActorProviderInner. The injected value therefore follows the\n\t\t// CURRENT `props.actor`: each injector keeps the reference of the setup(), and every\n\t\t// trap resolves against the newest actor (actorRef.value) after a change of the prop.\n\t\t// The proxy forwards each relevant trap. Therefore it behaves like the actor below it\n\t\t// for a read, for a write, for a membership test (`in`), for an enumeration\n\t\t// (Object.keys and a spread), and for a prototype test (`instanceof`). Each method\n\t\t// binds to the current raw actor. Therefore `this`, and also each private field,\n\t\t// works exactly as in a direct call.\n\t\t//\n\t\t// IMPORTANT: this proxy is NOT identity-equal to `props.actor`, because it is a\n\t\t// separate object, and therefore a separate key of a WeakMap. A consumer that uses\n\t\t// the identity as its key must receive the `props.actor` value itself, and never this\n\t\t// injected proxy. The most important such consumer is the guard of one bridge for\n\t\t// each actor in RouterBridgeBase: it uses the identity of the actor as the key of a\n\t\t// WeakMap at the module level.\n\t\t//\n\t\t// The identity of a method: the code keeps each bound method, with the method below\n\t\t// it as the key. A repeated read therefore returns the SAME function\n\t\t// (actor.send === actor.send), and the hot path allocates nothing. A read binds the\n\t\t// method again only after a change of the method below it. The watch handler below\n\t\t// CLEARS the cache on a change of the actor. Therefore each prototype method binds to\n\t\t// the new actor.\n\t\tconst boundMethodCache = new Map<PropertyKey, { source: unknown; bound: unknown }>();\n\t\tprovideActor(\n\t\t\tnew Proxy({} as AnyPlayActor, {\n\t\t\t\tget(_target, prop) {\n\t\t\t\t\tconst current = actorRef.value;\n\t\t\t\t\tconst value = Reflect.get(current, prop, current) as unknown;\n\t\t\t\t\tif (typeof value !== \"function\") return value;\n\t\t\t\t\tconst cached = boundMethodCache.get(prop);\n\t\t\t\t\tif (cached && cached.source === value) return cached.bound;\n\t\t\t\t\tconst bound = (value as (...args: unknown[]) => unknown).bind(current);\n\t\t\t\t\tboundMethodCache.set(prop, { source: value, bound });\n\t\t\t\t\treturn bound;\n\t\t\t\t},\n\t\t\t\thas(_target, prop) {\n\t\t\t\t\treturn prop in actorRef.value;\n\t\t\t\t},\n\t\t\t\tset(_target, prop, value) {\n\t\t\t\t\treturn Reflect.set(actorRef.value, prop, value, actorRef.value);\n\t\t\t\t},\n\t\t\t\tdeleteProperty(_target, prop) {\n\t\t\t\t\treturn Reflect.deleteProperty(actorRef.value, prop);\n\t\t\t\t},\n\t\t\t\townKeys() {\n\t\t\t\t\treturn Reflect.ownKeys(actorRef.value);\n\t\t\t\t},\n\t\t\t\tgetOwnPropertyDescriptor(_target, prop) {\n\t\t\t\t\tconst desc = Reflect.getOwnPropertyDescriptor(actorRef.value, prop);\n\t\t\t\t\tif (!desc) return undefined;\n\t\t\t\t\t// An invariant of a Proxy: the target of this proxy is an empty {}. Therefore each\n\t\t\t\t\t// key of ownKeys must resolve to a configurable descriptor here. Without that, the\n\t\t\t\t\t// [[GetOwnProperty]] invariant throws, because a proxy must not report a property that\n\t\t\t\t\t// its target has not as non-configurable. The own props of the actor are mutable at\n\t\t\t\t\t// run time in each case. Therefore `configurable: true` is correct enough for the\n\t\t\t\t\t// enumeration of Object.keys and of a spread.\n\t\t\t\t\tdesc.configurable = true;\n\t\t\t\t\treturn desc;\n\t\t\t\t},\n\t\t\t\tgetPrototypeOf() {\n\t\t\t\t\treturn Reflect.getPrototypeOf(actorRef.value);\n\t\t\t\t},\n\t\t\t}) as AnyPlayActor,\n\t\t);\n\n\t\t// Seed the first value, then subscribe. Both steps are synchronous, and no scheduler\n\t\t// runs between them.\n\t\t// Solid does the same with createEffect, and Svelte does the same with $effect.\n\t\t// The pattern is therefore the same in each framework.\n\t\tconst view = ref<PlaySpec | null>(actorRef.value.currentView.get());\n\n\t\t// The store lifecycle: it seeds the store again on a change of the viewKey, it\n\t\t// refreshes /context in place in every other case, it resets the store on a change of\n\t\t// the actor, and it guards the identity cache. The shared coordinator comes from\n\t\t// @xmachines/play-actor. Only the wiring of the reactivity below belongs to Vue.\n\t\tconst storeLifecycle = createViewStoreLifecycle((seed) =>\n\t\t\txstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t);\n\t\t// storeKey is the key of a SUBTREE REMOUNT. Therefore it must change only after a\n\t\t// new seed of the store, and never after a refresh of /context in place. Without this\n\t\t// rule, each update of the projection removes the subtree on the screen.\n\t\t// (The controlled mode seeds the store never again. Therefore the key changes never\n\t\t// there.)\n\t\tlet storeKey = 0;\n\n\t\t// The atom watcher connects the atoms to the reactivity of Vue.\n\t\t// The code assigns it again on a change of the actor. Therefore the cleanup always\n\t\t// releases the live watcher.\n\t\t// Every view emission clears the errored flag (see the reset rule above) before the\n\t\t// new view renders. A hit of the error boundary therefore retries here.\n\t\tlet unwatch = watchAtom(actorRef.value.currentView, (nextView) => {\n\t\t\terrored.value = false;\n\t\t\tfailureLatch.clear();\n\t\t\tview.value = nextView;\n\t\t});\n\n\t\t// The reset watches the STORE too. A render fails on it, so a caller that repairs a\n\t\t// controlled store — without a new emission — must see the children again.\n\t\t// play-react and play-solid hold the same rule, and the actor swap below covers the\n\t\t// third input.\n\t\twatch(\n\t\t\t() => props.store,\n\t\t\t() => {\n\t\t\t\terrored.value = false;\n\t\t\t\tfailureLatch.clear();\n\t\t\t},\n\t\t);\n\n\t\t// React to a change of `props.actor`: cancel the subscription to the currentView of\n\t\t// the OLD actor, seed the view from the NEW actor synchronously (`flush: \"sync\"`, so\n\t\t// that no scheduler runs between the steps, as in the seed and watch pattern of the\n\t\t// mount above), and subscribe to the new atom. The view of the new seed has a new\n\t\t// identity. Therefore the branch of the internal store below builds the store again,\n\t\t// and it changes storeKey, exactly like a normal view transition.\n\t\twatch(\n\t\t\t() => toRaw(props.actor as ViewActor),\n\t\t\t(nextActor) => {\n\t\t\t\tif (nextActor === actorRef.value) return;\n\t\t\t\tunwatch();\n\t\t\t\tactorRef.value = nextActor;\n\t\t\t\t// (The store lifecycle resets itself on a change of the actor, because a store that\n\t\t\t\t// stays alive must not outlive its actor.)\n\t\t\t\t// Clear the cache of the bound methods. Each prototype method therefore binds to the\n\t\t\t\t// new actor on the next read. See the get trap of the injected proxy.\n\t\t\t\tboundMethodCache.clear();\n\t\t\t\t// The new seed is a view emission — clear the errored flag with it.\n\t\t\t\terrored.value = false;\n\t\t\t\tfailureLatch.clear();\n\t\t\t\tview.value = nextActor.currentView.get();\n\t\t\t\tunwatch = watchAtom(nextActor.currentView, (nextView) => {\n\t\t\t\t\terrored.value = false;\n\t\t\t\t\tfailureLatch.clear();\n\t\t\t\t\tview.value = nextView;\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tguard.dispose();\n\t\t\tunwatch();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// The nonce of the retry. The read makes this render function depend on it, so\n\t\t\t// the reset of the host renders again — see `retry` above.\n\t\t\tvoid retryNonce.value;\n\n\t\t\t// A contained error of a descendant: show the fallback slot, or show nothing,\n\t\t\t// until the next view emission clears the flag and retries the render.\n\t\t\tif (errored.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\t// No view: show the fallback slot, or show nothing\n\t\t\tif (!view.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\tconst spec = view.value;\n\n\t\t\t// Resolve the store, which is external and controlled, or internal for each\n\t\t\t// viewKey, through the shared lifecycle. The children receive the store with the\n\t\t\t// guard, because /context is read-only to the spec. The machinery refreshes the\n\t\t\t// store through the reference without a guard, inside the coordinator.\n\t\t\t//\n\t\t\t// The try CONTAINS a failure of this resolution. `spec.state` can throw — a\n\t\t\t// projection with an accessor, or a seed of a store — and `onErrorCaptured`\n\t\t\t// above sees a throw of a DESCENDANT only, never one of this render function.\n\t\t\t// Without the try such a failure leaves the provider, reaches\n\t\t\t// app.config.errorHandler, and takes the application down, while `onError` and\n\t\t\t// the fallback slot both stay unused.\n\t\t\t//\n\t\t\t// The branch sets the errored flag NOT: a mutation of the state during a render\n\t\t\t// starts a second render. It returns the fallback for THIS render instead, and\n\t\t\t// the next view emission renders the children again — which is the reset rule,\n\t\t\t// with no flag to clear.\n\t\t\tlet resolution;\n\t\t\ttry {\n\t\t\t\tresolution = storeLifecycle.resolve(actorRef.value, spec, props.store);\n\t\t\t} catch (error) {\n\t\t\t\t// LATCH the failure, and report it ONE time. The render function runs again\n\t\t\t\t// for any tracked change, and a report on each attempt would call onError a\n\t\t\t\t// second and a third time for one failure — play-react, play-solid and\n\t\t\t\t// play-svelte each report once.\n\t\t\t\tif (failureLatch.shouldReport(actorRef.value, spec, props.store)) report(error);\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\t\t\tfailureLatch.clear();\n\t\t\tif (resolution.reseeded) storeKey++;\n\t\t\tconst store: StateStore = resolution.guardedStore;\n\n\t\t\t// ActorProviderInner renders inside StateProvider. Therefore useStateStore() works\n\t\t\treturn h(StateProvider, { store, key: storeKey }, () =>\n\t\t\t\th(ActorProviderInner, { registryResult: rawRegistryResult, spec, store }, slots),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"ActorProvider.js","names":["_sfc_main"],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — the low-level provider of the XMachines Vue render architecture.\n *\n * It owns the complete actor lifecycle:\n * - the view session of @xmachines/play-view, whose snapshots reach the Vue reactivity\n * through a shallowRef: the StateStore of each view, controlled and uncontrolled\n * - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider\n * - the ViewContextValue, which it provides through the ViewKey injection key\n * - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below\n * - the injection of onRenderError into the registry\n *\n * The author of a library who needs this control uses the component directly.\n * An end user takes <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - the Actor decides each state transition, with its guards\n * @invariant Passive Infrastructure - the component observes the atoms, and it sends the events\n * @invariant Atom-Only Reactivity - the state of the business logic is in the actor atoms\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\tonErrorCaptured,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n\tgetCurrentInstance,\n} from \"vue\";\nimport type { ComponentPublicInstance, PropType } from \"vue\";\nimport { createAtom } from \"@xmachines/play-atom\";\nimport { canRaiseAgain, failsTheRender, isComponentUpdate } from \"./error-source.js\";\nimport {\n\tbindStoreHandlers,\n\tcreateActorProxy,\n\tcreateRenderErrorBinding,\n\tcreateReportGuard,\n\tcreateViewSession,\n} from \"@xmachines/play-view\";\nimport type { PlaySpec, ViewActor, ViewSessionSnapshot } from \"@xmachines/play-view\";\nimport type { DefineRegistryResult, OnRenderError } from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport { ownMemberDescriptors } from \"@xmachines/json-render-core\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export the props type and the context accessors, for a consumer that imports from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { usePlayView } from \"./actor-provider-context.js\";\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — it renders inside StateProvider, so that it can call useStateStore()\n// It gives the ViewContextValue, the ActionProvider, and the VisibilityProvider to the Renderer below.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The code uses a shallowRef for the value of the view context, because a deep\n\t\t// reactivity costs too much. The Proxy below lets inject() always read the newest\n\t\t// value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Give the ViewContextValue through the inject and provide system of Vue.\n\t\t// The code calls provide synchronously in setup(), so that Vue registers the value on\n\t\t// the instance of the component. It uses a Proxy, so that each descendant always\n\t\t// receives the newest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() during setup(), which is synchronous and before the return.\n\t\t// A Vue composable that uses inject() must run during setup(), and not in a render\n\t\t// function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Keep the handlers, with the identity of the registryResult prop as the key. They\n\t\t// read the stateStore of setup() at the moment of an action. The code computes them\n\t\t// again only after a change of the definition of the registry, and not on each\n\t\t// render of a view update.\n\t\tconst handlers = computed(() => bindStoreHandlers(props.registryResult, () => stateStore));\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap the children with an ActionProvider and a VisibilityProvider. The Renderer of\n\t\t\t// PlayRenderer therefore works also with ActorProvider alone, without PlayUIProvider\n\t\t\t// and without JSONUIProvider.\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<OnRenderError>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonError: {\n\t\t\ttype: Function as PropType<(error: unknown, reset: () => void) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The error boundary. It contains an error of the RENDER of a descendant — the\n\t\t// render function, the setup function, and a lifecycle hook — so that a subtree\n\t\t// that throws cannot take the whole application down. `onErrorCaptured` notifies\n\t\t// `onError`, it sets the errored flag, and the render function below then returns\n\t\t// the `fallback` slot instead of the children.\n\t\t//\n\t\t// `onErrorCaptured` of Vue also fires for an error of an event handler, and of a\n\t\t// watcher callback, which no other renderer of this workspace sees: the boundary\n\t\t// of React, the ErrorBoundary of Solid, and `<svelte:boundary>` each catch a\n\t\t// failure of the render only. A click handler that throws must therefore NOT\n\t\t// replace the view with the fallback. This boundary leaves such an error\n\t\t// COMPLETELY alone: it calls `onError` never, and it returns undefined, so the\n\t\t// error continues to `app.config.errorHandler` exactly as it does without this\n\t\t// provider. A report here would give play-vue a wider `onError` contract than the\n\t\t// other four renderers, and it would reach a caller that wires both this prop and\n\t\t// the global handler two times for one click.\n\t\t//\n\t\t// RESET RULE: each new snapshot of the view session clears the flag (see its\n\t\t// listener below): a new view, a new actor, or a new controlled store. A view\n\t\t// transition therefore retries the render. Without the rule the user sends a recovery event, the actor\n\t\t// moves to a healthy view, and the screen keeps the fallback.\n\t\t//\n\t\t// The per-element boundary of @json-render catches a throw of a catalog component\n\t\t// below the root upstream, and reports it through `onRenderError`. A failure of the\n\t\t// root reaches this hook never: the session contains it (see the registry below).\n\t\t// This boundary is the outer net for everything else.\n\t\t//\n\t\t// The return of false stops a render error HERE. Without `onError` that error\n\t\t// therefore reaches neither `app.config.errorHandler` nor the console, and a\n\t\t// consumer that gives no handler loses it in silence. Write it to `console.error`\n\t\t// in that case, in the same way as the inner renderer does for a component that\n\t\t// throws without an `onRenderError` handler.\n\t\tconst errored = ref(false);\n\n\t\t// The report guard, from @xmachines/play-view: it blocks a reset that the host\n\t\t// calls from INSIDE the report, and every callback once the provider is gone. The\n\t\t// five renderers share the one implementation.\n\t\t//\n\t\t// The re-entry rule matters more here than a stack suggests: a write of a ref\n\t\t// renders on the NEXT tick, so a host with a retry-once policy loops with no stack\n\t\t// at all, and a flag around the retry itself would catch nothing.\n\t\t//\n\t\t// It CONTAINS a handler of the host that throws. The flag below schedules a\n\t\t// RENDER, and a throw that leaves the hook stops that render and skips the\n\t\t// `return false`, so the subtree that threw stays on the screen AND the error\n\t\t// reaches `app.config.errorHandler`.\n\t\tconst guard = createReportGuard({\n\t\t\tnoHandler:\n\t\t\t\t\"[@xmachines/play-vue] ActorProvider contained an error of a descendant. \" +\n\t\t\t\t\"Give an onError prop to receive it.\",\n\t\t\thandlerThrew:\n\t\t\t\t\"[@xmachines/play-vue] the onError handler of the host threw. \" +\n\t\t\t\t\"ActorProvider contained the failure of the view all the same.\",\n\t\t});\n\n\t\t/**\n\t\t * Clears the contained error and renders again.\n\t\t *\n\t\t * The session resolves the view that the actor holds NOW, and its new snapshot\n\t\t * renders again. A retry bound to the view that failed would take a host that keeps\n\t\t * the callback back onto the screen that threw.\n\t\t */\n\t\tconst retry = (): void => {\n\t\t\tif (guard.blocked()) return;\n\t\t\terrored.value = false;\n\t\t\tsession.retry();\n\t\t};\n\n\t\t/** Sends a contained failure to `onError`, or to the console when none is given. */\n\t\tconst report = (err: unknown): void => {\n\t\t\tconst handler = props.onError;\n\t\t\tguard.report(err, handler ? () => handler(err, retry) : undefined);\n\t\t};\n\n\t\t// The configuration of the application, read one time. `canRaiseAgain` asks the two\n\t\t// fields that `handleError` of Vue reads on every error. It lives in error-source.ts,\n\t\t// because its production half answers a spelling that a mounted test reaches never.\n\t\tconst appConfig = getCurrentInstance()?.appContext.config;\n\n\t\t// The error that this boundary let through LAST, and that the NEXT raise can still\n\t\t// claim as a repeat.\n\t\t//\n\t\t// The second raise is SYNCHRONOUS and IMMEDIATE. `logError` of the development\n\t\t// bundle re-throws, and the throw unwinds straight back into `callWithErrorHandling`\n\t\t// of `flushJobs`, which reports the same value again. No other raise reaches this\n\t\t// hook in between, so ONE slot holds the complete window.\n\t\t//\n\t\t// EVERY raise that fails the render takes the slot, and not a component update\n\t\t// alone. A record that no raise takes can otherwise outlive its window.\n\t\t//\n\t\t// The record names the INSTANCE beside the error value. A repeat carries the\n\t\t// instance whose JOB ran when the error unwound, and that is the owner of the\n\t\t// watcher OR one of its ANCESTORS: a pre-flush watcher of a child runs inside the\n\t\t// update of the parent that passes it a prop, and `flushJobs` reports the throw\n\t\t// under the parent — or under the outermost ancestor whose update ran. The take\n\t\t// therefore walks the `$parent` chain of the recorded instance. A SIBLING stands on\n\t\t// that chain never, and a sibling that fails with the same cached error is one\n\t\t// loader with two consumers: that failure is a first incident, and the boundary\n\t\t// contains it.\n\t\t//\n\t\t// The microtask is the BACKSTOP, for a raise that neither a repeat nor another\n\t\t// raise follows. A record for the life of the provider would disarm the boundary\n\t\t// for that error for ever, and a descendant that keeps a failure and raises it\n\t\t// again from a LATER render is an ordinary shape.\n\t\t//\n\t\t// Each `remember` schedules a clear of ITS OWN record, and that clear takes no\n\t\t// other. A clear that removed whatever the slot holds could run after a take\n\t\t// emptied the slot and a later `remember` filled it again, and it would then\n\t\t// disarm the boundary for a repeat that is still to come.\n\t\tlet letThrough: { error: unknown; instance: ComponentPublicInstance | null } | null = null;\n\t\tconst remember = (error: unknown, instance: ComponentPublicInstance | null): void => {\n\t\t\tconst record = { error, instance };\n\t\t\tletThrough = record;\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (letThrough === record) letThrough = null;\n\t\t\t});\n\t\t};\n\t\t/**\n\t\t * Takes the record. It answers TRUE when the record names this error, and when the\n\t\t * instance that raises it is the recorded one or one of its ancestors.\n\t\t *\n\t\t * The comparison reads `$` on both sides, which is the INTERNAL instance. Vue hands\n\t\t * `onErrorCaptured` the `proxy` of a component, and `$parent` answers with the\n\t\t * `exposeProxy` of a parent that called `expose()` — which the compiler makes every\n\t\t * `<script setup>` component do. The two objects differ, so a walk that compared\n\t\t * them found an exposed ancestor never, and the boundary contained a watcher error\n\t\t * that it must let through. `$` resolves through both proxies and names one object.\n\t\t */\n\t\tconst takeRepeat = (error: unknown, instance: ComponentPublicInstance | null): boolean => {\n\t\t\tconst record = letThrough;\n\t\t\tletThrough = null;\n\t\t\tif (record === null || record.error !== error) return false;\n\t\t\tfor (let node = record.instance; node !== null; node = node.$parent) {\n\t\t\t\tif (node.$ === instance?.$) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t\tonErrorCaptured((err, instance, info) => {\n\t\t\t// An error that did NOT fail the render leaves this boundary untouched: the\n\t\t\t// screen keeps its view, `onError` stays silent, and the return of undefined\n\t\t\t// sends the error on to `app.config.errorHandler`. The boundary of React, the\n\t\t\t// ErrorBoundary of Solid, and `<svelte:boundary>` each see such an error never,\n\t\t\t// so a call of `onError` here would give play-vue a wider contract than the\n\t\t\t// other four, AND it would report the same failure twice to a caller that wires\n\t\t\t// both `onError` and the global handler of the application.\n\t\t\tif (!failsTheRender(info)) {\n\t\t\t\t// Arm the record only where Vue WILL raise this error a second time. A record\n\t\t\t\t// that no repeat claims stands until the microtask, and a genuine failure of\n\t\t\t\t// a render in the same flush — the same descendant, the same cached error —\n\t\t\t\t// would then take it: no fallback, no `onError`, and no screen.\n\t\t\t\t//\n\t\t\t\t// `handleError` of Vue calls `app.config.errorHandler` where one exists, and\n\t\t\t\t// it reaches `logError` never; the production bundle throws only where the\n\t\t\t\t// application asks for `throwUnhandledErrorInProduction`. The one case that\n\t\t\t\t// this line cannot see is an ANCESTOR `errorCaptured` that answers false,\n\t\t\t\t// which stops Vue before `logError` too. That case stays open, and the doc of\n\t\t\t\t// `onError` names it.\n\t\t\t\tif (canRaiseAgain(info, appConfig)) remember(err, instance);\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\t// Vue can raise the SAME error a SECOND time under another source. The\n\t\t\t// development bundle of `logError` re-throws an error that no\n\t\t\t// `app.config.errorHandler` took. A queued job then loses that throw to\n\t\t\t// `callWithErrorHandling(job, job.i, 15)` of `flushJobs` — a `watch` callback\n\t\t\t// with the default `pre` flush, for one — and `flushJobs` reports it again as\n\t\t\t// \"component update\". The classification above answers \"render failure\" for that\n\t\t\t// second spelling, so a watcher that threw would take the view off the screen\n\t\t\t// after all. One error is one incident: an error that this boundary let through\n\t\t\t// in this turn stays through.\n\t\t\t//\n\t\t\t// The gate asks for the SOURCE of the repeat as well. `flushJobs` reports a\n\t\t\t// job under \"component update\", and no other source can carry a second raise\n\t\t\t// to this hook, so a record of the turn can disarm the boundary for that one\n\t\t\t// spelling alone. Without the question a setup function or a render function\n\t\t\t// that throws the SAME error value in the same turn — a loader that caches its\n\t\t\t// rejection, for one — would reach no fallback, no `onError`, and no screen.\n\t\t\t//\n\t\t\t// It returns FALSE, and not undefined. The FIRST raise went on to\n\t\t\t// `app.config.errorHandler`, which is the contract of a non-render source, and\n\t\t\t// the development bundle re-threw it there — that throw IS this second report.\n\t\t\t// A second `undefined` sends it on one more time, so `logError` warns twice for\n\t\t\t// one incident and throws again, and that throw leaves `flushJobs`. The\n\t\t\t// `finally` of `flushJobs` runs `queue.length = 0`. `flushJobs` therefore drops\n\t\t\t// every job behind the one that failed, and a sibling of the descendant that\n\t\t\t// threw renders never. One incident reaches the caller ONE time, and the flush\n\t\t\t// of Vue finishes.\n\t\t\t// `takeRepeat` runs for EVERY raise that fails the render, and not inside the\n\t\t\t// condition below: a raise of another source ENDS the window of the repeat, so\n\t\t\t// the record can disarm the boundary for the one raise that follows it and for\n\t\t\t// no other.\n\t\t\tconst repeated = takeRepeat(err, instance);\n\t\t\tif (isComponentUpdate(info) && repeated) {\n\t\t\t\t// The value reaches no console without this line. `logError` of the\n\t\t\t\t// development bundle writes the SOURCE, and not the value. It then throws\n\t\t\t\t// the value, and that throw IS this second report, which the `return`\n\t\t\t\t// below stops. `report()` wrote such an error before this gate existed, so\n\t\t\t\t// a host with no `onError` prop could still debug a watcher or a loader\n\t\t\t\t// that failed. The production bundle writes the value on the FIRST raise,\n\t\t\t\t// and it throws instead where the application asks for\n\t\t\t\t// `throwUnhandledErrorInProduction` — that application gets the write here.\n\t\t\t\t// One incident reaches the console ONE time in both bundles.\n\t\t\t\t//\n\t\t\t\t// The line carries the name of this package, as every other console write\n\t\t\t\t// of this provider does. Without it a developer reads a bare error and\n\t\t\t\t// cannot tell that the provider wrote it, and not Vue.\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"[@xmachines/play-vue] ActorProvider stopped a second report of this \" +\n\t\t\t\t\t\t\"error. Vue raised it again under the source of a component update, \" +\n\t\t\t\t\t\t\"and it failed no render.\",\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// The SCREEN comes first, and the report second, as `contain()` of play-dom\n\t\t\t// states it. A reporter can throw — one that re-throws to escalate, or a\n\t\t\t// transport that fails — and here the order alone is not enough: the flag\n\t\t\t// schedules a RENDER, and a throw that leaves this hook stops that render and\n\t\t\t// skips the `return false`. The GUARD holds that half, for the four renderers\n\t\t\t// that need it: it carries a `handlerThrew` message, so it contains the throw\n\t\t\t// of the handler and writes it to `console.error`.\n\t\t\t//\n\t\t\t// The five renderers hold the one rule: a handler of the host never defeats the\n\t\t\t// containment, and a host that must escalate raises the failure from a task of\n\t\t\t// its own.\n\t\t\terrored.value = true;\n\t\t\treport(err);\n\t\t\treturn false;\n\t\t});\n\n\t\t// Take the registryResult out of the proxy, and mark each component as raw, because\n\t\t// the reactivity of Vue costs too much here. `markRaw` marks the component object\n\t\t// itself, so a copy of the registry adds nothing to it.\n\t\t//\n\t\t// Put the handler of the provider into the registry. The property is not enumerable,\n\t\t// and it replaces the handler of the defineRegistry level. It gives each report to the\n\t\t// onRenderError prop, and it gives a failure of the ROOT to the session: json-render\n\t\t// reports such a failure to no hook of the host, so the session records it in a new\n\t\t// snapshot and reports it through `onFailure`, and the render function shows the\n\t\t// fallback. The binding keeps one copy for each registry, and the copy calls the\n\t\t// newest handler. json-render-core makes that copy with its own rule: the members\n\t\t// with their descriptors, so a getter still reads the source, and the slot metadata,\n\t\t// so each named slot of the catalog is validated. The code marks the copy raw.\n\t\t//\n\t\t// A computed, and not a value of setup(): a new registryResult or onRenderError prop\n\t\t// after the mount reaches the children.\n\t\tconst bindRenderError = createRenderErrorBinding<DefineRegistryResult>();\n\t\tlet rawSource: DefineRegistryResult | undefined;\n\t\tconst activeRegistryResult = computed((): DefineRegistryResult => {\n\t\t\tconst source = toRaw(props.registryResult);\n\t\t\tif (rawSource !== source) {\n\t\t\t\tfor (const descriptor of Object.values(ownMemberDescriptors(source.registry))) {\n\t\t\t\t\t// markRaw takes an object alone. An entry of null or undefined is no\n\t\t\t\t\t// component, and json-render renders no component for it. A getter is no\n\t\t\t\t\t// value here, and it reads the source at each access.\n\t\t\t\t\tconst { value } = descriptor;\n\t\t\t\t\tif (\n\t\t\t\t\t\t(typeof value === \"object\" && value !== null) ||\n\t\t\t\t\t\ttypeof value === \"function\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tmarkRaw(value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trawSource = source;\n\t\t\t}\n\t\t\tconst bound = bindRenderError(source, props.onRenderError, (error) =>\n\t\t\t\tsession.failView(error),\n\t\t\t);\n\t\t\tmarkRaw(bound.registry);\n\t\t\treturn bound;\n\t\t});\n\n\t\t// Give the actor to each descendant, through the provide and inject mechanism of Vue.\n\t\t//\n\t\t// The code gives a stable proxy, and not the raw actor, because each injector keeps\n\t\t// the reference of its setup(). Every access resolves against the newest actor\n\t\t// prop, taken out of the reactive proxy of Vue to reach the raw Atom objects. The proxy is NOT identity-equal to\n\t\t// `props.actor`: a consumer that keys a WeakMap on the identity of the actor, such as\n\t\t// the guard of one bridge for each actor in RouterBridgeBase, must receive the actor\n\t\t// itself.\n\t\tprovideActor(createActorProxy<AnyPlayActor>(() => toRaw(props.actor as ViewActor)));\n\n\t\t// The view session, from @xmachines/play-view. It resolves the store of the view\n\t\t// when the actor emits, when the host hands over a new actor or store, and for a\n\t\t// retry — never in a render — and it seeds, refreshes and drops the store by the rules\n\t\t// of the lifecycle. The five renderers share it, and only the wiring below belongs\n\t\t// to Vue.\n\t\t//\n\t\t// A failure of the resolution reports through `onFailure`. `spec.state` can throw —\n\t\t// a projection with an accessor, or a seed of a store — and `onErrorCaptured` above\n\t\t// sees a throw of a DESCENDANT only. The snapshot then holds no store, so the render\n\t\t// function shows the fallback, and the next new snapshot renders the children again.\n\t\tconst session = createViewSession(toRaw(props.actor as ViewActor), props.store, {\n\t\t\tcreateStore: (seed) => xstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t\tonFailure: (error) => report(error),\n\t\t});\n\t\t// A shallowRef: the snapshot is immutable, and a deep ref would wrap the spec and its\n\t\t// store in reactive proxies on each emission.\n\t\tconst snapshot = shallowRef<ViewSessionSnapshot>(session.getSnapshot());\n\n\t\t// setup() is no render, so the session connects here. Every new snapshot clears the\n\t\t// errored flag (see the reset rule above) before the new view renders: a new view, a\n\t\t// new actor, or a new controlled store. A hit of the error boundary therefore retries\n\t\t// here.\n\t\tconst release = session.subscribe(() => {\n\t\t\terrored.value = false;\n\t\t\tsnapshot.value = session.getSnapshot();\n\t\t});\n\t\tsnapshot.value = session.getSnapshot();\n\n\t\t// Hand a new actor or a new controlled store to the session. `flush: \"sync\"`, so that\n\t\t// no scheduler runs between the prop and the resolution. A new actor drops the store\n\t\t// of the old one, and a repaired controlled store renders the children again.\n\t\twatch(\n\t\t\t() => [toRaw(props.actor as ViewActor), props.store] as const,\n\t\t\t([nextActor, nextStore]) => {\n\t\t\t\tsession.setInputs(nextActor, nextStore);\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tguard.dispose();\n\t\t\trelease();\n\t\t\tsession.dispose();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// A contained error of a descendant: show the fallback slot, or show nothing,\n\t\t\t// until the next snapshot clears the flag and retries the render.\n\t\t\tif (errored.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\t// No view, or a failed resolution: show the fallback slot, or show nothing.\n\t\t\tconst { view: spec, store, generation } = snapshot.value;\n\t\t\tif (!spec || !store) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\t// ActorProviderInner renders inside StateProvider. Therefore useStateStore() works.\n\t\t\t// The children receive the store with the guard, because /context is read-only to\n\t\t\t// the spec. The generation is the key of a SUBTREE REMOUNT. The lifecycle changes it\n\t\t\t// for a new store only, and never for a refresh of /context in place. Without this\n\t\t\t// rule, each update of the projection removes the subtree on the screen.\n\t\t\treturn h(StateProvider, { store, key: generation }, () =>\n\t\t\t\th(\n\t\t\t\t\tActorProviderInner,\n\t\t\t\t\t{ registryResult: activeRegistryResult.value, spec, store },\n\t\t\t\t\tslots,\n\t\t\t\t),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { PropType } from 'vue';
|
|
2
|
+
import { DefineRegistryResult, OnRenderError } from '@xmachines/json-render-vue';
|
|
3
|
+
import { StateStore } from '@xmachines/json-render-core';
|
|
4
|
+
import { ActorProviderProps } from './types.js';
|
|
5
|
+
export type { ActorProviderProps } from './types.js';
|
|
6
|
+
export { usePlayView } from './actor-provider-context.js';
|
|
7
|
+
export type { ViewContextValue } from './actor-provider-context.js';
|
|
8
|
+
declare const _default: typeof __VLS_export;
|
|
9
|
+
export default _default;
|
|
10
|
+
declare const __VLS_export: import('@vue/runtime-core').DefineComponent<import('@vue/runtime-core').ExtractPropTypes<{
|
|
11
|
+
actor: {
|
|
12
|
+
type: PropType<ActorProviderProps["actor"]>;
|
|
13
|
+
required: true;
|
|
14
|
+
};
|
|
15
|
+
registryResult: {
|
|
16
|
+
type: PropType<DefineRegistryResult>;
|
|
17
|
+
required: true;
|
|
18
|
+
};
|
|
19
|
+
store: {
|
|
20
|
+
type: PropType<StateStore>;
|
|
21
|
+
default: undefined;
|
|
22
|
+
};
|
|
23
|
+
onRenderError: {
|
|
24
|
+
type: PropType<OnRenderError>;
|
|
25
|
+
default: undefined;
|
|
26
|
+
};
|
|
27
|
+
onError: {
|
|
28
|
+
type: PropType<(error: unknown, reset: () => void) => void>;
|
|
29
|
+
default: undefined;
|
|
30
|
+
};
|
|
31
|
+
}>, () => import('@vue/runtime-core').VNode<import('@vue/runtime-core').RendererNode, import('@vue/runtime-core').RendererElement, {
|
|
32
|
+
[key: string]: any;
|
|
33
|
+
}> | import('@vue/runtime-core').VNode<import('@vue/runtime-core').RendererNode, import('@vue/runtime-core').RendererElement, {
|
|
34
|
+
[key: string]: any;
|
|
35
|
+
}>[] | null, {}, {}, {}, import('@vue/runtime-core').ComponentOptionsMixin, import('@vue/runtime-core').ComponentOptionsMixin, {}, string, import('@vue/runtime-core').PublicProps, Readonly<import('@vue/runtime-core').ExtractPropTypes<{
|
|
36
|
+
actor: {
|
|
37
|
+
type: PropType<ActorProviderProps["actor"]>;
|
|
38
|
+
required: true;
|
|
39
|
+
};
|
|
40
|
+
registryResult: {
|
|
41
|
+
type: PropType<DefineRegistryResult>;
|
|
42
|
+
required: true;
|
|
43
|
+
};
|
|
44
|
+
store: {
|
|
45
|
+
type: PropType<StateStore>;
|
|
46
|
+
default: undefined;
|
|
47
|
+
};
|
|
48
|
+
onRenderError: {
|
|
49
|
+
type: PropType<OnRenderError>;
|
|
50
|
+
default: undefined;
|
|
51
|
+
};
|
|
52
|
+
onError: {
|
|
53
|
+
type: PropType<(error: unknown, reset: () => void) => void>;
|
|
54
|
+
default: undefined;
|
|
55
|
+
};
|
|
56
|
+
}>> & Readonly<{}>, {
|
|
57
|
+
store: StateStore;
|
|
58
|
+
onRenderError: OnRenderError;
|
|
59
|
+
onError: (error: unknown, reset: () => void) => void;
|
|
60
|
+
}, {}, {}, {}, string, import('@vue/runtime-core').ComponentProvideOptions, true, {}, any>;
|
|
61
|
+
//# sourceMappingURL=ActorProvider.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ActorProvider.vue.d.ts","sourceRoot":"","sources":["../src/ActorProvider.vue"],"names":[],"mappings":"AAkjBA,OAAO,KAAK,EAA2B,QAAQ,EAAE,MAAM,KAAK,CAAC;AAW7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAStF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAI9D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrD,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;wBAgF/C,OAAO,YAAY;AAAxC,wBAAyC;AASzC,QAAA,MAAM,YAAY;;cAIC,QAAQ,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;;;;cAIrC,QAAQ,CAAC,oBAAoB,CAAC;;;;cAI9B,QAAQ,CAAC,UAAU,CAAC;;;;cAIlB,QAAQ,CAAC,aAAa,CAAC;;;;cAIvB,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;;;;;;;;;cAhBvD,QAAQ,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;;;;cAIrC,QAAQ,CAAC,oBAAoB,CAAC;;;;cAI9B,QAAQ,CAAC,UAAU,CAAC;;;;cAIlB,QAAQ,CAAC,aAAa,CAAC;;;;cAIvB,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;;;;;;qBAApC,OAAO,SAAS,MAAM,IAAI,KAAK,IAAI;0FAyWvE,CAAC"}
|
|
@@ -3,16 +3,17 @@ import { canRaiseAgain, failsTheRender, isComponentUpdate } from "./error-source
|
|
|
3
3
|
import { provideActor } from "./useActor.js";
|
|
4
4
|
import { computed, defineComponent, getCurrentInstance, h, markRaw, onErrorCaptured, onUnmounted, provide, ref, shallowRef, toRaw, watch } from "vue";
|
|
5
5
|
import { ActionProvider, StateProvider, VisibilityProvider, useStateStore } from "@xmachines/json-render-vue";
|
|
6
|
-
import { createAtom
|
|
7
|
-
import {
|
|
6
|
+
import { createAtom } from "@xmachines/play-atom";
|
|
7
|
+
import { bindStoreHandlers, createActorProxy, createRenderErrorBinding, createReportGuard, createViewSession } from "@xmachines/play-view";
|
|
8
|
+
import { ownMemberDescriptors } from "@xmachines/json-render-core";
|
|
8
9
|
import { xstateStoreStateStore } from "@xmachines/json-render-xstate";
|
|
9
10
|
//#region packages/play-vue/src/ActorProvider.vue?vue&type=script&lang.ts
|
|
10
11
|
/**
|
|
11
12
|
* ActorProvider — the low-level provider of the XMachines Vue render architecture.
|
|
12
13
|
*
|
|
13
14
|
* It owns the complete actor lifecycle:
|
|
14
|
-
* - the
|
|
15
|
-
*
|
|
15
|
+
* - the view session of @xmachines/play-view, whose snapshots reach the Vue reactivity
|
|
16
|
+
* through a shallowRef: the StateStore of each view, controlled and uncontrolled
|
|
16
17
|
* - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider
|
|
17
18
|
* - the ViewContextValue, which it provides through the ViewKey injection key
|
|
18
19
|
* - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below
|
|
@@ -47,11 +48,7 @@ var ActorProviderInner = defineComponent({
|
|
|
47
48
|
return viewRef.value?.[prop];
|
|
48
49
|
} }));
|
|
49
50
|
const stateStore = useStateStore();
|
|
50
|
-
const
|
|
51
|
-
const prev = stateStore.getSnapshot();
|
|
52
|
-
stateStore.update(updater(prev));
|
|
53
|
-
};
|
|
54
|
-
const handlers = computed(() => props.registryResult.handlers(() => setStateAdapter, () => stateStore.getSnapshot()));
|
|
51
|
+
const handlers = computed(() => bindStoreHandlers(props.registryResult, () => stateStore));
|
|
55
52
|
return () => {
|
|
56
53
|
if (!props.spec) {
|
|
57
54
|
viewRef.value = null;
|
|
@@ -93,32 +90,21 @@ var ActorProvider_vue_vue_type_script_lang_default = defineComponent({
|
|
|
93
90
|
},
|
|
94
91
|
setup(props, { slots }) {
|
|
95
92
|
const errored = ref(false);
|
|
96
|
-
/**
|
|
97
|
-
* The report-once rule, from @xmachines/play-actor.
|
|
98
|
-
*
|
|
99
|
-
* It holds the actor, the view and the store of the failure that it reported. A
|
|
100
|
-
* latch that compared the identity of the ERROR held nothing: an accessor that
|
|
101
|
-
* throws builds a new one at each read, which is the ordinary shape of a failing
|
|
102
|
-
* projection. play-svelte and play-solid use the same latch.
|
|
103
|
-
*/
|
|
104
|
-
const failureLatch = createFailureLatch();
|
|
105
93
|
const guard = createReportGuard({
|
|
106
94
|
noHandler: "[@xmachines/play-vue] ActorProvider contained an error of a descendant. Give an onError prop to receive it.",
|
|
107
95
|
handlerThrew: "[@xmachines/play-vue] the onError handler of the host threw. ActorProvider contained the failure of the view all the same."
|
|
108
96
|
});
|
|
109
|
-
const retryNonce = ref(0);
|
|
110
97
|
/**
|
|
111
98
|
* Clears the contained error and renders again.
|
|
112
99
|
*
|
|
113
|
-
* The
|
|
114
|
-
*
|
|
115
|
-
*
|
|
100
|
+
* The session resolves the view that the actor holds NOW, and its new snapshot
|
|
101
|
+
* renders again. A retry bound to the view that failed would take a host that keeps
|
|
102
|
+
* the callback back onto the screen that threw.
|
|
116
103
|
*/
|
|
117
104
|
const retry = () => {
|
|
118
105
|
if (guard.blocked()) return;
|
|
119
106
|
errored.value = false;
|
|
120
|
-
|
|
121
|
-
retryNonce.value++;
|
|
107
|
+
session.retry();
|
|
122
108
|
};
|
|
123
109
|
/** Sends a contained failure to `onError`, or to the console when none is given. */
|
|
124
110
|
const report = (err) => {
|
|
@@ -169,99 +155,49 @@ var ActorProvider_vue_vue_type_script_lang_default = defineComponent({
|
|
|
169
155
|
report(err);
|
|
170
156
|
return false;
|
|
171
157
|
});
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
const value = Reflect.get(current, prop, current);
|
|
183
|
-
if (typeof value !== "function") return value;
|
|
184
|
-
const cached = boundMethodCache.get(prop);
|
|
185
|
-
if (cached && cached.source === value) return cached.bound;
|
|
186
|
-
const bound = value.bind(current);
|
|
187
|
-
boundMethodCache.set(prop, {
|
|
188
|
-
source: value,
|
|
189
|
-
bound
|
|
190
|
-
});
|
|
191
|
-
return bound;
|
|
192
|
-
},
|
|
193
|
-
has(_target, prop) {
|
|
194
|
-
return prop in actorRef.value;
|
|
195
|
-
},
|
|
196
|
-
set(_target, prop, value) {
|
|
197
|
-
return Reflect.set(actorRef.value, prop, value, actorRef.value);
|
|
198
|
-
},
|
|
199
|
-
deleteProperty(_target, prop) {
|
|
200
|
-
return Reflect.deleteProperty(actorRef.value, prop);
|
|
201
|
-
},
|
|
202
|
-
ownKeys() {
|
|
203
|
-
return Reflect.ownKeys(actorRef.value);
|
|
204
|
-
},
|
|
205
|
-
getOwnPropertyDescriptor(_target, prop) {
|
|
206
|
-
const desc = Reflect.getOwnPropertyDescriptor(actorRef.value, prop);
|
|
207
|
-
if (!desc) return void 0;
|
|
208
|
-
desc.configurable = true;
|
|
209
|
-
return desc;
|
|
210
|
-
},
|
|
211
|
-
getPrototypeOf() {
|
|
212
|
-
return Reflect.getPrototypeOf(actorRef.value);
|
|
158
|
+
const bindRenderError = createRenderErrorBinding();
|
|
159
|
+
let rawSource;
|
|
160
|
+
const activeRegistryResult = computed(() => {
|
|
161
|
+
const source = toRaw(props.registryResult);
|
|
162
|
+
if (rawSource !== source) {
|
|
163
|
+
for (const descriptor of Object.values(ownMemberDescriptors(source.registry))) {
|
|
164
|
+
const { value } = descriptor;
|
|
165
|
+
if (typeof value === "object" && value !== null || typeof value === "function") markRaw(value);
|
|
166
|
+
}
|
|
167
|
+
rawSource = source;
|
|
213
168
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
let storeKey = 0;
|
|
218
|
-
let unwatch = watchAtom(actorRef.value.currentView, (nextView) => {
|
|
219
|
-
errored.value = false;
|
|
220
|
-
failureLatch.clear();
|
|
221
|
-
view.value = nextView;
|
|
169
|
+
const bound = bindRenderError(source, props.onRenderError, (error) => session.failView(error));
|
|
170
|
+
markRaw(bound.registry);
|
|
171
|
+
return bound;
|
|
222
172
|
});
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
173
|
+
provideActor(createActorProxy(() => toRaw(props.actor)));
|
|
174
|
+
const session = createViewSession(toRaw(props.actor), props.store, {
|
|
175
|
+
createStore: (seed) => xstateStoreStateStore({ atom: createAtom(seed) }),
|
|
176
|
+
onFailure: (error) => report(error)
|
|
226
177
|
});
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
unwatch();
|
|
230
|
-
actorRef.value = nextActor;
|
|
231
|
-
boundMethodCache.clear();
|
|
178
|
+
const snapshot = shallowRef(session.getSnapshot());
|
|
179
|
+
const release = session.subscribe(() => {
|
|
232
180
|
errored.value = false;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
view.value = nextView;
|
|
239
|
-
});
|
|
181
|
+
snapshot.value = session.getSnapshot();
|
|
182
|
+
});
|
|
183
|
+
snapshot.value = session.getSnapshot();
|
|
184
|
+
watch(() => [toRaw(props.actor), props.store], ([nextActor, nextStore]) => {
|
|
185
|
+
session.setInputs(nextActor, nextStore);
|
|
240
186
|
}, { flush: "sync" });
|
|
241
187
|
onUnmounted(() => {
|
|
242
188
|
guard.dispose();
|
|
243
|
-
|
|
189
|
+
release();
|
|
190
|
+
session.dispose();
|
|
244
191
|
});
|
|
245
192
|
return () => {
|
|
246
|
-
retryNonce.value;
|
|
247
193
|
if (errored.value) return slots.fallback ? slots.fallback() : null;
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
let resolution;
|
|
251
|
-
try {
|
|
252
|
-
resolution = storeLifecycle.resolve(actorRef.value, spec, props.store);
|
|
253
|
-
} catch (error) {
|
|
254
|
-
if (failureLatch.shouldReport(actorRef.value, spec, props.store)) report(error);
|
|
255
|
-
return slots.fallback ? slots.fallback() : null;
|
|
256
|
-
}
|
|
257
|
-
failureLatch.clear();
|
|
258
|
-
if (resolution.reseeded) storeKey++;
|
|
259
|
-
const store = resolution.guardedStore;
|
|
194
|
+
const { view: spec, store, generation } = snapshot.value;
|
|
195
|
+
if (!spec || !store) return slots.fallback ? slots.fallback() : null;
|
|
260
196
|
return h(StateProvider, {
|
|
261
197
|
store,
|
|
262
|
-
key:
|
|
198
|
+
key: generation
|
|
263
199
|
}, () => h(ActorProviderInner, {
|
|
264
|
-
registryResult:
|
|
200
|
+
registryResult: activeRegistryResult.value,
|
|
265
201
|
spec,
|
|
266
202
|
store
|
|
267
203
|
}, slots));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ActorProvider.vue_vue_type_script_lang.js","names":[],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — the low-level provider of the XMachines Vue render architecture.\n *\n * It owns the complete actor lifecycle:\n * - the atom subscription (watchAtom), which connects the atoms to the Vue reactivity\n * - the StateStore lifecycle of each view, controlled and uncontrolled\n * - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider\n * - the ViewContextValue, which it provides through the ViewKey injection key\n * - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below\n * - the injection of onRenderError into the registry\n *\n * The author of a library who needs this control uses the component directly.\n * An end user takes <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - the Actor decides each state transition, with its guards\n * @invariant Passive Infrastructure - the component observes the atoms, and it sends the events\n * @invariant Atom-Only Reactivity - the state of the business logic is in the actor atoms\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\tonErrorCaptured,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n\tgetCurrentInstance,\n} from \"vue\";\nimport type { ComponentPublicInstance, PropType } from \"vue\";\nimport { createAtom, watchAtom } from \"@xmachines/play-atom\";\nimport { canRaiseAgain, failsTheRender, isComponentUpdate } from \"./error-source.js\";\nimport {\n\tattachRenderErrorHandler,\n\tcreateFailureLatch,\n\tcreateReportGuard,\n\tcreateViewStoreLifecycle,\n} from \"@xmachines/play-view\";\nimport type { Viewable, PlaySpec, ViewActor } from \"@xmachines/play-view\";\nimport type {\n\tDefineRegistryResult,\n\tSetState,\n\tRenderErrorHandler,\n} from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export the props type and the context accessors, for a consumer that imports from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { usePlayView } from \"./actor-provider-context.js\";\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — it renders inside StateProvider, so that it can call useStateStore()\n// It gives the ViewContextValue, the ActionProvider, and the VisibilityProvider to the Renderer below.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The code uses a shallowRef for the value of the view context, because a deep\n\t\t// reactivity costs too much. The Proxy below lets inject() always read the newest\n\t\t// value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Give the ViewContextValue through the inject and provide system of Vue.\n\t\t// The code calls provide synchronously in setup(), so that Vue registers the value on\n\t\t// the instance of the component. It uses a Proxy, so that each descendant always\n\t\t// receives the newest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() during setup(), which is synchronous and before the return.\n\t\t// A Vue composable that uses inject() must run during setup(), and not in a render\n\t\t// function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Build a SetState adapter, because the factory of the handlers expects the pattern\n\t\t// of an updater function. The code defines it one time, in setup(). It reads\n\t\t// stateStore.getSnapshot and stateStore.update at the moment of the call. Therefore\n\t\t// it always works on the live state of the store, and it needs no new definition when\n\t\t// the identity of stateStore changes between two renders.\n\t\tconst setStateAdapter: SetState = (updater) => {\n\t\t\tconst prev = stateStore.getSnapshot();\n\t\t\tstateStore.update(updater(prev));\n\t\t};\n\n\t\t// Keep the handlers, with the identity of the registryResult prop as the key. The\n\t\t// getter functions are stable closures, and they hold the stateStore of setup().\n\t\t// Therefore they cause no new computation. The code computes the handlers again only\n\t\t// after a change of the definition of the registry, and not on each render of a view\n\t\t// update.\n\t\tconst handlers = computed(() =>\n\t\t\tprops.registryResult.handlers(\n\t\t\t\t() => setStateAdapter,\n\t\t\t\t() => stateStore.getSnapshot(),\n\t\t\t),\n\t\t);\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap the children with an ActionProvider and a VisibilityProvider. The Renderer of\n\t\t\t// PlayRenderer therefore works also with ActorProvider alone, without PlayUIProvider\n\t\t\t// and without JSONUIProvider.\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<RenderErrorHandler>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonError: {\n\t\t\ttype: Function as PropType<(error: unknown, reset: () => void) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The error boundary. It contains an error of the RENDER of a descendant — the\n\t\t// render function, the setup function, and a lifecycle hook — so that a subtree\n\t\t// that throws cannot take the whole application down. `onErrorCaptured` notifies\n\t\t// `onError`, it sets the errored flag, and the render function below then returns\n\t\t// the `fallback` slot instead of the children.\n\t\t//\n\t\t// `onErrorCaptured` of Vue also fires for an error of an event handler, and of a\n\t\t// watcher callback, which no other renderer of this workspace sees: the boundary\n\t\t// of React, the ErrorBoundary of Solid, and `<svelte:boundary>` each catch a\n\t\t// failure of the render only. A click handler that throws must therefore NOT\n\t\t// replace the view with the fallback. This boundary leaves such an error\n\t\t// COMPLETELY alone: it calls `onError` never, and it returns undefined, so the\n\t\t// error continues to `app.config.errorHandler` exactly as it does without this\n\t\t// provider. A report here would give play-vue a wider `onError` contract than the\n\t\t// other four renderers, and it would reach a caller that wires both this prop and\n\t\t// the global handler two times for one click.\n\t\t//\n\t\t// RESET RULE: the next view emission clears the flag (see the callbacks of\n\t\t// watchAtom and the handler of the actor swap). A view transition therefore\n\t\t// retries the render. Without the rule the user sends a recovery event, the actor\n\t\t// moves to a healthy view, and the screen keeps the fallback.\n\t\t//\n\t\t// The per-element boundary of @json-render catches a throw of a catalog component\n\t\t// upstream, and reports it through `onRenderError`. This boundary is the outer net\n\t\t// for everything else.\n\t\t//\n\t\t// The return of false stops a render error HERE. Without `onError` that error\n\t\t// therefore reaches neither `app.config.errorHandler` nor the console, and a\n\t\t// consumer that gives no handler loses it in silence. Write it to `console.error`\n\t\t// in that case, in the same way as the inner renderer does for a component that\n\t\t// throws without an `onRenderError` handler.\n\t\tconst errored = ref(false);\n\t\t/**\n\t\t * The report-once rule, from @xmachines/play-actor.\n\t\t *\n\t\t * It holds the actor, the view and the store of the failure that it reported. A\n\t\t * latch that compared the identity of the ERROR held nothing: an accessor that\n\t\t * throws builds a new one at each read, which is the ordinary shape of a failing\n\t\t * projection. play-svelte and play-solid use the same latch.\n\t\t */\n\t\tconst failureLatch = createFailureLatch();\n\n\t\t// The report guard, from @xmachines/play-actor: it blocks a reset that the host\n\t\t// calls from INSIDE the report, and every callback once the provider is gone. The\n\t\t// five renderers share the one implementation.\n\t\t//\n\t\t// The re-entry rule matters more here than a stack suggests: a write of a ref\n\t\t// renders on the NEXT tick, so a host with a retry-once policy loops with no stack\n\t\t// at all, and a flag around the retry itself would catch nothing.\n\t\t//\n\t\t// It CONTAINS a handler of the host that throws. The flag below schedules a\n\t\t// RENDER, and a throw that leaves the hook stops that render and skips the\n\t\t// `return false`, so the subtree that threw stays on the screen AND the error\n\t\t// reaches `app.config.errorHandler`.\n\t\tconst guard = createReportGuard({\n\t\t\tnoHandler:\n\t\t\t\t\"[@xmachines/play-vue] ActorProvider contained an error of a descendant. \" +\n\t\t\t\t\"Give an onError prop to receive it.\",\n\t\t\thandlerThrew:\n\t\t\t\t\"[@xmachines/play-vue] the onError handler of the host threw. \" +\n\t\t\t\t\"ActorProvider contained the failure of the view all the same.\",\n\t\t});\n\t\t// The retry renders again through a nonce that the render function reads. Clearing\n\t\t// the flags alone renders nothing: `errored.value = false` writes the value that\n\t\t// the ref holds already on the path of a failed RESOLUTION, and Vue schedules\n\t\t// nothing for a write that changes no value.\n\t\tconst retryNonce = ref(0);\n\n\t\t/**\n\t\t * Clears the contained error and renders again.\n\t\t *\n\t\t * The render function reads `view.value`, so the retry resolves the view that the\n\t\t * actor holds NOW. A retry bound to the view that failed would take a host that\n\t\t * keeps the callback back onto the screen that threw.\n\t\t */\n\t\tconst retry = (): void => {\n\t\t\tif (guard.blocked()) return;\n\t\t\terrored.value = false;\n\t\t\tfailureLatch.clear();\n\t\t\tretryNonce.value++;\n\t\t};\n\n\t\t/** Sends a contained failure to `onError`, or to the console when none is given. */\n\t\tconst report = (err: unknown): void => {\n\t\t\tconst handler = props.onError;\n\t\t\tguard.report(err, handler ? () => handler(err, retry) : undefined);\n\t\t};\n\n\t\t// The configuration of the application, read one time. `canRaiseAgain` asks the two\n\t\t// fields that `handleError` of Vue reads on every error. It lives in error-source.ts,\n\t\t// because its production half answers a spelling that a mounted test reaches never.\n\t\tconst appConfig = getCurrentInstance()?.appContext.config;\n\n\t\t// The error that this boundary let through LAST, and that the NEXT raise can still\n\t\t// claim as a repeat.\n\t\t//\n\t\t// The second raise is SYNCHRONOUS and IMMEDIATE. `logError` of the development\n\t\t// bundle re-throws, and the throw unwinds straight back into `callWithErrorHandling`\n\t\t// of `flushJobs`, which reports the same value again. No other raise reaches this\n\t\t// hook in between, so ONE slot holds the complete window.\n\t\t//\n\t\t// EVERY raise that fails the render takes the slot, and not a component update\n\t\t// alone. A record that no raise takes can otherwise outlive its window.\n\t\t//\n\t\t// The record names the INSTANCE beside the error value. A repeat carries the\n\t\t// instance whose JOB ran when the error unwound, and that is the owner of the\n\t\t// watcher OR one of its ANCESTORS: a pre-flush watcher of a child runs inside the\n\t\t// update of the parent that passes it a prop, and `flushJobs` reports the throw\n\t\t// under the parent — or under the outermost ancestor whose update ran. The take\n\t\t// therefore walks the `$parent` chain of the recorded instance. A SIBLING stands on\n\t\t// that chain never, and a sibling that fails with the same cached error is one\n\t\t// loader with two consumers: that failure is a first incident, and the boundary\n\t\t// contains it.\n\t\t//\n\t\t// The microtask is the BACKSTOP, for a raise that neither a repeat nor another\n\t\t// raise follows. A record for the life of the provider would disarm the boundary\n\t\t// for that error for ever, and a descendant that keeps a failure and raises it\n\t\t// again from a LATER render is an ordinary shape.\n\t\t//\n\t\t// Each `remember` schedules a clear of ITS OWN record, and that clear takes no\n\t\t// other. A clear that removed whatever the slot holds could run after a take\n\t\t// emptied the slot and a later `remember` filled it again, and it would then\n\t\t// disarm the boundary for a repeat that is still to come.\n\t\tlet letThrough: { error: unknown; instance: ComponentPublicInstance | null } | null = null;\n\t\tconst remember = (error: unknown, instance: ComponentPublicInstance | null): void => {\n\t\t\tconst record = { error, instance };\n\t\t\tletThrough = record;\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (letThrough === record) letThrough = null;\n\t\t\t});\n\t\t};\n\t\t/**\n\t\t * Takes the record. It answers TRUE when the record names this error, and when the\n\t\t * instance that raises it is the recorded one or one of its ancestors.\n\t\t *\n\t\t * The comparison reads `$` on both sides, which is the INTERNAL instance. Vue hands\n\t\t * `onErrorCaptured` the `proxy` of a component, and `$parent` answers with the\n\t\t * `exposeProxy` of a parent that called `expose()` — which the compiler makes every\n\t\t * `<script setup>` component do. The two objects differ, so a walk that compared\n\t\t * them found an exposed ancestor never, and the boundary contained a watcher error\n\t\t * that it must let through. `$` resolves through both proxies and names one object.\n\t\t */\n\t\tconst takeRepeat = (error: unknown, instance: ComponentPublicInstance | null): boolean => {\n\t\t\tconst record = letThrough;\n\t\t\tletThrough = null;\n\t\t\tif (record === null || record.error !== error) return false;\n\t\t\tfor (let node = record.instance; node !== null; node = node.$parent) {\n\t\t\t\tif (node.$ === instance?.$) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t\tonErrorCaptured((err, instance, info) => {\n\t\t\t// An error that did NOT fail the render leaves this boundary untouched: the\n\t\t\t// screen keeps its view, `onError` stays silent, and the return of undefined\n\t\t\t// sends the error on to `app.config.errorHandler`. The boundary of React, the\n\t\t\t// ErrorBoundary of Solid, and `<svelte:boundary>` each see such an error never,\n\t\t\t// so a call of `onError` here would give play-vue a wider contract than the\n\t\t\t// other four, AND it would report the same failure twice to a caller that wires\n\t\t\t// both `onError` and the global handler of the application.\n\t\t\tif (!failsTheRender(info)) {\n\t\t\t\t// Arm the record only where Vue WILL raise this error a second time. A record\n\t\t\t\t// that no repeat claims stands until the microtask, and a genuine failure of\n\t\t\t\t// a render in the same flush — the same descendant, the same cached error —\n\t\t\t\t// would then take it: no fallback, no `onError`, and no screen.\n\t\t\t\t//\n\t\t\t\t// `handleError` of Vue calls `app.config.errorHandler` where one exists, and\n\t\t\t\t// it reaches `logError` never; the production bundle throws only where the\n\t\t\t\t// application asks for `throwUnhandledErrorInProduction`. The one case that\n\t\t\t\t// this line cannot see is an ANCESTOR `errorCaptured` that answers false,\n\t\t\t\t// which stops Vue before `logError` too. That case stays open, and the doc of\n\t\t\t\t// `onError` names it.\n\t\t\t\tif (canRaiseAgain(info, appConfig)) remember(err, instance);\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\t// Vue can raise the SAME error a SECOND time under another source. The\n\t\t\t// development bundle of `logError` re-throws an error that no\n\t\t\t// `app.config.errorHandler` took. A queued job then loses that throw to\n\t\t\t// `callWithErrorHandling(job, job.i, 15)` of `flushJobs` — a `watch` callback\n\t\t\t// with the default `pre` flush, for one — and `flushJobs` reports it again as\n\t\t\t// \"component update\". The classification above answers \"render failure\" for that\n\t\t\t// second spelling, so a watcher that threw would take the view off the screen\n\t\t\t// after all. One error is one incident: an error that this boundary let through\n\t\t\t// in this turn stays through.\n\t\t\t//\n\t\t\t// The gate asks for the SOURCE of the repeat as well. `flushJobs` reports a\n\t\t\t// job under \"component update\", and no other source can carry a second raise\n\t\t\t// to this hook, so a record of the turn can disarm the boundary for that one\n\t\t\t// spelling alone. Without the question a setup function or a render function\n\t\t\t// that throws the SAME error value in the same turn — a loader that caches its\n\t\t\t// rejection, for one — would reach no fallback, no `onError`, and no screen.\n\t\t\t//\n\t\t\t// It returns FALSE, and not undefined. The FIRST raise went on to\n\t\t\t// `app.config.errorHandler`, which is the contract of a non-render source, and\n\t\t\t// the development bundle re-threw it there — that throw IS this second report.\n\t\t\t// A second `undefined` sends it on one more time, so `logError` warns twice for\n\t\t\t// one incident and throws again, and that throw leaves `flushJobs`. The\n\t\t\t// `finally` of `flushJobs` runs `queue.length = 0`. `flushJobs` therefore drops\n\t\t\t// every job behind the one that failed, and a sibling of the descendant that\n\t\t\t// threw renders never. One incident reaches the caller ONE time, and the flush\n\t\t\t// of Vue finishes.\n\t\t\t// `takeRepeat` runs for EVERY raise that fails the render, and not inside the\n\t\t\t// condition below: a raise of another source ENDS the window of the repeat, so\n\t\t\t// the record can disarm the boundary for the one raise that follows it and for\n\t\t\t// no other.\n\t\t\tconst repeated = takeRepeat(err, instance);\n\t\t\tif (isComponentUpdate(info) && repeated) {\n\t\t\t\t// The value reaches no console without this line. `logError` of the\n\t\t\t\t// development bundle writes the SOURCE, and not the value. It then throws\n\t\t\t\t// the value, and that throw IS this second report, which the `return`\n\t\t\t\t// below stops. `report()` wrote such an error before this gate existed, so\n\t\t\t\t// a host with no `onError` prop could still debug a watcher or a loader\n\t\t\t\t// that failed. The production bundle writes the value on the FIRST raise,\n\t\t\t\t// and it throws instead where the application asks for\n\t\t\t\t// `throwUnhandledErrorInProduction` — that application gets the write here.\n\t\t\t\t// One incident reaches the console ONE time in both bundles.\n\t\t\t\t//\n\t\t\t\t// The line carries the name of this package, as every other console write\n\t\t\t\t// of this provider does. Without it a developer reads a bare error and\n\t\t\t\t// cannot tell that the provider wrote it, and not Vue.\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"[@xmachines/play-vue] ActorProvider stopped a second report of this \" +\n\t\t\t\t\t\t\"error. Vue raised it again under the source of a component update, \" +\n\t\t\t\t\t\t\"and it failed no render.\",\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// The SCREEN comes first, and the report second, as `contain()` of play-dom\n\t\t\t// states it. A reporter can throw — one that re-throws to escalate, or a\n\t\t\t// transport that fails — and here the order alone is not enough: the flag\n\t\t\t// schedules a RENDER, and a throw that leaves this hook stops that render and\n\t\t\t// skips the `return false`. The GUARD holds that half, for the four renderers\n\t\t\t// that need it: it carries a `handlerThrew` message, so it contains the throw\n\t\t\t// of the handler and writes it to `console.error`.\n\t\t\t//\n\t\t\t// The five renderers hold the one rule: a handler of the host never defeats the\n\t\t\t// containment, and a host that must escalate raises the failure from a task of\n\t\t\t// its own.\n\t\t\terrored.value = true;\n\t\t\treport(err);\n\t\t\treturn false;\n\t\t});\n\n\t\t// Take the actor out of the reactive proxy of Vue, to reach the raw Atom objects.\n\t\t// A shallowRef holds the actor. Therefore the injected value and the atom watcher\n\t\t// can follow `props.actor` when the prop changes after the mount.\n\t\tconst actorRef = shallowRef(toRaw(props.actor as ViewActor));\n\n\t\t// Take the registryResult out of the proxy, and mark each component as raw, because the reactivity of Vue costs too much here\n\t\tconst rawRegistry = Object.fromEntries(\n\t\t\tObject.entries(toRaw(props.registryResult).registry).map(([k, v]) => [\n\t\t\t\tk,\n\t\t\t\tmarkRaw(v as object),\n\t\t\t]),\n\t\t) as DefineRegistryResult[\"registry\"];\n\n\t\t// Put the onRenderError prop into the registry. The property is not enumerable, and\n\t\t// it replaces the handler of the defineRegistry level. attachRenderErrorHandler makes\n\t\t// a copy, and it changes the registry of the caller never.\n\t\t// The code must call markRaw on the copy again, because a copy does not carry the\n\t\t// non-enumerable flag of markRaw.\n\t\tconst rawRegistryResult: DefineRegistryResult = {\n\t\t\t...toRaw(props.registryResult),\n\t\t\tregistry: markRaw(\n\t\t\t\tprops.onRenderError\n\t\t\t\t\t? attachRenderErrorHandler(rawRegistry, props.onRenderError)\n\t\t\t\t\t: rawRegistry,\n\t\t\t),\n\t\t};\n\n\t\t// Give the actor to each descendant, through the provide and inject mechanism of Vue.\n\t\t//\n\t\t// The code gives a stable Proxy, and not the raw actor. The pattern is the same as\n\t\t// the ViewKey proxy of ActorProviderInner. The injected value therefore follows the\n\t\t// CURRENT `props.actor`: each injector keeps the reference of the setup(), and every\n\t\t// trap resolves against the newest actor (actorRef.value) after a change of the prop.\n\t\t// The proxy forwards each relevant trap. Therefore it behaves like the actor below it\n\t\t// for a read, for a write, for a membership test (`in`), for an enumeration\n\t\t// (Object.keys and a spread), and for a prototype test (`instanceof`). Each method\n\t\t// binds to the current raw actor. Therefore `this`, and also each private field,\n\t\t// works exactly as in a direct call.\n\t\t//\n\t\t// IMPORTANT: this proxy is NOT identity-equal to `props.actor`, because it is a\n\t\t// separate object, and therefore a separate key of a WeakMap. A consumer that uses\n\t\t// the identity as its key must receive the `props.actor` value itself, and never this\n\t\t// injected proxy. The most important such consumer is the guard of one bridge for\n\t\t// each actor in RouterBridgeBase: it uses the identity of the actor as the key of a\n\t\t// WeakMap at the module level.\n\t\t//\n\t\t// The identity of a method: the code keeps each bound method, with the method below\n\t\t// it as the key. A repeated read therefore returns the SAME function\n\t\t// (actor.send === actor.send), and the hot path allocates nothing. A read binds the\n\t\t// method again only after a change of the method below it. The watch handler below\n\t\t// CLEARS the cache on a change of the actor. Therefore each prototype method binds to\n\t\t// the new actor.\n\t\tconst boundMethodCache = new Map<PropertyKey, { source: unknown; bound: unknown }>();\n\t\tprovideActor(\n\t\t\tnew Proxy({} as AnyPlayActor, {\n\t\t\t\tget(_target, prop) {\n\t\t\t\t\tconst current = actorRef.value;\n\t\t\t\t\tconst value = Reflect.get(current, prop, current) as unknown;\n\t\t\t\t\tif (typeof value !== \"function\") return value;\n\t\t\t\t\tconst cached = boundMethodCache.get(prop);\n\t\t\t\t\tif (cached && cached.source === value) return cached.bound;\n\t\t\t\t\tconst bound = (value as (...args: unknown[]) => unknown).bind(current);\n\t\t\t\t\tboundMethodCache.set(prop, { source: value, bound });\n\t\t\t\t\treturn bound;\n\t\t\t\t},\n\t\t\t\thas(_target, prop) {\n\t\t\t\t\treturn prop in actorRef.value;\n\t\t\t\t},\n\t\t\t\tset(_target, prop, value) {\n\t\t\t\t\treturn Reflect.set(actorRef.value, prop, value, actorRef.value);\n\t\t\t\t},\n\t\t\t\tdeleteProperty(_target, prop) {\n\t\t\t\t\treturn Reflect.deleteProperty(actorRef.value, prop);\n\t\t\t\t},\n\t\t\t\townKeys() {\n\t\t\t\t\treturn Reflect.ownKeys(actorRef.value);\n\t\t\t\t},\n\t\t\t\tgetOwnPropertyDescriptor(_target, prop) {\n\t\t\t\t\tconst desc = Reflect.getOwnPropertyDescriptor(actorRef.value, prop);\n\t\t\t\t\tif (!desc) return undefined;\n\t\t\t\t\t// An invariant of a Proxy: the target of this proxy is an empty {}. Therefore each\n\t\t\t\t\t// key of ownKeys must resolve to a configurable descriptor here. Without that, the\n\t\t\t\t\t// [[GetOwnProperty]] invariant throws, because a proxy must not report a property that\n\t\t\t\t\t// its target has not as non-configurable. The own props of the actor are mutable at\n\t\t\t\t\t// run time in each case. Therefore `configurable: true` is correct enough for the\n\t\t\t\t\t// enumeration of Object.keys and of a spread.\n\t\t\t\t\tdesc.configurable = true;\n\t\t\t\t\treturn desc;\n\t\t\t\t},\n\t\t\t\tgetPrototypeOf() {\n\t\t\t\t\treturn Reflect.getPrototypeOf(actorRef.value);\n\t\t\t\t},\n\t\t\t}) as AnyPlayActor,\n\t\t);\n\n\t\t// Seed the first value, then subscribe. Both steps are synchronous, and no scheduler\n\t\t// runs between them.\n\t\t// Solid does the same with createEffect, and Svelte does the same with $effect.\n\t\t// The pattern is therefore the same in each framework.\n\t\tconst view = ref<PlaySpec | null>(actorRef.value.currentView.get());\n\n\t\t// The store lifecycle: it seeds the store again on a change of the viewKey, it\n\t\t// refreshes /context in place in every other case, it resets the store on a change of\n\t\t// the actor, and it guards the identity cache. The shared coordinator comes from\n\t\t// @xmachines/play-actor. Only the wiring of the reactivity below belongs to Vue.\n\t\tconst storeLifecycle = createViewStoreLifecycle((seed) =>\n\t\t\txstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t);\n\t\t// storeKey is the key of a SUBTREE REMOUNT. Therefore it must change only after a\n\t\t// new seed of the store, and never after a refresh of /context in place. Without this\n\t\t// rule, each update of the projection removes the subtree on the screen.\n\t\t// (The controlled mode seeds the store never again. Therefore the key changes never\n\t\t// there.)\n\t\tlet storeKey = 0;\n\n\t\t// The atom watcher connects the atoms to the reactivity of Vue.\n\t\t// The code assigns it again on a change of the actor. Therefore the cleanup always\n\t\t// releases the live watcher.\n\t\t// Every view emission clears the errored flag (see the reset rule above) before the\n\t\t// new view renders. A hit of the error boundary therefore retries here.\n\t\tlet unwatch = watchAtom(actorRef.value.currentView, (nextView) => {\n\t\t\terrored.value = false;\n\t\t\tfailureLatch.clear();\n\t\t\tview.value = nextView;\n\t\t});\n\n\t\t// The reset watches the STORE too. A render fails on it, so a caller that repairs a\n\t\t// controlled store — without a new emission — must see the children again.\n\t\t// play-react and play-solid hold the same rule, and the actor swap below covers the\n\t\t// third input.\n\t\twatch(\n\t\t\t() => props.store,\n\t\t\t() => {\n\t\t\t\terrored.value = false;\n\t\t\t\tfailureLatch.clear();\n\t\t\t},\n\t\t);\n\n\t\t// React to a change of `props.actor`: cancel the subscription to the currentView of\n\t\t// the OLD actor, seed the view from the NEW actor synchronously (`flush: \"sync\"`, so\n\t\t// that no scheduler runs between the steps, as in the seed and watch pattern of the\n\t\t// mount above), and subscribe to the new atom. The view of the new seed has a new\n\t\t// identity. Therefore the branch of the internal store below builds the store again,\n\t\t// and it changes storeKey, exactly like a normal view transition.\n\t\twatch(\n\t\t\t() => toRaw(props.actor as ViewActor),\n\t\t\t(nextActor) => {\n\t\t\t\tif (nextActor === actorRef.value) return;\n\t\t\t\tunwatch();\n\t\t\t\tactorRef.value = nextActor;\n\t\t\t\t// (The store lifecycle resets itself on a change of the actor, because a store that\n\t\t\t\t// stays alive must not outlive its actor.)\n\t\t\t\t// Clear the cache of the bound methods. Each prototype method therefore binds to the\n\t\t\t\t// new actor on the next read. See the get trap of the injected proxy.\n\t\t\t\tboundMethodCache.clear();\n\t\t\t\t// The new seed is a view emission — clear the errored flag with it.\n\t\t\t\terrored.value = false;\n\t\t\t\tfailureLatch.clear();\n\t\t\t\tview.value = nextActor.currentView.get();\n\t\t\t\tunwatch = watchAtom(nextActor.currentView, (nextView) => {\n\t\t\t\t\terrored.value = false;\n\t\t\t\t\tfailureLatch.clear();\n\t\t\t\t\tview.value = nextView;\n\t\t\t\t});\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tguard.dispose();\n\t\t\tunwatch();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// The nonce of the retry. The read makes this render function depend on it, so\n\t\t\t// the reset of the host renders again — see `retry` above.\n\t\t\tvoid retryNonce.value;\n\n\t\t\t// A contained error of a descendant: show the fallback slot, or show nothing,\n\t\t\t// until the next view emission clears the flag and retries the render.\n\t\t\tif (errored.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\t// No view: show the fallback slot, or show nothing\n\t\t\tif (!view.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\tconst spec = view.value;\n\n\t\t\t// Resolve the store, which is external and controlled, or internal for each\n\t\t\t// viewKey, through the shared lifecycle. The children receive the store with the\n\t\t\t// guard, because /context is read-only to the spec. The machinery refreshes the\n\t\t\t// store through the reference without a guard, inside the coordinator.\n\t\t\t//\n\t\t\t// The try CONTAINS a failure of this resolution. `spec.state` can throw — a\n\t\t\t// projection with an accessor, or a seed of a store — and `onErrorCaptured`\n\t\t\t// above sees a throw of a DESCENDANT only, never one of this render function.\n\t\t\t// Without the try such a failure leaves the provider, reaches\n\t\t\t// app.config.errorHandler, and takes the application down, while `onError` and\n\t\t\t// the fallback slot both stay unused.\n\t\t\t//\n\t\t\t// The branch sets the errored flag NOT: a mutation of the state during a render\n\t\t\t// starts a second render. It returns the fallback for THIS render instead, and\n\t\t\t// the next view emission renders the children again — which is the reset rule,\n\t\t\t// with no flag to clear.\n\t\t\tlet resolution;\n\t\t\ttry {\n\t\t\t\tresolution = storeLifecycle.resolve(actorRef.value, spec, props.store);\n\t\t\t} catch (error) {\n\t\t\t\t// LATCH the failure, and report it ONE time. The render function runs again\n\t\t\t\t// for any tracked change, and a report on each attempt would call onError a\n\t\t\t\t// second and a third time for one failure — play-react, play-solid and\n\t\t\t\t// play-svelte each report once.\n\t\t\t\tif (failureLatch.shouldReport(actorRef.value, spec, props.store)) report(error);\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\t\t\tfailureLatch.clear();\n\t\t\tif (resolution.reseeded) storeKey++;\n\t\t\tconst store: StateStore = resolution.guardedStore;\n\n\t\t\t// ActorProviderInner renders inside StateProvider. Therefore useStateStore() works\n\t\t\treturn h(StateProvider, { store, key: storeKey }, () =>\n\t\t\t\th(ActorProviderInner, { registryResult: rawRegistryResult, spec, store }, slots),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAwEA,IAAM,qBAAqB,gBAAgB;CAC1C,MAAM;CACN,OAAO;EACN,gBAAgB;GACf,MAAM;GACN,UAAU;EACX;EACA,MAAM;GACL,MAAM;GACN,SAAS;EACV;EACA,OAAO;GACN,MAAM;GACN,UAAU;EACX;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EAIvB,MAAM,UAAU,WAAoC,IAAI;EAMxD,QACC,SACA,IAAI,MAAM,CAAC,GAAuB,EACjC,IAAI,SAAS,MAAc;GAC1B,OAAO,QAAQ,QAAQ;EACxB,EACD,CAAC,CACF;EAKA,MAAM,aAAa,cAAc;EAOjC,MAAM,mBAA6B,YAAY;GAC9C,MAAM,OAAO,WAAW,YAAY;GACpC,WAAW,OAAO,QAAQ,IAAI,CAAC;EAChC;EAOA,MAAM,WAAW,eAChB,MAAM,eAAe,eACd,uBACA,WAAW,YAAY,CAC9B,CACD;EAEA,aAAa;GACZ,IAAI,CAAC,MAAM,MAAM;IAChB,QAAQ,QAAQ;IAChB,OAAO,MAAM,UAAU,KAAK;GAC7B;GAEA,QAAQ,QAAQ;IACf,MAAM,MAAM;IACZ,UAAU,SAAS;IACnB,UAAU,MAAM,eAAe;IAC/B,OAAO,MAAM;GACd;GAKA,OAAO,EAAE,gBAAgB,EAAE,UAAU,SAAS,MAAM,SACnD,EAAE,oBAAoB,CAAC,SAAS,MAAM,UAAU,KAAK,IAAI,CAC1D;EACD;CACD;AACD,CAAC;AAMD,IAAA,iDAAe,gBAAgB;CAC9B,MAAM;CACN,OAAO;EACN,OAAO;GACN,MAAM;GACN,UAAU;EACX;EACA,gBAAgB;GACf,MAAM;GACN,UAAU;EACX;EACA,OAAO;GACN,MAAM;GACN,SAAS,KAAA;EACV;EACA,eAAe;GACd,MAAM;GACN,SAAS,KAAA;EACV;EACA,SAAS;GACR,MAAM;GACN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EAgCvB,MAAM,UAAU,IAAI,KAAK;;;;;;;;;EASzB,MAAM,eAAe,mBAAmB;EAcxC,MAAM,QAAQ,kBAAkB;GAC/B,WACC;GAED,cACC;EAEF,CAAC;EAKD,MAAM,aAAa,IAAI,CAAC;;;;;;;;EASxB,MAAM,cAAoB;GACzB,IAAI,MAAM,QAAQ,GAAG;GACrB,QAAQ,QAAQ;GAChB,aAAa,MAAM;GACnB,WAAW;EACZ;;EAGA,MAAM,UAAU,QAAuB;GACtC,MAAM,UAAU,MAAM;GACtB,MAAM,OAAO,KAAK,gBAAgB,QAAQ,KAAK,KAAK,IAAI,KAAA,CAAS;EAClE;EAKA,MAAM,YAAY,mBAAmB,CAAC,EAAE,WAAW;EAgCnD,IAAI,aAAkF;EACtF,MAAM,YAAY,OAAgB,aAAmD;GACpF,MAAM,SAAS;IAAE;IAAO;GAAS;GACjC,aAAa;GACb,qBAAqB;IACpB,IAAI,eAAe,QAAQ,aAAa;GACzC,CAAC;EACF;;;;;;;;;;;;EAYA,MAAM,cAAc,OAAgB,aAAsD;GACzF,MAAM,SAAS;GACf,aAAa;GACb,IAAI,WAAW,QAAQ,OAAO,UAAU,OAAO,OAAO;GACtD,KAAK,IAAI,OAAO,OAAO,UAAU,SAAS,MAAM,OAAO,KAAK,SAC3D,IAAI,KAAK,MAAM,UAAU,GAAG,OAAO;GAEpC,OAAO;EACR;EAEA,iBAAiB,KAAK,UAAU,SAAS;GAQxC,IAAI,CAAC,eAAe,IAAI,GAAG;IAY1B,IAAI,cAAc,MAAM,SAAS,GAAG,SAAS,KAAK,QAAQ;IAC1D;GACD;GAgCA,MAAM,WAAW,WAAW,KAAK,QAAQ;GACzC,IAAI,kBAAkB,IAAI,KAAK,UAAU;IAcxC,QAAQ,MACP,mKAGA,GACD;IACA,OAAO;GACR;GAaA,QAAQ,QAAQ;GAChB,OAAO,GAAG;GACV,OAAO;EACR,CAAC;EAKD,MAAM,WAAW,WAAW,MAAM,MAAM,KAAkB,CAAC;EAG3D,MAAM,cAAc,OAAO,YAC1B,OAAO,QAAQ,MAAM,MAAM,cAAc,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,OAAO,CACpE,GACA,QAAQ,CAAW,CACpB,CAAC,CACF;EAOA,MAAM,oBAA0C;GAC/C,GAAG,MAAM,MAAM,cAAc;GAC7B,UAAU,QACT,MAAM,gBACH,yBAAyB,aAAa,MAAM,aAAa,IACzD,WACJ;EACD;EA2BA,MAAM,mCAAmB,IAAI,IAAsD;EACnF,aACC,IAAI,MAAM,CAAC,GAAmB;GAC7B,IAAI,SAAS,MAAM;IAClB,MAAM,UAAU,SAAS;IACzB,MAAM,QAAQ,QAAQ,IAAI,SAAS,MAAM,OAAO;IAChD,IAAI,OAAO,UAAU,YAAY,OAAO;IACxC,MAAM,SAAS,iBAAiB,IAAI,IAAI;IACxC,IAAI,UAAU,OAAO,WAAW,OAAO,OAAO,OAAO;IACrD,MAAM,QAAS,MAA0C,KAAK,OAAO;IACrE,iBAAiB,IAAI,MAAM;KAAE,QAAQ;KAAO;IAAM,CAAC;IACnD,OAAO;GACR;GACA,IAAI,SAAS,MAAM;IAClB,OAAO,QAAQ,SAAS;GACzB;GACA,IAAI,SAAS,MAAM,OAAO;IACzB,OAAO,QAAQ,IAAI,SAAS,OAAO,MAAM,OAAO,SAAS,KAAK;GAC/D;GACA,eAAe,SAAS,MAAM;IAC7B,OAAO,QAAQ,eAAe,SAAS,OAAO,IAAI;GACnD;GACA,UAAU;IACT,OAAO,QAAQ,QAAQ,SAAS,KAAK;GACtC;GACA,yBAAyB,SAAS,MAAM;IACvC,MAAM,OAAO,QAAQ,yBAAyB,SAAS,OAAO,IAAI;IAClE,IAAI,CAAC,MAAM,OAAO,KAAA;IAOlB,KAAK,eAAe;IACpB,OAAO;GACR;GACA,iBAAiB;IAChB,OAAO,QAAQ,eAAe,SAAS,KAAK;GAC7C;EACD,CAAC,CACF;EAMA,MAAM,OAAO,IAAqB,SAAS,MAAM,YAAY,IAAI,CAAC;EAMlE,MAAM,iBAAiB,0BAA0B,SAChD,sBAAsB,EAAE,MAAM,WAAW,IAAI,EAAE,CAAC,CACjD;EAMA,IAAI,WAAW;EAOf,IAAI,UAAU,UAAU,SAAS,MAAM,cAAc,aAAa;GACjE,QAAQ,QAAQ;GAChB,aAAa,MAAM;GACnB,KAAK,QAAQ;EACd,CAAC;EAMD,YACO,MAAM,aACN;GACL,QAAQ,QAAQ;GAChB,aAAa,MAAM;EACpB,CACD;EAQA,YACO,MAAM,MAAM,KAAkB,IACnC,cAAc;GACd,IAAI,cAAc,SAAS,OAAO;GAClC,QAAQ;GACR,SAAS,QAAQ;GAKjB,iBAAiB,MAAM;GAEvB,QAAQ,QAAQ;GAChB,aAAa,MAAM;GACnB,KAAK,QAAQ,UAAU,YAAY,IAAI;GACvC,UAAU,UAAU,UAAU,cAAc,aAAa;IACxD,QAAQ,QAAQ;IAChB,aAAa,MAAM;IACnB,KAAK,QAAQ;GACd,CAAC;EACF,GACA,EAAE,OAAO,OAAO,CACjB;EAEA,kBAAkB;GACjB,MAAM,QAAQ;GACd,QAAQ;EACT,CAAC;EAED,aAAa;GAGZ,WAAgB;GAIhB,IAAI,QAAQ,OACX,OAAO,MAAM,WAAW,MAAM,SAAS,IAAI;GAI5C,IAAI,CAAC,KAAK,OACT,OAAO,MAAM,WAAW,MAAM,SAAS,IAAI;GAG5C,MAAM,OAAO,KAAK;GAkBlB,IAAI;GACJ,IAAI;IACH,aAAa,eAAe,QAAQ,SAAS,OAAO,MAAM,MAAM,KAAK;GACtE,SAAS,OAAO;IAKf,IAAI,aAAa,aAAa,SAAS,OAAO,MAAM,MAAM,KAAK,GAAG,OAAO,KAAK;IAC9E,OAAO,MAAM,WAAW,MAAM,SAAS,IAAI;GAC5C;GACA,aAAa,MAAM;GACnB,IAAI,WAAW,UAAU;GACzB,MAAM,QAAoB,WAAW;GAGrC,OAAO,EAAE,eAAe;IAAE;IAAO,KAAK;GAAS,SAC9C,EAAE,oBAAoB;IAAE,gBAAgB;IAAmB;IAAM;GAAM,GAAG,KAAK,CAChF;EACD;CACD;AACD,CAAC"}
|
|
1
|
+
{"version":3,"file":"ActorProvider.vue_vue_type_script_lang.js","names":[],"sources":["../src/ActorProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * ActorProvider — the low-level provider of the XMachines Vue render architecture.\n *\n * It owns the complete actor lifecycle:\n * - the view session of @xmachines/play-view, whose snapshots reach the Vue reactivity\n * through a shallowRef: the StateStore of each view, controlled and uncontrolled\n * - the resolution of the handlers, through ActorProviderInner, which must be inside StateProvider\n * - the ViewContextValue, which it provides through the ViewKey injection key\n * - the ActionProvider wrapper and the VisibilityProvider wrapper, for the Renderer below\n * - the injection of onRenderError into the registry\n *\n * The author of a library who needs this control uses the component directly.\n * An end user takes <PlayUIProvider> instead.\n *\n * @invariant Actor Authority - the Actor decides each state transition, with its guards\n * @invariant Passive Infrastructure - the component observes the atoms, and it sends the events\n * @invariant Atom-Only Reactivity - the state of the business logic is in the actor atoms\n */\n\nimport {\n\tdefineComponent,\n\tref,\n\tcomputed,\n\ttoRaw,\n\tmarkRaw,\n\tonUnmounted,\n\tonErrorCaptured,\n\th,\n\tprovide,\n\tshallowRef,\n\twatch,\n\tgetCurrentInstance,\n} from \"vue\";\nimport type { ComponentPublicInstance, PropType } from \"vue\";\nimport { createAtom } from \"@xmachines/play-atom\";\nimport { canRaiseAgain, failsTheRender, isComponentUpdate } from \"./error-source.js\";\nimport {\n\tbindStoreHandlers,\n\tcreateActorProxy,\n\tcreateRenderErrorBinding,\n\tcreateReportGuard,\n\tcreateViewSession,\n} from \"@xmachines/play-view\";\nimport type { PlaySpec, ViewActor, ViewSessionSnapshot } from \"@xmachines/play-view\";\nimport type { DefineRegistryResult, OnRenderError } from \"@xmachines/json-render-vue\";\n\nimport {\n\tStateProvider,\n\tuseStateStore,\n\tActionProvider,\n\tVisibilityProvider,\n} from \"@xmachines/json-render-vue\";\nimport { ownMemberDescriptors } from \"@xmachines/json-render-core\";\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport { xstateStoreStateStore } from \"@xmachines/json-render-xstate\";\nimport { provideActor, type AnyPlayActor } from \"./useActor.js\";\nimport { ViewKey, type ViewContextValue } from \"./actor-provider-context.js\";\nimport type { ActorProviderProps } from \"./types.js\";\n\n// Re-export the props type and the context accessors, for a consumer that imports from this file\nexport type { ActorProviderProps } from \"./types.js\";\nexport { usePlayView } from \"./actor-provider-context.js\";\nexport type { ViewContextValue } from \"./actor-provider-context.js\";\n\n// ---------------------------------------------------------------------------\n// ActorProviderInner — it renders inside StateProvider, so that it can call useStateStore()\n// It gives the ViewContextValue, the ActionProvider, and the VisibilityProvider to the Renderer below.\n// ---------------------------------------------------------------------------\n\nconst ActorProviderInner = defineComponent({\n\tname: \"ActorProviderInner\",\n\tprops: {\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tspec: {\n\t\t\ttype: Object as PropType<PlaySpec | null>,\n\t\t\tdefault: null,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\trequired: true,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The code uses a shallowRef for the value of the view context, because a deep\n\t\t// reactivity costs too much. The Proxy below lets inject() always read the newest\n\t\t// value.\n\t\tconst viewRef = shallowRef<ViewContextValue | null>(null);\n\n\t\t// Give the ViewContextValue through the inject and provide system of Vue.\n\t\t// The code calls provide synchronously in setup(), so that Vue registers the value on\n\t\t// the instance of the component. It uses a Proxy, so that each descendant always\n\t\t// receives the newest viewRef.value.\n\t\tprovide(\n\t\t\tViewKey,\n\t\t\tnew Proxy({} as ViewContextValue, {\n\t\t\t\tget(_target, prop: string) {\n\t\t\t\t\treturn viewRef.value?.[prop as keyof ViewContextValue];\n\t\t\t\t},\n\t\t\t}),\n\t\t);\n\n\t\t// Call useStateStore() during setup(), which is synchronous and before the return.\n\t\t// A Vue composable that uses inject() must run during setup(), and not in a render\n\t\t// function.\n\t\tconst stateStore = useStateStore();\n\n\t\t// Keep the handlers, with the identity of the registryResult prop as the key. They\n\t\t// read the stateStore of setup() at the moment of an action. The code computes them\n\t\t// again only after a change of the definition of the registry, and not on each\n\t\t// render of a view update.\n\t\tconst handlers = computed(() => bindStoreHandlers(props.registryResult, () => stateStore));\n\n\t\treturn () => {\n\t\t\tif (!props.spec) {\n\t\t\t\tviewRef.value = null;\n\t\t\t\treturn slots.default?.() ?? null;\n\t\t\t}\n\n\t\t\tviewRef.value = {\n\t\t\t\tspec: props.spec,\n\t\t\t\thandlers: handlers.value,\n\t\t\t\tregistry: props.registryResult.registry,\n\t\t\t\tstore: props.store,\n\t\t\t};\n\n\t\t\t// Wrap the children with an ActionProvider and a VisibilityProvider. The Renderer of\n\t\t\t// PlayRenderer therefore works also with ActorProvider alone, without PlayUIProvider\n\t\t\t// and without JSONUIProvider.\n\t\t\treturn h(ActionProvider, { handlers: handlers.value }, () =>\n\t\t\t\th(VisibilityProvider, {}, () => slots.default?.() ?? null),\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// ActorProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"ActorProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ActorProviderProps[\"actor\"]>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<OnRenderError>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonError: {\n\t\t\ttype: Function as PropType<(error: unknown, reset: () => void) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\t// The error boundary. It contains an error of the RENDER of a descendant — the\n\t\t// render function, the setup function, and a lifecycle hook — so that a subtree\n\t\t// that throws cannot take the whole application down. `onErrorCaptured` notifies\n\t\t// `onError`, it sets the errored flag, and the render function below then returns\n\t\t// the `fallback` slot instead of the children.\n\t\t//\n\t\t// `onErrorCaptured` of Vue also fires for an error of an event handler, and of a\n\t\t// watcher callback, which no other renderer of this workspace sees: the boundary\n\t\t// of React, the ErrorBoundary of Solid, and `<svelte:boundary>` each catch a\n\t\t// failure of the render only. A click handler that throws must therefore NOT\n\t\t// replace the view with the fallback. This boundary leaves such an error\n\t\t// COMPLETELY alone: it calls `onError` never, and it returns undefined, so the\n\t\t// error continues to `app.config.errorHandler` exactly as it does without this\n\t\t// provider. A report here would give play-vue a wider `onError` contract than the\n\t\t// other four renderers, and it would reach a caller that wires both this prop and\n\t\t// the global handler two times for one click.\n\t\t//\n\t\t// RESET RULE: each new snapshot of the view session clears the flag (see its\n\t\t// listener below): a new view, a new actor, or a new controlled store. A view\n\t\t// transition therefore retries the render. Without the rule the user sends a recovery event, the actor\n\t\t// moves to a healthy view, and the screen keeps the fallback.\n\t\t//\n\t\t// The per-element boundary of @json-render catches a throw of a catalog component\n\t\t// below the root upstream, and reports it through `onRenderError`. A failure of the\n\t\t// root reaches this hook never: the session contains it (see the registry below).\n\t\t// This boundary is the outer net for everything else.\n\t\t//\n\t\t// The return of false stops a render error HERE. Without `onError` that error\n\t\t// therefore reaches neither `app.config.errorHandler` nor the console, and a\n\t\t// consumer that gives no handler loses it in silence. Write it to `console.error`\n\t\t// in that case, in the same way as the inner renderer does for a component that\n\t\t// throws without an `onRenderError` handler.\n\t\tconst errored = ref(false);\n\n\t\t// The report guard, from @xmachines/play-view: it blocks a reset that the host\n\t\t// calls from INSIDE the report, and every callback once the provider is gone. The\n\t\t// five renderers share the one implementation.\n\t\t//\n\t\t// The re-entry rule matters more here than a stack suggests: a write of a ref\n\t\t// renders on the NEXT tick, so a host with a retry-once policy loops with no stack\n\t\t// at all, and a flag around the retry itself would catch nothing.\n\t\t//\n\t\t// It CONTAINS a handler of the host that throws. The flag below schedules a\n\t\t// RENDER, and a throw that leaves the hook stops that render and skips the\n\t\t// `return false`, so the subtree that threw stays on the screen AND the error\n\t\t// reaches `app.config.errorHandler`.\n\t\tconst guard = createReportGuard({\n\t\t\tnoHandler:\n\t\t\t\t\"[@xmachines/play-vue] ActorProvider contained an error of a descendant. \" +\n\t\t\t\t\"Give an onError prop to receive it.\",\n\t\t\thandlerThrew:\n\t\t\t\t\"[@xmachines/play-vue] the onError handler of the host threw. \" +\n\t\t\t\t\"ActorProvider contained the failure of the view all the same.\",\n\t\t});\n\n\t\t/**\n\t\t * Clears the contained error and renders again.\n\t\t *\n\t\t * The session resolves the view that the actor holds NOW, and its new snapshot\n\t\t * renders again. A retry bound to the view that failed would take a host that keeps\n\t\t * the callback back onto the screen that threw.\n\t\t */\n\t\tconst retry = (): void => {\n\t\t\tif (guard.blocked()) return;\n\t\t\terrored.value = false;\n\t\t\tsession.retry();\n\t\t};\n\n\t\t/** Sends a contained failure to `onError`, or to the console when none is given. */\n\t\tconst report = (err: unknown): void => {\n\t\t\tconst handler = props.onError;\n\t\t\tguard.report(err, handler ? () => handler(err, retry) : undefined);\n\t\t};\n\n\t\t// The configuration of the application, read one time. `canRaiseAgain` asks the two\n\t\t// fields that `handleError` of Vue reads on every error. It lives in error-source.ts,\n\t\t// because its production half answers a spelling that a mounted test reaches never.\n\t\tconst appConfig = getCurrentInstance()?.appContext.config;\n\n\t\t// The error that this boundary let through LAST, and that the NEXT raise can still\n\t\t// claim as a repeat.\n\t\t//\n\t\t// The second raise is SYNCHRONOUS and IMMEDIATE. `logError` of the development\n\t\t// bundle re-throws, and the throw unwinds straight back into `callWithErrorHandling`\n\t\t// of `flushJobs`, which reports the same value again. No other raise reaches this\n\t\t// hook in between, so ONE slot holds the complete window.\n\t\t//\n\t\t// EVERY raise that fails the render takes the slot, and not a component update\n\t\t// alone. A record that no raise takes can otherwise outlive its window.\n\t\t//\n\t\t// The record names the INSTANCE beside the error value. A repeat carries the\n\t\t// instance whose JOB ran when the error unwound, and that is the owner of the\n\t\t// watcher OR one of its ANCESTORS: a pre-flush watcher of a child runs inside the\n\t\t// update of the parent that passes it a prop, and `flushJobs` reports the throw\n\t\t// under the parent — or under the outermost ancestor whose update ran. The take\n\t\t// therefore walks the `$parent` chain of the recorded instance. A SIBLING stands on\n\t\t// that chain never, and a sibling that fails with the same cached error is one\n\t\t// loader with two consumers: that failure is a first incident, and the boundary\n\t\t// contains it.\n\t\t//\n\t\t// The microtask is the BACKSTOP, for a raise that neither a repeat nor another\n\t\t// raise follows. A record for the life of the provider would disarm the boundary\n\t\t// for that error for ever, and a descendant that keeps a failure and raises it\n\t\t// again from a LATER render is an ordinary shape.\n\t\t//\n\t\t// Each `remember` schedules a clear of ITS OWN record, and that clear takes no\n\t\t// other. A clear that removed whatever the slot holds could run after a take\n\t\t// emptied the slot and a later `remember` filled it again, and it would then\n\t\t// disarm the boundary for a repeat that is still to come.\n\t\tlet letThrough: { error: unknown; instance: ComponentPublicInstance | null } | null = null;\n\t\tconst remember = (error: unknown, instance: ComponentPublicInstance | null): void => {\n\t\t\tconst record = { error, instance };\n\t\t\tletThrough = record;\n\t\t\tqueueMicrotask(() => {\n\t\t\t\tif (letThrough === record) letThrough = null;\n\t\t\t});\n\t\t};\n\t\t/**\n\t\t * Takes the record. It answers TRUE when the record names this error, and when the\n\t\t * instance that raises it is the recorded one or one of its ancestors.\n\t\t *\n\t\t * The comparison reads `$` on both sides, which is the INTERNAL instance. Vue hands\n\t\t * `onErrorCaptured` the `proxy` of a component, and `$parent` answers with the\n\t\t * `exposeProxy` of a parent that called `expose()` — which the compiler makes every\n\t\t * `<script setup>` component do. The two objects differ, so a walk that compared\n\t\t * them found an exposed ancestor never, and the boundary contained a watcher error\n\t\t * that it must let through. `$` resolves through both proxies and names one object.\n\t\t */\n\t\tconst takeRepeat = (error: unknown, instance: ComponentPublicInstance | null): boolean => {\n\t\t\tconst record = letThrough;\n\t\t\tletThrough = null;\n\t\t\tif (record === null || record.error !== error) return false;\n\t\t\tfor (let node = record.instance; node !== null; node = node.$parent) {\n\t\t\t\tif (node.$ === instance?.$) return true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\n\t\tonErrorCaptured((err, instance, info) => {\n\t\t\t// An error that did NOT fail the render leaves this boundary untouched: the\n\t\t\t// screen keeps its view, `onError` stays silent, and the return of undefined\n\t\t\t// sends the error on to `app.config.errorHandler`. The boundary of React, the\n\t\t\t// ErrorBoundary of Solid, and `<svelte:boundary>` each see such an error never,\n\t\t\t// so a call of `onError` here would give play-vue a wider contract than the\n\t\t\t// other four, AND it would report the same failure twice to a caller that wires\n\t\t\t// both `onError` and the global handler of the application.\n\t\t\tif (!failsTheRender(info)) {\n\t\t\t\t// Arm the record only where Vue WILL raise this error a second time. A record\n\t\t\t\t// that no repeat claims stands until the microtask, and a genuine failure of\n\t\t\t\t// a render in the same flush — the same descendant, the same cached error —\n\t\t\t\t// would then take it: no fallback, no `onError`, and no screen.\n\t\t\t\t//\n\t\t\t\t// `handleError` of Vue calls `app.config.errorHandler` where one exists, and\n\t\t\t\t// it reaches `logError` never; the production bundle throws only where the\n\t\t\t\t// application asks for `throwUnhandledErrorInProduction`. The one case that\n\t\t\t\t// this line cannot see is an ANCESTOR `errorCaptured` that answers false,\n\t\t\t\t// which stops Vue before `logError` too. That case stays open, and the doc of\n\t\t\t\t// `onError` names it.\n\t\t\t\tif (canRaiseAgain(info, appConfig)) remember(err, instance);\n\t\t\t\treturn undefined;\n\t\t\t}\n\n\t\t\t// Vue can raise the SAME error a SECOND time under another source. The\n\t\t\t// development bundle of `logError` re-throws an error that no\n\t\t\t// `app.config.errorHandler` took. A queued job then loses that throw to\n\t\t\t// `callWithErrorHandling(job, job.i, 15)` of `flushJobs` — a `watch` callback\n\t\t\t// with the default `pre` flush, for one — and `flushJobs` reports it again as\n\t\t\t// \"component update\". The classification above answers \"render failure\" for that\n\t\t\t// second spelling, so a watcher that threw would take the view off the screen\n\t\t\t// after all. One error is one incident: an error that this boundary let through\n\t\t\t// in this turn stays through.\n\t\t\t//\n\t\t\t// The gate asks for the SOURCE of the repeat as well. `flushJobs` reports a\n\t\t\t// job under \"component update\", and no other source can carry a second raise\n\t\t\t// to this hook, so a record of the turn can disarm the boundary for that one\n\t\t\t// spelling alone. Without the question a setup function or a render function\n\t\t\t// that throws the SAME error value in the same turn — a loader that caches its\n\t\t\t// rejection, for one — would reach no fallback, no `onError`, and no screen.\n\t\t\t//\n\t\t\t// It returns FALSE, and not undefined. The FIRST raise went on to\n\t\t\t// `app.config.errorHandler`, which is the contract of a non-render source, and\n\t\t\t// the development bundle re-threw it there — that throw IS this second report.\n\t\t\t// A second `undefined` sends it on one more time, so `logError` warns twice for\n\t\t\t// one incident and throws again, and that throw leaves `flushJobs`. The\n\t\t\t// `finally` of `flushJobs` runs `queue.length = 0`. `flushJobs` therefore drops\n\t\t\t// every job behind the one that failed, and a sibling of the descendant that\n\t\t\t// threw renders never. One incident reaches the caller ONE time, and the flush\n\t\t\t// of Vue finishes.\n\t\t\t// `takeRepeat` runs for EVERY raise that fails the render, and not inside the\n\t\t\t// condition below: a raise of another source ENDS the window of the repeat, so\n\t\t\t// the record can disarm the boundary for the one raise that follows it and for\n\t\t\t// no other.\n\t\t\tconst repeated = takeRepeat(err, instance);\n\t\t\tif (isComponentUpdate(info) && repeated) {\n\t\t\t\t// The value reaches no console without this line. `logError` of the\n\t\t\t\t// development bundle writes the SOURCE, and not the value. It then throws\n\t\t\t\t// the value, and that throw IS this second report, which the `return`\n\t\t\t\t// below stops. `report()` wrote such an error before this gate existed, so\n\t\t\t\t// a host with no `onError` prop could still debug a watcher or a loader\n\t\t\t\t// that failed. The production bundle writes the value on the FIRST raise,\n\t\t\t\t// and it throws instead where the application asks for\n\t\t\t\t// `throwUnhandledErrorInProduction` — that application gets the write here.\n\t\t\t\t// One incident reaches the console ONE time in both bundles.\n\t\t\t\t//\n\t\t\t\t// The line carries the name of this package, as every other console write\n\t\t\t\t// of this provider does. Without it a developer reads a bare error and\n\t\t\t\t// cannot tell that the provider wrote it, and not Vue.\n\t\t\t\tconsole.error(\n\t\t\t\t\t\"[@xmachines/play-vue] ActorProvider stopped a second report of this \" +\n\t\t\t\t\t\t\"error. Vue raised it again under the source of a component update, \" +\n\t\t\t\t\t\t\"and it failed no render.\",\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// The SCREEN comes first, and the report second, as `contain()` of play-dom\n\t\t\t// states it. A reporter can throw — one that re-throws to escalate, or a\n\t\t\t// transport that fails — and here the order alone is not enough: the flag\n\t\t\t// schedules a RENDER, and a throw that leaves this hook stops that render and\n\t\t\t// skips the `return false`. The GUARD holds that half, for the four renderers\n\t\t\t// that need it: it carries a `handlerThrew` message, so it contains the throw\n\t\t\t// of the handler and writes it to `console.error`.\n\t\t\t//\n\t\t\t// The five renderers hold the one rule: a handler of the host never defeats the\n\t\t\t// containment, and a host that must escalate raises the failure from a task of\n\t\t\t// its own.\n\t\t\terrored.value = true;\n\t\t\treport(err);\n\t\t\treturn false;\n\t\t});\n\n\t\t// Take the registryResult out of the proxy, and mark each component as raw, because\n\t\t// the reactivity of Vue costs too much here. `markRaw` marks the component object\n\t\t// itself, so a copy of the registry adds nothing to it.\n\t\t//\n\t\t// Put the handler of the provider into the registry. The property is not enumerable,\n\t\t// and it replaces the handler of the defineRegistry level. It gives each report to the\n\t\t// onRenderError prop, and it gives a failure of the ROOT to the session: json-render\n\t\t// reports such a failure to no hook of the host, so the session records it in a new\n\t\t// snapshot and reports it through `onFailure`, and the render function shows the\n\t\t// fallback. The binding keeps one copy for each registry, and the copy calls the\n\t\t// newest handler. json-render-core makes that copy with its own rule: the members\n\t\t// with their descriptors, so a getter still reads the source, and the slot metadata,\n\t\t// so each named slot of the catalog is validated. The code marks the copy raw.\n\t\t//\n\t\t// A computed, and not a value of setup(): a new registryResult or onRenderError prop\n\t\t// after the mount reaches the children.\n\t\tconst bindRenderError = createRenderErrorBinding<DefineRegistryResult>();\n\t\tlet rawSource: DefineRegistryResult | undefined;\n\t\tconst activeRegistryResult = computed((): DefineRegistryResult => {\n\t\t\tconst source = toRaw(props.registryResult);\n\t\t\tif (rawSource !== source) {\n\t\t\t\tfor (const descriptor of Object.values(ownMemberDescriptors(source.registry))) {\n\t\t\t\t\t// markRaw takes an object alone. An entry of null or undefined is no\n\t\t\t\t\t// component, and json-render renders no component for it. A getter is no\n\t\t\t\t\t// value here, and it reads the source at each access.\n\t\t\t\t\tconst { value } = descriptor;\n\t\t\t\t\tif (\n\t\t\t\t\t\t(typeof value === \"object\" && value !== null) ||\n\t\t\t\t\t\ttypeof value === \"function\"\n\t\t\t\t\t) {\n\t\t\t\t\t\tmarkRaw(value);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trawSource = source;\n\t\t\t}\n\t\t\tconst bound = bindRenderError(source, props.onRenderError, (error) =>\n\t\t\t\tsession.failView(error),\n\t\t\t);\n\t\t\tmarkRaw(bound.registry);\n\t\t\treturn bound;\n\t\t});\n\n\t\t// Give the actor to each descendant, through the provide and inject mechanism of Vue.\n\t\t//\n\t\t// The code gives a stable proxy, and not the raw actor, because each injector keeps\n\t\t// the reference of its setup(). Every access resolves against the newest actor\n\t\t// prop, taken out of the reactive proxy of Vue to reach the raw Atom objects. The proxy is NOT identity-equal to\n\t\t// `props.actor`: a consumer that keys a WeakMap on the identity of the actor, such as\n\t\t// the guard of one bridge for each actor in RouterBridgeBase, must receive the actor\n\t\t// itself.\n\t\tprovideActor(createActorProxy<AnyPlayActor>(() => toRaw(props.actor as ViewActor)));\n\n\t\t// The view session, from @xmachines/play-view. It resolves the store of the view\n\t\t// when the actor emits, when the host hands over a new actor or store, and for a\n\t\t// retry — never in a render — and it seeds, refreshes and drops the store by the rules\n\t\t// of the lifecycle. The five renderers share it, and only the wiring below belongs\n\t\t// to Vue.\n\t\t//\n\t\t// A failure of the resolution reports through `onFailure`. `spec.state` can throw —\n\t\t// a projection with an accessor, or a seed of a store — and `onErrorCaptured` above\n\t\t// sees a throw of a DESCENDANT only. The snapshot then holds no store, so the render\n\t\t// function shows the fallback, and the next new snapshot renders the children again.\n\t\tconst session = createViewSession(toRaw(props.actor as ViewActor), props.store, {\n\t\t\tcreateStore: (seed) => xstateStoreStateStore({ atom: createAtom(seed) }),\n\t\t\tonFailure: (error) => report(error),\n\t\t});\n\t\t// A shallowRef: the snapshot is immutable, and a deep ref would wrap the spec and its\n\t\t// store in reactive proxies on each emission.\n\t\tconst snapshot = shallowRef<ViewSessionSnapshot>(session.getSnapshot());\n\n\t\t// setup() is no render, so the session connects here. Every new snapshot clears the\n\t\t// errored flag (see the reset rule above) before the new view renders: a new view, a\n\t\t// new actor, or a new controlled store. A hit of the error boundary therefore retries\n\t\t// here.\n\t\tconst release = session.subscribe(() => {\n\t\t\terrored.value = false;\n\t\t\tsnapshot.value = session.getSnapshot();\n\t\t});\n\t\tsnapshot.value = session.getSnapshot();\n\n\t\t// Hand a new actor or a new controlled store to the session. `flush: \"sync\"`, so that\n\t\t// no scheduler runs between the prop and the resolution. A new actor drops the store\n\t\t// of the old one, and a repaired controlled store renders the children again.\n\t\twatch(\n\t\t\t() => [toRaw(props.actor as ViewActor), props.store] as const,\n\t\t\t([nextActor, nextStore]) => {\n\t\t\t\tsession.setInputs(nextActor, nextStore);\n\t\t\t},\n\t\t\t{ flush: \"sync\" },\n\t\t);\n\n\t\tonUnmounted(() => {\n\t\t\tguard.dispose();\n\t\t\trelease();\n\t\t\tsession.dispose();\n\t\t});\n\n\t\treturn () => {\n\t\t\t// A contained error of a descendant: show the fallback slot, or show nothing,\n\t\t\t// until the next snapshot clears the flag and retries the render.\n\t\t\tif (errored.value) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\t// No view, or a failed resolution: show the fallback slot, or show nothing.\n\t\t\tconst { view: spec, store, generation } = snapshot.value;\n\t\t\tif (!spec || !store) {\n\t\t\t\treturn slots.fallback ? slots.fallback() : null;\n\t\t\t}\n\n\t\t\t// ActorProviderInner renders inside StateProvider. Therefore useStateStore() works.\n\t\t\t// The children receive the store with the guard, because /context is read-only to\n\t\t\t// the spec. The generation is the key of a SUBTREE REMOUNT. The lifecycle changes it\n\t\t\t// for a new store only, and never for a refresh of /context in place. Without this\n\t\t\t// rule, each update of the projection removes the subtree on the screen.\n\t\t\treturn h(StateProvider, { store, key: generation }, () =>\n\t\t\t\th(\n\t\t\t\t\tActorProviderInner,\n\t\t\t\t\t{ registryResult: activeRegistryResult.value, spec, store },\n\t\t\t\t\tslots,\n\t\t\t\t),\n\t\t\t);\n\t\t};\n\t},\n});\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsEA,IAAM,qBAAqB,gBAAgB;CAC1C,MAAM;CACN,OAAO;EACN,gBAAgB;GACf,MAAM;GACN,UAAU;EACX;EACA,MAAM;GACL,MAAM;GACN,SAAS;EACV;EACA,OAAO;GACN,MAAM;GACN,UAAU;EACX;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EAIvB,MAAM,UAAU,WAAoC,IAAI;EAMxD,QACC,SACA,IAAI,MAAM,CAAC,GAAuB,EACjC,IAAI,SAAS,MAAc;GAC1B,OAAO,QAAQ,QAAQ;EACxB,EACD,CAAC,CACF;EAKA,MAAM,aAAa,cAAc;EAMjC,MAAM,WAAW,eAAe,kBAAkB,MAAM,sBAAsB,UAAU,CAAC;EAEzF,aAAa;GACZ,IAAI,CAAC,MAAM,MAAM;IAChB,QAAQ,QAAQ;IAChB,OAAO,MAAM,UAAU,KAAK;GAC7B;GAEA,QAAQ,QAAQ;IACf,MAAM,MAAM;IACZ,UAAU,SAAS;IACnB,UAAU,MAAM,eAAe;IAC/B,OAAO,MAAM;GACd;GAKA,OAAO,EAAE,gBAAgB,EAAE,UAAU,SAAS,MAAM,SACnD,EAAE,oBAAoB,CAAC,SAAS,MAAM,UAAU,KAAK,IAAI,CAC1D;EACD;CACD;AACD,CAAC;AAMD,IAAA,iDAAe,gBAAgB;CAC9B,MAAM;CACN,OAAO;EACN,OAAO;GACN,MAAM;GACN,UAAU;EACX;EACA,gBAAgB;GACf,MAAM;GACN,UAAU;EACX;EACA,OAAO;GACN,MAAM;GACN,SAAS,KAAA;EACV;EACA,eAAe;GACd,MAAM;GACN,SAAS,KAAA;EACV;EACA,SAAS;GACR,MAAM;GACN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EAiCvB,MAAM,UAAU,IAAI,KAAK;EAczB,MAAM,QAAQ,kBAAkB;GAC/B,WACC;GAED,cACC;EAEF,CAAC;;;;;;;;EASD,MAAM,cAAoB;GACzB,IAAI,MAAM,QAAQ,GAAG;GACrB,QAAQ,QAAQ;GAChB,QAAQ,MAAM;EACf;;EAGA,MAAM,UAAU,QAAuB;GACtC,MAAM,UAAU,MAAM;GACtB,MAAM,OAAO,KAAK,gBAAgB,QAAQ,KAAK,KAAK,IAAI,KAAA,CAAS;EAClE;EAKA,MAAM,YAAY,mBAAmB,CAAC,EAAE,WAAW;EAgCnD,IAAI,aAAkF;EACtF,MAAM,YAAY,OAAgB,aAAmD;GACpF,MAAM,SAAS;IAAE;IAAO;GAAS;GACjC,aAAa;GACb,qBAAqB;IACpB,IAAI,eAAe,QAAQ,aAAa;GACzC,CAAC;EACF;;;;;;;;;;;;EAYA,MAAM,cAAc,OAAgB,aAAsD;GACzF,MAAM,SAAS;GACf,aAAa;GACb,IAAI,WAAW,QAAQ,OAAO,UAAU,OAAO,OAAO;GACtD,KAAK,IAAI,OAAO,OAAO,UAAU,SAAS,MAAM,OAAO,KAAK,SAC3D,IAAI,KAAK,MAAM,UAAU,GAAG,OAAO;GAEpC,OAAO;EACR;EAEA,iBAAiB,KAAK,UAAU,SAAS;GAQxC,IAAI,CAAC,eAAe,IAAI,GAAG;IAY1B,IAAI,cAAc,MAAM,SAAS,GAAG,SAAS,KAAK,QAAQ;IAC1D;GACD;GAgCA,MAAM,WAAW,WAAW,KAAK,QAAQ;GACzC,IAAI,kBAAkB,IAAI,KAAK,UAAU;IAcxC,QAAQ,MACP,mKAGA,GACD;IACA,OAAO;GACR;GAaA,QAAQ,QAAQ;GAChB,OAAO,GAAG;GACV,OAAO;EACR,CAAC;EAkBD,MAAM,kBAAkB,yBAA+C;EACvE,IAAI;EACJ,MAAM,uBAAuB,eAAqC;GACjE,MAAM,SAAS,MAAM,MAAM,cAAc;GACzC,IAAI,cAAc,QAAQ;IACzB,KAAK,MAAM,cAAc,OAAO,OAAO,qBAAqB,OAAO,QAAQ,CAAC,GAAG;KAI9E,MAAM,EAAE,UAAU;KAClB,IACE,OAAO,UAAU,YAAY,UAAU,QACxC,OAAO,UAAU,YAEjB,QAAQ,KAAK;IAEf;IACA,YAAY;GACb;GACA,MAAM,QAAQ,gBAAgB,QAAQ,MAAM,gBAAgB,UAC3D,QAAQ,SAAS,KAAK,CACvB;GACA,QAAQ,MAAM,QAAQ;GACtB,OAAO;EACR,CAAC;EAUD,aAAa,uBAAqC,MAAM,MAAM,KAAkB,CAAC,CAAC;EAYlF,MAAM,UAAU,kBAAkB,MAAM,MAAM,KAAkB,GAAG,MAAM,OAAO;GAC/E,cAAc,SAAS,sBAAsB,EAAE,MAAM,WAAW,IAAI,EAAE,CAAC;GACvE,YAAY,UAAU,OAAO,KAAK;EACnC,CAAC;EAGD,MAAM,WAAW,WAAgC,QAAQ,YAAY,CAAC;EAMtE,MAAM,UAAU,QAAQ,gBAAgB;GACvC,QAAQ,QAAQ;GAChB,SAAS,QAAQ,QAAQ,YAAY;EACtC,CAAC;EACD,SAAS,QAAQ,QAAQ,YAAY;EAKrC,YACO,CAAC,MAAM,MAAM,KAAkB,GAAG,MAAM,KAAK,IAClD,CAAC,WAAW,eAAe;GAC3B,QAAQ,UAAU,WAAW,SAAS;EACvC,GACA,EAAE,OAAO,OAAO,CACjB;EAEA,kBAAkB;GACjB,MAAM,QAAQ;GACd,QAAQ;GACR,QAAQ,QAAQ;EACjB,CAAC;EAED,aAAa;GAGZ,IAAI,QAAQ,OACX,OAAO,MAAM,WAAW,MAAM,SAAS,IAAI;GAI5C,MAAM,EAAE,MAAM,MAAM,OAAO,eAAe,SAAS;GACnD,IAAI,CAAC,QAAQ,CAAC,OACb,OAAO,MAAM,WAAW,MAAM,SAAS,IAAI;GAQ5C,OAAO,EAAE,eAAe;IAAE;IAAO,KAAK;GAAW,SAChD,EACC,oBACA;IAAE,gBAAgB,qBAAqB;IAAO;IAAM;GAAM,GAC1D,KACD,CACD;EACD;CACD;AACD,CAAC"}
|
package/dist/PlayRenderer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayRenderer.js","names":[],"sources":["../src/PlayRenderer.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayRenderer — the leaf component without props of the XMachines Vue render architecture.\n *\n * It reads the current view context of the nearest ActorProvider, or of the nearest\n * PlayUIProvider. It then renders <Renderer spec={view.spec} registry={view.registry} />.\n *\n * Use it inside <ActorProvider> or <PlayUIProvider>.\n *\n * @example\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * @invariant Passive Infrastructure - the component observes the context. It never decides\n */\n\nimport { defineComponent, h } from \"vue\";\nimport { Renderer } from \"@xmachines/json-render-vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\n\nexport default defineComponent({\n\tname: \"PlayRenderer\",\n\tsetup() {\n\t\t// Call inject during setup(), which the composition API of Vue permits.\n\t\t// usePlayView() uses inject(), and inject() must run synchronously during\n\t\t// setup(). The Proxy of ActorProviderInner gives view.spec and view.registry their\n\t\t// newest values on each read in the render function.\n\t\tconst view = usePlayView();\n\t\treturn () => {\n\t\t\treturn h(Renderer, { spec: view.spec, registry: view.registry });\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"PlayRenderer.js","names":["_sfc_main"],"sources":["../src/PlayRenderer.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayRenderer — the leaf component without props of the XMachines Vue render architecture.\n *\n * It reads the current view context of the nearest ActorProvider, or of the nearest\n * PlayUIProvider. It then renders <Renderer spec={view.spec} registry={view.registry} />.\n *\n * Use it inside <ActorProvider> or <PlayUIProvider>.\n *\n * @example\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * @invariant Passive Infrastructure - the component observes the context. It never decides\n */\n\nimport { defineComponent, h } from \"vue\";\nimport { Renderer } from \"@xmachines/json-render-vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\n\nexport default defineComponent({\n\tname: \"PlayRenderer\",\n\tsetup() {\n\t\t// Call inject during setup(), which the composition API of Vue permits.\n\t\t// usePlayView() uses inject(), and inject() must run synchronously during\n\t\t// setup(). The Proxy of ActorProviderInner gives view.spec and view.registry their\n\t\t// newest values on each read in the render function.\n\t\tconst view = usePlayView();\n\t\treturn () => {\n\t\t\treturn h(Renderer, { spec: view.spec, registry: view.registry });\n\t\t};\n\t},\n});\n</script>\n"],"mappings":""}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare const _default: typeof __VLS_export;
|
|
2
|
+
export default _default;
|
|
3
|
+
declare const __VLS_export: import('@vue/runtime-core').DefineComponent<{}, () => import('@vue/runtime-core').VNode<import('@vue/runtime-core').RendererNode, import('@vue/runtime-core').RendererElement, {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
}>, {}, {}, {}, import('@vue/runtime-core').ComponentOptionsMixin, import('@vue/runtime-core').ComponentOptionsMixin, {}, string, import('@vue/runtime-core').PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import('@vue/runtime-core').ComponentProvideOptions, true, {}, any>;
|
|
6
|
+
//# sourceMappingURL=PlayRenderer.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlayRenderer.vue.d.ts","sourceRoot":"","sources":["../src/PlayRenderer.vue"],"names":[],"mappings":"wBA8DqB,OAAO,YAAY;AAAxC,wBAAyC;AASzC,QAAA,MAAM,YAAY;;mSAYhB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayUIProvider.js","names":[],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — the composite provider of an actor-driven UI.\n *\n * It wraps ActorProvider and JSONUIProvider, from @xmachines/json-render-vue. One\n * component therefore serves the complete actor lifecycle and the complete UI\n * rendering.\n *\n * The standard use:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For a custom provider composition, use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult,
|
|
1
|
+
{"version":3,"file":"PlayUIProvider.js","names":["_sfc_main"],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — the composite provider of an actor-driven UI.\n *\n * It wraps ActorProvider and JSONUIProvider, from @xmachines/json-render-vue. One\n * component therefore serves the complete actor lifecycle and the complete UI\n * rendering.\n *\n * The standard use:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For a custom provider composition, use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult, OnRenderError } from \"@xmachines/json-render-vue\";\n\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport type { ViewActor } from \"@xmachines/play-view\";\nimport ActorProvider from \"./ActorProvider.vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\nimport type { PlayUIProviderProps } from \"./types.js\";\n\n// Re-export the props type, for a consumer that imports from this file\nexport type { PlayUIProviderProps } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// JSONUIBridge — the inner component inside the tree of ActorProvider\n// It reads the ViewContextValue with usePlayView(), and it gives the handlers\n// and the registry to JSONUIProvider. Therefore ActorProvider and JSONUIProvider\n// share one state.\n// ---------------------------------------------------------------------------\n\nconst JSONUIBridge = defineComponent({\n\tname: \"JSONUIBridge\",\n\tprops: {\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<(path: string) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<string, (value: unknown, args?: Record<string, unknown>) => boolean>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<\n\t\t\t\t\tstring,\n\t\t\t\t\t(args?: Record<string, unknown>, state?: Record<string, unknown>) => unknown\n\t\t\t\t>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () => {\n\t\t\tconst view = usePlayView();\n\t\t\treturn h(\n\t\t\t\tJSONUIProvider,\n\t\t\t\t{\n\t\t\t\t\tregistry: view.registry,\n\t\t\t\t\thandlers: view.handlers,\n\t\t\t\t\tstore: view.store,\n\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t},\n\t\t\t\tslots,\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// PlayUIProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"PlayUIProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ViewActor>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<OnRenderError>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonError: {\n\t\t\ttype: Function as PropType<(error: unknown, reset: () => void) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<PlayUIProviderProps[\"navigate\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"validationFunctions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"functions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () =>\n\t\t\th(\n\t\t\t\tActorProvider,\n\t\t\t\t{\n\t\t\t\t\tactor: props.actor,\n\t\t\t\t\tregistryResult: props.registryResult,\n\t\t\t\t\t...(props.store ? { store: props.store } : {}),\n\t\t\t\t\t...(props.onRenderError ? { onRenderError: props.onRenderError } : {}),\n\t\t\t\t\t...(props.onError ? { onError: props.onError } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdefault: () =>\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\tJSONUIBridge,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tslots,\n\t\t\t\t\t\t),\n\t\t\t\t\tfallback: slots.fallback,\n\t\t\t\t},\n\t\t\t);\n\t},\n});\n</script>\n"],"mappings":""}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { PropType } from 'vue';
|
|
2
|
+
import { DefineRegistryResult, OnRenderError } from '@xmachines/json-render-vue';
|
|
3
|
+
import { StateStore } from '@xmachines/json-render-core';
|
|
4
|
+
import { ViewActor } from '@xmachines/play-view';
|
|
5
|
+
import { PlayUIProviderProps } from './types.js';
|
|
6
|
+
export type { PlayUIProviderProps } from './types.js';
|
|
7
|
+
declare const _default: typeof __VLS_export;
|
|
8
|
+
export default _default;
|
|
9
|
+
declare const __VLS_export: import('@vue/runtime-core').DefineComponent<import('@vue/runtime-core').ExtractPropTypes<{
|
|
10
|
+
actor: {
|
|
11
|
+
type: PropType<ViewActor>;
|
|
12
|
+
required: true;
|
|
13
|
+
};
|
|
14
|
+
registryResult: {
|
|
15
|
+
type: PropType<DefineRegistryResult>;
|
|
16
|
+
required: true;
|
|
17
|
+
};
|
|
18
|
+
store: {
|
|
19
|
+
type: PropType<StateStore>;
|
|
20
|
+
default: undefined;
|
|
21
|
+
};
|
|
22
|
+
onRenderError: {
|
|
23
|
+
type: PropType<OnRenderError>;
|
|
24
|
+
default: undefined;
|
|
25
|
+
};
|
|
26
|
+
onError: {
|
|
27
|
+
type: PropType<(error: unknown, reset: () => void) => void>;
|
|
28
|
+
default: undefined;
|
|
29
|
+
};
|
|
30
|
+
navigate: {
|
|
31
|
+
type: PropType<PlayUIProviderProps["navigate"]>;
|
|
32
|
+
default: undefined;
|
|
33
|
+
};
|
|
34
|
+
validationFunctions: {
|
|
35
|
+
type: PropType<PlayUIProviderProps["validationFunctions"]>;
|
|
36
|
+
default: undefined;
|
|
37
|
+
};
|
|
38
|
+
functions: {
|
|
39
|
+
type: PropType<PlayUIProviderProps["functions"]>;
|
|
40
|
+
default: undefined;
|
|
41
|
+
};
|
|
42
|
+
}>, () => import('@vue/runtime-core').VNode<import('@vue/runtime-core').RendererNode, import('@vue/runtime-core').RendererElement, {
|
|
43
|
+
[key: string]: any;
|
|
44
|
+
}>, {}, {}, {}, import('@vue/runtime-core').ComponentOptionsMixin, import('@vue/runtime-core').ComponentOptionsMixin, {}, string, import('@vue/runtime-core').PublicProps, Readonly<import('@vue/runtime-core').ExtractPropTypes<{
|
|
45
|
+
actor: {
|
|
46
|
+
type: PropType<ViewActor>;
|
|
47
|
+
required: true;
|
|
48
|
+
};
|
|
49
|
+
registryResult: {
|
|
50
|
+
type: PropType<DefineRegistryResult>;
|
|
51
|
+
required: true;
|
|
52
|
+
};
|
|
53
|
+
store: {
|
|
54
|
+
type: PropType<StateStore>;
|
|
55
|
+
default: undefined;
|
|
56
|
+
};
|
|
57
|
+
onRenderError: {
|
|
58
|
+
type: PropType<OnRenderError>;
|
|
59
|
+
default: undefined;
|
|
60
|
+
};
|
|
61
|
+
onError: {
|
|
62
|
+
type: PropType<(error: unknown, reset: () => void) => void>;
|
|
63
|
+
default: undefined;
|
|
64
|
+
};
|
|
65
|
+
navigate: {
|
|
66
|
+
type: PropType<PlayUIProviderProps["navigate"]>;
|
|
67
|
+
default: undefined;
|
|
68
|
+
};
|
|
69
|
+
validationFunctions: {
|
|
70
|
+
type: PropType<PlayUIProviderProps["validationFunctions"]>;
|
|
71
|
+
default: undefined;
|
|
72
|
+
};
|
|
73
|
+
functions: {
|
|
74
|
+
type: PropType<PlayUIProviderProps["functions"]>;
|
|
75
|
+
default: undefined;
|
|
76
|
+
};
|
|
77
|
+
}>> & Readonly<{}>, {
|
|
78
|
+
store: StateStore;
|
|
79
|
+
onRenderError: OnRenderError;
|
|
80
|
+
navigate: ((path: string) => void) | undefined;
|
|
81
|
+
onError: (error: unknown, reset: () => void) => void;
|
|
82
|
+
validationFunctions: Record<string, (value: unknown, args?: Record<string, unknown>) => boolean> | undefined;
|
|
83
|
+
functions: Record<string, (args?: Record<string, unknown>, state?: Record<string, unknown>) => unknown> | undefined;
|
|
84
|
+
}, {}, {}, {}, string, import('@vue/runtime-core').ComponentProvideOptions, true, {}, any>;
|
|
85
|
+
//# sourceMappingURL=PlayUIProvider.vue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PlayUIProvider.vue.d.ts","sourceRoot":"","sources":["../src/PlayUIProvider.vue"],"names":[],"mappings":"AAkLA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAEpC,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEtF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;wBAyDjC,OAAO,YAAY;AAAxC,wBAAyC;AASzC,QAAA,MAAM,YAAY;;cAIC,QAAQ,CAAC,SAAS,CAAC;;;;cAInB,QAAQ,CAAC,oBAAoB,CAAC;;;;cAI9B,QAAQ,CAAC,UAAU,CAAC;;;;cAIlB,QAAQ,CAAC,aAAa,CAAC;;;;cAIvB,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;;;;cAIrD,QAAQ,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;;;;cAI3C,QAAQ,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,CAAC;;;;cAIpD,QAAQ,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;;;;;;;cA5B1C,QAAQ,CAAC,SAAS,CAAC;;;;cAInB,QAAQ,CAAC,oBAAoB,CAAC;;;;cAI9B,QAAQ,CAAC,UAAU,CAAC;;;;cAIlB,QAAQ,CAAC,aAAa,CAAC;;;;cAIvB,QAAQ,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;;;;cAIrD,QAAQ,CAAC,mBAAmB,CAAC,UAAU,CAAC,CAAC;;;;cAI3C,QAAQ,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,CAAC;;;;cAIpD,QAAQ,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;;;;;;;qBAZvB,OAAO,SAAS,MAAM,IAAI,KAAK,IAAI;;;0FA4CvE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlayUIProvider.vue_vue_type_script_lang.js","names":[],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — the composite provider of an actor-driven UI.\n *\n * It wraps ActorProvider and JSONUIProvider, from @xmachines/json-render-vue. One\n * component therefore serves the complete actor lifecycle and the complete UI\n * rendering.\n *\n * The standard use:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For a custom provider composition, use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult,
|
|
1
|
+
{"version":3,"file":"PlayUIProvider.vue_vue_type_script_lang.js","names":["ActorProvider"],"sources":["../src/PlayUIProvider.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * PlayUIProvider — the composite provider of an actor-driven UI.\n *\n * It wraps ActorProvider and JSONUIProvider, from @xmachines/json-render-vue. One\n * component therefore serves the complete actor lifecycle and the complete UI\n * rendering.\n *\n * The standard use:\n * ```ts\n * <PlayUIProvider :actor=\"actor\" :registryResult=\"registryResult\">\n * <PlayRenderer />\n * </PlayUIProvider>\n * ```\n *\n * For a custom provider composition, use <ActorProvider> directly.\n *\n * @packageDocumentation\n */\n\nimport { defineComponent, h } from \"vue\";\nimport type { PropType } from \"vue\";\nimport { JSONUIProvider } from \"@xmachines/json-render-vue\";\nimport type { DefineRegistryResult, OnRenderError } from \"@xmachines/json-render-vue\";\n\nimport type { StateStore } from \"@xmachines/json-render-core\";\nimport type { ViewActor } from \"@xmachines/play-view\";\nimport ActorProvider from \"./ActorProvider.vue\";\nimport { usePlayView } from \"./actor-provider-context.js\";\nimport type { PlayUIProviderProps } from \"./types.js\";\n\n// Re-export the props type, for a consumer that imports from this file\nexport type { PlayUIProviderProps } from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// JSONUIBridge — the inner component inside the tree of ActorProvider\n// It reads the ViewContextValue with usePlayView(), and it gives the handlers\n// and the registry to JSONUIProvider. Therefore ActorProvider and JSONUIProvider\n// share one state.\n// ---------------------------------------------------------------------------\n\nconst JSONUIBridge = defineComponent({\n\tname: \"JSONUIBridge\",\n\tprops: {\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<(path: string) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<string, (value: unknown, args?: Record<string, unknown>) => boolean>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<\n\t\t\t\tRecord<\n\t\t\t\t\tstring,\n\t\t\t\t\t(args?: Record<string, unknown>, state?: Record<string, unknown>) => unknown\n\t\t\t\t>\n\t\t\t>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () => {\n\t\t\tconst view = usePlayView();\n\t\t\treturn h(\n\t\t\t\tJSONUIProvider,\n\t\t\t\t{\n\t\t\t\t\tregistry: view.registry,\n\t\t\t\t\thandlers: view.handlers,\n\t\t\t\t\tstore: view.store,\n\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t: {}),\n\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t},\n\t\t\t\tslots,\n\t\t\t);\n\t\t};\n\t},\n});\n\n// ---------------------------------------------------------------------------\n// PlayUIProvider — the main export\n// ---------------------------------------------------------------------------\n\nexport default defineComponent({\n\tname: \"PlayUIProvider\",\n\tprops: {\n\t\tactor: {\n\t\t\ttype: Object as PropType<ViewActor>,\n\t\t\trequired: true,\n\t\t},\n\t\tregistryResult: {\n\t\t\ttype: Object as PropType<DefineRegistryResult>,\n\t\t\trequired: true,\n\t\t},\n\t\tstore: {\n\t\t\ttype: Object as PropType<StateStore>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonRenderError: {\n\t\t\ttype: Function as PropType<OnRenderError>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tonError: {\n\t\t\ttype: Function as PropType<(error: unknown, reset: () => void) => void>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tnavigate: {\n\t\t\ttype: Function as PropType<PlayUIProviderProps[\"navigate\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tvalidationFunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"validationFunctions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t\tfunctions: {\n\t\t\ttype: Object as PropType<PlayUIProviderProps[\"functions\"]>,\n\t\t\tdefault: undefined,\n\t\t},\n\t},\n\tsetup(props, { slots }) {\n\t\treturn () =>\n\t\t\th(\n\t\t\t\tActorProvider,\n\t\t\t\t{\n\t\t\t\t\tactor: props.actor,\n\t\t\t\t\tregistryResult: props.registryResult,\n\t\t\t\t\t...(props.store ? { store: props.store } : {}),\n\t\t\t\t\t...(props.onRenderError ? { onRenderError: props.onRenderError } : {}),\n\t\t\t\t\t...(props.onError ? { onError: props.onError } : {}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tdefault: () =>\n\t\t\t\t\t\th(\n\t\t\t\t\t\t\tJSONUIBridge,\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t...(props.navigate ? { navigate: props.navigate } : {}),\n\t\t\t\t\t\t\t\t...(props.validationFunctions\n\t\t\t\t\t\t\t\t\t? { validationFunctions: props.validationFunctions }\n\t\t\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\t\t\t...(props.functions ? { functions: props.functions } : {}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tslots,\n\t\t\t\t\t\t),\n\t\t\t\t\tfallback: slots.fallback,\n\t\t\t\t},\n\t\t\t);\n\t},\n});\n</script>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyCA,IAAM,eAAe,gBAAgB;CACpC,MAAM;CACN,OAAO;EACN,UAAU;GACT,MAAM;GACN,SAAS,KAAA;EACV;EACA,qBAAqB;GACpB,MAAM;GAGN,SAAS,KAAA;EACV;EACA,WAAW;GACV,MAAM;GAMN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EACvB,aAAa;GACZ,MAAM,OAAO,YAAY;GACzB,OAAO,EACN,gBACA;IACC,UAAU,KAAK;IACf,UAAU,KAAK;IACf,OAAO,KAAK;IACZ,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;IACrD,GAAI,MAAM,sBACP,EAAE,qBAAqB,MAAM,oBAAoB,IACjD,CAAC;IACJ,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GACzD,GACA,KACD;EACD;CACD;AACD,CAAC;AAMD,IAAA,kDAAe,gBAAgB;CAC9B,MAAM;CACN,OAAO;EACN,OAAO;GACN,MAAM;GACN,UAAU;EACX;EACA,gBAAgB;GACf,MAAM;GACN,UAAU;EACX;EACA,OAAO;GACN,MAAM;GACN,SAAS,KAAA;EACV;EACA,eAAe;GACd,MAAM;GACN,SAAS,KAAA;EACV;EACA,SAAS;GACR,MAAM;GACN,SAAS,KAAA;EACV;EACA,UAAU;GACT,MAAM;GACN,SAAS,KAAA;EACV;EACA,qBAAqB;GACpB,MAAM;GACN,SAAS,KAAA;EACV;EACA,WAAW;GACV,MAAM;GACN,SAAS,KAAA;EACV;CACD;CACA,MAAM,OAAO,EAAE,SAAS;EACvB,aACC,EACCA,uBACA;GACC,OAAO,MAAM;GACb,gBAAgB,MAAM;GACtB,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;GAC5C,GAAI,MAAM,gBAAgB,EAAE,eAAe,MAAM,cAAc,IAAI,CAAC;GACpE,GAAI,MAAM,UAAU,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;EACnD,GACA;GACC,eACC,EACC,cACA;IACC,GAAI,MAAM,WAAW,EAAE,UAAU,MAAM,SAAS,IAAI,CAAC;IACrD,GAAI,MAAM,sBACP,EAAE,qBAAqB,MAAM,oBAAoB,IACjD,CAAC;IACJ,GAAI,MAAM,YAAY,EAAE,WAAW,MAAM,UAAU,IAAI,CAAC;GACzD,GACA,KACD;GACD,UAAU,MAAM;EACjB,CACD;CACF;AACD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-registry.js","names":[],"sources":["../src/define-registry.ts"],"sourcesContent":["/**\n * The `defineRegistry` wrapper of @xmachines/play-vue.\n *\n * It wraps `defineRegistry` from `@xmachines/json-render-vue`, and it adds support\n * for an SFC.\n *\n * ## Vue only — React and Solid do not need this wrapper\n *\n * In React, `useContext()` works everywhere inside the component call tree. In\n * Solid, `useContext()` works inside a reactive computation and inside a component\n * render. Neither framework has the strict rule of the Vue function `inject()`,\n * which runs during a synchronous `setup()` only. Therefore the `defineRegistry`\n * implementation of each of them calls `componentFn(ctx)` directly, and it wraps\n * nothing.\n *\n * The DOM renderer has no component system at all. It has render functions that\n * return an `HTMLElement`. An injection context is therefore not relevant.\n *\n * Vue alone needs this adapter.\n *\n * ## The reason for this wrapper\n *\n * The `defineRegistry` function of `@xmachines/json-render-vue` calls each\n * registered component as a plain function: `componentFn(ctx)`. A `.vue` SFC, which\n * is the output of `defineComponent` or of `<script setup>`, is an **object**, not a\n * function. A call to that object throws.\n *\n * There is a second and deeper reason. `defineRegistry` calls each component inside\n * its own render function, which is the return value of `setup()`. The Vue function\n * `inject()`, and each composable on it, such as `useStateBinding` and\n * `useStateStore`, works during the synchronous run of `setup()` only, not inside a\n * render function. For this reason a plain `.ts` `ComponentFn` file can call no Vue\n * composable.\n *\n * This wrapper finds each Vue SFC in the `components` map, and it wraps the SFC with\n * `h(SFC, ctx)`. The SFC then renders as a child component with its own `setup()`,\n * and every composable works inside `<script setup>`.\n *\n * ## Use\n *\n * Import `defineRegistry` from `@xmachines/play-vue`, not from `@xmachines/json-render-vue`:\n *\n * ```ts\n * import { defineRegistry } from \"@xmachines/play-vue\";\n * // not: import { defineRegistry } from \"@xmachines/json-render-vue\";\n *\n * import LoginSFC from \"./views/Login.vue\";\n * import DashboardSFC from \"./views/Dashboard.vue\";\n *\n * const { registry } = defineRegistry(catalog, {\n * components: {\n * Login: LoginSFC, // a .vue SFC — the wrapper handles it\n * Dashboard: DashboardSFC, // a .vue SFC — the wrapper handles it\n * },\n * });\n * ```\n *\n * A plain `ComponentFn` function also works, and the wrapper passes it through\n * without a change. One registry can hold both SFCs and plain functions.\n */\n\nimport { h, type Component } from \"vue\";\nimport {\n\tdefineRegistry as defineRegistryBase,\n\ttype ComponentContext,\n\ttype ComponentFn,\n\ttype Components,\n} from \"@xmachines/json-render-vue\";\nimport type { Catalog, InferCatalogComponents } from \"@xmachines/json-render-core\";\n\n/**\n * Tells you if a value is a Vue component object, which is an SFC, and not a plain\n * `ComponentFn` function.\n *\n * A Vue SFC from `defineComponent` or from the compilation of `<script setup>` is a\n * plain object, and a call to it is not possible. A `ComponentFn` is always a plain\n * function.\n *\n * The function makes four tests, in this order:\n * 1. `__vccOpts` — vite-plugin-vue and vue-loader set it on every `<script setup>` SFC.\n * 2. `__name` — Vite sets it on a named SFC. It is present beside `__vccOpts`, and\n * also on the output of `defineComponent({ name: \"...\" })` without `<script setup>`.\n * 3. `setup` is a function — this is the `defineComponent({ setup() {} })` signature.\n * 4. `render` is a function — this is the `defineComponent({ render() {} })` signature.\n *\n * Tests 3 and 4 require a **function**. A plain object with a `setup` key or a\n * `render` key is therefore not a component for this function.\n */\nfunction isVueSFC(value: unknown): value is Component {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst v = value as Record<string, unknown>;\n\t// The markers of the compiler. They identify a Vue component without a doubt.\n\tif (\"__vccOpts\" in v || \"__name\" in v) return true;\n\t// The output of defineComponent(): the code must be able to call setup or render, and their presence is not sufficient.\n\treturn typeof v[\"setup\"] === \"function\" || typeof v[\"render\"] === \"function\";\n}\n\n/**\n * Wraps a Vue SFC as a `ComponentFn`, and renders it with `h()`.\n *\n * The SFC receives the complete `ComponentContext` as its props. It renders in the\n * `setup()` function of its own child component, where each Vue composable works\n * correctly.\n */\nfunction wrapSFC<C extends Catalog, K extends keyof InferCatalogComponents<C>>(\n\tcomponent: Component,\n): ComponentFn<C, K> {\n\treturn (ctx: ComponentContext<C, K>) => h(component, ctx);\n}\n\nexport type ComponentEntry<C extends Catalog, K extends keyof InferCatalogComponents<C>> =\n\t| ComponentFn<C, K>\n\t| Component;\n\nexport type ComponentsMap<C extends Catalog> = {\n\t[K in keyof InferCatalogComponents<C>]?: ComponentEntry<C, K>;\n};\n\nexport type DefineRegistryOptions<C extends Catalog> = Omit<\n\tParameters<typeof defineRegistryBase<C>>[1],\n\t\"components\"\n> & {\n\tcomponents?: ComponentsMap<C>;\n};\n\n/**\n * Creates a component registry. It wraps each `.vue` SFC, so that the SFC works\n * correctly with the render pipeline of `@xmachines/json-render-vue`.\n *\n * This function is the drop-in replacement for `defineRegistry` from\n * `@xmachines/json-render-vue`. Import it from `@xmachines/play-vue`, and you get\n * the support for an SFC.\n *\n * @param catalog - The json-render catalog. It defines the prop shape of each component.\n * @param options - The registry options. Each `components` entry is a `.vue` SFC,\n * which is an object, or a plain `ComponentFn` function. The wrapper handles both.\n */\nexport function defineRegistry<C extends Catalog>(\n\tcatalog: C,\n\toptions: DefineRegistryOptions<C>,\n): ReturnType<typeof defineRegistryBase<C>> {\n\tconst wrappedComponents = {} as Components<C>;\n\n\tfor (const [key, component] of Object.entries(options.components ?? {})) {\n\t\tif (component === undefined) continue;\n\t\tconst k = key as keyof InferCatalogComponents<C>;\n\t\twrappedComponents[k] = isVueSFC(component)\n\t\t\t? wrapSFC(component as Component)\n\t\t\t: (component as ComponentFn<C, typeof k>);\n\t}\n\n\tconst baseOptions = options as Parameters<typeof defineRegistryBase<C>>[1];\n\treturn defineRegistryBase(catalog, { ...baseOptions, components: wrappedComponents });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwFA,SAAS,SAAS,OAAoC;CACrD,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,IAAI;CAEV,IAAI,eAAe,KAAK,YAAY,GAAG,OAAO;CAE9C,OAAO,OAAO,EAAE,aAAa,cAAc,OAAO,EAAE,cAAc;AACnE;;;;;;;;AASA,SAAS,QACR,WACoB;CACpB,QAAQ,QAAgC,EAAE,WAAW,GAAG;AACzD;;;;;;;;;;;;;AA6BA,
|
|
1
|
+
{"version":3,"file":"define-registry.js","names":["defineRegistry","defineRegistryBase","baseOptions"],"sources":["../src/define-registry.ts"],"sourcesContent":["/**\n * The `defineRegistry` wrapper of @xmachines/play-vue.\n *\n * It wraps `defineRegistry` from `@xmachines/json-render-vue`, and it adds support\n * for an SFC.\n *\n * ## Vue only — React and Solid do not need this wrapper\n *\n * In React, `useContext()` works everywhere inside the component call tree. In\n * Solid, `useContext()` works inside a reactive computation and inside a component\n * render. Neither framework has the strict rule of the Vue function `inject()`,\n * which runs during a synchronous `setup()` only. Therefore the `defineRegistry`\n * implementation of each of them calls `componentFn(ctx)` directly, and it wraps\n * nothing.\n *\n * The DOM renderer has no component system at all. It has render functions that\n * return an `HTMLElement`. An injection context is therefore not relevant.\n *\n * Vue alone needs this adapter.\n *\n * ## The reason for this wrapper\n *\n * The `defineRegistry` function of `@xmachines/json-render-vue` calls each\n * registered component as a plain function: `componentFn(ctx)`. A `.vue` SFC, which\n * is the output of `defineComponent` or of `<script setup>`, is an **object**, not a\n * function. A call to that object throws.\n *\n * There is a second and deeper reason. `defineRegistry` calls each component inside\n * its own render function, which is the return value of `setup()`. The Vue function\n * `inject()`, and each composable on it, such as `useStateBinding` and\n * `useStateStore`, works during the synchronous run of `setup()` only, not inside a\n * render function. For this reason a plain `.ts` `ComponentFn` file can call no Vue\n * composable.\n *\n * This wrapper finds each Vue SFC in the `components` map, and it wraps the SFC with\n * `h(SFC, ctx)`. The SFC then renders as a child component with its own `setup()`,\n * and every composable works inside `<script setup>`.\n *\n * ## Use\n *\n * Import `defineRegistry` from `@xmachines/play-vue`, not from `@xmachines/json-render-vue`:\n *\n * ```ts\n * import { defineRegistry } from \"@xmachines/play-vue\";\n * // not: import { defineRegistry } from \"@xmachines/json-render-vue\";\n *\n * import LoginSFC from \"./views/Login.vue\";\n * import DashboardSFC from \"./views/Dashboard.vue\";\n *\n * const { registry } = defineRegistry(catalog, {\n * components: {\n * Login: LoginSFC, // a .vue SFC — the wrapper handles it\n * Dashboard: DashboardSFC, // a .vue SFC — the wrapper handles it\n * },\n * });\n * ```\n *\n * A plain `ComponentFn` function also works, and the wrapper passes it through\n * without a change. One registry can hold both SFCs and plain functions.\n */\n\nimport { h, type Component } from \"vue\";\nimport {\n\tdefineRegistry as defineRegistryBase,\n\ttype ComponentContext,\n\ttype ComponentFn,\n\ttype Components,\n} from \"@xmachines/json-render-vue\";\nimport type { Catalog, InferCatalogComponents } from \"@xmachines/json-render-core\";\n\n/**\n * Tells you if a value is a Vue component object, which is an SFC, and not a plain\n * `ComponentFn` function.\n *\n * A Vue SFC from `defineComponent` or from the compilation of `<script setup>` is a\n * plain object, and a call to it is not possible. A `ComponentFn` is always a plain\n * function.\n *\n * The function makes four tests, in this order:\n * 1. `__vccOpts` — vite-plugin-vue and vue-loader set it on every `<script setup>` SFC.\n * 2. `__name` — Vite sets it on a named SFC. It is present beside `__vccOpts`, and\n * also on the output of `defineComponent({ name: \"...\" })` without `<script setup>`.\n * 3. `setup` is a function — this is the `defineComponent({ setup() {} })` signature.\n * 4. `render` is a function — this is the `defineComponent({ render() {} })` signature.\n *\n * Tests 3 and 4 require a **function**. A plain object with a `setup` key or a\n * `render` key is therefore not a component for this function.\n */\nfunction isVueSFC(value: unknown): value is Component {\n\tif (typeof value !== \"object\" || value === null) return false;\n\tconst v = value as Record<string, unknown>;\n\t// The markers of the compiler. They identify a Vue component without a doubt.\n\tif (\"__vccOpts\" in v || \"__name\" in v) return true;\n\t// The output of defineComponent(): the code must be able to call setup or render, and their presence is not sufficient.\n\treturn typeof v[\"setup\"] === \"function\" || typeof v[\"render\"] === \"function\";\n}\n\n/**\n * Wraps a Vue SFC as a `ComponentFn`, and renders it with `h()`.\n *\n * The SFC receives the complete `ComponentContext` as its props. It renders in the\n * `setup()` function of its own child component, where each Vue composable works\n * correctly.\n */\nfunction wrapSFC<C extends Catalog, K extends keyof InferCatalogComponents<C>>(\n\tcomponent: Component,\n): ComponentFn<C, K> {\n\treturn (ctx: ComponentContext<C, K>) => h(component, ctx);\n}\n\nexport type ComponentEntry<C extends Catalog, K extends keyof InferCatalogComponents<C>> =\n\t| ComponentFn<C, K>\n\t| Component;\n\nexport type ComponentsMap<C extends Catalog> = {\n\t[K in keyof InferCatalogComponents<C>]?: ComponentEntry<C, K>;\n};\n\nexport type DefineRegistryOptions<C extends Catalog> = Omit<\n\tParameters<typeof defineRegistryBase<C>>[1],\n\t\"components\"\n> & {\n\tcomponents?: ComponentsMap<C>;\n};\n\n/**\n * Creates a component registry. It wraps each `.vue` SFC, so that the SFC works\n * correctly with the render pipeline of `@xmachines/json-render-vue`.\n *\n * This function is the drop-in replacement for `defineRegistry` from\n * `@xmachines/json-render-vue`. Import it from `@xmachines/play-vue`, and you get\n * the support for an SFC.\n *\n * @param catalog - The json-render catalog. It defines the prop shape of each component.\n * @param options - The registry options. Each `components` entry is a `.vue` SFC,\n * which is an object, or a plain `ComponentFn` function. The wrapper handles both.\n */\nexport function defineRegistry<C extends Catalog>(\n\tcatalog: C,\n\toptions: DefineRegistryOptions<C>,\n): ReturnType<typeof defineRegistryBase<C>> {\n\tconst wrappedComponents = {} as Components<C>;\n\n\tfor (const [key, component] of Object.entries(options.components ?? {})) {\n\t\tif (component === undefined) continue;\n\t\tconst k = key as keyof InferCatalogComponents<C>;\n\t\twrappedComponents[k] = isVueSFC(component)\n\t\t\t? wrapSFC(component as Component)\n\t\t\t: (component as ComponentFn<C, typeof k>);\n\t}\n\n\tconst baseOptions = options as Parameters<typeof defineRegistryBase<C>>[1];\n\treturn defineRegistryBase(catalog, { ...baseOptions, components: wrappedComponents });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwFA,SAAS,SAAS,OAAoC;CACrD,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO;CACxD,MAAM,IAAI;CAEV,IAAI,eAAe,KAAK,YAAY,GAAG,OAAO;CAE9C,OAAO,OAAO,EAAE,aAAa,cAAc,OAAO,EAAE,cAAc;AACnE;;;;;;;;AASA,SAAS,QACR,WACoB;CACpB,QAAQ,QAAgC,EAAE,WAAW,GAAG;AACzD;;;;;;;;;;;;;AA6BA,SAAgBA,iBACf,SACA,SAC2C;CAC3C,MAAM,oBAAoB,CAAC;CAE3B,KAAK,MAAM,CAAC,KAAK,cAAc,OAAO,QAAQ,QAAQ,cAAc,CAAC,CAAC,GAAG;EACxE,IAAI,cAAc,KAAA,GAAW;EAC7B,MAAM,IAAI;EACV,kBAAkB,KAAK,SAAS,SAAS,IACtC,QAAQ,SAAsB,IAC7B;CACL;CAGA,OAAOC,eAAmB,SAAS;EAAE,GAAGC;EAAa,YAAY;CAAkB,CAAC;AACrF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
export { default as PlayRenderer } from "./PlayRenderer.vue";
|
|
16
16
|
export { default as ActorProvider } from "./ActorProvider.vue";
|
|
17
17
|
export { default as PlayUIProvider } from "./PlayUIProvider.vue";
|
|
18
|
-
export type { ActorProviderProps, PlayUIProviderProps, RenderErrorHandler } from "./types.js";
|
|
18
|
+
export type { ActorProviderProps, PlayUIProviderProps, RenderErrorHandler, OnRenderError, RenderErrorInfo, RenderErrorKind, } from "./types.js";
|
|
19
19
|
export { usePlayView } from "./actor-provider-context.js";
|
|
20
20
|
export type { ViewContextValue } from "./actor-provider-context.js";
|
|
21
21
|
export { useActor } from "./useActor.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGjE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGjE,YAAY,EACX,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,eAAe,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,qBAAqB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGjG,OAAO,EACN,cAAc,EACd,aAAa,EACb,cAAc,EACd,kBAAkB,EAClB,kBAAkB,EAClB,QAAQ,EACR,YAAY,EACZ,kBAAkB,GAClB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACX,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,aAAa,EACb,WAAW,EACX,gBAAgB,EAChB,oBAAoB,GACpB,MAAM,4BAA4B,CAAC;AAQpC,OAAO,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -49,9 +49,13 @@ export interface ActorProviderProps extends BaseActorProviderProps<DefineRegistr
|
|
|
49
49
|
* The boundary stops the error. Without this prop the provider therefore writes the
|
|
50
50
|
* error to `console.error`, because `app.config.errorHandler` does not see it.
|
|
51
51
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
52
|
+
* The per-element boundary of `json-render` catches a throw of a catalog component
|
|
53
|
+
* below the root, and it reports it through `onRenderError` alone. A failure of the
|
|
54
|
+
* ROOT — its component, a prop, or its `visible` condition — leaves no view, and
|
|
55
|
+
* json-render gives it to no boundary of the host. The provider contains it as a
|
|
56
|
+
* failure of the view all the same: it shows the fallback, and it calls this handler
|
|
57
|
+
* one time. `onRenderError` also receives it, with `info.kind` `"root"`. This boundary
|
|
58
|
+
* is the outer net for everything else.
|
|
55
59
|
*
|
|
56
60
|
* The second parameter is the RESET, for a retry that the host starts — a "Retry"
|
|
57
61
|
* button of its own. It clears the contained error and renders again, and it resolves
|
|
@@ -77,7 +81,7 @@ export interface ActorProviderProps extends BaseActorProviderProps<DefineRegistr
|
|
|
77
81
|
/**
|
|
78
82
|
* The props of PlayUIProvider — every ActorProvider prop, and also the props of JSONUIProvider.
|
|
79
83
|
*/
|
|
80
|
-
export type { RenderErrorHandler } from "@xmachines/json-render-vue";
|
|
84
|
+
export type { RenderErrorHandler, OnRenderError, RenderErrorInfo, RenderErrorKind, } from "@xmachines/json-render-vue";
|
|
81
85
|
export interface PlayUIProviderProps extends ActorProviderProps {
|
|
82
86
|
/** The navigate function. The provider gives it to JSONUIProvider, which resolves each link with it */
|
|
83
87
|
navigate?: (path: string) => void;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB,CAAC,oBAAoB,CAAC;IACvF
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE;;;;;;;;GAQG;AACH,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB,CAAC,oBAAoB,CAAC;IACvF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4DG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CACtD;AAED;;GAEG;AACH,YAAY,EACX,kBAAkB,EAClB,aAAa,EACb,eAAe,EACf,eAAe,GACf,MAAM,4BAA4B,CAAC;AAEpC,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC9D,uGAAuG;IACvG,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,MAAM,CAC3B,MAAM,EACN,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAC3D,CAAC;IACF,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CACjB,MAAM,EACN,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAC5E,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xmachines/play-vue",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Vue renderer for XMachines Play architecture",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"reactive",
|
|
@@ -46,37 +46,38 @@
|
|
|
46
46
|
"test:watch": "vitest"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@xmachines/play-actor": "
|
|
50
|
-
"@xmachines/play-view": "
|
|
49
|
+
"@xmachines/play-actor": "7.0.0",
|
|
50
|
+
"@xmachines/play-view": "7.0.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@testing-library/jest-dom": "^7.0.1",
|
|
54
|
-
"@types/node": "^26.6.
|
|
54
|
+
"@types/node": "^26.6.4",
|
|
55
55
|
"@vitejs/plugin-vue": "^6.0.9",
|
|
56
|
-
"@vitest/browser-playwright": "^5.0.
|
|
57
|
-
"@vue/
|
|
58
|
-
"@
|
|
59
|
-
"@xmachines/json-render-
|
|
60
|
-
"@xmachines/json-render-
|
|
61
|
-
"@xmachines/
|
|
62
|
-
"@xmachines/play
|
|
63
|
-
"
|
|
64
|
-
"
|
|
56
|
+
"@vitest/browser-playwright": "^5.0.3",
|
|
57
|
+
"@vue/language-core": "^3.3.12",
|
|
58
|
+
"@vue/test-utils": "^2.5.1",
|
|
59
|
+
"@xmachines/json-render-core": "0.21.0-xm.6",
|
|
60
|
+
"@xmachines/json-render-vue": "0.21.0-xm.6",
|
|
61
|
+
"@xmachines/json-render-xstate": "0.21.0-xm.6",
|
|
62
|
+
"@xmachines/play": "7.0.0",
|
|
63
|
+
"@xmachines/play-atom": "7.0.0",
|
|
64
|
+
"oxfmt": "^0.71.0",
|
|
65
|
+
"oxlint": "^1.86.0",
|
|
65
66
|
"typescript": "^5.9.3 || ^6.0.3",
|
|
66
|
-
"vite": "^8.3.
|
|
67
|
-
"vite-plugin-dts": "^5.1.
|
|
68
|
-
"vitest": "^5.0.
|
|
69
|
-
"vue": "^3.5.
|
|
67
|
+
"vite": "^8.3.2",
|
|
68
|
+
"vite-plugin-dts": "^5.1.2",
|
|
69
|
+
"vitest": "^5.0.3",
|
|
70
|
+
"vue": "^3.5.43",
|
|
70
71
|
"xstate": "^5.33.0",
|
|
71
72
|
"zod": "^4.6.5"
|
|
72
73
|
},
|
|
73
74
|
"peerDependencies": {
|
|
74
|
-
"@xmachines/json-render-core": "
|
|
75
|
-
"@xmachines/json-render-vue": "
|
|
76
|
-
"@xmachines/json-render-xstate": "
|
|
77
|
-
"@xmachines/play": "
|
|
78
|
-
"@xmachines/play-atom": "
|
|
79
|
-
"vue": "^3.5.
|
|
75
|
+
"@xmachines/json-render-core": "0.21.0-xm.6",
|
|
76
|
+
"@xmachines/json-render-vue": "0.21.0-xm.6",
|
|
77
|
+
"@xmachines/json-render-xstate": "0.21.0-xm.6",
|
|
78
|
+
"@xmachines/play": "7.0.0",
|
|
79
|
+
"@xmachines/play-atom": "7.0.0",
|
|
80
|
+
"vue": "^3.5.11"
|
|
80
81
|
},
|
|
81
82
|
"engines": {
|
|
82
83
|
"node": ">=24.0.0"
|