@jay-framework/editor-protocol 0.11.0 → 0.13.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.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,20 @@
1
+ interface ContractTag {
2
+ tag: string;
3
+ type: string | string[];
4
+ dataType?: string;
5
+ elementType?: string;
6
+ required?: boolean;
7
+ repeated?: boolean;
8
+ tags?: ContractTag[];
9
+ link?: string;
10
+ trackBy?: string;
11
+ async?: boolean;
12
+ phase?: string;
13
+ }
14
+ interface Contract {
15
+ name: string;
16
+ tags: ContractTag[];
17
+ }
1
18
  interface BaseMessage<TResponse extends BaseResponse = BaseResponse> {
2
19
  type: string;
3
20
  }
@@ -34,6 +51,17 @@ interface HasImageMessage extends BaseMessage<HasImageResponse> {
34
51
  interface GetProjectInfoMessage extends BaseMessage<GetProjectInfoResponse> {
35
52
  type: 'getProjectInfo';
36
53
  }
54
+ interface ExportMessage<TVendorDoc> extends BaseMessage<ExportResponse> {
55
+ type: 'export';
56
+ vendorId: string;
57
+ pageUrl: string;
58
+ vendorDoc: TVendorDoc;
59
+ }
60
+ interface ImportMessage<TVendorDoc> extends BaseMessage<ImportResponse<TVendorDoc>> {
61
+ type: 'import';
62
+ vendorId: string;
63
+ pageUrl: string;
64
+ }
37
65
  interface PublishResponse extends BaseResponse {
38
66
  type: 'publish';
39
67
  status: {
@@ -59,7 +87,7 @@ interface ProjectPage {
59
87
  name: string;
60
88
  url: string;
61
89
  filePath: string;
62
- contractSchema?: ContractSchema;
90
+ contract?: Contract;
63
91
  usedComponents: {
64
92
  appName: string;
65
93
  componentName: string;
@@ -71,55 +99,9 @@ interface ProjectComponent {
71
99
  filePath: string;
72
100
  contractPath?: string;
73
101
  }
74
- interface StaticContractDef {
75
- name: string;
76
- contract: string;
77
- component: string;
78
- description?: string;
79
- }
80
- interface DynamicContractDef {
81
- prefix: string;
82
- component: string;
83
- generator: string;
84
- }
85
- interface PluginManifest {
86
- name: string;
87
- module?: string;
88
- contracts?: StaticContractDef[];
89
- dynamic_contracts?: DynamicContractDef;
90
- }
91
102
  interface Plugin {
92
- manifest: PluginManifest;
93
- location: {
94
- type: 'local' | 'npm';
95
- path?: string;
96
- module?: string;
97
- };
98
- }
99
- interface InstalledApp {
100
103
  name: string;
101
- module: string;
102
- pages: {
103
- name: string;
104
- headless_components: {
105
- name: string;
106
- key: string;
107
- contract: string;
108
- slugs?: string[];
109
- }[];
110
- }[];
111
- components: {
112
- name: string;
113
- headless_components: {
114
- name: string;
115
- key: string;
116
- contract: string;
117
- }[];
118
- }[];
119
- config_map?: {
120
- display_name: string;
121
- key: string;
122
- }[];
104
+ contracts: Contract[];
123
105
  }
124
106
  interface ProjectInfo {
125
107
  name: string;
@@ -127,64 +109,49 @@ interface ProjectInfo {
127
109
  pages: ProjectPage[];
128
110
  components: ProjectComponent[];
129
111
  plugins: Plugin[];
130
- installedApps: InstalledApp[];
131
- installedAppContracts: {
132
- [appName: string]: InstalledAppContracts;
133
- };
134
112
  }
135
113
  interface GetProjectInfoResponse extends BaseResponse {
136
114
  type: 'getProjectInfo';
137
115
  info: ProjectInfo;
138
116
  }
139
- interface ContractTag {
140
- tag: string;
141
- type: string | string[];
142
- dataType?: string;
143
- elementType?: string;
144
- required?: boolean;
145
- repeated?: boolean;
146
- tags?: ContractTag[];
147
- link?: string;
117
+ interface ExportResponse extends BaseResponse {
118
+ type: 'export';
119
+ vendorSourcePath?: string;
120
+ jayHtmlPath?: string;
121
+ contractPath?: string;
122
+ warnings?: string[];
148
123
  }
149
- interface ContractSchema {
150
- name: string;
151
- tags: ContractTag[];
124
+ interface ImportResponse<TVendorDoc> extends BaseResponse {
125
+ type: 'import';
126
+ vendorDoc?: TVendorDoc;
152
127
  }
153
- interface InstalledAppContracts {
154
- appName: string;
155
- module: string;
156
- pages: Array<{
157
- pageName: string;
158
- contractSchema: ContractSchema;
159
- }>;
160
- components: Array<{
161
- componentName: string;
162
- contractSchema: ContractSchema;
163
- }>;
164
- }
165
- type EditorProtocolMessageTypes = PublishMessage | SaveImageMessage | HasImageMessage | GetProjectInfoMessage;
166
- type EditorProtocolResponseTypes = PublishResponse | SaveImageResponse | HasImageResponse | GetProjectInfoResponse;
167
- interface ProtocolMessage {
128
+ type EditorProtocolMessageTypes<TVendorDoc> = PublishMessage | SaveImageMessage | HasImageMessage | GetProjectInfoMessage | ExportMessage<TVendorDoc> | ImportMessage<TVendorDoc>;
129
+ type EditorProtocolResponseTypes<TVendorDoc> = PublishResponse | SaveImageResponse | HasImageResponse | GetProjectInfoResponse | ExportResponse | ImportResponse<TVendorDoc>;
130
+ interface ProtocolMessage<TVendorDoc> {
168
131
  id: string;
169
132
  timestamp: number;
170
- payload: EditorProtocolMessageTypes;
133
+ payload: EditorProtocolMessageTypes<TVendorDoc>;
171
134
  }
172
- interface ProtocolResponse {
135
+ interface ProtocolResponse<TVendorDoc> {
173
136
  id: string;
174
137
  timestamp: number;
175
- payload: EditorProtocolResponseTypes;
138
+ payload: EditorProtocolResponseTypes<TVendorDoc>;
176
139
  }
177
140
  interface EditorProtocol {
178
141
  publish(params: PublishMessage): Promise<PublishResponse>;
179
142
  saveImage(params: SaveImageMessage): Promise<SaveImageResponse>;
180
143
  hasImage(params: HasImageMessage): Promise<HasImageResponse>;
181
144
  getProjectInfo(params: GetProjectInfoMessage): Promise<GetProjectInfoResponse>;
145
+ export<TVendorDoc>(params: ExportMessage<TVendorDoc>): Promise<ExportResponse>;
146
+ import<TVendorDoc>(params: ImportMessage<TVendorDoc>): Promise<ImportResponse<TVendorDoc>>;
182
147
  }
183
148
  interface DevServerProtocol {
184
149
  onPublish(callback: EditorProtocol['publish']): void;
185
150
  onSaveImage(callback: EditorProtocol['saveImage']): void;
186
151
  onHasImage(callback: EditorProtocol['hasImage']): void;
187
152
  onGetProjectInfo(callback: EditorProtocol['getProjectInfo']): void;
153
+ onExport(callback: EditorProtocol['export']): void;
154
+ onImport(callback: EditorProtocol['import']): void;
188
155
  }
189
156
 
190
157
  interface EditorConfig {
@@ -206,11 +173,150 @@ declare function createPublishMessage(pages?: PublishMessage['pages'], component
206
173
  declare function createSaveImageMessage(imageId: string, imageData: string): SaveImageMessage;
207
174
  declare function createHasImageMessage(imageId: string): HasImageMessage;
208
175
  declare function createGetProjectInfoMessage(): GetProjectInfoMessage;
176
+ declare function createExportMessage<TVendorDoc>(vendorId: string, pageUrl: string, vendorDoc: TVendorDoc): ExportMessage<TVendorDoc>;
177
+ declare function createImportMessage<TVendorDoc>(vendorId: string, pageUrl: string): ImportMessage<TVendorDoc>;
209
178
  declare function createPublishResponse(status: PublishResponse['status']): PublishResponse;
210
179
  declare function createSaveImageResponse(success: boolean, imageUrl?: string, error?: string): SaveImageResponse;
211
180
  declare function createHasImageResponse(exists: boolean, imageUrl?: string): HasImageResponse;
212
181
  declare function createGetProjectInfoResponse(info: ProjectInfo, success?: boolean, error?: string): GetProjectInfoResponse;
213
- declare function createProtocolMessage(payload: EditorProtocolMessageTypes): ProtocolMessage;
214
- declare function createProtocolResponse(id: string, payload: EditorProtocolResponseTypes): ProtocolResponse;
182
+ declare function createExportResponse(success: boolean, vendorSourcePath?: string, jayHtmlPath?: string, contractPath?: string, warnings?: string[], error?: string): ExportResponse;
183
+ declare function createImportResponse<TVendorDoc>(success: boolean, vendorDoc?: TVendorDoc, error?: string): ImportResponse<TVendorDoc>;
184
+ declare function createProtocolMessage<TVendorDoc>(payload: EditorProtocolMessageTypes<TVendorDoc>): ProtocolMessage<TVendorDoc>;
185
+ declare function createProtocolResponse<TVendorDoc>(id: string, payload: EditorProtocolResponseTypes<TVendorDoc>): ProtocolResponse<TVendorDoc>;
186
+
187
+ /**
188
+ * Figma Vendor Document Type
189
+ *
190
+ * A JSON-compatible representation of Figma nodes that can be safely
191
+ * transmitted over the protocol.
192
+ *
193
+ * @example
194
+ * ```typescript
195
+ * import { FigmaVendorDocument } from '@jay-framework/editor-protocol';
196
+ *
197
+ * const sectionNode = figma.currentPage.selection[0];
198
+ * const vendorDoc: FigmaVendorDocument = serializeNode(sectionNode);
199
+ *
200
+ * await editorProtocol.export({
201
+ * vendorId: 'figma',
202
+ * pageUrl: '/home',
203
+ * vendorDoc
204
+ * });
205
+ * ```
206
+ */
207
+ type FigmaVendorDocument = {
208
+ id: string;
209
+ name: string;
210
+ type: string;
211
+ visible?: boolean;
212
+ locked?: boolean;
213
+ parentId?: string;
214
+ children?: FigmaVendorDocument[];
215
+ x?: number;
216
+ y?: number;
217
+ width?: number;
218
+ height?: number;
219
+ pluginData?: {
220
+ [key: string]: string;
221
+ };
222
+ componentPropertyDefinitions?: {
223
+ [propertyName: string]: {
224
+ type: 'VARIANT' | 'BOOLEAN' | 'TEXT' | 'INSTANCE_SWAP';
225
+ variantOptions?: string[];
226
+ defaultValue?: string | boolean;
227
+ };
228
+ };
229
+ componentSetId?: string;
230
+ componentSetName?: string;
231
+ mainComponentId?: string;
232
+ mainComponentName?: string;
233
+ componentProperties?: any;
234
+ variantProperties?: {
235
+ [propertyName: string]: string;
236
+ };
237
+ variants?: FigmaVendorDocument[];
238
+ characters?: string;
239
+ fontName?: {
240
+ family: string;
241
+ style: string;
242
+ } | 'MIXED';
243
+ fontSize?: number | 'MIXED';
244
+ fontWeight?: number | 'MIXED';
245
+ textAlignHorizontal?: 'LEFT' | 'CENTER' | 'RIGHT' | 'JUSTIFIED';
246
+ textAlignVertical?: 'TOP' | 'CENTER' | 'BOTTOM';
247
+ letterSpacing?: {
248
+ value: number;
249
+ unit: 'PIXELS' | 'PERCENT';
250
+ };
251
+ lineHeight?: {
252
+ value: number;
253
+ unit: 'PIXELS' | 'PERCENT' | 'AUTO';
254
+ } | {
255
+ unit: 'AUTO';
256
+ };
257
+ textDecoration?: 'NONE' | 'UNDERLINE' | 'STRIKETHROUGH';
258
+ textCase?: 'ORIGINAL' | 'UPPER' | 'LOWER' | 'TITLE';
259
+ textTruncation?: 'DISABLED' | 'ENDING';
260
+ maxLines?: number;
261
+ maxWidth?: number;
262
+ textAutoResize?: 'NONE' | 'WIDTH_AND_HEIGHT' | 'HEIGHT' | 'TRUNCATE';
263
+ hasMissingFont?: boolean;
264
+ hyperlinks?: Array<{
265
+ start: number;
266
+ end: number;
267
+ url: string;
268
+ }>;
269
+ fills?: any[];
270
+ strokes?: any[];
271
+ effects?: any[];
272
+ cornerRadius?: number | 'MIXED';
273
+ topLeftRadius?: number;
274
+ topRightRadius?: number;
275
+ bottomLeftRadius?: number;
276
+ bottomRightRadius?: number;
277
+ strokeWeight?: number;
278
+ strokeTopWeight?: number;
279
+ strokeBottomWeight?: number;
280
+ strokeLeftWeight?: number;
281
+ strokeRightWeight?: number;
282
+ dashPattern?: number[];
283
+ layoutMode?: 'NONE' | 'HORIZONTAL' | 'VERTICAL';
284
+ primaryAxisAlignItems?: 'MIN' | 'CENTER' | 'MAX' | 'SPACE_BETWEEN';
285
+ counterAxisAlignItems?: 'MIN' | 'CENTER' | 'MAX';
286
+ itemSpacing?: number;
287
+ paddingLeft?: number;
288
+ paddingRight?: number;
289
+ paddingTop?: number;
290
+ paddingBottom?: number;
291
+ layoutPositioning?: 'AUTO' | 'ABSOLUTE';
292
+ layoutSizingHorizontal?: 'FIXED' | 'HUG' | 'FILL';
293
+ layoutSizingVertical?: 'FIXED' | 'HUG' | 'FILL';
294
+ layoutGrow?: number;
295
+ layoutAlign?: 'MIN' | 'CENTER' | 'MAX' | 'STRETCH';
296
+ layoutWrap?: 'NO_WRAP' | 'WRAP';
297
+ clipsContent?: boolean;
298
+ overflowDirection?: 'NONE' | 'HORIZONTAL' | 'VERTICAL' | 'BOTH';
299
+ scrollBehavior?: 'SCROLLS' | 'FIXED';
300
+ parentLayoutMode?: 'NONE' | 'HORIZONTAL' | 'VERTICAL';
301
+ parentType?: string;
302
+ parentOverflowDirection?: 'NONE' | 'HORIZONTAL' | 'VERTICAL' | 'BOTH';
303
+ parentNumberOfFixedChildren?: number;
304
+ parentChildIndex?: number;
305
+ opacity?: number;
306
+ rotation?: number;
307
+ vectorPaths?: Array<{
308
+ windingRule: 'NONZERO' | 'EVENODD';
309
+ data: string;
310
+ }>;
311
+ fillGeometry?: Array<{
312
+ windingRule: 'NONZERO' | 'EVENODD';
313
+ data: string;
314
+ }>;
315
+ strokeGeometry?: Array<{
316
+ windingRule: 'NONZERO' | 'EVENODD';
317
+ data: string;
318
+ }>;
319
+ [key: string]: any;
320
+ };
215
321
 
216
- export { type BaseMessage, type BaseResponse, type ConnectionState, type ContractSchema, type ContractTag, type DevServerProtocol, type DynamicContractDef, type EditorConfig, type EditorProtocol, type EditorProtocolMessageTypes, type EditorProtocolResponseTypes, type GetProjectInfoMessage, type GetProjectInfoResponse, type HasImageMessage, type HasImageResponse, type InstalledApp, type InstalledAppContracts, type Plugin, type PluginManifest, type PortDiscoveryResponse, type ProjectComponent, type ProjectInfo, type ProjectPage, type ProtocolMessage, type ProtocolResponse, type PublishComponent, type PublishMessage, type PublishPage, type PublishResponse, type PublishStatus, type SaveImageMessage, type SaveImageResponse, type StaticContractDef, createGetProjectInfoMessage, createGetProjectInfoResponse, createHasImageMessage, createHasImageResponse, createProtocolMessage, createProtocolResponse, createPublishMessage, createPublishResponse, createSaveImageMessage, createSaveImageResponse };
322
+ export { type BaseMessage, type BaseResponse, type ConnectionState, type Contract, type ContractTag, type DevServerProtocol, type EditorConfig, type EditorProtocol, type EditorProtocolMessageTypes, type EditorProtocolResponseTypes, type ExportMessage, type ExportResponse, type FigmaVendorDocument, type GetProjectInfoMessage, type GetProjectInfoResponse, type HasImageMessage, type HasImageResponse, type ImportMessage, type ImportResponse, type Plugin, type PortDiscoveryResponse, type ProjectComponent, type ProjectInfo, type ProjectPage, type ProtocolMessage, type ProtocolResponse, type PublishComponent, type PublishMessage, type PublishPage, type PublishResponse, type PublishStatus, type SaveImageMessage, type SaveImageResponse, createExportMessage, createExportResponse, createGetProjectInfoMessage, createGetProjectInfoResponse, createHasImageMessage, createHasImageResponse, createImportMessage, createImportResponse, createProtocolMessage, createProtocolResponse, createPublishMessage, createPublishResponse, createSaveImageMessage, createSaveImageResponse };
package/dist/index.js CHANGED
@@ -23,6 +23,21 @@ function createGetProjectInfoMessage() {
23
23
  type: "getProjectInfo"
24
24
  };
25
25
  }
26
+ function createExportMessage(vendorId, pageUrl, vendorDoc) {
27
+ return {
28
+ type: "export",
29
+ vendorId,
30
+ pageUrl,
31
+ vendorDoc
32
+ };
33
+ }
34
+ function createImportMessage(vendorId, pageUrl) {
35
+ return {
36
+ type: "import",
37
+ vendorId,
38
+ pageUrl
39
+ };
40
+ }
26
41
  function createPublishResponse(status) {
27
42
  return {
28
43
  type: "publish",
@@ -54,6 +69,25 @@ function createGetProjectInfoResponse(info, success = true, error) {
54
69
  error
55
70
  };
56
71
  }
72
+ function createExportResponse(success, vendorSourcePath, jayHtmlPath, contractPath, warnings, error) {
73
+ return {
74
+ type: "export",
75
+ success,
76
+ vendorSourcePath,
77
+ jayHtmlPath,
78
+ contractPath,
79
+ warnings,
80
+ error
81
+ };
82
+ }
83
+ function createImportResponse(success, vendorDoc, error) {
84
+ return {
85
+ type: "import",
86
+ success,
87
+ vendorDoc,
88
+ error
89
+ };
90
+ }
57
91
  let messageIdCounter = 0;
58
92
  function generateMessageId() {
59
93
  const timestamp = Date.now();
@@ -75,10 +109,14 @@ function createProtocolResponse(id, payload) {
75
109
  };
76
110
  }
77
111
  export {
112
+ createExportMessage,
113
+ createExportResponse,
78
114
  createGetProjectInfoMessage,
79
115
  createGetProjectInfoResponse,
80
116
  createHasImageMessage,
81
117
  createHasImageResponse,
118
+ createImportMessage,
119
+ createImportResponse,
82
120
  createProtocolMessage,
83
121
  createProtocolResponse,
84
122
  createPublishMessage,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jay-framework/editor-protocol",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -23,9 +23,12 @@
23
23
  "test": ":",
24
24
  "test:watch": ":"
25
25
  },
26
+ "dependencies": {
27
+ "@jay-framework/compiler-shared": "^0.13.0"
28
+ },
26
29
  "devDependencies": {
27
- "@jay-framework/dev-environment": "^0.11.0",
28
- "@jay-framework/jay-cli": "^0.11.0",
30
+ "@jay-framework/dev-environment": "^0.13.0",
31
+ "@jay-framework/jay-cli": "^0.13.0",
29
32
  "@types/node": "^22.15.21",
30
33
  "rimraf": "^5.0.5",
31
34
  "tsup": "^8.0.1",
package/readme.md CHANGED
@@ -25,12 +25,16 @@ import {
25
25
  createPublishMessage,
26
26
  createSaveImageMessage,
27
27
  createHasImageMessage,
28
+ createExportMessage,
29
+ createImportMessage,
28
30
  createProtocolMessage,
29
31
  } from '@jay-framework/editor-protocol';
30
32
 
31
33
  // Use in editor applications
32
34
  const editor: EditorProtocol = {
33
35
  publish: async (params) => ({
36
+ type: 'publish',
37
+ success: true,
34
38
  status: [
35
39
  {
36
40
  success: true,
@@ -39,8 +43,40 @@ const editor: EditorProtocol = {
39
43
  },
40
44
  ],
41
45
  }),
42
- saveImage: async (params) => ({ success: true, imageUrl: '/assets/image.png' }),
43
- hasImage: async (params) => ({ exists: true, imageUrl: '/assets/image.png' }),
46
+ saveImage: async (params) => ({
47
+ type: 'saveImage',
48
+ success: true,
49
+ imageUrl: '/assets/image.png',
50
+ }),
51
+ hasImage: async (params) => ({
52
+ type: 'hasImage',
53
+ success: true,
54
+ exists: true,
55
+ imageUrl: '/assets/image.png',
56
+ }),
57
+ getProjectInfo: async (params) => ({
58
+ type: 'getProjectInfo',
59
+ success: true,
60
+ info: {
61
+ name: 'My Project',
62
+ localPath: '/path/to/project',
63
+ pages: [],
64
+ components: [],
65
+ plugins: [],
66
+ },
67
+ }),
68
+ export: async (params) => ({
69
+ type: 'export',
70
+ success: true,
71
+ vendorSourcePath: '/pages/home/page.figma.json',
72
+ }),
73
+ import: async (params) => ({
74
+ type: 'import',
75
+ success: true,
76
+ vendorDoc: {
77
+ /* vendor document */
78
+ },
79
+ }),
44
80
  };
45
81
 
46
82
  // Use in dev servers
@@ -48,6 +84,9 @@ const server: DevServerProtocol = {
48
84
  onPublish: (callback) => {},
49
85
  onSaveImage: (callback) => {},
50
86
  onHasImage: (callback) => {},
87
+ onGetProjectInfo: (callback) => {},
88
+ onExport: (callback) => {},
89
+ onImport: (callback) => {},
51
90
  };
52
91
 
53
92
  // Create messages using constructors
@@ -91,6 +130,9 @@ const protocolMessage = createProtocolMessage(publishMessage);
91
130
  - `createPublishMessage(pages?, components?)` - Creates a publish message with optional pages and components
92
131
  - `createSaveImageMessage(imageId, imageData)` - Creates a save image message
93
132
  - `createHasImageMessage(imageId)` - Creates a has image message
133
+ - `createGetProjectInfoMessage()` - Creates a get project info message
134
+ - `createExportMessage<TVendorDoc>(vendorId, pageUrl, vendorDoc)` - Creates an export message with vendor document
135
+ - `createImportMessage<TVendorDoc>(vendorId, pageUrl)` - Creates an import message to retrieve vendor document
94
136
  - `createProtocolMessage(payload)` - Creates a protocol message wrapper with auto-generated timestamp-based ID
95
137
 
96
138
  ### Response Constructors
@@ -98,6 +140,9 @@ const protocolMessage = createProtocolMessage(publishMessage);
98
140
  - `createPublishResponse(status)` - Creates a publish response
99
141
  - `createSaveImageResponse(success, imageUrl?, error?)` - Creates a save image response
100
142
  - `createHasImageResponse(exists, imageUrl?)` - Creates a has image response
143
+ - `createGetProjectInfoResponse(info, success?, error?)` - Creates a get project info response
144
+ - `createExportResponse(success, vendorSourcePath?, jayHtmlPath?, contractPath?, warnings?, error?)` - Creates an export response
145
+ - `createImportResponse<TVendorDoc>(success, vendorDoc?, error?)` - Creates an import response with vendor document
101
146
  - `createProtocolResponse(id, payload)` - Creates a protocol response wrapper with timestamp
102
147
 
103
148
  ## Protocol Operations
@@ -121,6 +166,81 @@ Saves base64 image data to the dev server's public assets.
121
166
 
122
167
  Checks if an image with the given ID already exists on the server.
123
168
 
169
+ ### Get Project Info
170
+
171
+ Retrieves comprehensive project information including pages, components, and installed plugins with their contracts.
172
+
173
+ ### Export
174
+
175
+ Exports a vendor-specific document (e.g., Figma, Wix) to the dev server at a specific page route. The document is saved as `page.<vendorId>.json` alongside the page's jay-html file.
176
+
177
+ **Use case**: When a designer exports a Figma design to Jay, the original Figma document can be saved so it can be re-imported later.
178
+
179
+ **Example:**
180
+
181
+ ```typescript
182
+ import { createExportMessage } from '@jay-framework/editor-protocol';
183
+
184
+ interface FigmaDocument {
185
+ nodeId: string;
186
+ name: string;
187
+ layers: any[];
188
+ }
189
+
190
+ const figmaDoc: FigmaDocument = {
191
+ nodeId: 'abc123',
192
+ name: 'Homepage',
193
+ layers: [
194
+ /* ... */
195
+ ],
196
+ };
197
+
198
+ const exportMessage = createExportMessage<FigmaDocument>(
199
+ 'figma', // vendorId
200
+ '/home', // pageUrl
201
+ figmaDoc, // vendor document
202
+ );
203
+
204
+ const response = await editorClient.export(exportMessage);
205
+ // File saved at: src/pages/home/page.figma.json
206
+ ```
207
+
208
+ ### Import
209
+
210
+ Imports a previously exported vendor document from the dev server for a specific page route.
211
+
212
+ **Use case**: When reopening a page in Figma, retrieve the original Figma document to maintain design history and node references.
213
+
214
+ **Example:**
215
+
216
+ ```typescript
217
+ import { createImportMessage } from '@jay-framework/editor-protocol';
218
+
219
+ interface FigmaDocument {
220
+ nodeId: string;
221
+ name: string;
222
+ layers: any[];
223
+ }
224
+
225
+ const importMessage = createImportMessage<FigmaDocument>(
226
+ 'figma', // vendorId
227
+ '/home', // pageUrl
228
+ );
229
+
230
+ const response = await editorClient.import(importMessage);
231
+ if (response.success && response.vendorDoc) {
232
+ const figmaDoc = response.vendorDoc;
233
+ // Restore Figma design from saved document
234
+ console.log('Restored Figma node:', figmaDoc.nodeId);
235
+ }
236
+ ```
237
+
238
+ **File naming convention**: Vendor documents are saved as `page.<vendorId>.json` in the same directory as the page's jay-html file. For example:
239
+
240
+ - `/src/pages/home/page.jay-html`
241
+ - `/src/pages/home/page.figma.json`
242
+ - `/src/pages/home/page.wix.json`
243
+
124
244
  ## Contract Publishing
125
245
 
126
246
  Contract files enable headless component support by defining the component's data interface and refs structure. When publishing components or pages, you can optionally include contract content: