@jay-framework/jay-stack-cli 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/README.md +58 -0
- package/agent-kit-template/INSTRUCTIONS.md +120 -0
- package/agent-kit-template/cli-commands.md +229 -0
- package/agent-kit-template/contracts-and-plugins.md +293 -0
- package/agent-kit-template/jay-html-syntax.md +312 -0
- package/agent-kit-template/project-structure.md +242 -0
- package/agent-kit-template/routing.md +112 -0
- package/dist/index.d.ts +82 -2
- package/dist/index.js +2620 -629
- package/lib/vendors/README.md +510 -0
- package/lib/vendors/figma/README.md +396 -0
- package/package.json +13 -8
- package/test/vendors/figma/fixtures/README.md +164 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
# Jay Framework Vendors
|
|
2
|
+
|
|
3
|
+
This directory contains vendor implementations that convert design tool documents (Figma, Sketch, Adobe XD, etc.) into Jay HTML format.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Vendors are **contributed by the community** as part of the Jay Framework open-source project. Each vendor implements a simple interface to transform their native document format into Jay HTML.
|
|
8
|
+
|
|
9
|
+
## Directory Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
vendors/
|
|
13
|
+
├── types.ts # Vendor interface definition
|
|
14
|
+
├── registry.ts # Vendor registration system
|
|
15
|
+
├── index.ts # Public API
|
|
16
|
+
└── figma/ # Figma vendor implementation
|
|
17
|
+
└── index.ts
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How It Works
|
|
21
|
+
|
|
22
|
+
1. **Vendor Registration**: Vendors are statically imported in `registry.ts` and registered at server startup
|
|
23
|
+
2. **Export Flow**: When an editor plugin calls `export()`, the server:
|
|
24
|
+
- Saves the vendor document as `page.<vendorId>.json`
|
|
25
|
+
- Looks up the vendor by ID
|
|
26
|
+
- Calls `vendor.convertToJayHtml()` to generate Jay HTML
|
|
27
|
+
- Saves the result to `page.jay-html`
|
|
28
|
+
|
|
29
|
+
## Vendor Interface
|
|
30
|
+
|
|
31
|
+
Every vendor must implement this simple interface:
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
interface Vendor<TVendorDoc = any> {
|
|
35
|
+
vendorId: string;
|
|
36
|
+
|
|
37
|
+
convertToJayHtml(vendorDoc: TVendorDoc, pageUrl: string): Promise<string>;
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Parameters
|
|
42
|
+
|
|
43
|
+
- **`vendorDoc`**: The vendor's native document format (e.g., Figma SectionNode)
|
|
44
|
+
- **`pageUrl`**: The page route (e.g., `/home`, `/products`)
|
|
45
|
+
|
|
46
|
+
### Returns
|
|
47
|
+
|
|
48
|
+
A Promise that resolves to a **Jay HTML string**.
|
|
49
|
+
|
|
50
|
+
## Contributing a New Vendor
|
|
51
|
+
|
|
52
|
+
### Overview
|
|
53
|
+
|
|
54
|
+
When adding a new vendor, you need to:
|
|
55
|
+
|
|
56
|
+
1. Define the vendor document type in editor-protocol (single source of truth)
|
|
57
|
+
2. Implement the vendor converter (imports the type)
|
|
58
|
+
3. Register the vendor
|
|
59
|
+
|
|
60
|
+
### Step 1: Define Vendor Document Type
|
|
61
|
+
|
|
62
|
+
**Important**: The vendor document type is defined **ONCE** in the editor-protocol package. This is the single source of truth that both plugins and vendors import from.
|
|
63
|
+
|
|
64
|
+
#### A. Define in Editor Protocol
|
|
65
|
+
|
|
66
|
+
Edit `/packages/jay-stack/editor-protocol/lib/vendor-documents.ts`:
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
/**
|
|
70
|
+
* YourVendor Document Type
|
|
71
|
+
*
|
|
72
|
+
* The structure that YourVendor plugins must send when exporting.
|
|
73
|
+
* This is the single source of truth - both plugins and the vendor
|
|
74
|
+
* implementation import from here.
|
|
75
|
+
*/
|
|
76
|
+
export type YourVendorDocument = {
|
|
77
|
+
// Your vendor's serializable document structure
|
|
78
|
+
id: string;
|
|
79
|
+
name: string;
|
|
80
|
+
nodes: YourVendorNode[];
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export type YourVendorNode = {
|
|
84
|
+
id: string;
|
|
85
|
+
type: string;
|
|
86
|
+
// ... node properties
|
|
87
|
+
};
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
This allows **both plugin developers AND the vendor implementation** to import:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { YourVendorDocument } from '@jay-framework/editor-protocol';
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Step 2: Implement the Vendor
|
|
97
|
+
|
|
98
|
+
Create `your-vendor-id/index.ts` and **import** the type:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { Vendor } from '../types';
|
|
102
|
+
import type { YourVendorDocument } from '@jay-framework/editor-protocol';
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* YourVendor Implementation
|
|
106
|
+
*
|
|
107
|
+
* Imports YourVendorDocument from @jay-framework/editor-protocol,
|
|
108
|
+
* which is the single source of truth.
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
export const yourVendorVendor: Vendor<YourVendorDocument> = {
|
|
112
|
+
vendorId: 'your-vendor-id',
|
|
113
|
+
|
|
114
|
+
async convertToJayHtml(vendorDoc: YourVendorDocument, pageUrl: string): Promise<string> {
|
|
115
|
+
// Parse vendor document
|
|
116
|
+
const elements = parseVendorDocument(vendorDoc);
|
|
117
|
+
|
|
118
|
+
// Generate Jay HTML
|
|
119
|
+
const jayHtml = generateJayHtml(elements);
|
|
120
|
+
|
|
121
|
+
return jayHtml;
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
function parseVendorDocument(doc: YourVendorDocument) {
|
|
126
|
+
// Your parsing logic
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function generateJayHtml(elements: any[]): string {
|
|
131
|
+
// Your Jay HTML generation logic
|
|
132
|
+
return '<section>...</section>';
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Key Points:**
|
|
137
|
+
|
|
138
|
+
- ✅ **Import the type** from `@jay-framework/editor-protocol`
|
|
139
|
+
- ✅ **No duplicate definitions** - there's only one source of truth
|
|
140
|
+
- ✅ **Use `import type`** for type-only imports (better for tree-shaking)
|
|
141
|
+
vendorId: 'your-vendor-id',
|
|
142
|
+
async convertToJayHtml(
|
|
143
|
+
vendorDoc: YourVendorDocument,
|
|
144
|
+
pageUrl: string,
|
|
145
|
+
): Promise<string> {
|
|
146
|
+
// Parse vendor document
|
|
147
|
+
const elements = parseVendorDocument(vendorDoc);
|
|
148
|
+
|
|
149
|
+
// Generate Jay HTML
|
|
150
|
+
const jayHtml = generateJayHtml(elements);
|
|
151
|
+
|
|
152
|
+
return jayHtml;
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
function parseVendorDocument(doc: YourVendorDocument) {
|
|
158
|
+
// Your parsing logic
|
|
159
|
+
return [];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function generateJayHtml(elements: any[]): string {
|
|
163
|
+
// Your Jay HTML generation logic
|
|
164
|
+
return '<section>...</section>';
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
````
|
|
168
|
+
|
|
169
|
+
### Step 3: Create Vendor README
|
|
170
|
+
|
|
171
|
+
Create `your-vendor-id/README.md`:
|
|
172
|
+
|
|
173
|
+
```markdown
|
|
174
|
+
# YourVendor Vendor
|
|
175
|
+
|
|
176
|
+
Converts YourVendor documents to Jay HTML.
|
|
177
|
+
|
|
178
|
+
## For Plugin Developers
|
|
179
|
+
|
|
180
|
+
Import the document type from editor protocol:
|
|
181
|
+
|
|
182
|
+
\`\`\`typescript
|
|
183
|
+
import { YourVendorDocument } from '@jay-framework/editor-protocol';
|
|
184
|
+
|
|
185
|
+
const vendorDoc: YourVendorDocument = {
|
|
186
|
+
id: 'doc-123',
|
|
187
|
+
name: 'My Page',
|
|
188
|
+
nodes: [...]
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
await editorProtocol.export({
|
|
192
|
+
vendorId: 'your-vendor-id',
|
|
193
|
+
pageUrl: '/home',
|
|
194
|
+
vendorDoc
|
|
195
|
+
});
|
|
196
|
+
\`\`\`
|
|
197
|
+
|
|
198
|
+
## Document Structure
|
|
199
|
+
|
|
200
|
+
See the type definition in `@jay-framework/editor-protocol/lib/vendor-documents.ts`.
|
|
201
|
+
````
|
|
202
|
+
|
|
203
|
+
### Step 4: Register Your Vendor
|
|
204
|
+
|
|
205
|
+
Edit `registry.ts`:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// Add import
|
|
209
|
+
import { yourVendorVendor } from './your-vendor-id';
|
|
210
|
+
|
|
211
|
+
// Add to registry Map
|
|
212
|
+
const vendorRegistry = new Map<string, Vendor>([
|
|
213
|
+
[figmaVendor.vendorId, figmaVendor],
|
|
214
|
+
[yourVendorVendor.vendorId, yourVendorVendor], // Add your vendor here
|
|
215
|
+
]);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Step 5: Test Your Vendor
|
|
219
|
+
|
|
220
|
+
1. Build the package:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
cd /Users/noamsi/projects/jay/packages/jay-stack/stack-cli
|
|
224
|
+
npm run build
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
2. Start a dev server:
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
jay dev
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
3. Look for your vendor in the startup logs:
|
|
234
|
+
|
|
235
|
+
```
|
|
236
|
+
📦 Initializing vendors...
|
|
237
|
+
✅ Registered vendor: figma
|
|
238
|
+
✅ Registered vendor: your-vendor-id
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
4. Test export from your editor plugin
|
|
242
|
+
|
|
243
|
+
## Example: Figma Vendor
|
|
244
|
+
|
|
245
|
+
See `figma/index.ts` for a complete example implementation.
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
export const figmaVendor: Vendor<FigmaDocument> = {
|
|
249
|
+
vendorId: 'figma',
|
|
250
|
+
|
|
251
|
+
async convertToJayHtml(vendorDoc, pageUrl) {
|
|
252
|
+
console.log(`Converting Figma document for page: ${pageUrl}`);
|
|
253
|
+
|
|
254
|
+
// Parse Figma document
|
|
255
|
+
const elements = parseFigmaNodes(vendorDoc);
|
|
256
|
+
|
|
257
|
+
// Generate Jay HTML
|
|
258
|
+
const jayHtml = generateJayHtmlFromElements(elements);
|
|
259
|
+
|
|
260
|
+
return jayHtml;
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Best Practices
|
|
266
|
+
|
|
267
|
+
### 1. Single Source of Truth
|
|
268
|
+
|
|
269
|
+
**The vendor document type is defined ONCE** in `editor-protocol/lib/vendor-documents.ts`. Both plugins and vendors import from there:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
// ✅ CORRECT - Import from editor-protocol (single source of truth)
|
|
273
|
+
import type { MyVendorDocument } from '@jay-framework/editor-protocol';
|
|
274
|
+
|
|
275
|
+
export const myVendor: Vendor<MyVendorDocument> = {
|
|
276
|
+
// Implementation uses imported type
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// ❌ WRONG - Don't redefine the type locally
|
|
280
|
+
export type MyVendorDocument = {
|
|
281
|
+
/* ... */
|
|
282
|
+
}; // DON'T DO THIS
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Why?**
|
|
286
|
+
|
|
287
|
+
- **No duplication** - type is defined once
|
|
288
|
+
- **Always in sync** - impossible to have mismatches
|
|
289
|
+
- **Single update point** - change in one place updates everywhere
|
|
290
|
+
- **Follows DRY principle** - Don't Repeat Yourself
|
|
291
|
+
|
|
292
|
+
### 2. Use `type` for Vendor Documents, Not `interface`
|
|
293
|
+
|
|
294
|
+
In the editor-protocol, use `type` instead of `interface` for vendor documents:
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// ✅ CORRECT - Use 'type' for serializable data
|
|
298
|
+
export type MyVendorDocument = {
|
|
299
|
+
name: string;
|
|
300
|
+
nodes: MyVendorNode[];
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// ❌ WRONG - Don't use 'interface' for data sent over network
|
|
304
|
+
interface MyVendorDocument {
|
|
305
|
+
name: string;
|
|
306
|
+
nodes: MyVendorNode[];
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
**Why?**
|
|
311
|
+
|
|
312
|
+
- `type` is more explicit about being a data structure
|
|
313
|
+
- `type` makes it clear this is serializable data, not an API contract
|
|
314
|
+
- Follows TypeScript best practices for data transfer objects (DTOs)
|
|
315
|
+
|
|
316
|
+
### 3. Use `import type` for Type-Only Imports
|
|
317
|
+
|
|
318
|
+
When importing vendor document types, use `import type`:
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
// ✅ CORRECT - Type-only import (better for tree-shaking)
|
|
322
|
+
import type { MyVendorDocument } from '@jay-framework/editor-protocol';
|
|
323
|
+
|
|
324
|
+
// ⚠️ OK but not optimal - Regular import
|
|
325
|
+
import { MyVendorDocument } from '@jay-framework/editor-protocol';
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### 4. Type Safety
|
|
329
|
+
|
|
330
|
+
} catch (error) {
|
|
331
|
+
throw new Error(`Failed to generate Jay HTML: ${error.message}`);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
````
|
|
337
|
+
|
|
338
|
+
### 3. Logging
|
|
339
|
+
|
|
340
|
+
Add console logs to help with debugging:
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
async convertToJayHtml(vendorDoc, pageUrl) {
|
|
344
|
+
console.log(`Converting ${this.vendorId} document for ${pageUrl}`);
|
|
345
|
+
console.log(`Document has ${vendorDoc.nodes.length} nodes`);
|
|
346
|
+
|
|
347
|
+
const jayHtml = generateJayHtml(vendorDoc);
|
|
348
|
+
|
|
349
|
+
console.log(`Generated ${jayHtml.length} characters of Jay HTML`);
|
|
350
|
+
return jayHtml;
|
|
351
|
+
}
|
|
352
|
+
````
|
|
353
|
+
|
|
354
|
+
### 4. Semantic HTML
|
|
355
|
+
|
|
356
|
+
Generate proper semantic HTML:
|
|
357
|
+
|
|
358
|
+
```typescript
|
|
359
|
+
function generateJayHtml(doc: MyVendorDoc): string {
|
|
360
|
+
// Use semantic tags
|
|
361
|
+
let html = '<section>\n';
|
|
362
|
+
|
|
363
|
+
for (const node of doc.nodes) {
|
|
364
|
+
if (node.type === 'heading') {
|
|
365
|
+
html += ` <h1>${node.text}</h1>\n`;
|
|
366
|
+
} else if (node.type === 'paragraph') {
|
|
367
|
+
html += ` <p>${node.text}</p>\n`;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
html += '</section>';
|
|
372
|
+
return html;
|
|
373
|
+
}
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
### 5. Handle Edge Cases
|
|
377
|
+
|
|
378
|
+
Account for various document structures:
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
async convertToJayHtml(vendorDoc, pageUrl) {
|
|
382
|
+
// Handle empty document
|
|
383
|
+
if (!vendorDoc.nodes || vendorDoc.nodes.length === 0) {
|
|
384
|
+
return '<section><p>Empty page</p></section>';
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// Handle unsupported features gracefully
|
|
388
|
+
const supportedNodes = vendorDoc.nodes.filter(node =>
|
|
389
|
+
['text', 'frame', 'image'].includes(node.type)
|
|
390
|
+
);
|
|
391
|
+
|
|
392
|
+
return generateJayHtml(supportedNodes);
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
## Testing
|
|
397
|
+
|
|
398
|
+
### Unit Tests
|
|
399
|
+
|
|
400
|
+
Create unit tests for your vendor:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import { yourVendor } from './your-vendor-id';
|
|
404
|
+
|
|
405
|
+
describe('YourVendor', () => {
|
|
406
|
+
it('should convert basic document', async () => {
|
|
407
|
+
const doc = { nodes: [{ type: 'text', text: 'Hello' }] };
|
|
408
|
+
const html = await yourVendor.convertToJayHtml(doc, '/test');
|
|
409
|
+
|
|
410
|
+
expect(html).toContain('Hello');
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('should handle empty document', async () => {
|
|
414
|
+
const doc = { nodes: [] };
|
|
415
|
+
const html = await yourVendor.convertToJayHtml(doc, '/test');
|
|
416
|
+
|
|
417
|
+
expect(html).toBeTruthy();
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### Integration Tests
|
|
423
|
+
|
|
424
|
+
Test the full export flow:
|
|
425
|
+
|
|
426
|
+
1. Start dev server
|
|
427
|
+
2. Call export API from plugin
|
|
428
|
+
3. Verify `page.jay-html` is created
|
|
429
|
+
4. Verify HTML is valid
|
|
430
|
+
|
|
431
|
+
## Architecture
|
|
432
|
+
|
|
433
|
+
```
|
|
434
|
+
┌─────────────────┐
|
|
435
|
+
│ Editor Plugin │
|
|
436
|
+
│ (Figma/etc.) │
|
|
437
|
+
└────────┬────────┘
|
|
438
|
+
│ export({ vendorId, vendorDoc, pageUrl })
|
|
439
|
+
▼
|
|
440
|
+
┌─────────────────────────┐
|
|
441
|
+
│ Editor Protocol │
|
|
442
|
+
└────────┬────────────────┘
|
|
443
|
+
▼
|
|
444
|
+
┌─────────────────────────┐
|
|
445
|
+
│ onExport Handler │
|
|
446
|
+
│ 1. Save JSON │
|
|
447
|
+
│ 2. Lookup vendor │
|
|
448
|
+
│ 3. Call convertToJayHtml
|
|
449
|
+
└────────┬────────────────┘
|
|
450
|
+
▼
|
|
451
|
+
┌─────────────────────────┐
|
|
452
|
+
│ Vendor Registry │
|
|
453
|
+
│ getVendor(vendorId) │
|
|
454
|
+
└────────┬────────────────┘
|
|
455
|
+
▼
|
|
456
|
+
┌─────────────────────────┐
|
|
457
|
+
│ Your Vendor │
|
|
458
|
+
│ convertToJayHtml() │
|
|
459
|
+
│ Returns: string │
|
|
460
|
+
└────────┬────────────────┘
|
|
461
|
+
▼
|
|
462
|
+
┌─────────────────────────┐
|
|
463
|
+
│ Save to File System │
|
|
464
|
+
│ page.jay-html │
|
|
465
|
+
└─────────────────────────┘
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
## FAQ
|
|
469
|
+
|
|
470
|
+
### Q: Where should vendor code live?
|
|
471
|
+
|
|
472
|
+
**A:** In the Jay Framework repository under `packages/jay-stack/stack-cli/lib/vendors/`. Vendors contribute their implementations as part of the open-source project.
|
|
473
|
+
|
|
474
|
+
### Q: Can vendors have dependencies?
|
|
475
|
+
|
|
476
|
+
**A:** Yes, add them to `packages/jay-stack/stack-cli/package.json`.
|
|
477
|
+
|
|
478
|
+
### Q: How do I handle vendor-specific types?
|
|
479
|
+
|
|
480
|
+
**A:** Import types from your vendor's SDK (e.g., `@figma/plugin-typings`) or define your own interfaces.
|
|
481
|
+
|
|
482
|
+
### Q: What if conversion fails?
|
|
483
|
+
|
|
484
|
+
**A:** Throw an error with a descriptive message. The framework will catch it and return it in the export response.
|
|
485
|
+
|
|
486
|
+
### Q: Can I generate multiple files?
|
|
487
|
+
|
|
488
|
+
**A:** The current interface returns a single HTML string that gets saved to `page.jay-html`. If you need to generate additional files (like contracts), please open an issue to discuss the requirements.
|
|
489
|
+
|
|
490
|
+
### Q: How do I debug my vendor?
|
|
491
|
+
|
|
492
|
+
**A:** Add `console.log()` statements. They will appear in the dev server console when export is called.
|
|
493
|
+
|
|
494
|
+
## Contributing
|
|
495
|
+
|
|
496
|
+
1. Fork the Jay Framework repository
|
|
497
|
+
2. Create your vendor implementation
|
|
498
|
+
3. Add tests
|
|
499
|
+
4. Submit a pull request
|
|
500
|
+
5. Maintainers will review and merge
|
|
501
|
+
|
|
502
|
+
## Resources
|
|
503
|
+
|
|
504
|
+
- [Jay Framework Documentation](https://github.com/jay-framework/jay)
|
|
505
|
+
- [Editor Protocol Specification](../../editor-protocol/README.md)
|
|
506
|
+
- [Example: Figma Vendor](./figma/index.ts)
|
|
507
|
+
|
|
508
|
+
## License
|
|
509
|
+
|
|
510
|
+
Same as Jay Framework - check the root LICENSE file.
|