@rainbow-robotics/plugin-ui 0.1.2-dev.43 → 0.1.2-dev.45
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 +222 -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 +68 -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 +38 -2
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +29 -4
- package/dist/sdk.js.map +2 -2
- package/dist/viteHost.d.ts +48 -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 +53 -0
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +128 -0
- package/dist/ws.js.map +7 -0
- package/package.json +43 -20
- package/src/host-ui.ts +80 -0
- package/src/host.tsx +236 -308
- package/src/index.d.ts +1 -0
- package/src/manifest.ts +25 -4
- package/src/pluginData.tsx +241 -0
- package/src/react.tsx +16 -127
- package/src/sdk.ts +74 -7
- package/src/viteHost.ts +316 -0
- package/src/ws.ts +47 -0
- package/build-browser.mjs +0 -84
- package/dist/connect.d.ts +0 -11
- package/dist/connect.d.ts.map +0 -1
- package/dist/connect.js +0 -34
- 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-37HVFFJB.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/chunks/chunk-4MGSRUAS.js +0 -1
- package/dist-browser/@rainbow-robotics/plugin-ui/chunks/chunk-Q6XGCIPE.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 -64
- package/src/elements.ts +0 -257
package/src/viteHost.ts
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugins for a HOST app previewing locally-developed plugins.
|
|
3
|
+
* Host-agnostic — paths are parameters.
|
|
4
|
+
*
|
|
5
|
+
* import {
|
|
6
|
+
* pluginPreviewRuntimePlugin,
|
|
7
|
+
* pluginPreviewAssetsPlugin,
|
|
8
|
+
* isPluginPreviewMode,
|
|
9
|
+
* } from "@rainbow-robotics/plugin-ui/vite-host";
|
|
10
|
+
*
|
|
11
|
+
* There's no "plugin runtime vendor bundle" to serve anymore — a plugin
|
|
12
|
+
* either loads via its own dev server (dev) or as a plain ESM module whose
|
|
13
|
+
* bare imports (react, rb-components, plugin-ui/*) resolve via the import map
|
|
14
|
+
* this file injects, to the host's own already-loaded instances (build/robot).
|
|
15
|
+
* See ./host.tsx.
|
|
16
|
+
*/
|
|
17
|
+
import type { Plugin } from "vite";
|
|
18
|
+
import { createReadStream, existsSync, readFileSync, statSync } from "node:fs";
|
|
19
|
+
import { createRequire } from "node:module";
|
|
20
|
+
import { extname, resolve } from "node:path";
|
|
21
|
+
|
|
22
|
+
const require = createRequire(import.meta.url);
|
|
23
|
+
|
|
24
|
+
export const defaultPreviewAssetPrefixes = [
|
|
25
|
+
"/imgs/",
|
|
26
|
+
"/fonts/",
|
|
27
|
+
"/models/",
|
|
28
|
+
"/sounds/",
|
|
29
|
+
"/data/",
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
export const contentTypeByExt: Record<string, string> = {
|
|
33
|
+
".avif": "image/avif",
|
|
34
|
+
".css": "text/css; charset=utf-8",
|
|
35
|
+
".gif": "image/gif",
|
|
36
|
+
".glb": "model/gltf-binary",
|
|
37
|
+
".jpeg": "image/jpeg",
|
|
38
|
+
".jpg": "image/jpeg",
|
|
39
|
+
".js": "text/javascript; charset=utf-8",
|
|
40
|
+
".json": "application/json; charset=utf-8",
|
|
41
|
+
".mp3": "audio/mpeg",
|
|
42
|
+
".png": "image/png",
|
|
43
|
+
".svg": "image/svg+xml",
|
|
44
|
+
".wasm": "application/wasm",
|
|
45
|
+
".webp": "image/webp",
|
|
46
|
+
".woff": "font/woff",
|
|
47
|
+
".woff2": "font/woff2",
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const isPluginPreviewMode = (mode: string) => mode === "plugin-preview";
|
|
51
|
+
|
|
52
|
+
/* -------------------------------------------------------------------------- */
|
|
53
|
+
/* Shared-runtime import map (plugins reuse the host's loaded instances) */
|
|
54
|
+
/* -------------------------------------------------------------------------- */
|
|
55
|
+
|
|
56
|
+
const SHARED_BASE = "/plugin-shared";
|
|
57
|
+
|
|
58
|
+
// Each shared specifier → named exports the shim re-exports from
|
|
59
|
+
// window.__RB_SHARED__[specifier] (set by the host, e.g. nexus/src/pluginShared).
|
|
60
|
+
// A built plugin imports these as bare externals; the host page's import map
|
|
61
|
+
// (below) points them at these shims → the host's single instance.
|
|
62
|
+
//
|
|
63
|
+
// `names`: hardcoded list (small, stable modules).
|
|
64
|
+
// `parseNamesFrom`: a require()-resolvable specifier whose SOURCE text we
|
|
65
|
+
// parse for `export { ... }` names — used for react.tsx, which fully
|
|
66
|
+
// re-exports the rb-components barrel (100+ names) and would drift if
|
|
67
|
+
// hardcoded here. We parse the source text rather than importing/executing
|
|
68
|
+
// the module: the barrel is a .ts source file, unresolvable/unexecutable by
|
|
69
|
+
// plain Node (no loader), and even importing our OWN compiled dist/react.js
|
|
70
|
+
// would still transitively hit that same unexecutable .ts re-export.
|
|
71
|
+
const SHARED_MODULES: Record<
|
|
72
|
+
string,
|
|
73
|
+
{
|
|
74
|
+
file: string;
|
|
75
|
+
names?: string[];
|
|
76
|
+
parseNamesFrom?: { specifier: string; extraNames?: string[] };
|
|
77
|
+
hasDefault?: boolean;
|
|
78
|
+
}
|
|
79
|
+
> = {
|
|
80
|
+
react: {
|
|
81
|
+
file: "react",
|
|
82
|
+
hasDefault: true,
|
|
83
|
+
names: [
|
|
84
|
+
"Children", "Component", "Fragment", "Profiler", "PureComponent",
|
|
85
|
+
"StrictMode", "Suspense", "cloneElement", "createContext",
|
|
86
|
+
"createElement", "createRef", "forwardRef", "isValidElement", "lazy",
|
|
87
|
+
"memo", "startTransition", "useCallback", "useContext", "useDebugValue",
|
|
88
|
+
"useDeferredValue", "useEffect", "useId", "useImperativeHandle",
|
|
89
|
+
"useInsertionEffect", "useLayoutEffect", "useMemo", "useReducer",
|
|
90
|
+
"useRef", "useState", "useSyncExternalStore", "useTransition", "version",
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
"react/jsx-runtime": {
|
|
94
|
+
file: "react_jsx-runtime",
|
|
95
|
+
names: ["Fragment", "jsx", "jsxs"],
|
|
96
|
+
},
|
|
97
|
+
"react/jsx-dev-runtime": {
|
|
98
|
+
file: "react_jsx-dev-runtime",
|
|
99
|
+
names: ["Fragment", "jsxDEV"],
|
|
100
|
+
},
|
|
101
|
+
"react-dom": {
|
|
102
|
+
file: "react-dom",
|
|
103
|
+
hasDefault: true,
|
|
104
|
+
names: [
|
|
105
|
+
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
|
|
106
|
+
"createPortal",
|
|
107
|
+
"createRoot",
|
|
108
|
+
"findDOMNode",
|
|
109
|
+
"flushSync",
|
|
110
|
+
"hydrate",
|
|
111
|
+
"hydrateRoot",
|
|
112
|
+
"render",
|
|
113
|
+
"unmountComponentAtNode",
|
|
114
|
+
"unstable_batchedUpdates",
|
|
115
|
+
"unstable_renderSubtreeIntoContainer",
|
|
116
|
+
"version",
|
|
117
|
+
],
|
|
118
|
+
},
|
|
119
|
+
"react-dom/client": {
|
|
120
|
+
file: "react-dom_client",
|
|
121
|
+
names: ["createRoot", "hydrateRoot"],
|
|
122
|
+
},
|
|
123
|
+
"@rainbow-robotics/plugin-ui/react": {
|
|
124
|
+
file: "plugin-ui_react",
|
|
125
|
+
// react.tsx re-exports the full rb-components barrel (export *) plus the sdk
|
|
126
|
+
// hooks.
|
|
127
|
+
parseNamesFrom: {
|
|
128
|
+
specifier: "@repo/rb-components/new_components",
|
|
129
|
+
extraNames: ["useRb", "useRbFormData", "useRbSave"],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
"@rainbow-robotics/plugin-ui/sdk": {
|
|
133
|
+
file: "plugin-ui_sdk",
|
|
134
|
+
names: ["RbContext", "useRb", "useRbFormData", "useRbSave"],
|
|
135
|
+
},
|
|
136
|
+
"@rainbow-robotics/plugin-ui/host-ui": {
|
|
137
|
+
file: "plugin-ui_host-ui",
|
|
138
|
+
names: [
|
|
139
|
+
"alert",
|
|
140
|
+
"confirm",
|
|
141
|
+
"getHostServices",
|
|
142
|
+
"prompt",
|
|
143
|
+
"setHostServices",
|
|
144
|
+
"toast",
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
"@rainbow-robotics/plugin-ui/ws": {
|
|
148
|
+
file: "plugin-ui_ws",
|
|
149
|
+
names: ["RbWs", "createLazyRbSdk"],
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Parses `export { a, b as c, ... }` value names out of a source file's text
|
|
154
|
+
// (skips `export type { ... }` blocks and individual `type X` entries within
|
|
155
|
+
// a mixed block — types don't exist as runtime module properties). Static
|
|
156
|
+
// text parsing, not module execution, so it works for .ts source files with
|
|
157
|
+
// no loader and has no ESM-resolution footguns.
|
|
158
|
+
function parseExportedValueNames(source: string): string[] {
|
|
159
|
+
const names = new Set<string>();
|
|
160
|
+
const blockRe = /export\s+(type\s+)?\{([^}]*)\}/g;
|
|
161
|
+
let match: RegExpExecArray | null;
|
|
162
|
+
while ((match = blockRe.exec(source))) {
|
|
163
|
+
if (match[1]) continue; // whole `export type { ... }` block
|
|
164
|
+
for (const rawEntry of match[2].split(",")) {
|
|
165
|
+
const entry = rawEntry.trim();
|
|
166
|
+
if (!entry || entry.startsWith("type ")) continue;
|
|
167
|
+
const asMatch = entry.match(/^\S+\s+as\s+(\S+)$/);
|
|
168
|
+
names.add(asMatch ? asMatch[1] : entry);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return [...names];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const nameCache = new Map<string, string[]>();
|
|
175
|
+
|
|
176
|
+
function resolveNames(spec: string): string[] {
|
|
177
|
+
const mod = SHARED_MODULES[spec];
|
|
178
|
+
if (mod.names) return mod.names;
|
|
179
|
+
if (!mod.parseNamesFrom) {
|
|
180
|
+
throw new Error(`[plugin-ui] ${spec} has neither "names" nor "parseNamesFrom"`);
|
|
181
|
+
}
|
|
182
|
+
if (!nameCache.has(spec)) {
|
|
183
|
+
const { specifier, extraNames = [] } = mod.parseNamesFrom;
|
|
184
|
+
const sourcePath = require.resolve(specifier);
|
|
185
|
+
const parsed = parseExportedValueNames(readFileSync(sourcePath, "utf8"));
|
|
186
|
+
nameCache.set(spec, [...new Set([...parsed, ...extraNames])]);
|
|
187
|
+
}
|
|
188
|
+
return nameCache.get(spec)!;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function shimSource(spec: string): string {
|
|
192
|
+
const mod = SHARED_MODULES[spec];
|
|
193
|
+
const names = resolveNames(spec);
|
|
194
|
+
const g = `(globalThis.__RB_SHARED__||{})[${JSON.stringify(spec)}]`;
|
|
195
|
+
return (
|
|
196
|
+
`const m = ${g};\n` +
|
|
197
|
+
`if (!m) throw new Error("[plugin-ui] host shared module not registered: ${spec}");\n` +
|
|
198
|
+
`export const { ${names.join(", ")} } = m;\n` +
|
|
199
|
+
(mod.hasDefault ? `export default (m.default ?? m);\n` : "")
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const fileToSpec = Object.fromEntries(
|
|
204
|
+
Object.entries(SHARED_MODULES).map(([spec, { file }]) => [file, spec]),
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
function importMapScript(): string {
|
|
208
|
+
const imports: Record<string, string> = {};
|
|
209
|
+
for (const [spec, { file }] of Object.entries(SHARED_MODULES)) {
|
|
210
|
+
imports[spec] = `${SHARED_BASE}/${file}.js`;
|
|
211
|
+
}
|
|
212
|
+
return `<script type="importmap">${JSON.stringify({ imports })}</script>`;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Serves the shared-runtime shim modules at /plugin-shared/*.js and injects the
|
|
217
|
+
* import map so a dynamically-imported plugin's bare `import "react"` /
|
|
218
|
+
* `import "@rainbow-robotics/plugin-ui/react"` etc. resolve to the host's OWN
|
|
219
|
+
* instances (via window.__RB_SHARED__). Applied in all modes — any nexus build
|
|
220
|
+
* that can host plugins needs it.
|
|
221
|
+
*/
|
|
222
|
+
export const pluginSharedRuntimePlugin = (): Plugin => ({
|
|
223
|
+
name: "plugin-ui-shared-runtime",
|
|
224
|
+
transformIndexHtml(html) {
|
|
225
|
+
return html.replace("</head>", ` ${importMapScript()}\n </head>`);
|
|
226
|
+
},
|
|
227
|
+
configureServer(server) {
|
|
228
|
+
server.middlewares.use((req, res, next) => {
|
|
229
|
+
const url = req.url?.split("?")[0];
|
|
230
|
+
if (!url?.startsWith(`${SHARED_BASE}/`)) return next();
|
|
231
|
+
const file = url.slice(`${SHARED_BASE}/`.length).replace(/\.js$/, "");
|
|
232
|
+
const spec = fileToSpec[file];
|
|
233
|
+
if (!spec) return next();
|
|
234
|
+
res.setHeader("Content-Type", "text/javascript; charset=utf-8");
|
|
235
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
236
|
+
res.end(shimSource(spec));
|
|
237
|
+
});
|
|
238
|
+
},
|
|
239
|
+
generateBundle() {
|
|
240
|
+
for (const [spec, { file }] of Object.entries(SHARED_MODULES)) {
|
|
241
|
+
this.emitFile({
|
|
242
|
+
type: "asset",
|
|
243
|
+
fileName: `plugin-shared/${file}.js`,
|
|
244
|
+
source: shimSource(spec),
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
/** Inject the preview-host runtime flags into index.html (plugin-preview only). */
|
|
251
|
+
export const pluginPreviewRuntimePlugin = (): Plugin => ({
|
|
252
|
+
name: "plugin-ui-preview-runtime",
|
|
253
|
+
apply: (_config, { mode }) => isPluginPreviewMode(mode),
|
|
254
|
+
transformIndexHtml(html) {
|
|
255
|
+
return html.replace(
|
|
256
|
+
"</head>",
|
|
257
|
+
[
|
|
258
|
+
" <script>",
|
|
259
|
+
" window.__RB_PLUGIN_PREVIEW_HOST__ = true;",
|
|
260
|
+
" window.__RB_ASSETS_BASE_URL__ = window.location.origin;",
|
|
261
|
+
" </script>",
|
|
262
|
+
" </head>",
|
|
263
|
+
].join("\n"),
|
|
264
|
+
);
|
|
265
|
+
},
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
/** Serve the host's static assets (imgs/fonts/...) in plugin-preview dev mode. */
|
|
269
|
+
export const pluginPreviewAssetsPlugin = (opts: {
|
|
270
|
+
assetsDir: string;
|
|
271
|
+
prefixes?: string[];
|
|
272
|
+
}): Plugin => {
|
|
273
|
+
const { assetsDir, prefixes = defaultPreviewAssetPrefixes } = opts;
|
|
274
|
+
return {
|
|
275
|
+
name: "plugin-ui-preview-assets",
|
|
276
|
+
apply: (_config, { command, mode }) =>
|
|
277
|
+
command === "serve" && isPluginPreviewMode(mode),
|
|
278
|
+
configureServer(server) {
|
|
279
|
+
server.middlewares.use((req, res, next) => {
|
|
280
|
+
const url = req.url?.split("?")[0];
|
|
281
|
+
if (!url || !prefixes.some((prefix) => url.startsWith(prefix)))
|
|
282
|
+
return next();
|
|
283
|
+
|
|
284
|
+
const decodedUrl = decodeURIComponent(url);
|
|
285
|
+
const filePath = resolve(assetsDir, `.${decodedUrl}`);
|
|
286
|
+
if (!filePath.startsWith(assetsDir)) return next();
|
|
287
|
+
if (!existsSync(filePath) || !statSync(filePath).isFile()) return next();
|
|
288
|
+
|
|
289
|
+
const contentType = contentTypeByExt[extname(filePath)];
|
|
290
|
+
if (contentType) res.setHeader("Content-Type", contentType);
|
|
291
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
292
|
+
createReadStream(filePath).pipe(res);
|
|
293
|
+
});
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* All host-side plugin-ui Vite plugins in one call. Each self-gates by mode, so
|
|
300
|
+
* a host just spreads this into its `plugins` array.
|
|
301
|
+
*
|
|
302
|
+
* plugins: [muscatVitePlugin({ previewAssetsDir: resolve(here, "../assets/public") })]
|
|
303
|
+
*/
|
|
304
|
+
export const muscatVitePlugin = (opts: {
|
|
305
|
+
/** Host static assets dir served in plugin-preview dev mode. */
|
|
306
|
+
previewAssetsDir: string;
|
|
307
|
+
/** Override preview asset URL prefixes. */
|
|
308
|
+
previewAssetPrefixes?: string[];
|
|
309
|
+
}): Plugin[] => [
|
|
310
|
+
pluginSharedRuntimePlugin(),
|
|
311
|
+
pluginPreviewRuntimePlugin(),
|
|
312
|
+
pluginPreviewAssetsPlugin({
|
|
313
|
+
assetsDir: opts.previewAssetsDir,
|
|
314
|
+
prefixes: opts.previewAssetPrefixes,
|
|
315
|
+
}),
|
|
316
|
+
];
|
package/src/ws.ts
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* server emits : msg, serve_call
|
|
11
11
|
*/
|
|
12
12
|
import { io, type Socket } from "socket.io-client";
|
|
13
|
+
// Type-only — no runtime coupling to host-ui.ts.
|
|
14
|
+
import type { PluginUIServices } from "./host-ui";
|
|
13
15
|
|
|
14
16
|
export interface WsHandle {
|
|
15
17
|
undeclare(): void;
|
|
@@ -154,3 +156,48 @@ export class RbWs {
|
|
|
154
156
|
this._socket.disconnect();
|
|
155
157
|
}
|
|
156
158
|
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Builds an rb-sdk-shaped object (pub/sub/action/serve + the passed-through
|
|
162
|
+
* toast/alert/confirm/prompt) that lazily awaits a not-yet-connected `RbWs` —
|
|
163
|
+
* so callers don't block their first render on the WebSocket handshake (there
|
|
164
|
+
* may be no backend reachable yet). Shared by both host mount paths (see
|
|
165
|
+
* ./host.tsx and muscat-plugin-kit's dev bootstrap), which otherwise
|
|
166
|
+
* duplicate this wiring.
|
|
167
|
+
*/
|
|
168
|
+
export function createLazyRbSdk(
|
|
169
|
+
wsPromise: Promise<RbWs>,
|
|
170
|
+
services: PluginUIServices,
|
|
171
|
+
// Per-mount, host-provided (unlike `services`, which is a global singleton):
|
|
172
|
+
// initial `data` and the `onSave` registration the host reads back. Plain
|
|
173
|
+
// values/closures, so they cross the dev React-instance boundary safely.
|
|
174
|
+
mount?: {
|
|
175
|
+
data?: unknown;
|
|
176
|
+
onSave?: (getPayload: () => unknown) => () => void;
|
|
177
|
+
},
|
|
178
|
+
) {
|
|
179
|
+
return {
|
|
180
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
181
|
+
pub: async (topic: string, payload: any) =>
|
|
182
|
+
(await wsPromise).pub(topic, payload),
|
|
183
|
+
sub: async (
|
|
184
|
+
topic: string,
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
186
|
+
handler: (payload: any) => void,
|
|
187
|
+
) => (await wsPromise).sub(topic, handler),
|
|
188
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
189
|
+
action: async (topic: string, payload?: any) =>
|
|
190
|
+
(await wsPromise).action(topic, payload),
|
|
191
|
+
serve: async (
|
|
192
|
+
topic: string,
|
|
193
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
194
|
+
handler: (payload?: any) => any,
|
|
195
|
+
) => (await wsPromise).serve(topic, handler),
|
|
196
|
+
toast: services.toast,
|
|
197
|
+
alert: services.alert,
|
|
198
|
+
confirm: services.confirm,
|
|
199
|
+
prompt: services.prompt,
|
|
200
|
+
data: mount?.data,
|
|
201
|
+
onSave: mount?.onSave ?? (() => () => {}),
|
|
202
|
+
};
|
|
203
|
+
}
|
package/build-browser.mjs
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// Builds @rainbow-robotics/plugin-ui as browser ESM for the sandbox import map.
|
|
2
|
-
// Output: dist-browser/@rainbow-robotics/plugin-ui/{connect,react,sdk,elements}.js
|
|
3
|
-
// dist-browser/vendor/react-runtime.js
|
|
4
|
-
//
|
|
5
|
-
// Consumed by:
|
|
6
|
-
// - nexus (vite plugin emits dist-browser/ → dist/plugin-runtime/)
|
|
7
|
-
// - preview-host (serves dist-browser/ at /plugin-runtime/)
|
|
8
|
-
//
|
|
9
|
-
// Run: node libraries/plugin-ui/build-browser.mjs
|
|
10
|
-
import { build } from "esbuild";
|
|
11
|
-
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
12
|
-
import { dirname, resolve } from "node:path";
|
|
13
|
-
import { fileURLToPath } from "node:url";
|
|
14
|
-
|
|
15
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
16
|
-
const src = resolve(here, "src");
|
|
17
|
-
const out = resolve(here, "dist-browser");
|
|
18
|
-
const repoRoot = resolve(here, "../..");
|
|
19
|
-
|
|
20
|
-
const define = { "process.env.NODE_ENV": JSON.stringify("production") };
|
|
21
|
-
const shared = {
|
|
22
|
-
bundle: true,
|
|
23
|
-
format: "esm",
|
|
24
|
-
platform: "browser",
|
|
25
|
-
target: "es2020",
|
|
26
|
-
minify: true,
|
|
27
|
-
sourcemap: false,
|
|
28
|
-
define,
|
|
29
|
-
logLevel: "warning",
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
rmSync(out, { recursive: true, force: true });
|
|
33
|
-
mkdirSync(resolve(out, "@rainbow-robotics/plugin-ui"), { recursive: true });
|
|
34
|
-
mkdirSync(resolve(out, "vendor"), { recursive: true });
|
|
35
|
-
|
|
36
|
-
// Plugin-UI entry points (react / react-dom provided by vendor bundle below)
|
|
37
|
-
await build({
|
|
38
|
-
...shared,
|
|
39
|
-
entryPoints: {
|
|
40
|
-
connect: resolve(src, "connect.ts"),
|
|
41
|
-
react: resolve(src, "react.tsx"),
|
|
42
|
-
sdk: resolve(src, "sdk.ts"),
|
|
43
|
-
elements: resolve(src, "elements.ts"),
|
|
44
|
-
},
|
|
45
|
-
outdir: resolve(out, "@rainbow-robotics/plugin-ui"),
|
|
46
|
-
entryNames: "[name]",
|
|
47
|
-
chunkNames: "chunks/[name]-[hash]",
|
|
48
|
-
splitting: true,
|
|
49
|
-
external: ["react", "react-dom/client"],
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
// Single vendor bundle: React + ReactDOM (sandbox loads this once via import map)
|
|
53
|
-
const reactShim = `
|
|
54
|
-
import React from "react";
|
|
55
|
-
import * as ReactClient from "react-dom/client";
|
|
56
|
-
import * as JsxRuntime from "react/jsx-runtime";
|
|
57
|
-
import * as JsxDevRuntime from "react/jsx-dev-runtime";
|
|
58
|
-
export default React;
|
|
59
|
-
export const { Children, Fragment, Profiler, StrictMode, Suspense,
|
|
60
|
-
cloneElement, createContext, createElement, createRef, forwardRef,
|
|
61
|
-
isValidElement, lazy, memo, startTransition, useCallback, useContext,
|
|
62
|
-
useDebugValue, useDeferredValue, useEffect, useId, useImperativeHandle,
|
|
63
|
-
useInsertionEffect, useLayoutEffect, useMemo, useReducer, useRef,
|
|
64
|
-
useState, useSyncExternalStore, useTransition, version } = React;
|
|
65
|
-
export const { createRoot, hydrateRoot } = ReactClient;
|
|
66
|
-
export const { jsx, jsxs } = JsxRuntime;
|
|
67
|
-
export const { jsxDEV } = JsxDevRuntime;
|
|
68
|
-
`;
|
|
69
|
-
|
|
70
|
-
await build({
|
|
71
|
-
...shared,
|
|
72
|
-
stdin: { contents: reactShim, resolveDir: repoRoot, loader: "js" },
|
|
73
|
-
outfile: resolve(out, "vendor", "react-runtime.js"),
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Aliases so all standard React specifiers map to the single vendor file
|
|
77
|
-
for (const name of ["react", "react-jsx-runtime", "react-jsx-dev-runtime", "react-dom-client"]) {
|
|
78
|
-
writeFileSync(
|
|
79
|
-
resolve(out, "vendor", `${name}.js`),
|
|
80
|
-
'export * from "./react-runtime.js"; export { default } from "./react-runtime.js";\n',
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
console.log("[plugin-ui] dist-browser ready →", out);
|
package/dist/connect.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { type ComponentType } from "react";
|
|
2
|
-
/**
|
|
3
|
-
* Mount a plugin. Call this once from the sandbox entry (content.tsx).
|
|
4
|
-
*
|
|
5
|
-
* @example
|
|
6
|
-
* import { connect } from "@rainbow-robotics/plugin-ui/connect";
|
|
7
|
-
* import App from "./App";
|
|
8
|
-
* connect(App);
|
|
9
|
-
*/
|
|
10
|
-
export declare function connect(App: ComponentType): void;
|
|
11
|
-
//# sourceMappingURL=connect.d.ts.map
|
package/dist/connect.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AAUA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAe1D;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA8BhD"}
|
package/dist/connect.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { RemoteMutationObserver } from "@remote-dom/core/elements";
|
|
2
|
-
import { ThreadWindow } from "@quilted/threads";
|
|
3
|
-
import { createElement } from "react";
|
|
4
|
-
import { createRoot } from "react-dom/client";
|
|
5
|
-
import { defineElements } from "./elements";
|
|
6
|
-
import { RbContext } from "./sdk";
|
|
7
|
-
import { RbWs } from "./ws";
|
|
8
|
-
function connect(App) {
|
|
9
|
-
defineElements();
|
|
10
|
-
const host = ThreadWindow.parent.import({
|
|
11
|
-
targetOrigin: "*"
|
|
12
|
-
});
|
|
13
|
-
void host.connect().then(async ({ connection, toast, socketUrl, pluginId }) => {
|
|
14
|
-
const ws = await RbWs.connect(socketUrl, pluginId);
|
|
15
|
-
const rb = {
|
|
16
|
-
pub: (topic, payload) => ws.pub(topic, payload),
|
|
17
|
-
sub: (topic, handler) => ws.sub(topic, handler),
|
|
18
|
-
action: (topic, payload) => ws.action(topic, payload),
|
|
19
|
-
serve: (topic, handler) => ws.serve(topic, handler),
|
|
20
|
-
toast: (message, type) => toast(message, type)
|
|
21
|
-
};
|
|
22
|
-
const root = document.createElement("remote-root");
|
|
23
|
-
document.body.append(root);
|
|
24
|
-
const observer = new RemoteMutationObserver(connection);
|
|
25
|
-
observer.observe(root);
|
|
26
|
-
createRoot(root).render(
|
|
27
|
-
createElement(RbContext.Provider, { value: rb }, createElement(App))
|
|
28
|
-
);
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
export {
|
|
32
|
-
connect
|
|
33
|
-
};
|
|
34
|
-
//# sourceMappingURL=connect.js.map
|
package/dist/connect.js.map
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/connect.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Sandbox bootstrap \u2014 runs *inside* the plugin iframe.\n *\n * The sandbox initiates the handshake: imports the host's `connect()` and calls\n * it. The host responds with the RemoteConnection, toast(), and Socket.IO config\n * (socketUrl + pluginId). We open a Socket.IO connection and wire up the rb object.\n */\nimport { RemoteMutationObserver } from \"@remote-dom/core/elements\";\nimport type { RemoteConnection } from \"@remote-dom/core\";\nimport { ThreadWindow } from \"@quilted/threads\";\nimport { createElement, type ComponentType } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { defineElements } from \"./elements\";\nimport { RbContext, type RbSdk } from \"./sdk\";\nimport { RbWs } from \"./ws\";\n\ninterface HostExports {\n connect: () => Promise<{\n connection: RemoteConnection;\n toast: (message: string, type?: string) => void;\n socketUrl: string;\n pluginId: string;\n }>;\n}\n\n/**\n * Mount a plugin. Call this once from the sandbox entry (content.tsx).\n *\n * @example\n * import { connect } from \"@rainbow-robotics/plugin-ui/connect\";\n * import App from \"./App\";\n * connect(App);\n */\nexport function connect(App: ComponentType): void {\n defineElements();\n\n const host = ThreadWindow.parent.import<HostExports>({\n targetOrigin: \"*\",\n });\n\n void host\n .connect()\n .then(async ({ connection, toast, socketUrl, pluginId }) => {\n const ws = await RbWs.connect(socketUrl, pluginId);\n\n const rb: RbSdk = {\n pub: (topic, payload) => ws.pub(topic, payload),\n sub: (topic, handler) => ws.sub(topic, handler),\n action: (topic, payload) => ws.action(topic, payload),\n serve: (topic, handler) => ws.serve(topic, handler),\n toast: (message, type) => toast(message, type),\n };\n\n const root = document.createElement(\"remote-root\");\n document.body.append(root);\n\n const observer = new RemoteMutationObserver(connection);\n observer.observe(root);\n\n createRoot(root).render(\n createElement(RbContext.Provider, { value: rb }, createElement(App)),\n );\n });\n}\n"],
|
|
5
|
-
"mappings": "AAOA,SAAS,8BAA8B;AAEvC,SAAS,oBAAoB;AAC7B,SAAS,qBAAyC;AAClD,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,iBAA6B;AACtC,SAAS,YAAY;AAmBd,SAAS,QAAQ,KAA0B;AAChD,iBAAe;AAEf,QAAM,OAAO,aAAa,OAAO,OAAoB;AAAA,IACnD,cAAc;AAAA,EAChB,CAAC;AAED,OAAK,KACF,QAAQ,EACR,KAAK,OAAO,EAAE,YAAY,OAAO,WAAW,SAAS,MAAM;AAC1D,UAAM,KAAK,MAAM,KAAK,QAAQ,WAAW,QAAQ;AAEjD,UAAM,KAAY;AAAA,MAChB,KAAK,CAAC,OAAO,YAAY,GAAG,IAAI,OAAO,OAAO;AAAA,MAC9C,KAAK,CAAC,OAAO,YAAY,GAAG,IAAI,OAAO,OAAO;AAAA,MAC9C,QAAQ,CAAC,OAAO,YAAY,GAAG,OAAO,OAAO,OAAO;AAAA,MACpD,OAAO,CAAC,OAAO,YAAY,GAAG,MAAM,OAAO,OAAO;AAAA,MAClD,OAAO,CAAC,SAAS,SAAS,MAAM,SAAS,IAAI;AAAA,IAC/C;AAEA,UAAM,OAAO,SAAS,cAAc,aAAa;AACjD,aAAS,KAAK,OAAO,IAAI;AAEzB,UAAM,WAAW,IAAI,uBAAuB,UAAU;AACtD,aAAS,QAAQ,IAAI;AAErB,eAAW,IAAI,EAAE;AAAA,MACf,cAAc,UAAU,UAAU,EAAE,OAAO,GAAG,GAAG,cAAc,GAAG,CAAC;AAAA,IACrE;AAAA,EACF,CAAC;AACL;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|