@rainbow-robotics/plugin-ui 0.1.2-dev.5 → 0.1.2-dev.50
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 +236 -75
- package/build-dist.mjs +55 -17
- package/dist/host-ui.d.ts +49 -0
- package/dist/host-ui.d.ts.map +1 -0
- package/dist/host-ui.js +33 -0
- package/dist/host-ui.js.map +7 -0
- package/dist/manifest.d.ts +20 -4
- package/dist/manifest.d.ts.map +1 -1
- package/dist/manifest.js +1 -1
- package/dist/manifest.js.map +2 -2
- package/dist/pluginData.d.ts +62 -0
- package/dist/pluginData.d.ts.map +1 -0
- package/dist/react.d.ts +3430 -36
- package/dist/react.js +5 -54
- package/dist/react.js.map +2 -2
- package/dist/sdk.d.ts +54 -4
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +44 -10
- package/dist/sdk.js.map +2 -2
- package/dist/viteHost.d.ts +46 -0
- package/dist/viteHost.d.ts.map +1 -0
- package/dist/viteHost.js +262 -0
- package/dist/viteHost.js.map +7 -0
- package/dist/ws.d.ts +73 -0
- package/dist/ws.d.ts.map +1 -0
- package/dist/ws.js +129 -0
- package/dist/ws.js.map +7 -0
- package/package.json +41 -22
- package/src/host-ui.ts +80 -0
- package/src/host.tsx +225 -295
- package/src/index.d.ts +1 -0
- package/src/manifest.ts +25 -4
- package/src/pluginData.tsx +232 -0
- package/src/react.tsx +9 -127
- package/src/sdk.ts +119 -18
- package/src/viteHost.ts +309 -0
- package/src/ws.ts +204 -0
- package/build-browser.mjs +0 -84
- package/dist/connect.d.ts +0 -12
- package/dist/connect.d.ts.map +0 -1
- package/dist/connect.js +0 -29
- package/dist/connect.js.map +0 -7
- package/dist/elements.d.ts +0 -195
- package/dist/elements.d.ts.map +0 -1
- package/dist/elements.js +0 -115
- package/dist/elements.js.map +0 -7
- package/dist/react.d.ts.map +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/chunks/chunk-AMCIKVG7.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/chunks/chunk-GJWPOWHG.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/chunks/chunk-JRCDA3EG.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/connect.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/elements.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/react.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/sdk.js +0 -1
- package/dist-browser/vendor/react-dom-client.js +0 -1
- package/dist-browser/vendor/react-jsx-dev-runtime.js +0 -1
- package/dist-browser/vendor/react-jsx-runtime.js +0 -1
- package/dist-browser/vendor/react-runtime.js +0 -65
- package/dist-browser/vendor/react.js +0 -1
- package/src/connect.ts +0 -68
- package/src/elements.ts +0 -257
package/README.md
CHANGED
|
@@ -1,85 +1,246 @@
|
|
|
1
1
|
# @rainbow-robotics/plugin-ui
|
|
2
2
|
|
|
3
|
-
Muscat plugin UI
|
|
3
|
+
# Muscat plugin UI contract and host mounting architecture
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
`muscat-pk build` keeps it **external**. A plugin ZIP must not contain this
|
|
7
|
-
runtime. Muscat/robot and preview-host provide their own matching
|
|
8
|
-
`@rainbow-robotics/plugin-ui` browser runtime and render the real rb-components on the
|
|
9
|
-
host side.
|
|
5
|
+
A Muscat plugin is a plain React component exported as `export default App`.
|
|
10
6
|
|
|
11
|
-
|
|
7
|
+
Plugin mounting works through two paths, both handled by the `./host` package.
|
|
12
8
|
|
|
9
|
+
## Dev environment: `muscat-pk dev`
|
|
10
|
+
|
|
11
|
+
In dev, the plugin's own Vite dev server (using the plugin's `vite.config.ts`) serves a bootstrap module.
|
|
12
|
+
|
|
13
|
+
The host dynamically imports that bootstrap module to run the plugin.
|
|
14
|
+
|
|
15
|
+
Characteristics of this approach:
|
|
16
|
+
|
|
17
|
+
* Full HMR support
|
|
18
|
+
* The plugin runs as its own independent React root
|
|
19
|
+
* The plugin uses its own React instance
|
|
20
|
+
* The host's React tree and the plugin's React tree are separate
|
|
21
|
+
|
|
22
|
+
In other words, in dev the plugin runs inside the host page, but it does not share the React runtime with the host.
|
|
23
|
+
|
|
24
|
+
## Build & robot environment: `muscat-pk build`
|
|
25
|
+
|
|
26
|
+
`muscat-pk build` is not its own bundler — it's a thin wrapper that **runs `vite build` using the plugin project's own `vite.config.ts`**
|
|
27
|
+
(no `--config` is passed; it just sets `cwd` to the plugin root and runs `vite build` — Vite reads that directory's `vite.config.ts` on its own).
|
|
28
|
+
|
|
29
|
+
The scaffolded `vite.config.ts` looks like this:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { defineConfig } from "vite";
|
|
33
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
34
|
+
import { muscat } from "@rainbow-robotics/muscat-plugin-kit/vite";
|
|
35
|
+
export default defineConfig({ plugins: [tailwindcss(), muscat()] });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**The external list and rollup config live in `@rainbow-robotics/muscat-plugin-kit`'s `muscat()` preset (`cli/vite.mjs`), not in this package (`@rainbow-robotics/plugin-ui`).** The roles split as follows:
|
|
39
|
+
|
|
40
|
+
| Package | Responsibility |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `@rainbow-robotics/muscat-plugin-kit` | Build time — the `muscat()` preset (external list, entry discovery, rollup config) |
|
|
43
|
+
| `@rainbow-robotics/plugin-ui` (this package) | Runtime — `./host` (mounting), `./vite-host` (import-map injection on the nexus side) |
|
|
44
|
+
|
|
45
|
+
The `muscat()` preset leaves the following dependencies out of the plugin bundle as external bare specifiers:
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
react
|
|
49
|
+
react-dom
|
|
50
|
+
@rainbow-robotics/plugin-ui/*
|
|
51
|
+
@repo/rb-components
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The host page includes an import map set up by `./vite-host`.
|
|
55
|
+
|
|
56
|
+
This import map resolves those bare specifiers to the actual module instances the host has already loaded.
|
|
57
|
+
|
|
58
|
+
So a plugin loaded in production behaves as follows:
|
|
59
|
+
|
|
60
|
+
* Uses the same React instance as the host
|
|
61
|
+
* Mounts as a real nested React tree inside the host's React tree
|
|
62
|
+
* Shares `RbContext`
|
|
63
|
+
* Shares the host's UI context
|
|
64
|
+
* Minimizes the plugin bundle size
|
|
65
|
+
|
|
66
|
+
In dev the plugin runs as its own independent React root; in build/robot environments it runs nested inside the host's React tree.
|
|
67
|
+
|
|
68
|
+
### Plugins with no UI skip the vite build entirely
|
|
69
|
+
|
|
70
|
+
`muscat-pk build` collects `contributes[].ui` from `manifest.json` and verifies that a matching `ui/{name}.tsx` (or `.ts`/`.jsx`/`.js`) file actually exists.
|
|
71
|
+
|
|
72
|
+
* If `contributes` declares a `ui` but the file doesn't exist → build fails (clear error)
|
|
73
|
+
* If `contributes` declares no `ui` and the `ui/` directory has no files either (a backend-only plugin) → **the vite build is skipped entirely.** `dist/` only contains manifest.json/assets/backend files.
|
|
74
|
+
|
|
75
|
+
This logic lives in `buildPlugin()` in `libraries/muscat-plugin-kit/cli/src/build.mjs`.
|
|
76
|
+
|
|
77
|
+
### When Node.js isn't available
|
|
78
|
+
|
|
79
|
+
`muscat-pk build` isn't its own bundler — it **spawns `vite build` as a child process**, so a JS runtime must be available to run that child process.
|
|
80
|
+
|
|
81
|
+
* **`muscat-pk` installed via npm** → already running under Node, so this issue never occurs.
|
|
82
|
+
* **`muscat-pk` installed via the S3 self-contained binary (compiled with Bun)** → looks on PATH in order: `bun` → `node` → `nodejs`. If none are found:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
Node.js 20+ (or Bun) is required to build the plugin UI.
|
|
86
|
+
Install Node.js: https://nodejs.org
|
|
87
|
+
Then run: npm install (inside the plugin directory)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
is printed and the process exits with `exitCode 1` quietly (no stack trace). This logic lives in `findJsRuntime()` / `runViteBuild()` in `build.mjs`.
|
|
91
|
+
|
|
92
|
+
# Entry points
|
|
93
|
+
|
|
94
|
+
## `./react`
|
|
95
|
+
|
|
96
|
+
Used by:
|
|
97
|
+
|
|
98
|
+
```text
|
|
99
|
+
plugin
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Re-exports every `new-components` export from `@repo/rb-components`, plus the `useRb`, `useRbFormData`, and `useRbSave` hooks from `./sdk`.
|
|
103
|
+
|
|
104
|
+
Plugins should use UI components through this entry point rather than importing `@repo/rb-components` directly.
|
|
105
|
+
|
|
106
|
+
`muscat-pk mcp` parses this package's `dist/react.d.ts` (a self-contained bundle of rb-components' types) to give AI coding agents component lists and prop info.
|
|
107
|
+
|
|
108
|
+
## `./sdk`
|
|
109
|
+
|
|
110
|
+
Used by:
|
|
111
|
+
|
|
112
|
+
```text
|
|
113
|
+
plugin
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Provides `useRb()`.
|
|
117
|
+
|
|
118
|
+
`useRb()` gives access to:
|
|
119
|
+
|
|
120
|
+
* Zenoh-WebSocket-based robot publish
|
|
121
|
+
* subscribe
|
|
122
|
+
* action calls
|
|
123
|
+
* serve
|
|
124
|
+
* toast
|
|
125
|
+
* alert
|
|
126
|
+
* confirm
|
|
127
|
+
* prompt
|
|
128
|
+
|
|
129
|
+
Instead of implementing dialog/toast UI itself, a plugin delegates these requests to the host's real dialog and toast implementation.
|
|
130
|
+
|
|
131
|
+
See `./host-ui` for the actual host UI service implementation.
|
|
132
|
+
|
|
133
|
+
`useRbFormData()` / `useRbSave()` are also provided by `./sdk`. The host passes previously-saved `data` to the plugin, and the plugin registers a payload getter via `onSave` — form save/restore is owned by the host, not the plugin.
|
|
134
|
+
|
|
135
|
+
## `./ws`
|
|
136
|
+
|
|
137
|
+
Used by:
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
plugin dev bootstrap only
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Provides `RbWs`.
|
|
144
|
+
|
|
145
|
+
`RbWs` is the WebSocket client `useRb()` uses internally.
|
|
146
|
+
|
|
147
|
+
This entry point isn't used by a plugin's normal production code — it's only used by the dev-environment bootstrap module.
|
|
148
|
+
|
|
149
|
+
## `./manifest`
|
|
150
|
+
|
|
151
|
+
Used by:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
nexus
|
|
155
|
+
muscat-pk
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Provides the plugin manifest schema.
|
|
159
|
+
|
|
160
|
+
Acts as the single source of truth for the manifest definition.
|
|
161
|
+
|
|
162
|
+
`contributes[].point` (`CONTRIBUTION_POINTS`) has 4 possible values:
|
|
163
|
+
|
|
164
|
+
| point | Description |
|
|
165
|
+
|---|---|
|
|
166
|
+
| `toolbar` | A live UI panel exposed in the top toolbar |
|
|
167
|
+
| `lnb` | A live UI panel exposed in the left navigation bar (LNB) |
|
|
168
|
+
| `move.panel` | A live UI panel exposed in the Move panel |
|
|
169
|
+
| `program.panel` | A custom command the plugin defines for the Program page's rule-based sequence builder |
|
|
170
|
+
|
|
171
|
+
`toolbar`/`lnb`/`move.panel` back ends use `RBManipulateSDK`/`RBAmrSDK` or `rb.action()` directly. `program.panel` declares `commandInfo` (`funcName: "rb_program_sdk.plugin_execute"`) and its backend runs through `PluginProgramContext` (`on_execute`, `check_stop`, `get_variable`, `set_variable`, `done`).
|
|
172
|
+
|
|
173
|
+
## `./plugin-data`
|
|
174
|
+
|
|
175
|
+
Used by:
|
|
176
|
+
|
|
177
|
+
```text
|
|
178
|
+
nexus only
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Provides:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
PluginDataProvider
|
|
185
|
+
usePluginData()
|
|
13
186
|
```
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
187
|
+
|
|
188
|
+
Decides where and how a plugin is loaded from.
|
|
189
|
+
|
|
190
|
+
## `./host`
|
|
191
|
+
|
|
192
|
+
Used by:
|
|
193
|
+
|
|
194
|
+
```text
|
|
195
|
+
nexus only
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Provides `PluginHost`.
|
|
199
|
+
|
|
200
|
+
`PluginHost` handles both mounting paths described above:
|
|
201
|
+
|
|
202
|
+
* The dev environment's dynamic Vite bootstrap import
|
|
203
|
+
* The build/robot environment's ESM module mount
|
|
204
|
+
|
|
205
|
+
## `./vite-host`
|
|
206
|
+
|
|
207
|
+
Used by:
|
|
208
|
+
|
|
209
|
+
```text
|
|
210
|
+
nexus vite.config.ts
|
|
23
211
|
```
|
|
24
212
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
| `rb-text-input` | `RBTextInput` | `onInput` (string) |
|
|
57
|
-
| `rb-switch` | `RBSwitch` | `onChange` (boolean) |
|
|
58
|
-
| `rb-select` | `RBSelectBox` | `onChange` (string) |
|
|
59
|
-
|
|
60
|
-
> ⚠️ Author bindings and the host **must** declare matching `eventProps`.
|
|
61
|
-
> `createRemoteComponent` / `createRemoteComponentRenderer` only treat a prop as
|
|
62
|
-
> an event listener when it is in `eventProps`; they do **not** auto-derive from
|
|
63
|
-
> the element's `remoteEvents`.
|
|
64
|
-
|
|
65
|
-
## Verified versions
|
|
66
|
-
|
|
67
|
-
`@remote-dom/core@^1.11` · `@remote-dom/react@^1.2` · `@quilted/threads@^4`.
|
|
68
|
-
Notable corrections vs. early design notes: `RemoteMutationObserver` is from
|
|
69
|
-
`@remote-dom/core/elements` (not `/core`); there is no `@remote-dom/core/messaging`
|
|
70
|
-
— threading lives in `@quilted/threads`.
|
|
71
|
-
|
|
72
|
-
## Demo (M1 end-to-end check)
|
|
73
|
-
|
|
74
|
-
`demo/` is a standalone vite harness (excluded from build/lint/types). It serves
|
|
75
|
-
a host page + sandbox page and verifies the full round-trip in a real browser:
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
# from repo root
|
|
79
|
-
node_modules/.bin/vite --config packages/rb-plugin-kit/demo/vite.config.ts
|
|
80
|
-
# then, with the server on :5199:
|
|
81
|
-
node packages/rb-plugin-kit/demo/e2e.mjs
|
|
213
|
+
Provides Vite plugins.
|
|
214
|
+
|
|
215
|
+
Main responsibilities:
|
|
216
|
+
|
|
217
|
+
* Injecting the import map
|
|
218
|
+
* Supporting the plugin preview dev environment
|
|
219
|
+
|
|
220
|
+
# Plugin production bundle rules
|
|
221
|
+
|
|
222
|
+
A plugin's production bundle should only import these entry points:
|
|
223
|
+
|
|
224
|
+
```text
|
|
225
|
+
./react
|
|
226
|
+
./sdk
|
|
227
|
+
./host-ui
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`./host-ui` is used optionally, only when needed.
|
|
231
|
+
|
|
232
|
+
The following entry points, on the other hand, are host-only:
|
|
233
|
+
|
|
234
|
+
```text
|
|
235
|
+
./host
|
|
236
|
+
./vite-host
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
These modules include host-only dependencies:
|
|
240
|
+
|
|
241
|
+
```text
|
|
242
|
+
@repo/rb-components
|
|
243
|
+
vite
|
|
82
244
|
```
|
|
83
245
|
|
|
84
|
-
|
|
85
|
-
in nexus.
|
|
246
|
+
So `./host` and `./vite-host` are never included in a plugin bundle.
|
package/build-dist.mjs
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
// Builds @rainbow-robotics/plugin-ui for npm consumers (plugin authors).
|
|
2
|
-
// Output: dist/*.js (ESM, deps external) + dist/*.d.ts (via tsc)
|
|
3
|
-
//
|
|
4
|
-
// host.tsx is intentionally excluded — it depends on @repo/rb-components
|
|
5
|
-
// which is a Muscat-internal package. External devs never import ./host.
|
|
6
|
-
//
|
|
7
|
-
// Run: node libraries/plugin-ui/build-dist.mjs
|
|
8
1
|
import { build } from "esbuild";
|
|
9
|
-
import {
|
|
2
|
+
import { rollup } from "rollup";
|
|
3
|
+
import dts from "rollup-plugin-dts";
|
|
4
|
+
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
10
6
|
import { rmSync } from "node:fs";
|
|
11
7
|
import { dirname, resolve } from "node:path";
|
|
12
8
|
import { fileURLToPath } from "node:url";
|
|
@@ -18,25 +14,67 @@ rmSync(resolve(here, "dist"), { recursive: true, force: true });
|
|
|
18
14
|
// JS: transpile only (no bundling — consumers resolve deps themselves)
|
|
19
15
|
await build({
|
|
20
16
|
entryPoints: {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
sdk: resolve(here, "src/sdk.ts"),
|
|
24
|
-
elements: resolve(here, "src/elements.ts"),
|
|
17
|
+
react: resolve(here, "src/react.tsx"),
|
|
18
|
+
sdk: resolve(here, "src/sdk.ts"),
|
|
25
19
|
manifest: resolve(here, "src/manifest.ts"),
|
|
20
|
+
viteHost: resolve(here, "src/viteHost.ts"),
|
|
21
|
+
"host-ui": resolve(here, "src/host-ui.ts"),
|
|
22
|
+
// ws is used by the dev bootstrap + host.tsx to build the rb sdk.
|
|
23
|
+
ws: resolve(here, "src/ws.ts"),
|
|
26
24
|
},
|
|
27
25
|
outdir: resolve(here, "dist"),
|
|
28
26
|
format: "esm",
|
|
29
|
-
bundle: false,
|
|
27
|
+
bundle: false, // each file transpiled independently, deps stay as imports
|
|
30
28
|
platform: "neutral",
|
|
31
29
|
target: "es2022",
|
|
32
30
|
sourcemap: true,
|
|
33
31
|
logLevel: "warning",
|
|
34
32
|
});
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const tsc = spawnSync(
|
|
35
|
+
"node",
|
|
36
|
+
[
|
|
37
|
+
"../../node_modules/typescript/bin/tsc",
|
|
38
|
+
"-p",
|
|
39
|
+
"tsconfig.build.json",
|
|
40
|
+
"--emitDeclarationOnly",
|
|
41
|
+
"--noEmit",
|
|
42
|
+
"false",
|
|
43
|
+
],
|
|
44
|
+
{ cwd: here, stdio: "inherit" },
|
|
45
|
+
);
|
|
46
|
+
if (tsc.status !== 0) {
|
|
47
|
+
console.warn(
|
|
48
|
+
"[plugin-ui] tsc reported errors during declaration emit (likely the known rb-providers/rb-utils " +
|
|
49
|
+
"global.d.ts gap, unrelated to plugin-ui) — .d.ts files were still written; continuing.",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const reactExternal = (id) =>
|
|
54
|
+
/^react($|\/)/.test(id) || /^react-dom($|\/)/.test(id);
|
|
55
|
+
|
|
56
|
+
const ASSET_RE =
|
|
57
|
+
/\.(css|scss|sass|less|svg|png|jpe?g|gif|webp|woff2?)(\?\w+)?$|^swiper\/css/;
|
|
58
|
+
const stubAssets = {
|
|
59
|
+
name: "stub-assets-for-dts",
|
|
60
|
+
resolveId: (id) => (ASSET_RE.test(id) ? "\0asset-stub" : null),
|
|
61
|
+
load: (id) => (id === "\0asset-stub" ? "export default undefined;" : null),
|
|
62
|
+
};
|
|
63
|
+
const dtsBundle = await rollup({
|
|
64
|
+
input: resolve(here, "src/react.tsx"),
|
|
65
|
+
external: reactExternal,
|
|
66
|
+
plugins: [
|
|
67
|
+
stubAssets,
|
|
68
|
+
nodeResolve({ extensions: [".d.ts", ".ts", ".tsx", ".js", ".jsx"] }),
|
|
69
|
+
dts({ respectExternal: false }),
|
|
70
|
+
],
|
|
71
|
+
onwarn: () => {},
|
|
72
|
+
});
|
|
73
|
+
await dtsBundle.write({
|
|
74
|
+
file: resolve(here, "dist/react.d.ts"),
|
|
75
|
+
format: "es",
|
|
40
76
|
});
|
|
77
|
+
await dtsBundle.close();
|
|
78
|
+
rmSync(resolve(here, "dist/react.d.ts.map"), { force: true });
|
|
41
79
|
|
|
42
80
|
console.log("[plugin-ui] dist/ ready");
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ReactElement } from "react";
|
|
2
|
+
export interface PluginUIServices {
|
|
3
|
+
alert: (params: {
|
|
4
|
+
title?: string;
|
|
5
|
+
message: string;
|
|
6
|
+
buttonText?: string;
|
|
7
|
+
}) => Promise<void>;
|
|
8
|
+
confirm: (params: {
|
|
9
|
+
title?: string;
|
|
10
|
+
message: string;
|
|
11
|
+
buttonText?: {
|
|
12
|
+
yes: string;
|
|
13
|
+
no: string;
|
|
14
|
+
};
|
|
15
|
+
}) => Promise<boolean>;
|
|
16
|
+
prompt: (params: {
|
|
17
|
+
title?: string;
|
|
18
|
+
message: string;
|
|
19
|
+
value?: string;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
buttonText?: {
|
|
22
|
+
yes: string;
|
|
23
|
+
no: string;
|
|
24
|
+
};
|
|
25
|
+
}) => Promise<string | undefined>;
|
|
26
|
+
toast: (params: {
|
|
27
|
+
title?: string;
|
|
28
|
+
message: string | ReactElement;
|
|
29
|
+
type?: "info" | "danger" | "warning" | "caution" | "success";
|
|
30
|
+
actionLabel?: string;
|
|
31
|
+
handleActionClick?: () => void;
|
|
32
|
+
closeOnActionClick?: boolean;
|
|
33
|
+
duration?: number;
|
|
34
|
+
onClose?: () => void;
|
|
35
|
+
}) => void;
|
|
36
|
+
}
|
|
37
|
+
/** Called by the host when it mounts a plugin. */
|
|
38
|
+
export declare function setHostServices(next: PluginUIServices): void;
|
|
39
|
+
/** Read the injected services, throwing a clear error if the host forgot. */
|
|
40
|
+
export declare function getHostServices(): PluginUIServices;
|
|
41
|
+
/** Open a host alert dialog from a plugin. */
|
|
42
|
+
export declare function alert(params: Parameters<PluginUIServices["alert"]>[0]): Promise<void>;
|
|
43
|
+
/** Open a host confirm dialog from a plugin. Resolves true/false. */
|
|
44
|
+
export declare function confirm(params: Parameters<PluginUIServices["confirm"]>[0]): Promise<boolean>;
|
|
45
|
+
/** Open a host prompt dialog from a plugin. Resolves the entered value, or undefined if cancelled. */
|
|
46
|
+
export declare function prompt(params: Parameters<PluginUIServices["prompt"]>[0]): Promise<string | undefined>;
|
|
47
|
+
/** Show a host toast from a plugin. */
|
|
48
|
+
export declare function toast(params: Parameters<PluginUIServices["toast"]>[0]): void;
|
|
49
|
+
//# sourceMappingURL=host-ui.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"host-ui.d.ts","sourceRoot":"","sources":["../src/host-ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAErC,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,CAAC,MAAM,EAAE;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACpB,OAAO,EAAE,CAAC,MAAM,EAAE;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE;YACX,GAAG,EAAE,MAAM,CAAC;YACZ,EAAE,EAAE,MAAM,CAAC;SACZ,CAAC;KACH,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,MAAM,EAAE,CAAC,MAAM,EAAE;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE;YACX,GAAG,EAAE,MAAM,CAAC;YACZ,EAAE,EAAE,MAAM,CAAC;SACZ,CAAC;KACH,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClC,KAAK,EAAE,CAAC,MAAM,EAAE;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,GAAG,YAAY,CAAC;QAC/B,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;QAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;QAC/B,kBAAkB,CAAC,EAAE,OAAO,CAAC;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;KACtB,KAAK,IAAI,CAAC;CACZ;AAID,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAE5D;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,IAAI,gBAAgB,CAOlD;AAED,8CAA8C;AAC9C,wBAAgB,KAAK,CACnB,MAAM,EAAE,UAAU,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAC/C,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,qEAAqE;AACrE,wBAAgB,OAAO,CACrB,MAAM,EAAE,UAAU,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GACjD,OAAO,CAAC,OAAO,CAAC,CAElB;AAED,sGAAsG;AACtG,wBAAgB,MAAM,CACpB,MAAM,EAAE,UAAU,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,GAChD,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAE7B;AAED,uCAAuC;AACvC,wBAAgB,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAE5E"}
|
package/dist/host-ui.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
let services = null;
|
|
2
|
+
function setHostServices(next) {
|
|
3
|
+
services = next;
|
|
4
|
+
}
|
|
5
|
+
function getHostServices() {
|
|
6
|
+
if (!services) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"[plugin-ui] services not set \u2014 the plugin must be mounted by a Muscat host."
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
return services;
|
|
12
|
+
}
|
|
13
|
+
function alert(params) {
|
|
14
|
+
return getHostServices().alert(params);
|
|
15
|
+
}
|
|
16
|
+
function confirm(params) {
|
|
17
|
+
return getHostServices().confirm(params);
|
|
18
|
+
}
|
|
19
|
+
function prompt(params) {
|
|
20
|
+
return getHostServices().prompt(params);
|
|
21
|
+
}
|
|
22
|
+
function toast(params) {
|
|
23
|
+
getHostServices().toast(params);
|
|
24
|
+
}
|
|
25
|
+
export {
|
|
26
|
+
alert,
|
|
27
|
+
confirm,
|
|
28
|
+
getHostServices,
|
|
29
|
+
prompt,
|
|
30
|
+
setHostServices,
|
|
31
|
+
toast
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=host-ui.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/host-ui.ts"],
|
|
4
|
+
"sourcesContent": ["import { ReactElement } from \"react\";\n\nexport interface PluginUIServices {\n alert: (params: {\n title?: string;\n message: string;\n buttonText?: string;\n }) => Promise<void>;\n confirm: (params: {\n title?: string;\n message: string;\n buttonText?: {\n yes: string;\n no: string;\n };\n }) => Promise<boolean>;\n prompt: (params: {\n title?: string;\n message: string;\n value?: string;\n placeholder?: string;\n buttonText?: {\n yes: string;\n no: string;\n };\n }) => Promise<string | undefined>;\n toast: (params: {\n title?: string;\n message: string | ReactElement;\n type?: \"info\" | \"danger\" | \"warning\" | \"caution\" | \"success\";\n actionLabel?: string;\n handleActionClick?: () => void;\n closeOnActionClick?: boolean;\n duration?: number;\n onClose?: () => void;\n }) => void;\n}\n\nlet services: PluginUIServices | null = null;\n\n/** Called by the host when it mounts a plugin. */\nexport function setHostServices(next: PluginUIServices): void {\n services = next;\n}\n\n/** Read the injected services, throwing a clear error if the host forgot. */\nexport function getHostServices(): PluginUIServices {\n if (!services) {\n throw new Error(\n \"[plugin-ui] services not set \u2014 the plugin must be mounted by a Muscat host.\",\n );\n }\n return services;\n}\n\n/** Open a host alert dialog from a plugin. */\nexport function alert(\n params: Parameters<PluginUIServices[\"alert\"]>[0],\n): Promise<void> {\n return getHostServices().alert(params);\n}\n\n/** Open a host confirm dialog from a plugin. Resolves true/false. */\nexport function confirm(\n params: Parameters<PluginUIServices[\"confirm\"]>[0],\n): Promise<boolean> {\n return getHostServices().confirm(params);\n}\n\n/** Open a host prompt dialog from a plugin. Resolves the entered value, or undefined if cancelled. */\nexport function prompt(\n params: Parameters<PluginUIServices[\"prompt\"]>[0],\n): Promise<string | undefined> {\n return getHostServices().prompt(params);\n}\n\n/** Show a host toast from a plugin. */\nexport function toast(params: Parameters<PluginUIServices[\"toast\"]>[0]): void {\n getHostServices().toast(params);\n}\n"],
|
|
5
|
+
"mappings": "AAsCA,IAAI,WAAoC;AAGjC,SAAS,gBAAgB,MAA8B;AAC5D,aAAW;AACb;AAGO,SAAS,kBAAoC;AAClD,MAAI,CAAC,UAAU;AACb,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,MACd,QACe;AACf,SAAO,gBAAgB,EAAE,MAAM,MAAM;AACvC;AAGO,SAAS,QACd,QACkB;AAClB,SAAO,gBAAgB,EAAE,QAAQ,MAAM;AACzC;AAGO,SAAS,OACd,QAC6B;AAC7B,SAAO,gBAAgB,EAAE,OAAO,MAAM;AACxC;AAGO,SAAS,MAAM,QAAwD;AAC5E,kBAAgB,EAAE,MAAM,MAAM;AAChC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/manifest.d.ts
CHANGED
|
@@ -5,19 +5,31 @@
|
|
|
5
5
|
* Evolve additively only.
|
|
6
6
|
*/
|
|
7
7
|
/** Known contribution points the host understands. */
|
|
8
|
-
export declare const CONTRIBUTION_POINTS: readonly ["
|
|
8
|
+
export declare const CONTRIBUTION_POINTS: readonly ["toolbar", "lnb", "move.panel", "program.panel"];
|
|
9
9
|
export type ContributionPoint = (typeof CONTRIBUTION_POINTS)[number];
|
|
10
10
|
/** How a header.toolbar contribution opens when clicked. */
|
|
11
11
|
export type ContributionOpens = "popover" | "panel" | "page";
|
|
12
12
|
export interface PluginContribution {
|
|
13
13
|
/** Where this contribution mounts. */
|
|
14
14
|
point: ContributionPoint | (string & {});
|
|
15
|
+
/** UI entry name relative to ui/ (without extension). Defaults to "content". */
|
|
16
|
+
ui?: string;
|
|
15
17
|
/** Icon path relative to the plugin root (e.g. "assets/icon.svg"). */
|
|
16
|
-
icon?: string
|
|
18
|
+
icon?: string | {
|
|
19
|
+
"16"?: string;
|
|
20
|
+
"48"?: string;
|
|
21
|
+
"126"?: string;
|
|
22
|
+
};
|
|
17
23
|
/** Display label. */
|
|
18
|
-
label?: string
|
|
24
|
+
label?: string | Record<string, string>;
|
|
19
25
|
/** For header.toolbar: how the contribution surfaces. */
|
|
20
26
|
opens?: ContributionOpens;
|
|
27
|
+
commandInfo?: {
|
|
28
|
+
name: string;
|
|
29
|
+
icon: string;
|
|
30
|
+
funcName: string;
|
|
31
|
+
args?: Record<string, any>;
|
|
32
|
+
};
|
|
21
33
|
}
|
|
22
34
|
export interface PluginAction {
|
|
23
35
|
/** Action id referenced by `rb.action(id, payload)`. */
|
|
@@ -48,7 +60,11 @@ export interface PluginManifest {
|
|
|
48
60
|
/** Minimum host (Muscat) version this plugin supports. */
|
|
49
61
|
minAppVersion?: string;
|
|
50
62
|
/** Icon path relative to plugin root. */
|
|
51
|
-
|
|
63
|
+
icons: string | {
|
|
64
|
+
"16"?: string;
|
|
65
|
+
"48"?: string;
|
|
66
|
+
"128"?: string;
|
|
67
|
+
};
|
|
52
68
|
/** UI / chrome contributions. */
|
|
53
69
|
contributes?: PluginContribution[];
|
|
54
70
|
/** Host actions the plugin can invoke. */
|
package/dist/manifest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,4DAKtB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC,MAAM,CAAC,CAAC;AAErE,4DAA4D;AAC5D,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,sCAAsC;IACtC,KAAK,EAAE,iBAAiB,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;IACzC,gFAAgF;IAChF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,IAAI,CAAC,EACD,MAAM,GACN;QACE,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACN,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,yDAAyD;IACzD,KAAK,CAAC,EAAE,iBAAiB,CAAC;IAC1B,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAC5B,CAAC;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IACE,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B,CAAC;AAEN,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,EAAE,EAAE,MAAM,CAAC;IACX,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,KAAK,EACD,MAAM,GACN;QACE,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACN,iCAAiC;IACjC,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACnC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,oCAAoC;IACpC,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAiBzD"}
|
package/dist/manifest.js
CHANGED
package/dist/manifest.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/manifest.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Plugin manifest schema \u2014 the single source of truth shared by the front end\n * (nexus reads it) and the back end (rby2 mirrors it for validation).\n *\n * Evolve additively only.\n */\n\n/** Known contribution points the host understands. */\nexport const CONTRIBUTION_POINTS = [\n \"
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Plugin manifest schema \u2014 the single source of truth shared by the front end\n * (nexus reads it) and the back end (rby2 mirrors it for validation).\n *\n * Evolve additively only.\n */\n\n/** Known contribution points the host understands. */\nexport const CONTRIBUTION_POINTS = [\n \"toolbar\",\n \"lnb\",\n \"move.panel\",\n \"program.panel\",\n] as const;\n\nexport type ContributionPoint = (typeof CONTRIBUTION_POINTS)[number];\n\n/** How a header.toolbar contribution opens when clicked. */\nexport type ContributionOpens = \"popover\" | \"panel\" | \"page\";\n\nexport interface PluginContribution {\n /** Where this contribution mounts. */\n point: ContributionPoint | (string & {});\n /** UI entry name relative to ui/ (without extension). Defaults to \"content\". */\n ui?: string;\n /** Icon path relative to the plugin root (e.g. \"assets/icon.svg\"). */\n icon?:\n | string\n | {\n \"16\"?: string;\n \"48\"?: string;\n \"126\"?: string;\n };\n /** Display label. */\n label?: string | Record<string, string>;\n /** For header.toolbar: how the contribution surfaces. */\n opens?: ContributionOpens;\n commandInfo?: {\n name: string;\n icon: string;\n funcName: string;\n args?: Record<string, any>;\n };\n}\n\nexport interface PluginAction {\n /** Action id referenced by `rb.action(id, payload)`. */\n id: string;\n /** Transport topic (Zenoh / ROS2) the back end routes to. */\n topic: string;\n /** Optional payload schema hint (field \u2192 type name). */\n schema?: Record<string, string>;\n}\n\nexport type PluginRuntime =\n | { type: \"none\" }\n | { type: \"python\"; entry: string }\n | {\n type: \"ros2\";\n package: string;\n launch: string;\n rosClient: \"rclpy\" | \"rclcpp\";\n };\n\nexport interface PluginManifest {\n /** Reverse-DNS unique id, e.g. \"com.rainbow.gripper-tool\". */\n id: string;\n /** Human-readable name. */\n name: string;\n /** Plugin version (semver). */\n version: string;\n /** Minimum host (Muscat) version this plugin supports. */\n minAppVersion?: string;\n /** Icon path relative to plugin root. */\n icons:\n | string\n | {\n \"16\"?: string;\n \"48\"?: string;\n \"128\"?: string;\n };\n /** UI / chrome contributions. */\n contributes?: PluginContribution[];\n /** Host actions the plugin can invoke. */\n actions?: PluginAction[];\n /** Back-end runtime declaration. */\n runtime?: PluginRuntime;\n}\n\n/**\n * Lightweight structural check. Returns the list of problems (empty = valid).\n * Kept dependency-free so both front and back ends can reuse it; richer\n * validation (zod) can layer on top later without breaking this contract.\n */\nexport function validateManifest(value: unknown): string[] {\n const errors: string[] = [];\n if (typeof value !== \"object\" || value === null) {\n return [\"manifest must be an object\"];\n }\n const m = value as Record<string, unknown>;\n if (typeof m.id !== \"string\" || m.id.length === 0)\n errors.push(\"manifest.id is required (string)\");\n if (typeof m.name !== \"string\" || m.name.length === 0)\n errors.push(\"manifest.name is required (string)\");\n if (typeof m.version !== \"string\" || m.version.length === 0)\n errors.push(\"manifest.version is required (string)\");\n if (m.contributes !== undefined && !Array.isArray(m.contributes))\n errors.push(\"manifest.contributes must be an array\");\n if (m.actions !== undefined && !Array.isArray(m.actions))\n errors.push(\"manifest.actions must be an array\");\n return errors;\n}\n"],
|
|
5
|
+
"mappings": "AASO,MAAM,sBAAsB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAiFO,SAAS,iBAAiB,OAA0B;AACzD,QAAM,SAAmB,CAAC;AAC1B,MAAI,OAAO,UAAU,YAAY,UAAU,MAAM;AAC/C,WAAO,CAAC,4BAA4B;AAAA,EACtC;AACA,QAAM,IAAI;AACV,MAAI,OAAO,EAAE,OAAO,YAAY,EAAE,GAAG,WAAW;AAC9C,WAAO,KAAK,kCAAkC;AAChD,MAAI,OAAO,EAAE,SAAS,YAAY,EAAE,KAAK,WAAW;AAClD,WAAO,KAAK,oCAAoC;AAClD,MAAI,OAAO,EAAE,YAAY,YAAY,EAAE,QAAQ,WAAW;AACxD,WAAO,KAAK,uCAAuC;AACrD,MAAI,EAAE,gBAAgB,UAAa,CAAC,MAAM,QAAQ,EAAE,WAAW;AAC7D,WAAO,KAAK,uCAAuC;AACrD,MAAI,EAAE,YAAY,UAAa,CAAC,MAAM,QAAQ,EAAE,OAAO;AACrD,WAAO,KAAK,mCAAmC;AACjD,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|