@paperclipai/plugin-sdk 2026.3.17-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +888 -0
  3. package/dist/bundlers.d.ts +57 -0
  4. package/dist/bundlers.d.ts.map +1 -0
  5. package/dist/bundlers.js +105 -0
  6. package/dist/bundlers.js.map +1 -0
  7. package/dist/define-plugin.d.ts +218 -0
  8. package/dist/define-plugin.d.ts.map +1 -0
  9. package/dist/define-plugin.js +85 -0
  10. package/dist/define-plugin.js.map +1 -0
  11. package/dist/dev-cli.d.ts +3 -0
  12. package/dist/dev-cli.d.ts.map +1 -0
  13. package/dist/dev-cli.js +49 -0
  14. package/dist/dev-cli.js.map +1 -0
  15. package/dist/dev-server.d.ts +34 -0
  16. package/dist/dev-server.d.ts.map +1 -0
  17. package/dist/dev-server.js +194 -0
  18. package/dist/dev-server.js.map +1 -0
  19. package/dist/host-client-factory.d.ts +229 -0
  20. package/dist/host-client-factory.d.ts.map +1 -0
  21. package/dist/host-client-factory.js +353 -0
  22. package/dist/host-client-factory.js.map +1 -0
  23. package/dist/index.d.ts +84 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +84 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/protocol.d.ts +881 -0
  28. package/dist/protocol.d.ts.map +1 -0
  29. package/dist/protocol.js +297 -0
  30. package/dist/protocol.js.map +1 -0
  31. package/dist/testing.d.ts +63 -0
  32. package/dist/testing.d.ts.map +1 -0
  33. package/dist/testing.js +700 -0
  34. package/dist/testing.js.map +1 -0
  35. package/dist/types.d.ts +982 -0
  36. package/dist/types.d.ts.map +1 -0
  37. package/dist/types.js +12 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/ui/components.d.ts +257 -0
  40. package/dist/ui/components.d.ts.map +1 -0
  41. package/dist/ui/components.js +97 -0
  42. package/dist/ui/components.js.map +1 -0
  43. package/dist/ui/hooks.d.ts +120 -0
  44. package/dist/ui/hooks.d.ts.map +1 -0
  45. package/dist/ui/hooks.js +148 -0
  46. package/dist/ui/hooks.js.map +1 -0
  47. package/dist/ui/index.d.ts +50 -0
  48. package/dist/ui/index.d.ts.map +1 -0
  49. package/dist/ui/index.js +48 -0
  50. package/dist/ui/index.js.map +1 -0
  51. package/dist/ui/runtime.d.ts +3 -0
  52. package/dist/ui/runtime.d.ts.map +1 -0
  53. package/dist/ui/runtime.js +30 -0
  54. package/dist/ui/runtime.js.map +1 -0
  55. package/dist/ui/types.d.ts +308 -0
  56. package/dist/ui/types.d.ts.map +1 -0
  57. package/dist/ui/types.js +17 -0
  58. package/dist/ui/types.js.map +1 -0
  59. package/dist/worker-rpc-host.d.ts +127 -0
  60. package/dist/worker-rpc-host.d.ts.map +1 -0
  61. package/dist/worker-rpc-host.js +941 -0
  62. package/dist/worker-rpc-host.js.map +1 -0
  63. package/package.json +88 -0
