@contrail/extensions-sdk 1.0.18-5 → 1.0.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/extensions-sdk",
3
- "version": "1.0.18-5",
3
+ "version": "1.0.18",
4
4
  "description": "Client library for interfacing with VibeIQ's services and apps from an extension.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -1,183 +0,0 @@
1
- # Extension SDK Guide
2
-
3
- This guide explains how the Contrail Extensions SDK works, how the **host app** (Boards, Showcase, Plan) establishes the connection and passes context, and how **external developers** write extensions that consume that context.
4
-
5
- ---
6
-
7
- ## How context works
8
-
9
- The host sends the full `AppContext` **once** over the Penpal connection when it calls `init(context)` after the extension registers. The extension receives it during `registerAppExtension()` and can read it at any time via `getAppContext()`. There is no real-time context update mechanism; the extension only has the snapshot provided at initialization.
10
-
11
- ---
12
-
13
- ## For the Host App: Establishing the Connection
14
-
15
- The host app is responsible for loading the extension in an iframe, registering with the SDK, and passing the initial context.
16
-
17
- ### 1. Install and import the SDK
18
-
19
- ```ts
20
- import {
21
- AppExtensionHost,
22
- AppContext,
23
- AppExtensionMessage,
24
- AppExtensionMessageHandler,
25
- } from '@contrail/extensions-sdk'; // or your package name
26
- ```
27
-
28
- ### 2. Create the extension iframe
29
-
30
- Create an `HTMLIFrameElement` that loads your extension's entry URL (e.g. the built extension app). The extension script inside the iframe will call `AppExtension.registerAppExtension()` and use Penpal to connect to the parent.
31
-
32
- ### 3. Implement the message handler
33
-
34
- The host must implement `AppExtensionMessageHandler` to handle commands from the extension (e.g. close, custom commands):
35
-
36
- ```ts
37
- const messageHandler: AppExtensionMessageHandler = {
38
- async handleMessage(message: AppExtensionMessage): Promise<unknown> {
39
- switch (message.command) {
40
- case 'close':
41
- // Close the extension panel or navigate away
42
- break;
43
- // Handle other commands your extension sends via sendMessageToHost()
44
- default:
45
- break;
46
- }
47
- return undefined;
48
- },
49
- };
50
- ```
51
-
52
- ### 4. Build initial context and register with the extension
53
-
54
- Gather the `AppContext` (user, app type, board/plan/showcase snapshot, etc.) and call `registerHostWithAppExtension`. This establishes the Penpal connection and sends the context once via `init(context)`.
55
-
56
- ```ts
57
- const iframe = document.querySelector('iframe#extension') as HTMLIFrameElement;
58
- const context: AppContext = {
59
- user: currentUser,
60
- appContext: {
61
- vibeIQApp: VibeIQAppType.SHOWCASE,
62
- showcase: {
63
- id: showcase.id,
64
- name: showcase.name,
65
- orgId: showcase.orgId,
66
- currentFrame: activeFrame,
67
- frames: showcase.frames,
68
- // ... other fields
69
- },
70
- // board, plan, selectedElements, etc. as needed
71
- },
72
- };
73
-
74
- await AppExtensionHost.registerHostWithAppExtension(iframe, context, messageHandler);
75
- // Connection is ready. The extension has received context via init().
76
- ```
77
-
78
- The extension receives this context once at init. If the host needs to change what the extension sees (e.g. after navigating to a different showcase or frame), it would need to re-load or re-initialize the extension with new context; the SDK does not support pushing context updates after init.
79
-
80
- ---
81
-
82
- ## For Extension Developers: Writing an Extension
83
-
84
- Extensions run inside an iframe loaded by the host. They use the SDK to register with the host and read the context that was passed at initialization.
85
-
86
- ### 1. Install and import the SDK
87
-
88
- ```ts
89
- import {
90
- AppExtension,
91
- getAppContext,
92
- VibeIQAppType,
93
- } from '@contrail/extensions-sdk';
94
- ```
95
-
96
- ### 2. Register the extension on load
97
-
98
- Your extension entry point (e.g. main.tsx or main.ts) must call `AppExtension.registerAppExtension()` and wait for it. This sets up the Penpal connection and waits for the host to call `init(context)`.
99
-
100
- ```ts
101
- // In your extension's bootstrap (e.g. main.tsx)
102
- async function bootstrap() {
103
- await AppExtension.registerAppExtension();
104
- // Connection is ready. Initial context is set.
105
- // Mount your app (e.g. React root).
106
- }
107
-
108
- bootstrap().catch(console.error);
109
- ```
110
-
111
- Do not render your UI or depend on context until `registerAppExtension()` has resolved. The host calls `init(context)` once; that is the only time context is provided.
112
-
113
- ### 3. Read context
114
-
115
- Use `getAppContext()` to read the context snapshot that was passed at init:
116
-
117
- ```ts
118
- const context = getAppContext();
119
-
120
- if (context.appContext?.vibeIQApp === VibeIQAppType.SHOWCASE) {
121
- const showcase = context.appContext.showcase;
122
- const currentFrame = showcase?.currentFrame;
123
- const frames = showcase?.frames;
124
- }
125
-
126
- const selectedElements = context.appContext?.selectedElements ?? [];
127
- ```
128
-
129
- This context does not change after init. The extension only has the snapshot the host provided when the connection was established.
130
-
131
- ### 4. Showcase context
132
-
133
- When the host app is Showcase (or includes showcase in context), the host includes `showcase` in the `AppContext` passed to `registerHostWithAppExtension` / `init(context)`. The extension reads it via `getAppContext().appContext?.showcase` (e.g. `currentFrame`, `frames`). There is no API to receive showcase updates after init; the extension works with the initial snapshot.
134
-
135
- ### 5. Sending messages to the host
136
-
137
- Use the SDK APIs that talk to the host over the Penpal connection:
138
-
139
- ```ts
140
- // Close the extension (host handles in messageHandler)
141
- AppExtension.close();
142
- ```
143
-
144
- For app-specific commands (e.g. Board or Plan actions), use the SDK's app modules (e.g. `Boards`, `Plan`), which send messages to the host internally. Custom commands can be sent via those modules or whatever host-messaging API your SDK exposes; the host receives them in `messageHandler.handleMessage`.
145
-
146
- ### 6. Clipboard: bulk add items
147
-
148
- Extensions can request that the host bulk-add items to the user's clipboard by sending a message with a list of `{ itemId, projectItemId }`. The host dispatches its existing clipboard store action; there is no success or error response unless the host adds one later.
149
-
150
- **Board:** Use `BoardsApp.addItemsToClipboard(clipboardItems)`:
151
-
152
- ```ts
153
- import { BoardsApp } from '@contrail/extensions-sdk';
154
-
155
- BoardsApp.addItemsToClipboard([
156
- { itemId: 'item-1', projectItemId: 'proj-1' },
157
- { itemId: 'item-2', projectItemId: null },
158
- ]);
159
- ```
160
-
161
- You can also send the command explicitly with `command: BoardCommand.ADD_ITEMS_TO_CLIPBOARD` and `data: { clipboardItems }` via your extension's host message channel.
162
-
163
- **Showcase:** Use `ShowcaseApp.addItemsToClipboard(clipboardItems)`:
164
-
165
- ```ts
166
- import { ShowcaseApp } from '@contrail/extensions-sdk';
167
-
168
- ShowcaseApp.addItemsToClipboard([
169
- { itemId: 'item-1', projectItemId: 'proj-1' },
170
- { itemId: 'item-2', projectItemId: null },
171
- ]);
172
- ```
173
-
174
- You can also send the command explicitly with `command: ShowcaseCommand.ADD_ITEMS_TO_CLIPBOARD` and `data: { clipboardItems }` via your extension's host message channel.
175
-
176
- **Payload:** `clipboardItems: Array<{ itemId: string; projectItemId?: string | null }>`. The host normalizes and dispatches its existing clipboard action; no new API or store logic is required on the host.
177
-
178
- ---
179
-
180
- ## Summary
181
-
182
- - **Host:** Load extension iframe → build `AppContext` → call `AppExtensionHost.registerHostWithAppExtension(iframe, context, messageHandler)`. Context is sent once via `init(context)`; there is no API to push context updates after that.
183
- - **Extension:** Call `AppExtension.registerAppExtension()` at startup → use `getAppContext()` to read the context snapshot received at init. Showcase and other app data are available under `getAppContext().appContext` (e.g. `appContext.showcase`).