@rainbow-robotics/plugin-ui 0.1.2-dev.9 → 1.0.1
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 +3436 -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 +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 +53 -0
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +141 -0
- package/dist/ws.js.map +7 -0
- package/package.json +45 -21
- package/src/host-ui.ts +80 -0
- package/src/host.tsx +229 -308
- 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 +81 -13
- package/src/viteHost.ts +309 -0
- package/src/ws.ts +127 -20
- 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 -62
- package/src/elements.ts +0 -257
package/dist/react.js
CHANGED
|
@@ -1,57 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
RbSliderElement,
|
|
4
|
-
RbButtonElement,
|
|
5
|
-
RbIconButtonElement,
|
|
6
|
-
RbTextElement,
|
|
7
|
-
RbTextInputElement,
|
|
8
|
-
RbSwitchElement,
|
|
9
|
-
RbSelectElement
|
|
10
|
-
} from "./elements";
|
|
11
|
-
const events = (map) => ({ eventProps: map });
|
|
12
|
-
const Slider = createRemoteComponent(
|
|
13
|
-
"rb-slider",
|
|
14
|
-
RbSliderElement,
|
|
15
|
-
events({ onChange: { event: "change" } })
|
|
16
|
-
);
|
|
17
|
-
const Button = createRemoteComponent(
|
|
18
|
-
"rb-button",
|
|
19
|
-
RbButtonElement,
|
|
20
|
-
events({ onPress: { event: "press" } })
|
|
21
|
-
);
|
|
22
|
-
const IconButton = createRemoteComponent(
|
|
23
|
-
"rb-icon-button",
|
|
24
|
-
RbIconButtonElement,
|
|
25
|
-
events({ onPress: { event: "press" } })
|
|
26
|
-
);
|
|
27
|
-
const Text = createRemoteComponent(
|
|
28
|
-
"rb-text",
|
|
29
|
-
RbTextElement
|
|
30
|
-
);
|
|
31
|
-
const TextInput = createRemoteComponent(
|
|
32
|
-
"rb-text-input",
|
|
33
|
-
RbTextInputElement,
|
|
34
|
-
events({ onInput: { event: "input" } })
|
|
35
|
-
);
|
|
36
|
-
const Switch = createRemoteComponent(
|
|
37
|
-
"rb-switch",
|
|
38
|
-
RbSwitchElement,
|
|
39
|
-
events({ onChange: { event: "change" } })
|
|
40
|
-
);
|
|
41
|
-
const Select = createRemoteComponent(
|
|
42
|
-
"rb-select",
|
|
43
|
-
RbSelectElement,
|
|
44
|
-
events({ onChange: { event: "change" } })
|
|
45
|
-
);
|
|
46
|
-
import { useRb } from "./sdk";
|
|
1
|
+
export * from "@repo/rb-components/new_components";
|
|
2
|
+
import { useRb, useRbFormData, useRbSave } from "./sdk.js";
|
|
47
3
|
export {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
Slider,
|
|
52
|
-
Switch,
|
|
53
|
-
Text,
|
|
54
|
-
TextInput,
|
|
55
|
-
useRb
|
|
4
|
+
useRb,
|
|
5
|
+
useRbFormData,
|
|
6
|
+
useRbSave
|
|
56
7
|
};
|
|
57
8
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/react.tsx"],
|
|
4
|
-
"sourcesContent": ["/**\n * Author
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/**\n * Author component surface \u2014 re-exports the @repo/rb-components new_components\n * barrel, plus the sdk hooks.\n *\n * import { RBSlider, RBLabelButton, useRb } from \"@rainbow-robotics/plugin-ui/react\";\n *\n * The runtime import-map shim (./viteHost.ts) reads this module's exports\n * rather than a hardcoded list, so the two stay in sync.\n */\nexport * from \"@repo/rb-components/new_components\";\n\nexport { useRb, useRbFormData, useRbSave } from \"./sdk.js\";\nexport type { RbSdk } from \"./sdk\";\n"],
|
|
5
|
+
"mappings": "AASA,cAAc;AAEd,SAAS,OAAO,eAAe,iBAAiB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/sdk.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { WsSubscriber as Subscriber, WsQueryable as Queryable } from "./ws";
|
|
2
|
+
import type { PluginUIServices } from "./host-ui";
|
|
2
3
|
export type RbNotifyType = "info" | "success" | "warning" | "error";
|
|
3
4
|
export interface RbSdk {
|
|
4
5
|
/**
|
|
5
6
|
* Publish JSON payload to a topic.
|
|
6
|
-
* "sensor/data" →
|
|
7
|
+
* "sensor/data" → {pluginId}/sensor/data
|
|
7
8
|
* "/broadcast/x" → broadcast/x (absolute)
|
|
8
9
|
*/
|
|
9
10
|
pub: <P = any>(topic: string, payload: P) => Promise<void>;
|
|
@@ -20,9 +21,44 @@ export interface RbSdk {
|
|
|
20
21
|
*/
|
|
21
22
|
serve: <P = any, R = any>(topic: string, handler: (payload?: P) => R | Promise<R>) => Promise<Queryable>;
|
|
22
23
|
/** Show a transient notification through the host's toast system. */
|
|
23
|
-
toast:
|
|
24
|
+
toast: PluginUIServices["toast"];
|
|
25
|
+
/** Show a host alert dialog. */
|
|
26
|
+
alert: PluginUIServices["alert"];
|
|
27
|
+
/** Show a host confirm dialog. Resolves true/false. */
|
|
28
|
+
confirm: PluginUIServices["confirm"];
|
|
29
|
+
/** Show a host prompt dialog. Resolves the entered value, or undefined if cancelled. */
|
|
30
|
+
prompt: PluginUIServices["prompt"];
|
|
31
|
+
/**
|
|
32
|
+
* Host-provided initial data for this mount — e.g. the previously-saved
|
|
33
|
+
* values when the host re-opens a form. `undefined` for a fresh mount.
|
|
34
|
+
* Prefer the `useRbFormData()` hook over reading this directly.
|
|
35
|
+
*/
|
|
36
|
+
data?: unknown;
|
|
37
|
+
/**
|
|
38
|
+
* Register a getter the host calls (synchronously) to collect this plugin's
|
|
39
|
+
* save payload — e.g. when the host's Save button is clicked. The returned
|
|
40
|
+
* value must be JSON-serialisable (the host persists it). Returns an
|
|
41
|
+
* unregister fn. Prefer the `useRbSave()` hook.
|
|
42
|
+
*/
|
|
43
|
+
onSave: (getPayload: () => unknown) => () => void;
|
|
24
44
|
}
|
|
25
45
|
export declare const RbContext: import("react").Context<RbSdk>;
|
|
26
46
|
/** Access the host SDK from within a plugin component. */
|
|
27
47
|
export declare function useRb(): RbSdk;
|
|
48
|
+
/**
|
|
49
|
+
* Read the host-provided initial data for this mount (e.g. previously-saved
|
|
50
|
+
* form values). `undefined` for a fresh mount.
|
|
51
|
+
*
|
|
52
|
+
* const saved = useRbFormData<MyArgs>();
|
|
53
|
+
* const methods = useForm({ defaultValues: saved ?? DEFAULTS });
|
|
54
|
+
*/
|
|
55
|
+
export declare function useRbFormData<T = unknown>(): T | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Register a getter the host calls to collect this plugin's save payload when
|
|
58
|
+
* the host's Save is clicked. The latest `getPayload` is always used, so it can
|
|
59
|
+
* close over current state. The returned value must be JSON-serialisable.
|
|
60
|
+
*
|
|
61
|
+
* useRbSave(() => ({ args: getValues(), summary: buildSummary() }));
|
|
62
|
+
*/
|
|
63
|
+
export declare function useRbSave<T = unknown>(getPayload: () => T): void;
|
|
28
64
|
//# sourceMappingURL=sdk.d.ts.map
|
package/dist/sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,YAAY,IAAI,UAAU,EAC1B,WAAW,IAAI,SAAS,EACzB,MAAM,MAAM,CAAC;AAGd,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpE,MAAM,WAAW,KAAK;IACpB;;;;OAIG;IACH,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3D,+DAA+D;IAC/D,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EACX,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,KAC1B,OAAO,CAAC,UAAU,CAAC,CAAC;IAEzB;;;OAGG;IACH,MAAM,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IAErE;;;OAGG;IACH,KAAK,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EACtB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,KACrC,OAAO,CAAC,SAAS,CAAC,CAAC;IAExB,qEAAqE;IACrE,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAEjC,gCAAgC;IAChC,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACjC,uDAAuD;IACvD,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACrC,wFAAwF;IACxF,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAEnC;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;;OAKG;IACH,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,OAAO,KAAK,MAAM,IAAI,CAAC;CACnD;AAuCD,eAAO,MAAM,SAAS,gCAAgC,CAAC;AAEvD,0DAA0D;AAC1D,wBAAgB,KAAK,IAAI,KAAK,CAE7B;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,GAAG,SAAS,CAE1D;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,GAAG,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,GAAG,IAAI,CAKhE"}
|
package/dist/sdk.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useContext } from "react";
|
|
1
|
+
import { createContext, useContext, useEffect, useRef } from "react";
|
|
2
2
|
const noopSdk = {
|
|
3
3
|
pub: async (_topic, _payload) => {
|
|
4
4
|
console.warn("[plugin-ui] rb.pub called outside of a host context");
|
|
@@ -17,16 +17,41 @@ const noopSdk = {
|
|
|
17
17
|
return { undeclare: async () => {
|
|
18
18
|
} };
|
|
19
19
|
},
|
|
20
|
-
toast: (
|
|
21
|
-
console.warn("[plugin-ui] rb.toast (no host):",
|
|
20
|
+
toast: (params) => {
|
|
21
|
+
console.warn("[plugin-ui] rb.toast (no host):", params);
|
|
22
|
+
},
|
|
23
|
+
alert: async (_) => {
|
|
24
|
+
console.warn("[plugin-ui] rb.alert called outside of a host context");
|
|
25
|
+
},
|
|
26
|
+
confirm: async (_) => {
|
|
27
|
+
console.warn("[plugin-ui] rb.confirm called outside of a host context");
|
|
28
|
+
return false;
|
|
29
|
+
},
|
|
30
|
+
prompt: async (_) => {
|
|
31
|
+
console.warn("[plugin-ui] rb.prompt called outside of a host context");
|
|
32
|
+
return void 0;
|
|
33
|
+
},
|
|
34
|
+
data: void 0,
|
|
35
|
+
onSave: () => () => {
|
|
22
36
|
}
|
|
23
37
|
};
|
|
24
38
|
const RbContext = createContext(noopSdk);
|
|
25
39
|
function useRb() {
|
|
26
40
|
return useContext(RbContext);
|
|
27
41
|
}
|
|
42
|
+
function useRbFormData() {
|
|
43
|
+
return useRb().data;
|
|
44
|
+
}
|
|
45
|
+
function useRbSave(getPayload) {
|
|
46
|
+
const rb = useRb();
|
|
47
|
+
const ref = useRef(getPayload);
|
|
48
|
+
ref.current = getPayload;
|
|
49
|
+
useEffect(() => rb.onSave(() => ref.current()), [rb]);
|
|
50
|
+
}
|
|
28
51
|
export {
|
|
29
52
|
RbContext,
|
|
30
|
-
useRb
|
|
53
|
+
useRb,
|
|
54
|
+
useRbFormData,
|
|
55
|
+
useRbSave
|
|
31
56
|
};
|
|
32
57
|
//# sourceMappingURL=sdk.js.map
|
package/dist/sdk.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/sdk.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * Plugin runtime SDK
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\n/**\n * Plugin runtime SDK (`useRb()`).\n *\n * pub/sub/action/serve talk to the Zenoh router over WebSocket. Topics are\n * namespaced to {pluginId}/... ; a leading \"/\" makes the path absolute.\n * alert/confirm/prompt/toast delegate to the host.\n */\nimport { createContext, useContext, useEffect, useRef } from \"react\";\nimport type {\n WsSubscriber as Subscriber,\n WsQueryable as Queryable,\n} from \"./ws\";\n// Type-only import \u2014 no runtime coupling to host-ui.ts (which itself has no\n// dependency back on sdk.ts, so this stays one-directional).\nimport type { PluginUIServices } from \"./host-ui\";\n\nexport type RbNotifyType = \"info\" | \"success\" | \"warning\" | \"error\";\n\nexport interface RbSdk {\n /**\n * Publish JSON payload to a topic.\n * \"sensor/data\" \u2192 {pluginId}/sensor/data\n * \"/broadcast/x\" \u2192 broadcast/x (absolute)\n */\n pub: <P = any>(topic: string, payload: P) => Promise<void>;\n\n /** Subscribe to a topic. Returns a handle with undeclare(). */\n sub: <P = any>(\n topic: string,\n handler: (payload: P) => void,\n ) => Promise<Subscriber>;\n\n /**\n * Send a request and await the first reply (Zenoh query).\n * Use this to call a backend handler registered with rb.serve() / ZenohRouter.\n */\n action: <R = any, P = any>(topic: string, payload?: P) => Promise<R>;\n\n /**\n * Register a queryable \u2014 the frontend responds to backend queries.\n * Mirror of rb.action() on the other side.\n */\n serve: <P = any, R = any>(\n topic: string,\n handler: (payload?: P) => R | Promise<R>,\n ) => Promise<Queryable>;\n\n /** Show a transient notification through the host's toast system. */\n toast: PluginUIServices[\"toast\"];\n\n /** Show a host alert dialog. */\n alert: PluginUIServices[\"alert\"];\n /** Show a host confirm dialog. Resolves true/false. */\n confirm: PluginUIServices[\"confirm\"];\n /** Show a host prompt dialog. Resolves the entered value, or undefined if cancelled. */\n prompt: PluginUIServices[\"prompt\"];\n\n /**\n * Host-provided initial data for this mount \u2014 e.g. the previously-saved\n * values when the host re-opens a form. `undefined` for a fresh mount.\n * Prefer the `useRbFormData()` hook over reading this directly.\n */\n data?: unknown;\n\n /**\n * Register a getter the host calls (synchronously) to collect this plugin's\n * save payload \u2014 e.g. when the host's Save button is clicked. The returned\n * value must be JSON-serialisable (the host persists it). Returns an\n * unregister fn. Prefer the `useRbSave()` hook.\n */\n onSave: (getPayload: () => unknown) => () => void;\n}\n\nconst noopSdk: RbSdk = {\n pub: async <P = any>(_topic?: string, _payload?: P) => {\n console.warn(\"[plugin-ui] rb.pub called outside of a host context\");\n },\n sub: async <P = any>(_topic?: string, _handler?: (payload: P) => void) => {\n console.warn(\"[plugin-ui] rb.sub called outside of a host context\");\n return { undeclare: async () => {} } as unknown as Subscriber;\n },\n action: async <R = any, P = any>(_topic?: string, _payload?: P) => {\n console.warn(\"[plugin-ui] rb.action called outside of a host context\");\n return undefined as R;\n },\n serve: async <P = any, R = any>(\n _topic?: string,\n _handler?: (payload?: P) => R,\n ) => {\n console.warn(\"[plugin-ui] rb.serve called outside of a host context\");\n return { undeclare: async () => {} } as unknown as Queryable;\n },\n toast: (params) => {\n console.warn(\"[plugin-ui] rb.toast (no host):\", params);\n },\n alert: async (_) => {\n console.warn(\"[plugin-ui] rb.alert called outside of a host context\");\n },\n confirm: async (_) => {\n console.warn(\"[plugin-ui] rb.confirm called outside of a host context\");\n return false;\n },\n prompt: async (_) => {\n console.warn(\"[plugin-ui] rb.prompt called outside of a host context\");\n return undefined;\n },\n data: undefined,\n onSave: () => () => {},\n};\n\nexport const RbContext = createContext<RbSdk>(noopSdk);\n\n/** Access the host SDK from within a plugin component. */\nexport function useRb(): RbSdk {\n return useContext(RbContext);\n}\n\n/**\n * Read the host-provided initial data for this mount (e.g. previously-saved\n * form values). `undefined` for a fresh mount.\n *\n * const saved = useRbFormData<MyArgs>();\n * const methods = useForm({ defaultValues: saved ?? DEFAULTS });\n */\nexport function useRbFormData<T = unknown>(): T | undefined {\n return useRb().data as T | undefined;\n}\n\n/**\n * Register a getter the host calls to collect this plugin's save payload when\n * the host's Save is clicked. The latest `getPayload` is always used, so it can\n * close over current state. The returned value must be JSON-serialisable.\n *\n * useRbSave(() => ({ args: getValues(), summary: buildSummary() }));\n */\nexport function useRbSave<T = unknown>(getPayload: () => T): void {\n const rb = useRb();\n const ref = useRef(getPayload);\n ref.current = getPayload;\n useEffect(() => rb.onSave(() => ref.current()), [rb]);\n}\n"],
|
|
5
|
+
"mappings": "AAQA,SAAS,eAAe,YAAY,WAAW,cAAc;AAkE7D,MAAM,UAAiB;AAAA,EACrB,KAAK,OAAgB,QAAiB,aAAiB;AACrD,YAAQ,KAAK,qDAAqD;AAAA,EACpE;AAAA,EACA,KAAK,OAAgB,QAAiB,aAAoC;AACxE,YAAQ,KAAK,qDAAqD;AAClE,WAAO,EAAE,WAAW,YAAY;AAAA,IAAC,EAAE;AAAA,EACrC;AAAA,EACA,QAAQ,OAAyB,QAAiB,aAAiB;AACjE,YAAQ,KAAK,wDAAwD;AACrE,WAAO;AAAA,EACT;AAAA,EACA,OAAO,OACL,QACA,aACG;AACH,YAAQ,KAAK,uDAAuD;AACpE,WAAO,EAAE,WAAW,YAAY;AAAA,IAAC,EAAE;AAAA,EACrC;AAAA,EACA,OAAO,CAAC,WAAW;AACjB,YAAQ,KAAK,mCAAmC,MAAM;AAAA,EACxD;AAAA,EACA,OAAO,OAAO,MAAM;AAClB,YAAQ,KAAK,uDAAuD;AAAA,EACtE;AAAA,EACA,SAAS,OAAO,MAAM;AACpB,YAAQ,KAAK,yDAAyD;AACtE,WAAO;AAAA,EACT;AAAA,EACA,QAAQ,OAAO,MAAM;AACnB,YAAQ,KAAK,wDAAwD;AACrE,WAAO;AAAA,EACT;AAAA,EACA,MAAM;AAAA,EACN,QAAQ,MAAM,MAAM;AAAA,EAAC;AACvB;AAEO,MAAM,YAAY,cAAqB,OAAO;AAG9C,SAAS,QAAe;AAC7B,SAAO,WAAW,SAAS;AAC7B;AASO,SAAS,gBAA4C;AAC1D,SAAO,MAAM,EAAE;AACjB;AASO,SAAS,UAAuB,YAA2B;AAChE,QAAM,KAAK,MAAM;AACjB,QAAM,MAAM,OAAO,UAAU;AAC7B,MAAI,UAAU;AACd,YAAU,MAAM,GAAG,OAAO,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;AACtD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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
|
+
* A built plugin's bare imports (react, rb-components, plugin-ui/*) resolve via
|
|
12
|
+
* the import map this file injects, to the host's already-loaded instances.
|
|
13
|
+
* See ./host.tsx.
|
|
14
|
+
*/
|
|
15
|
+
import type { Plugin } from "vite";
|
|
16
|
+
export declare const defaultPreviewAssetPrefixes: string[];
|
|
17
|
+
export declare const contentTypeByExt: Record<string, string>;
|
|
18
|
+
export declare const isPluginPreviewMode: (mode: string) => mode is "plugin-preview";
|
|
19
|
+
/**
|
|
20
|
+
* Serves the shared-runtime shim modules at /plugin-shared/*.js and injects the
|
|
21
|
+
* import map so a dynamically-imported plugin's bare `import "react"` /
|
|
22
|
+
* `import "@rainbow-robotics/plugin-ui/react"` etc. resolve to the host's OWN
|
|
23
|
+
* instances (via window.__RB_SHARED__). Applied in all modes — any nexus build
|
|
24
|
+
* that can host plugins needs it.
|
|
25
|
+
*/
|
|
26
|
+
export declare const pluginSharedRuntimePlugin: () => Plugin;
|
|
27
|
+
/** Inject the preview-host runtime flags into index.html (plugin-preview only). */
|
|
28
|
+
export declare const pluginPreviewRuntimePlugin: () => Plugin;
|
|
29
|
+
/** Serve the host's static assets (imgs/fonts/...) in plugin-preview dev mode. */
|
|
30
|
+
export declare const pluginPreviewAssetsPlugin: (opts: {
|
|
31
|
+
assetsDir: string;
|
|
32
|
+
prefixes?: string[];
|
|
33
|
+
}) => Plugin;
|
|
34
|
+
/**
|
|
35
|
+
* All host-side plugin-ui Vite plugins in one call. Each self-gates by mode, so
|
|
36
|
+
* a host just spreads this into its `plugins` array.
|
|
37
|
+
*
|
|
38
|
+
* plugins: [muscatVitePlugin({ previewAssetsDir: resolve(here, "../assets/public") })]
|
|
39
|
+
*/
|
|
40
|
+
export declare const muscatVitePlugin: (opts: {
|
|
41
|
+
/** Host static assets dir served in plugin-preview dev mode. */
|
|
42
|
+
previewAssetsDir: string;
|
|
43
|
+
/** Override preview asset URL prefixes. */
|
|
44
|
+
previewAssetPrefixes?: string[];
|
|
45
|
+
}) => Plugin[];
|
|
46
|
+
//# sourceMappingURL=viteHost.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viteHost.d.ts","sourceRoot":"","sources":["../src/viteHost.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAOnC,eAAO,MAAM,2BAA2B,UAMvC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAgBnD,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,MAAM,MAAM,6BAA8B,CAAC;AAgK/E;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB,QAAO,MA0B3C,CAAC;AAEH,mFAAmF;AACnF,eAAO,MAAM,0BAA0B,QAAO,MAe5C,CAAC;AAEH,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,GAAI,MAAM;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,KAAG,MAwBH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,MAAM;IACrC,gEAAgE;IAChE,gBAAgB,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC,KAAG,MAAM,EAOT,CAAC"}
|
package/dist/viteHost.js
ADDED
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { createReadStream, existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import { extname, resolve } from "node:path";
|
|
4
|
+
const require2 = createRequire(import.meta.url);
|
|
5
|
+
const defaultPreviewAssetPrefixes = [
|
|
6
|
+
"/imgs/",
|
|
7
|
+
"/fonts/",
|
|
8
|
+
"/models/",
|
|
9
|
+
"/sounds/",
|
|
10
|
+
"/data/"
|
|
11
|
+
];
|
|
12
|
+
const contentTypeByExt = {
|
|
13
|
+
".avif": "image/avif",
|
|
14
|
+
".css": "text/css; charset=utf-8",
|
|
15
|
+
".gif": "image/gif",
|
|
16
|
+
".glb": "model/gltf-binary",
|
|
17
|
+
".jpeg": "image/jpeg",
|
|
18
|
+
".jpg": "image/jpeg",
|
|
19
|
+
".js": "text/javascript; charset=utf-8",
|
|
20
|
+
".json": "application/json; charset=utf-8",
|
|
21
|
+
".mp3": "audio/mpeg",
|
|
22
|
+
".png": "image/png",
|
|
23
|
+
".svg": "image/svg+xml",
|
|
24
|
+
".wasm": "application/wasm",
|
|
25
|
+
".webp": "image/webp",
|
|
26
|
+
".woff": "font/woff",
|
|
27
|
+
".woff2": "font/woff2"
|
|
28
|
+
};
|
|
29
|
+
const isPluginPreviewMode = (mode) => mode === "plugin-preview";
|
|
30
|
+
const SHARED_BASE = "/plugin-shared";
|
|
31
|
+
const SHARED_MODULES = {
|
|
32
|
+
react: {
|
|
33
|
+
file: "react",
|
|
34
|
+
hasDefault: true,
|
|
35
|
+
names: [
|
|
36
|
+
"Children",
|
|
37
|
+
"Component",
|
|
38
|
+
"Fragment",
|
|
39
|
+
"Profiler",
|
|
40
|
+
"PureComponent",
|
|
41
|
+
"StrictMode",
|
|
42
|
+
"Suspense",
|
|
43
|
+
"cloneElement",
|
|
44
|
+
"createContext",
|
|
45
|
+
"createElement",
|
|
46
|
+
"createRef",
|
|
47
|
+
"forwardRef",
|
|
48
|
+
"isValidElement",
|
|
49
|
+
"lazy",
|
|
50
|
+
"memo",
|
|
51
|
+
"startTransition",
|
|
52
|
+
"useCallback",
|
|
53
|
+
"useContext",
|
|
54
|
+
"useDebugValue",
|
|
55
|
+
"useDeferredValue",
|
|
56
|
+
"useEffect",
|
|
57
|
+
"useId",
|
|
58
|
+
"useImperativeHandle",
|
|
59
|
+
"useInsertionEffect",
|
|
60
|
+
"useLayoutEffect",
|
|
61
|
+
"useMemo",
|
|
62
|
+
"useReducer",
|
|
63
|
+
"useRef",
|
|
64
|
+
"useState",
|
|
65
|
+
"useSyncExternalStore",
|
|
66
|
+
"useTransition",
|
|
67
|
+
"version"
|
|
68
|
+
]
|
|
69
|
+
},
|
|
70
|
+
"react/jsx-runtime": {
|
|
71
|
+
file: "react_jsx-runtime",
|
|
72
|
+
names: ["Fragment", "jsx", "jsxs"]
|
|
73
|
+
},
|
|
74
|
+
"react/jsx-dev-runtime": {
|
|
75
|
+
file: "react_jsx-dev-runtime",
|
|
76
|
+
names: ["Fragment", "jsxDEV"]
|
|
77
|
+
},
|
|
78
|
+
"react-dom": {
|
|
79
|
+
file: "react-dom",
|
|
80
|
+
hasDefault: true,
|
|
81
|
+
names: [
|
|
82
|
+
"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED",
|
|
83
|
+
"createPortal",
|
|
84
|
+
"createRoot",
|
|
85
|
+
"findDOMNode",
|
|
86
|
+
"flushSync",
|
|
87
|
+
"hydrate",
|
|
88
|
+
"hydrateRoot",
|
|
89
|
+
"render",
|
|
90
|
+
"unmountComponentAtNode",
|
|
91
|
+
"unstable_batchedUpdates",
|
|
92
|
+
"unstable_renderSubtreeIntoContainer",
|
|
93
|
+
"version"
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
"react-dom/client": {
|
|
97
|
+
file: "react-dom_client",
|
|
98
|
+
names: ["createRoot", "hydrateRoot"]
|
|
99
|
+
},
|
|
100
|
+
"@rainbow-robotics/plugin-ui/react": {
|
|
101
|
+
file: "plugin-ui_react",
|
|
102
|
+
// react.tsx re-exports the full rb-components barrel (export *) plus the sdk
|
|
103
|
+
// hooks.
|
|
104
|
+
parseNamesFrom: {
|
|
105
|
+
specifier: "@repo/rb-components/new_components",
|
|
106
|
+
extraNames: ["useRb", "useRbFormData", "useRbSave"]
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
"@rainbow-robotics/plugin-ui/sdk": {
|
|
110
|
+
file: "plugin-ui_sdk",
|
|
111
|
+
names: ["RbContext", "useRb", "useRbFormData", "useRbSave"]
|
|
112
|
+
},
|
|
113
|
+
"@rainbow-robotics/plugin-ui/host-ui": {
|
|
114
|
+
file: "plugin-ui_host-ui",
|
|
115
|
+
names: [
|
|
116
|
+
"alert",
|
|
117
|
+
"confirm",
|
|
118
|
+
"getHostServices",
|
|
119
|
+
"prompt",
|
|
120
|
+
"setHostServices",
|
|
121
|
+
"toast"
|
|
122
|
+
]
|
|
123
|
+
},
|
|
124
|
+
"@rainbow-robotics/plugin-ui/ws": {
|
|
125
|
+
file: "plugin-ui_ws",
|
|
126
|
+
names: ["RbWs", "createLazyRbSdk"]
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
function parseExportedValueNames(source) {
|
|
130
|
+
const names = /* @__PURE__ */ new Set();
|
|
131
|
+
const blockRe = /export\s+(type\s+)?\{([^}]*)\}/g;
|
|
132
|
+
let match;
|
|
133
|
+
while (match = blockRe.exec(source)) {
|
|
134
|
+
if (match[1]) continue;
|
|
135
|
+
for (const rawEntry of match[2].split(",")) {
|
|
136
|
+
const entry = rawEntry.trim();
|
|
137
|
+
if (!entry || entry.startsWith("type ")) continue;
|
|
138
|
+
const asMatch = entry.match(/^\S+\s+as\s+(\S+)$/);
|
|
139
|
+
names.add(asMatch ? asMatch[1] : entry);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return [...names];
|
|
143
|
+
}
|
|
144
|
+
const nameCache = /* @__PURE__ */ new Map();
|
|
145
|
+
function resolveNames(spec) {
|
|
146
|
+
const mod = SHARED_MODULES[spec];
|
|
147
|
+
if (mod.names) return mod.names;
|
|
148
|
+
if (!mod.parseNamesFrom) {
|
|
149
|
+
throw new Error(`[plugin-ui] ${spec} has neither "names" nor "parseNamesFrom"`);
|
|
150
|
+
}
|
|
151
|
+
if (!nameCache.has(spec)) {
|
|
152
|
+
const { specifier, extraNames = [] } = mod.parseNamesFrom;
|
|
153
|
+
const sourcePath = require2.resolve(specifier);
|
|
154
|
+
const parsed = parseExportedValueNames(readFileSync(sourcePath, "utf8"));
|
|
155
|
+
nameCache.set(spec, [.../* @__PURE__ */ new Set([...parsed, ...extraNames])]);
|
|
156
|
+
}
|
|
157
|
+
return nameCache.get(spec);
|
|
158
|
+
}
|
|
159
|
+
function shimSource(spec) {
|
|
160
|
+
const mod = SHARED_MODULES[spec];
|
|
161
|
+
const names = resolveNames(spec);
|
|
162
|
+
const g = `(globalThis.__RB_SHARED__||{})[${JSON.stringify(spec)}]`;
|
|
163
|
+
return `const m = ${g};
|
|
164
|
+
if (!m) throw new Error("[plugin-ui] host shared module not registered: ${spec}");
|
|
165
|
+
export const { ${names.join(", ")} } = m;
|
|
166
|
+
` + (mod.hasDefault ? `export default (m.default ?? m);
|
|
167
|
+
` : "");
|
|
168
|
+
}
|
|
169
|
+
const fileToSpec = Object.fromEntries(
|
|
170
|
+
Object.entries(SHARED_MODULES).map(([spec, { file }]) => [file, spec])
|
|
171
|
+
);
|
|
172
|
+
function importMapScript() {
|
|
173
|
+
const imports = {};
|
|
174
|
+
for (const [spec, { file }] of Object.entries(SHARED_MODULES)) {
|
|
175
|
+
imports[spec] = `${SHARED_BASE}/${file}.js`;
|
|
176
|
+
}
|
|
177
|
+
return `<script type="importmap">${JSON.stringify({ imports })}</script>`;
|
|
178
|
+
}
|
|
179
|
+
const pluginSharedRuntimePlugin = () => ({
|
|
180
|
+
name: "plugin-ui-shared-runtime",
|
|
181
|
+
transformIndexHtml(html) {
|
|
182
|
+
return html.replace("</head>", ` ${importMapScript()}
|
|
183
|
+
</head>`);
|
|
184
|
+
},
|
|
185
|
+
configureServer(server) {
|
|
186
|
+
server.middlewares.use((req, res, next) => {
|
|
187
|
+
const url = req.url?.split("?")[0];
|
|
188
|
+
if (!url?.startsWith(`${SHARED_BASE}/`)) return next();
|
|
189
|
+
const file = url.slice(`${SHARED_BASE}/`.length).replace(/\.js$/, "");
|
|
190
|
+
const spec = fileToSpec[file];
|
|
191
|
+
if (!spec) return next();
|
|
192
|
+
res.setHeader("Content-Type", "text/javascript; charset=utf-8");
|
|
193
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
194
|
+
res.end(shimSource(spec));
|
|
195
|
+
});
|
|
196
|
+
},
|
|
197
|
+
generateBundle() {
|
|
198
|
+
for (const [spec, { file }] of Object.entries(SHARED_MODULES)) {
|
|
199
|
+
this.emitFile({
|
|
200
|
+
type: "asset",
|
|
201
|
+
fileName: `plugin-shared/${file}.js`,
|
|
202
|
+
source: shimSource(spec)
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
const pluginPreviewRuntimePlugin = () => ({
|
|
208
|
+
name: "plugin-ui-preview-runtime",
|
|
209
|
+
apply: (_config, { mode }) => isPluginPreviewMode(mode),
|
|
210
|
+
transformIndexHtml(html) {
|
|
211
|
+
return html.replace(
|
|
212
|
+
"</head>",
|
|
213
|
+
[
|
|
214
|
+
" <script>",
|
|
215
|
+
" window.__RB_PLUGIN_PREVIEW_HOST__ = true;",
|
|
216
|
+
" window.__RB_ASSETS_BASE_URL__ = window.location.origin;",
|
|
217
|
+
" </script>",
|
|
218
|
+
" </head>"
|
|
219
|
+
].join("\n")
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
const pluginPreviewAssetsPlugin = (opts) => {
|
|
224
|
+
const { assetsDir, prefixes = defaultPreviewAssetPrefixes } = opts;
|
|
225
|
+
return {
|
|
226
|
+
name: "plugin-ui-preview-assets",
|
|
227
|
+
apply: (_config, { command, mode }) => command === "serve" && isPluginPreviewMode(mode),
|
|
228
|
+
configureServer(server) {
|
|
229
|
+
server.middlewares.use((req, res, next) => {
|
|
230
|
+
const url = req.url?.split("?")[0];
|
|
231
|
+
if (!url || !prefixes.some((prefix) => url.startsWith(prefix)))
|
|
232
|
+
return next();
|
|
233
|
+
const decodedUrl = decodeURIComponent(url);
|
|
234
|
+
const filePath = resolve(assetsDir, `.${decodedUrl}`);
|
|
235
|
+
if (!filePath.startsWith(assetsDir)) return next();
|
|
236
|
+
if (!existsSync(filePath) || !statSync(filePath).isFile()) return next();
|
|
237
|
+
const contentType = contentTypeByExt[extname(filePath)];
|
|
238
|
+
if (contentType) res.setHeader("Content-Type", contentType);
|
|
239
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
240
|
+
createReadStream(filePath).pipe(res);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
};
|
|
245
|
+
const muscatVitePlugin = (opts) => [
|
|
246
|
+
pluginSharedRuntimePlugin(),
|
|
247
|
+
pluginPreviewRuntimePlugin(),
|
|
248
|
+
pluginPreviewAssetsPlugin({
|
|
249
|
+
assetsDir: opts.previewAssetsDir,
|
|
250
|
+
prefixes: opts.previewAssetPrefixes
|
|
251
|
+
})
|
|
252
|
+
];
|
|
253
|
+
export {
|
|
254
|
+
contentTypeByExt,
|
|
255
|
+
defaultPreviewAssetPrefixes,
|
|
256
|
+
isPluginPreviewMode,
|
|
257
|
+
muscatVitePlugin,
|
|
258
|
+
pluginPreviewAssetsPlugin,
|
|
259
|
+
pluginPreviewRuntimePlugin,
|
|
260
|
+
pluginSharedRuntimePlugin
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=viteHost.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/viteHost.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Vite plugins for a HOST app previewing locally-developed plugins.\n * Host-agnostic \u2014 paths are parameters.\n *\n * import {\n * pluginPreviewRuntimePlugin,\n * pluginPreviewAssetsPlugin,\n * isPluginPreviewMode,\n * } from \"@rainbow-robotics/plugin-ui/vite-host\";\n *\n * A built plugin's bare imports (react, rb-components, plugin-ui/*) resolve via\n * the import map this file injects, to the host's already-loaded instances.\n * See ./host.tsx.\n */\nimport type { Plugin } from \"vite\";\nimport { createReadStream, existsSync, readFileSync, statSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { extname, resolve } from \"node:path\";\n\nconst require = createRequire(import.meta.url);\n\nexport const defaultPreviewAssetPrefixes = [\n \"/imgs/\",\n \"/fonts/\",\n \"/models/\",\n \"/sounds/\",\n \"/data/\",\n];\n\nexport const contentTypeByExt: Record<string, string> = {\n \".avif\": \"image/avif\",\n \".css\": \"text/css; charset=utf-8\",\n \".gif\": \"image/gif\",\n \".glb\": \"model/gltf-binary\",\n \".jpeg\": \"image/jpeg\",\n \".jpg\": \"image/jpeg\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".mp3\": \"audio/mpeg\",\n \".png\": \"image/png\",\n \".svg\": \"image/svg+xml\",\n \".wasm\": \"application/wasm\",\n \".webp\": \"image/webp\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\nexport const isPluginPreviewMode = (mode: string) => mode === \"plugin-preview\";\n\n/* -------------------------------------------------------------------------- */\n/* Shared-runtime import map (plugins reuse the host's loaded instances) */\n/* -------------------------------------------------------------------------- */\n\nconst SHARED_BASE = \"/plugin-shared\";\n\n// Each shared specifier \u2192 the named exports its shim re-exports from\n// window.__RB_SHARED__[specifier] (set by the host, e.g. nexus/src/pluginShared).\n//\n// `names`: hardcoded list (small, stable modules).\n// `parseNamesFrom`: parse the export names out of a source file's text \u2014 used\n// for react.tsx, which re-exports the whole rb-components barrel (100+ names).\n// We text-parse rather than import it: the barrel is .ts source, which plain\n// Node can't execute.\nconst SHARED_MODULES: Record<\n string,\n {\n file: string;\n names?: string[];\n parseNamesFrom?: { specifier: string; extraNames?: string[] };\n hasDefault?: boolean;\n }\n> = {\n react: {\n file: \"react\",\n hasDefault: true,\n names: [\n \"Children\", \"Component\", \"Fragment\", \"Profiler\", \"PureComponent\",\n \"StrictMode\", \"Suspense\", \"cloneElement\", \"createContext\",\n \"createElement\", \"createRef\", \"forwardRef\", \"isValidElement\", \"lazy\",\n \"memo\", \"startTransition\", \"useCallback\", \"useContext\", \"useDebugValue\",\n \"useDeferredValue\", \"useEffect\", \"useId\", \"useImperativeHandle\",\n \"useInsertionEffect\", \"useLayoutEffect\", \"useMemo\", \"useReducer\",\n \"useRef\", \"useState\", \"useSyncExternalStore\", \"useTransition\", \"version\",\n ],\n },\n \"react/jsx-runtime\": {\n file: \"react_jsx-runtime\",\n names: [\"Fragment\", \"jsx\", \"jsxs\"],\n },\n \"react/jsx-dev-runtime\": {\n file: \"react_jsx-dev-runtime\",\n names: [\"Fragment\", \"jsxDEV\"],\n },\n \"react-dom\": {\n file: \"react-dom\",\n hasDefault: true,\n names: [\n \"__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED\",\n \"createPortal\",\n \"createRoot\",\n \"findDOMNode\",\n \"flushSync\",\n \"hydrate\",\n \"hydrateRoot\",\n \"render\",\n \"unmountComponentAtNode\",\n \"unstable_batchedUpdates\",\n \"unstable_renderSubtreeIntoContainer\",\n \"version\",\n ],\n },\n \"react-dom/client\": {\n file: \"react-dom_client\",\n names: [\"createRoot\", \"hydrateRoot\"],\n },\n \"@rainbow-robotics/plugin-ui/react\": {\n file: \"plugin-ui_react\",\n // react.tsx re-exports the full rb-components barrel (export *) plus the sdk\n // hooks.\n parseNamesFrom: {\n specifier: \"@repo/rb-components/new_components\",\n extraNames: [\"useRb\", \"useRbFormData\", \"useRbSave\"],\n },\n },\n \"@rainbow-robotics/plugin-ui/sdk\": {\n file: \"plugin-ui_sdk\",\n names: [\"RbContext\", \"useRb\", \"useRbFormData\", \"useRbSave\"],\n },\n \"@rainbow-robotics/plugin-ui/host-ui\": {\n file: \"plugin-ui_host-ui\",\n names: [\n \"alert\",\n \"confirm\",\n \"getHostServices\",\n \"prompt\",\n \"setHostServices\",\n \"toast\",\n ],\n },\n \"@rainbow-robotics/plugin-ui/ws\": {\n file: \"plugin-ui_ws\",\n names: [\"RbWs\", \"createLazyRbSdk\"],\n },\n};\n\n// Parses `export { a, b as c, ... }` value names out of a source file's text\n// (skips `export type { ... }` blocks and individual `type X` entries within\n// a mixed block \u2014 types don't exist as runtime module properties). Static\n// text parsing, not module execution, so it works for .ts source files with\n// no loader and has no ESM-resolution footguns.\nfunction parseExportedValueNames(source: string): string[] {\n const names = new Set<string>();\n const blockRe = /export\\s+(type\\s+)?\\{([^}]*)\\}/g;\n let match: RegExpExecArray | null;\n while ((match = blockRe.exec(source))) {\n if (match[1]) continue; // whole `export type { ... }` block\n for (const rawEntry of match[2].split(\",\")) {\n const entry = rawEntry.trim();\n if (!entry || entry.startsWith(\"type \")) continue;\n const asMatch = entry.match(/^\\S+\\s+as\\s+(\\S+)$/);\n names.add(asMatch ? asMatch[1] : entry);\n }\n }\n return [...names];\n}\n\nconst nameCache = new Map<string, string[]>();\n\nfunction resolveNames(spec: string): string[] {\n const mod = SHARED_MODULES[spec];\n if (mod.names) return mod.names;\n if (!mod.parseNamesFrom) {\n throw new Error(`[plugin-ui] ${spec} has neither \"names\" nor \"parseNamesFrom\"`);\n }\n if (!nameCache.has(spec)) {\n const { specifier, extraNames = [] } = mod.parseNamesFrom;\n const sourcePath = require.resolve(specifier);\n const parsed = parseExportedValueNames(readFileSync(sourcePath, \"utf8\"));\n nameCache.set(spec, [...new Set([...parsed, ...extraNames])]);\n }\n return nameCache.get(spec)!;\n}\n\nfunction shimSource(spec: string): string {\n const mod = SHARED_MODULES[spec];\n const names = resolveNames(spec);\n const g = `(globalThis.__RB_SHARED__||{})[${JSON.stringify(spec)}]`;\n return (\n `const m = ${g};\\n` +\n `if (!m) throw new Error(\"[plugin-ui] host shared module not registered: ${spec}\");\\n` +\n `export const { ${names.join(\", \")} } = m;\\n` +\n (mod.hasDefault ? `export default (m.default ?? m);\\n` : \"\")\n );\n}\n\nconst fileToSpec = Object.fromEntries(\n Object.entries(SHARED_MODULES).map(([spec, { file }]) => [file, spec]),\n);\n\nfunction importMapScript(): string {\n const imports: Record<string, string> = {};\n for (const [spec, { file }] of Object.entries(SHARED_MODULES)) {\n imports[spec] = `${SHARED_BASE}/${file}.js`;\n }\n return `<script type=\"importmap\">${JSON.stringify({ imports })}</script>`;\n}\n\n/**\n * Serves the shared-runtime shim modules at /plugin-shared/*.js and injects the\n * import map so a dynamically-imported plugin's bare `import \"react\"` /\n * `import \"@rainbow-robotics/plugin-ui/react\"` etc. resolve to the host's OWN\n * instances (via window.__RB_SHARED__). Applied in all modes \u2014 any nexus build\n * that can host plugins needs it.\n */\nexport const pluginSharedRuntimePlugin = (): Plugin => ({\n name: \"plugin-ui-shared-runtime\",\n transformIndexHtml(html) {\n return html.replace(\"</head>\", ` ${importMapScript()}\\n </head>`);\n },\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const url = req.url?.split(\"?\")[0];\n if (!url?.startsWith(`${SHARED_BASE}/`)) return next();\n const file = url.slice(`${SHARED_BASE}/`.length).replace(/\\.js$/, \"\");\n const spec = fileToSpec[file];\n if (!spec) return next();\n res.setHeader(\"Content-Type\", \"text/javascript; charset=utf-8\");\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.end(shimSource(spec));\n });\n },\n generateBundle() {\n for (const [spec, { file }] of Object.entries(SHARED_MODULES)) {\n this.emitFile({\n type: \"asset\",\n fileName: `plugin-shared/${file}.js`,\n source: shimSource(spec),\n });\n }\n },\n});\n\n/** Inject the preview-host runtime flags into index.html (plugin-preview only). */\nexport const pluginPreviewRuntimePlugin = (): Plugin => ({\n name: \"plugin-ui-preview-runtime\",\n apply: (_config, { mode }) => isPluginPreviewMode(mode),\n transformIndexHtml(html) {\n return html.replace(\n \"</head>\",\n [\n \" <script>\",\n \" window.__RB_PLUGIN_PREVIEW_HOST__ = true;\",\n \" window.__RB_ASSETS_BASE_URL__ = window.location.origin;\",\n \" </script>\",\n \" </head>\",\n ].join(\"\\n\"),\n );\n },\n});\n\n/** Serve the host's static assets (imgs/fonts/...) in plugin-preview dev mode. */\nexport const pluginPreviewAssetsPlugin = (opts: {\n assetsDir: string;\n prefixes?: string[];\n}): Plugin => {\n const { assetsDir, prefixes = defaultPreviewAssetPrefixes } = opts;\n return {\n name: \"plugin-ui-preview-assets\",\n apply: (_config, { command, mode }) =>\n command === \"serve\" && isPluginPreviewMode(mode),\n configureServer(server) {\n server.middlewares.use((req, res, next) => {\n const url = req.url?.split(\"?\")[0];\n if (!url || !prefixes.some((prefix) => url.startsWith(prefix)))\n return next();\n\n const decodedUrl = decodeURIComponent(url);\n const filePath = resolve(assetsDir, `.${decodedUrl}`);\n if (!filePath.startsWith(assetsDir)) return next();\n if (!existsSync(filePath) || !statSync(filePath).isFile()) return next();\n\n const contentType = contentTypeByExt[extname(filePath)];\n if (contentType) res.setHeader(\"Content-Type\", contentType);\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n createReadStream(filePath).pipe(res);\n });\n },\n };\n};\n\n/**\n * All host-side plugin-ui Vite plugins in one call. Each self-gates by mode, so\n * a host just spreads this into its `plugins` array.\n *\n * plugins: [muscatVitePlugin({ previewAssetsDir: resolve(here, \"../assets/public\") })]\n */\nexport const muscatVitePlugin = (opts: {\n /** Host static assets dir served in plugin-preview dev mode. */\n previewAssetsDir: string;\n /** Override preview asset URL prefixes. */\n previewAssetPrefixes?: string[];\n}): Plugin[] => [\n pluginSharedRuntimePlugin(),\n pluginPreviewRuntimePlugin(),\n pluginPreviewAssetsPlugin({\n assetsDir: opts.previewAssetsDir,\n prefixes: opts.previewAssetPrefixes,\n }),\n];\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["require"]
|
|
7
|
+
}
|
package/dist/ws.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { PluginUIServices } from "./host-ui";
|
|
1
2
|
export interface WsHandle {
|
|
2
3
|
undeclare(): void;
|
|
3
4
|
}
|
|
@@ -17,4 +18,56 @@ export declare class RbWs {
|
|
|
17
18
|
serve<P = any, R = any>(topic: string, handler: (payload?: P) => R | Promise<R>): Promise<WsQueryable>;
|
|
18
19
|
close(): void;
|
|
19
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Builds an rb-sdk-shaped object (pub/sub/action/serve + the passed-through
|
|
23
|
+
* toast/alert/confirm/prompt) that lazily awaits a not-yet-connected `RbWs` —
|
|
24
|
+
* so callers don't block their first render on the WebSocket handshake (there
|
|
25
|
+
* may be no backend reachable yet). Shared by both host mount paths (see
|
|
26
|
+
* ./host.tsx and muscat-plugin-kit's dev bootstrap), which otherwise
|
|
27
|
+
* duplicate this wiring.
|
|
28
|
+
*/
|
|
29
|
+
export declare function createLazyRbSdk(wsPromise: Promise<RbWs>, services: PluginUIServices, mount?: {
|
|
30
|
+
data?: unknown;
|
|
31
|
+
onSave?: (getPayload: () => unknown) => () => void;
|
|
32
|
+
}): {
|
|
33
|
+
pub: (topic: string, payload: any) => Promise<void>;
|
|
34
|
+
sub: (topic: string, handler: (payload: any) => void) => Promise<WsHandle>;
|
|
35
|
+
action: (topic: string, payload?: any) => Promise<any>;
|
|
36
|
+
serve: (topic: string, handler: (payload?: any) => any) => Promise<WsHandle>;
|
|
37
|
+
toast: (params: {
|
|
38
|
+
title?: string;
|
|
39
|
+
message: string | import("react").ReactElement;
|
|
40
|
+
type?: "info" | "danger" | "warning" | "caution" | "success";
|
|
41
|
+
actionLabel?: string;
|
|
42
|
+
handleActionClick?: () => void;
|
|
43
|
+
closeOnActionClick?: boolean;
|
|
44
|
+
duration?: number;
|
|
45
|
+
onClose?: () => void;
|
|
46
|
+
}) => void;
|
|
47
|
+
alert: (params: {
|
|
48
|
+
title?: string;
|
|
49
|
+
message: string;
|
|
50
|
+
buttonText?: string;
|
|
51
|
+
}) => Promise<void>;
|
|
52
|
+
confirm: (params: {
|
|
53
|
+
title?: string;
|
|
54
|
+
message: string;
|
|
55
|
+
buttonText?: {
|
|
56
|
+
yes: string;
|
|
57
|
+
no: string;
|
|
58
|
+
};
|
|
59
|
+
}) => Promise<boolean>;
|
|
60
|
+
prompt: (params: {
|
|
61
|
+
title?: string;
|
|
62
|
+
message: string;
|
|
63
|
+
value?: string;
|
|
64
|
+
placeholder?: string;
|
|
65
|
+
buttonText?: {
|
|
66
|
+
yes: string;
|
|
67
|
+
no: string;
|
|
68
|
+
};
|
|
69
|
+
}) => Promise<string | undefined>;
|
|
70
|
+
data: unknown;
|
|
71
|
+
onSave: (getPayload: () => unknown) => () => void;
|
|
72
|
+
};
|
|
20
73
|
//# sourceMappingURL=ws.d.ts.map
|