@@ -0,0 +1,148 @@
1
+ import { getSdkUiRuntimeValue } from "./runtime.js";
2
+ // ---------------------------------------------------------------------------
3
+ // usePluginData
4
+ // ---------------------------------------------------------------------------
5
+ /**
6
+ * Fetch data from the plugin worker's registered `getData` handler.
7
+ *
8
+ * Calls `ctx.data.register(key, handler)` in the worker and returns the
9
+ * result as reactive state. Re-fetches when `params` changes.
10
+ *
11
+ * @template T The expected shape of the returned data
12
+ * @param key - The data key matching the handler registered with `ctx.data.register()`
13
+ * @param params - Optional parameters forwarded to the handler
14
+ * @returns `PluginDataResult<T>` with `data`, `loading`, `error`, and `refresh`
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * function SyncWidget({ context }: PluginWidgetProps) {
19
+ * const { data, loading, error } = usePluginData<SyncHealth>("sync-health", {
20
+ * companyId: context.companyId,
21
+ * });
22
+ *
23
+ * if (loading) return <div>Loading…</div>;
24
+ * if (error) return <div>Error: {error.message}</div>;
25
+ * return <div>Synced Issues: {data!.syncedCount}</div>;
26
+ * }
27
+ * ```
28
+ *
29
+ * @see PLUGIN_SPEC.md §13.8 — `getData`
30
+ * @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
31
+ */
32
+ export function usePluginData(key, params) {
33
+ const impl = getSdkUiRuntimeValue("usePluginData");
34
+ return impl(key, params);
35
+ }
36
+ // ---------------------------------------------------------------------------
37
+ // usePluginAction
38
+ // ---------------------------------------------------------------------------
39
+ /**
40
+ * Get a callable function that invokes the plugin worker's registered
41
+ * `performAction` handler.
42
+ *
43
+ * The returned function is async and throws a `PluginBridgeError` on failure.
44
+ *
45
+ * @param key - The action key matching the handler registered with `ctx.actions.register()`
46
+ * @returns An async function that sends the action to the worker and resolves with the result
47
+ *
48
+ * @example
49
+ * ```tsx
50
+ * function ResyncButton({ context }: PluginWidgetProps) {
51
+ * const resync = usePluginAction("resync");
52
+ * const [error, setError] = useState<string | null>(null);
53
+ *
54
+ * async function handleClick() {
55
+ * try {
56
+ * await resync({ companyId: context.companyId });
57
+ * } catch (err) {
58
+ * setError((err as PluginBridgeError).message);
59
+ * }
60
+ * }
61
+ *
62
+ * return <button onClick={handleClick}>Resync Now</button>;
63
+ * }
64
+ * ```
65
+ *
66
+ * @see PLUGIN_SPEC.md §13.9 — `performAction`
67
+ * @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
68
+ */
69
+ export function usePluginAction(key) {
70
+ const impl = getSdkUiRuntimeValue("usePluginAction");
71
+ return impl(key);
72
+ }
73
+ // ---------------------------------------------------------------------------
74
+ // useHostContext
75
+ // ---------------------------------------------------------------------------
76
+ /**
77
+ * Read the current host context (active company, project, entity, user).
78
+ *
79
+ * Use this to know which context the plugin component is being rendered in
80
+ * so you can scope data requests and actions accordingly.
81
+ *
82
+ * @returns The current `PluginHostContext`
83
+ *
84
+ * @example
85
+ * ```tsx
86
+ * function IssueTab() {
87
+ * const { companyId, entityId } = useHostContext();
88
+ * const { data } = usePluginData("linear-link", { issueId: entityId });
89
+ * return <div>{data?.linearIssueUrl}</div>;
90
+ * }
91
+ * ```
92
+ *
93
+ * @see PLUGIN_SPEC.md §19 — UI Extension Model
94
+ */
95
+ export function useHostContext() {
96
+ const impl = getSdkUiRuntimeValue("useHostContext");
97
+ return impl();
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // usePluginStream
101
+ // ---------------------------------------------------------------------------
102
+ /**
103
+ * Subscribe to a real-time event stream pushed from the plugin worker.
104
+ *
105
+ * Opens an SSE connection to `GET /api/plugins/:pluginId/bridge/stream/:channel`
106
+ * and accumulates events as they arrive. The worker pushes events using
107
+ * `ctx.streams.emit(channel, event)`.
108
+ *
109
+ * @template T The expected shape of each streamed event
110
+ * @param channel - The stream channel name (must match what the worker uses in `ctx.streams.emit`)
111
+ * @param options - Optional configuration for the stream
112
+ * @returns `PluginStreamResult<T>` with `events`, `lastEvent`, connection status, and `close()`
113
+ *
114
+ * @example
115
+ * ```tsx
116
+ * function ChatMessages() {
117
+ * const { events, connected, close } = usePluginStream<ChatToken>("chat-stream");
118
+ *
119
+ * return (
120
+ * <div>
121
+ * {events.map((e, i) => <span key={i}>{e.text}</span>)}
122
+ * {connected && <span className="pulse" />}
123
+ * <button onClick={close}>Stop</button>
124
+ * </div>
125
+ * );
126
+ * }
127
+ * ```
128
+ *
129
+ * @see PLUGIN_SPEC.md §19.8 — Real-Time Streaming
130
+ */
131
+ export function usePluginStream(channel, options) {
132
+ const impl = getSdkUiRuntimeValue("usePluginStream");
133
+ return impl(channel, options);
134
+ }
135
+ // ---------------------------------------------------------------------------
136
+ // usePluginToast
137
+ // ---------------------------------------------------------------------------
138
+ /**
139
+ * Trigger a host toast notification from plugin UI.
140
+ *
141
+ * This lets plugin pages and widgets surface user-facing feedback through the
142
+ * same toast system as the host app without reaching into host internals.
143
+ */
144
+ export function usePluginToast() {
145
+ const impl = getSdkUiRuntimeValue("usePluginToast");
146
+ return impl();
147
+ }
148
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/ui/hooks.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEpD,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,MAAgC;IAEhC,MAAM,IAAI,GAAG,oBAAoB,CAE/B,eAAe,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,IAAI,GAAG,oBAAoB,CAAsC,iBAAiB,CAAC,CAAC;IAC1F,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,GAAG,oBAAoB,CAA0B,gBAAgB,CAAC,CAAC;IAC7E,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAe,EACf,OAAgC;IAEhC,MAAM,IAAI,GAAG,oBAAoB,CAE/B,iBAAiB,CAAC,CAAC;IACrB,OAAO,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAChC,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,MAAM,IAAI,GAAG,oBAAoB,CAAsB,gBAAgB,CAAC,CAAC;IACzE,OAAO,IAAI,EAAE,CAAC;AAChB,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * `@paperclipai/plugin-sdk/ui` — Paperclip plugin UI SDK.
3
+ *
4
+ * Import this subpath from plugin UI bundles (React components that run in
5
+ * the host frontend). Do **not** import this from plugin worker code.
6
+ *
7
+ * The worker-side SDK is available from `@paperclipai/plugin-sdk` (root).
8
+ *
9
+ * @see PLUGIN_SPEC.md §19.0.1 — Plugin UI SDK
10
+ * @see PLUGIN_SPEC.md §29.2 — SDK Versioning
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * // Plugin UI bundle entry (dist/ui/index.tsx)
15
+ * import { usePluginData, usePluginAction } from "@paperclipai/plugin-sdk/ui";
16
+ * import type { PluginWidgetProps } from "@paperclipai/plugin-sdk/ui";
17
+ *
18
+ * export function DashboardWidget({ context }: PluginWidgetProps) {
19
+ * const { data, loading, error } = usePluginData("sync-health", {
20
+ * companyId: context.companyId,
21
+ * });
22
+ * const resync = usePluginAction("resync");
23
+ *
24
+ * if (loading) return <div>Loading…</div>;
25
+ * if (error) return <div>Error: {error.message}</div>;
26
+ *
27
+ * return (
28
+ * <div style={{ display: "grid", gap: 8 }}>
29
+ * <strong>Synced Issues</strong>
30
+ * <div>{data!.syncedCount}</div>
31
+ * <button onClick={() => resync({ companyId: context.companyId })}>
32
+ * Resync Now
33
+ * </button>
34
+ * </div>
35
+ * );
36
+ * }
37
+ * ```
38
+ */
39
+ /**
40
+ * Bridge hooks for plugin UI components to communicate with the plugin worker.
41
+ *
42
+ * - `usePluginData(key, params)` — fetch data from the worker's `getData` handler
43
+ * - `usePluginAction(key)` — get a callable that invokes the worker's `performAction` handler
44
+ * - `useHostContext()` — read the current active company, project, entity, and user IDs
45
+ * - `usePluginStream(channel)` — subscribe to real-time SSE events from the worker
46
+ */
47
+ export { usePluginData, usePluginAction, useHostContext, usePluginStream, usePluginToast, } from "./hooks.js";
48
+ export type { PluginBridgeError, PluginBridgeErrorCode, PluginHostContext, PluginModalBoundsRequest, PluginRenderCloseEvent, PluginRenderCloseHandler, PluginRenderCloseLifecycle, PluginRenderEnvironmentContext, PluginLauncherBounds, PluginLauncherRenderEnvironment, PluginDataResult, PluginActionFn, PluginStreamResult, PluginToastTone, PluginToastAction, PluginToastInput, PluginToastFn, } from "./types.js";
49
+ export type { PluginPageProps, PluginWidgetProps, PluginDetailTabProps, PluginSidebarProps, PluginProjectSidebarItemProps, PluginCommentAnnotationProps, PluginCommentContextMenuItemProps, PluginSettingsPageProps, } from "./types.js";
50
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;GAOG;AACH,OAAO,EACL,aAAa,EACb,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,0BAA0B,EAC1B,8BAA8B,EAC9B,oBAAoB,EACpB,+BAA+B,EAC/B,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,YAAY,EACV,eAAe,EACf,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,6BAA6B,EAC7B,4BAA4B,EAC5B,iCAAiC,EACjC,uBAAuB,GACxB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * `@paperclipai/plugin-sdk/ui` — Paperclip plugin UI SDK.
3
+ *
4
+ * Import this subpath from plugin UI bundles (React components that run in
5
+ * the host frontend). Do **not** import this from plugin worker code.
6
+ *
7
+ * The worker-side SDK is available from `@paperclipai/plugin-sdk` (root).
8
+ *
9
+ * @see PLUGIN_SPEC.md §19.0.1 — Plugin UI SDK
10
+ * @see PLUGIN_SPEC.md §29.2 — SDK Versioning
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * // Plugin UI bundle entry (dist/ui/index.tsx)
15
+ * import { usePluginData, usePluginAction } from "@paperclipai/plugin-sdk/ui";
16
+ * import type { PluginWidgetProps } from "@paperclipai/plugin-sdk/ui";
17
+ *
18
+ * export function DashboardWidget({ context }: PluginWidgetProps) {
19
+ * const { data, loading, error } = usePluginData("sync-health", {
20
+ * companyId: context.companyId,
21
+ * });
22
+ * const resync = usePluginAction("resync");
23
+ *
24
+ * if (loading) return <div>Loading…</div>;
25
+ * if (error) return <div>Error: {error.message}</div>;
26
+ *
27
+ * return (
28
+ * <div style={{ display: "grid", gap: 8 }}>
29
+ * <strong>Synced Issues</strong>
30
+ * <div>{data!.syncedCount}</div>
31
+ * <button onClick={() => resync({ companyId: context.companyId })}>
32
+ * Resync Now
33
+ * </button>
34
+ * </div>
35
+ * );
36
+ * }
37
+ * ```
38
+ */
39
+ /**
40
+ * Bridge hooks for plugin UI components to communicate with the plugin worker.
41
+ *
42
+ * - `usePluginData(key, params)` — fetch data from the worker's `getData` handler
43
+ * - `usePluginAction(key)` — get a callable that invokes the worker's `performAction` handler
44
+ * - `useHostContext()` — read the current active company, project, entity, and user IDs
45
+ * - `usePluginStream(channel)` — subscribe to real-time SSE events from the worker
46
+ */
47
+ export { usePluginData, usePluginAction, useHostContext, usePluginStream, usePluginToast, } from "./hooks.js";
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH;;;;;;;GAOG;AACH,OAAO,EACL,aAAa,EACb,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function getSdkUiRuntimeValue<T>(name: string): T;
2
+ export declare function renderSdkUiComponent<TProps>(name: string, props: TProps): unknown;
3
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/ui/runtime.ts"],"names":[],"mappings":"AAsBA,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,CAMvD;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EACzC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAiBT"}
@@ -0,0 +1,30 @@
1
+ function getBridgeRegistry() {
2
+ return globalThis.__paperclipPluginBridge__;
3
+ }
4
+ function missingBridgeValueError(name) {
5
+ return new Error(`Paperclip plugin UI runtime is not initialized for "${name}". ` +
6
+ 'Ensure the host loaded the plugin bridge before rendering this UI module.');
7
+ }
8
+ export function getSdkUiRuntimeValue(name) {
9
+ const value = getBridgeRegistry()?.sdkUi?.[name];
10
+ if (value === undefined) {
11
+ throw missingBridgeValueError(name);
12
+ }
13
+ return value;
14
+ }
15
+ export function renderSdkUiComponent(name, props) {
16
+ const registry = getBridgeRegistry();
17
+ const component = registry?.sdkUi?.[name];
18
+ if (component === undefined) {
19
+ throw missingBridgeValueError(name);
20
+ }
21
+ const createElement = registry?.react?.createElement;
22
+ if (typeof createElement === "function") {
23
+ return createElement(component, props);
24
+ }
25
+ if (typeof component === "function") {
26
+ return component(props);
27
+ }
28
+ throw new Error(`Paperclip plugin UI component "${name}" is not callable`);
29
+ }
30
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/ui/runtime.ts"],"names":[],"mappings":"AAWA,SAAS,iBAAiB;IACxB,OAAQ,UAA2B,CAAC,yBAAyB,CAAC;AAChE,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAY;IAC3C,OAAO,IAAI,KAAK,CACd,uDAAuD,IAAI,KAAK;QAC9D,2EAA2E,CAC9E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAI,IAAY;IAClD,MAAM,KAAK,GAAG,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC;IACjD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,IAAY,EACZ,KAAa;IAEb,MAAM,QAAQ,GAAG,iBAAiB,EAAE,CAAC;IACrC,MAAM,SAAS,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC;IAC1C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,MAAM,aAAa,GAAG,QAAQ,EAAE,KAAK,EAAE,aAAa,CAAC;IACrD,IAAI,OAAO,aAAa,KAAK,UAAU,EAAE,CAAC;QACxC,OAAO,aAAa,CAAC,SAAS,EAAE,KAAgC,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,OAAO,SAAS,KAAK,UAAU,EAAE,CAAC;QACpC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,IAAI,KAAK,CAAC,kCAAkC,IAAI,mBAAmB,CAAC,CAAC;AAC7E,CAAC"}
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Paperclip plugin UI SDK — types for plugin frontend components.
3
+ *
4
+ * Plugin UI bundles import from `@paperclipai/plugin-sdk/ui`. This subpath
5
+ * provides the bridge hooks, component prop interfaces, and error types that
6
+ * plugin React components use to communicate with the host.
7
+ *
8
+ * Plugin UI bundles are loaded as ES modules into designated extension slots.
9
+ * All communication with the plugin worker goes through the host bridge — plugin
10
+ * components must NOT access host internals or call host APIs directly.
11
+ *
12
+ * @see PLUGIN_SPEC.md §19 — UI Extension Model
13
+ * @see PLUGIN_SPEC.md §19.0.1 — Plugin UI SDK
14
+ * @see PLUGIN_SPEC.md §29.2 — SDK Versioning
15
+ */
16
+ import type { PluginBridgeErrorCode } from "@paperclipai/shared";
17
+ import type { PluginLauncherRenderContextSnapshot, PluginModalBoundsRequest, PluginRenderCloseEvent } from "../protocol.js";
18
+ export type { PluginBridgeErrorCode, PluginLauncherBounds, PluginLauncherRenderEnvironment, } from "@paperclipai/shared";
19
+ export type { PluginLauncherRenderContextSnapshot, PluginModalBoundsRequest, PluginRenderCloseEvent, } from "../protocol.js";
20
+ /**
21
+ * Structured error returned by the bridge when a UI → worker call fails.
22
+ *
23
+ * Plugin components receive this in `usePluginData()` as the `error` field
24
+ * and may encounter it as a thrown value from `usePluginAction()`.
25
+ *
26
+ * Error codes:
27
+ * - `WORKER_UNAVAILABLE` — plugin worker is not running
28
+ * - `CAPABILITY_DENIED` — plugin lacks the required capability
29
+ * - `WORKER_ERROR` — worker returned an error from its handler
30
+ * - `TIMEOUT` — worker did not respond within the configured timeout
31
+ * - `UNKNOWN` — unexpected bridge-level failure
32
+ *
33
+ * @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
34
+ */
35
+ export interface PluginBridgeError {
36
+ /** Machine-readable error code. */
37
+ code: PluginBridgeErrorCode;
38
+ /** Human-readable error message. */
39
+ message: string;
40
+ /**
41
+ * Original error details from the worker, if available.
42
+ * Only present when `code === "WORKER_ERROR"`.
43
+ */
44
+ details?: unknown;
45
+ }
46
+ /**
47
+ * Read-only host context passed to every plugin component via `useHostContext()`.
48
+ *
49
+ * Plugin components use this to know which company, project, or entity is
50
+ * currently active so they can scope their data requests accordingly.
51
+ *
52
+ * @see PLUGIN_SPEC.md §19 — UI Extension Model
53
+ */
54
+ export interface PluginHostContext {
55
+ /** UUID of the currently active company, if any. */
56
+ companyId: string | null;
57
+ /** URL prefix for the current company (e.g. `"my-company"`). */
58
+ companyPrefix: string | null;
59
+ /** UUID of the currently active project, if any. */
60
+ projectId: string | null;
61
+ /** UUID of the current entity (for detail tab contexts), if any. */
62
+ entityId: string | null;
63
+ /** Type of the current entity (e.g. `"issue"`, `"agent"`). */
64
+ entityType: string | null;
65
+ /**
66
+ * UUID of the parent entity when rendering nested slots.
67
+ * For `commentAnnotation` slots this is the issue ID containing the comment.
68
+ */
69
+ parentEntityId?: string | null;
70
+ /** UUID of the current authenticated user. */
71
+ userId: string | null;
72
+ /** Runtime metadata for the host container currently rendering this plugin UI. */
73
+ renderEnvironment?: PluginRenderEnvironmentContext | null;
74
+ }
75
+ /**
76
+ * Async-capable callback invoked during a host-managed close lifecycle.
77
+ */
78
+ export type PluginRenderCloseHandler = (event: PluginRenderCloseEvent) => void | Promise<void>;
79
+ /**
80
+ * Close lifecycle hooks available when the plugin UI is rendered inside a
81
+ * host-managed launcher environment.
82
+ */
83
+ export interface PluginRenderCloseLifecycle {
84
+ /** Register a callback before the host closes the current environment. */
85
+ onBeforeClose?(handler: PluginRenderCloseHandler): () => void;
86
+ /** Register a callback after the host closes the current environment. */
87
+ onClose?(handler: PluginRenderCloseHandler): () => void;
88
+ }
89
+ /**
90
+ * Runtime information about the host container currently rendering a plugin UI.
91
+ */
92
+ export interface PluginRenderEnvironmentContext extends PluginLauncherRenderContextSnapshot {
93
+ /** Optional host callback for requesting new bounds while a modal is open. */
94
+ requestModalBounds?(request: PluginModalBoundsRequest): Promise<void>;
95
+ /** Optional close lifecycle callbacks for host-managed overlays. */
96
+ closeLifecycle?: PluginRenderCloseLifecycle | null;
97
+ }
98
+ /**
99
+ * Props passed to a plugin page component.
100
+ *
101
+ * A page is a full-page extension at `/plugins/:pluginId` or `/:company/plugins/:pluginId`.
102
+ *
103
+ * @see PLUGIN_SPEC.md §19.1 — Global Operator Routes
104
+ * @see PLUGIN_SPEC.md §19.2 — Company-Context Routes
105
+ */
106
+ export interface PluginPageProps {
107
+ /** The current host context. */
108
+ context: PluginHostContext;
109
+ }
110
+ /**
111
+ * Props passed to a plugin dashboard widget component.
112
+ *
113
+ * A dashboard widget is rendered as a card or section on the main dashboard.
114
+ *
115
+ * @see PLUGIN_SPEC.md §19.4 — Dashboard Widgets
116
+ */
117
+ export interface PluginWidgetProps {
118
+ /** The current host context. */
119
+ context: PluginHostContext;
120
+ }
121
+ /**
122
+ * Props passed to a plugin detail tab component.
123
+ *
124
+ * A detail tab is rendered as an additional tab on a project, issue, agent,
125
+ * goal, or run detail page.
126
+ *
127
+ * @see PLUGIN_SPEC.md §19.3 — Detail Tabs
128
+ */
129
+ export interface PluginDetailTabProps {
130
+ /** The current host context, always including `entityId` and `entityType`. */
131
+ context: PluginHostContext & {
132
+ entityId: string;
133
+ entityType: string;
134
+ };
135
+ }
136
+ /**
137
+ * Props passed to a plugin sidebar component.
138
+ *
139
+ * A sidebar entry adds a link or section to the application sidebar.
140
+ *
141
+ * @see PLUGIN_SPEC.md §19.5 — Sidebar Entries
142
+ */
143
+ export interface PluginSidebarProps {
144
+ /** The current host context. */
145
+ context: PluginHostContext;
146
+ }
147
+ /**
148
+ * Props passed to a plugin project sidebar item component.
149
+ *
150
+ * A project sidebar item is rendered **once per project** under that project's
151
+ * row in the sidebar Projects list. The host passes the current project's id
152
+ * in `context.entityId` and `context.entityType` is `"project"`.
153
+ *
154
+ * Use this slot to add a link (e.g. "Files", "Linear Sync") that navigates to
155
+ * the project detail with a plugin tab selected: `/projects/:projectRef?tab=plugin:key:slotId`.
156
+ *
157
+ * @see PLUGIN_SPEC.md §19.5.1 — Project sidebar items
158
+ */
159
+ export interface PluginProjectSidebarItemProps {
160
+ /** Host context plus entityId (project id) and entityType "project". */
161
+ context: PluginHostContext & {
162
+ entityId: string;
163
+ entityType: "project";
164
+ };
165
+ }
166
+ /**
167
+ * Props passed to a plugin comment annotation component.
168
+ *
169
+ * A comment annotation is rendered below each individual comment in the
170
+ * issue detail timeline. The host passes the comment ID as `entityId`
171
+ * and `"comment"` as `entityType`, plus the parent issue ID as
172
+ * `parentEntityId` so the plugin can scope data fetches to both.
173
+ *
174
+ * Use this slot to augment comments with parsed file links, sentiment
175
+ * badges, inline actions, or any per-comment metadata.
176
+ *
177
+ * @see PLUGIN_SPEC.md §19.6 — Comment Annotations
178
+ */
179
+ export interface PluginCommentAnnotationProps {
180
+ /** Host context with comment and parent issue identifiers. */
181
+ context: PluginHostContext & {
182
+ /** UUID of the comment being annotated. */
183
+ entityId: string;
184
+ /** Always `"comment"` for comment annotation slots. */
185
+ entityType: "comment";
186
+ /** UUID of the parent issue containing this comment. */
187
+ parentEntityId: string;
188
+ };
189
+ }
190
+ /**
191
+ * Props passed to a plugin comment context menu item component.
192
+ *
193
+ * A comment context menu item is rendered in a "more" dropdown menu on
194
+ * each comment in the issue detail timeline. The host passes the comment
195
+ * ID as `entityId` and `"comment"` as `entityType`, plus the parent
196
+ * issue ID as `parentEntityId`.
197
+ *
198
+ * Use this slot to add per-comment actions such as "Create sub-issue from
199
+ * comment", "Translate", "Flag for review", or any custom plugin action.
200
+ *
201
+ * @see PLUGIN_SPEC.md §19.7 — Comment Context Menu Items
202
+ */
203
+ export interface PluginCommentContextMenuItemProps {
204
+ /** Host context with comment and parent issue identifiers. */
205
+ context: PluginHostContext & {
206
+ /** UUID of the comment this menu item acts on. */
207
+ entityId: string;
208
+ /** Always `"comment"` for comment context menu item slots. */
209
+ entityType: "comment";
210
+ /** UUID of the parent issue containing this comment. */
211
+ parentEntityId: string;
212
+ };
213
+ }
214
+ /**
215
+ * Props passed to a plugin settings page component.
216
+ *
217
+ * Overrides the auto-generated JSON Schema form when the plugin declares
218
+ * a `settingsPage` UI slot. The component is responsible for reading and
219
+ * writing config through the bridge.
220
+ *
221
+ * @see PLUGIN_SPEC.md §19.8 — Plugin Settings UI
222
+ */
223
+ export interface PluginSettingsPageProps {
224
+ /** The current host context. */
225
+ context: PluginHostContext;
226
+ }
227
+ /**
228
+ * Return value of `usePluginData(key, params)`.
229
+ *
230
+ * Mirrors a standard async data-fetching hook pattern:
231
+ * exactly one of `data` or `error` is non-null at any time (unless `loading`).
232
+ *
233
+ * @template T The type of the data returned by the worker handler
234
+ *
235
+ * @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
236
+ */
237
+ export interface PluginDataResult<T = unknown> {
238
+ /** The data returned by the worker's `getData` handler. `null` while loading or on error. */
239
+ data: T | null;
240
+ /** `true` while the initial request or a refresh is in flight. */
241
+ loading: boolean;
242
+ /** Bridge error if the request failed. `null` on success or while loading. */
243
+ error: PluginBridgeError | null;
244
+ /**
245
+ * Manually trigger a data refresh.
246
+ * Useful for poll-based updates or post-action refreshes.
247
+ */
248
+ refresh(): void;
249
+ }
250
+ export type PluginToastTone = "info" | "success" | "warn" | "error";
251
+ export interface PluginToastAction {
252
+ label: string;
253
+ href: string;
254
+ }
255
+ export interface PluginToastInput {
256
+ id?: string;
257
+ dedupeKey?: string;
258
+ title: string;
259
+ body?: string;
260
+ tone?: PluginToastTone;
261
+ ttlMs?: number;
262
+ action?: PluginToastAction;
263
+ }
264
+ export type PluginToastFn = (input: PluginToastInput) => string | null;
265
+ /**
266
+ * Return value of `usePluginStream<T>(channel)`.
267
+ *
268
+ * Provides a growing array of events pushed from the plugin worker via SSE,
269
+ * plus connection status metadata.
270
+ *
271
+ * @template T The type of each event emitted by the worker
272
+ *
273
+ * @see PLUGIN_SPEC.md §19.8 — Real-Time Streaming
274
+ */
275
+ export interface PluginStreamResult<T = unknown> {
276
+ /** All events received so far, in arrival order. */
277
+ events: T[];
278
+ /** The most recently received event, or `null` if none yet. */
279
+ lastEvent: T | null;
280
+ /** `true` while the SSE connection is being established. */
281
+ connecting: boolean;
282
+ /** `true` once the SSE connection is open and receiving events. */
283
+ connected: boolean;
284
+ /** Error if the SSE connection failed or was interrupted. `null` otherwise. */
285
+ error: Error | null;
286
+ /** Close the SSE connection and stop receiving events. */
287
+ close(): void;
288
+ }
289
+ /**
290
+ * Return value of `usePluginAction(key)`.
291
+ *
292
+ * Returns an async function that, when called, sends an action request
293
+ * to the worker's `performAction` handler and returns the result.
294
+ *
295
+ * On failure, the async function throws a `PluginBridgeError`.
296
+ *
297
+ * @see PLUGIN_SPEC.md §19.7 — Error Propagation Through The Bridge
298
+ *
299
+ * @example
300
+ * ```tsx
301
+ * const resync = usePluginAction("resync");
302
+ * <button onClick={() => resync({ companyId }).catch(err => console.error(err))}>
303
+ * Resync Now
304
+ * </button>
305
+ * ```
306
+ */
307
+ export type PluginActionFn = (params?: Record<string, unknown>) => Promise<unknown>;
308
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ui/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Paperclip plugin UI SDK — types for plugin frontend components.
3
+ *
4
+ * Plugin UI bundles import from `@paperclipai/plugin-sdk/ui`. This subpath
5
+ * provides the bridge hooks, component prop interfaces, and error types that
6
+ * plugin React components use to communicate with the host.
7
+ *
8
+ * Plugin UI bundles are loaded as ES modules into designated extension slots.
9
+ * All communication with the plugin worker goes through the host bridge — plugin
10
+ * components must NOT access host internals or call host APIs directly.
11
+ *
12
+ * @see PLUGIN_SPEC.md §19 — UI Extension Model
13
+ * @see PLUGIN_SPEC.md §19.0.1 — Plugin UI SDK
14
+ * @see PLUGIN_SPEC.md §29.2 — SDK Versioning
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ui/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}