@abraca/dabra 1.8.2 → 1.9.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/dist/abracadabra-provider.cjs +125 -0
- package/dist/abracadabra-provider.cjs.map +1 -1
- package/dist/abracadabra-provider.esm.js +125 -0
- package/dist/abracadabra-provider.esm.js.map +1 -1
- package/dist/index.d.ts +60 -1
- package/package.json +1 -1
- package/src/ContentManager.ts +160 -0
- package/src/DocConverters.ts +1707 -0
- package/src/DocTypes.ts +618 -0
- package/src/DocUtils.ts +89 -0
- package/src/DocumentManager.ts +342 -0
- package/src/E2EAbracadabraProvider.ts +189 -0
- package/src/FileBlobStore.ts +10 -0
- package/src/MetaManager.ts +100 -0
- package/src/TreeManager.ts +429 -0
- package/src/types.ts +8 -0
package/src/DocTypes.ts
ADDED
|
@@ -0,0 +1,618 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical type definitions for Abracadabra document tree entries, page
|
|
3
|
+
* metadata, and the static page-type catalog.
|
|
4
|
+
*
|
|
5
|
+
* These types were previously scattered across `mcp/converters/types.ts` and
|
|
6
|
+
* `mcp/converters/page-types.ts`. By living in the provider package they
|
|
7
|
+
* become first-class SDK types that any consumer (`@abraca/dabra`) can import
|
|
8
|
+
* directly, removing the need for fragile relative-path re-exports.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ── Meta field primitives ────────────────────────────────────────────────────
|
|
12
|
+
|
|
13
|
+
export type MetaFieldType
|
|
14
|
+
= | 'datetimerange'
|
|
15
|
+
| 'daterange'
|
|
16
|
+
| 'timerange'
|
|
17
|
+
| 'datetime'
|
|
18
|
+
| 'date'
|
|
19
|
+
| 'time'
|
|
20
|
+
| 'slider'
|
|
21
|
+
| 'number'
|
|
22
|
+
| 'toggle'
|
|
23
|
+
| 'select'
|
|
24
|
+
| 'multiselect'
|
|
25
|
+
| 'colorPreset'
|
|
26
|
+
| 'colorPicker'
|
|
27
|
+
| 'location'
|
|
28
|
+
| 'icon'
|
|
29
|
+
| 'textarea'
|
|
30
|
+
| 'url'
|
|
31
|
+
| 'rating'
|
|
32
|
+
| 'tags'
|
|
33
|
+
| 'members'
|
|
34
|
+
|
|
35
|
+
export interface UserMetaField {
|
|
36
|
+
id: string
|
|
37
|
+
type: string
|
|
38
|
+
label?: string
|
|
39
|
+
key?: string
|
|
40
|
+
latKey?: string
|
|
41
|
+
lngKey?: string
|
|
42
|
+
startKey?: string
|
|
43
|
+
endKey?: string
|
|
44
|
+
allDayKey?: string
|
|
45
|
+
presets?: string[]
|
|
46
|
+
options?: string[]
|
|
47
|
+
min?: number
|
|
48
|
+
max?: number
|
|
49
|
+
step?: number
|
|
50
|
+
unit?: string
|
|
51
|
+
default?: boolean
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── PageMeta — the full union of all metadata fields ─────────────────────────
|
|
55
|
+
|
|
56
|
+
export interface PageMeta extends Record<string, unknown> {
|
|
57
|
+
// Universal display
|
|
58
|
+
color?: string
|
|
59
|
+
icon?: string
|
|
60
|
+
subtitle?: string
|
|
61
|
+
note?: string
|
|
62
|
+
|
|
63
|
+
// Datetime
|
|
64
|
+
datetimeStart?: string
|
|
65
|
+
datetimeEnd?: string
|
|
66
|
+
allDay?: boolean
|
|
67
|
+
dateStart?: string
|
|
68
|
+
dateEnd?: string
|
|
69
|
+
timeStart?: string
|
|
70
|
+
timeEnd?: string
|
|
71
|
+
dateTaken?: string
|
|
72
|
+
|
|
73
|
+
// Task/status
|
|
74
|
+
checked?: boolean
|
|
75
|
+
priority?: number
|
|
76
|
+
status?: string
|
|
77
|
+
taskProgress?: number
|
|
78
|
+
rating?: number
|
|
79
|
+
tags?: string[]
|
|
80
|
+
members?: { id: string; label: string }[]
|
|
81
|
+
|
|
82
|
+
// Contact/value
|
|
83
|
+
url?: string
|
|
84
|
+
email?: string
|
|
85
|
+
phone?: string
|
|
86
|
+
number?: number
|
|
87
|
+
unit?: string
|
|
88
|
+
|
|
89
|
+
// Cover image
|
|
90
|
+
coverUploadId?: string
|
|
91
|
+
coverDocId?: string
|
|
92
|
+
coverMimeType?: string
|
|
93
|
+
|
|
94
|
+
// Geo/Map
|
|
95
|
+
geoType?: 'marker' | 'line' | 'measure'
|
|
96
|
+
geoLat?: number
|
|
97
|
+
geoLng?: number
|
|
98
|
+
geoDescription?: string
|
|
99
|
+
|
|
100
|
+
// Dashboard
|
|
101
|
+
deskX?: number
|
|
102
|
+
deskY?: number
|
|
103
|
+
deskZ?: number
|
|
104
|
+
deskMode?: string
|
|
105
|
+
|
|
106
|
+
// Mindmap
|
|
107
|
+
mmX?: number
|
|
108
|
+
mmY?: number
|
|
109
|
+
|
|
110
|
+
// Graph
|
|
111
|
+
graphX?: number
|
|
112
|
+
graphY?: number
|
|
113
|
+
graphPinned?: boolean
|
|
114
|
+
|
|
115
|
+
// Spatial (3D) — spatial uses the universal `color` key (no spColor)
|
|
116
|
+
spShape?: string
|
|
117
|
+
spOpacity?: number
|
|
118
|
+
spX?: number
|
|
119
|
+
spY?: number
|
|
120
|
+
spZ?: number
|
|
121
|
+
spRX?: number
|
|
122
|
+
spRY?: number
|
|
123
|
+
spRZ?: number
|
|
124
|
+
spSX?: number
|
|
125
|
+
spSY?: number
|
|
126
|
+
spSZ?: number
|
|
127
|
+
spModelUploadId?: string
|
|
128
|
+
spModelDocId?: string
|
|
129
|
+
|
|
130
|
+
// Slides
|
|
131
|
+
slidesTransition?: string
|
|
132
|
+
slidesTheme?: string
|
|
133
|
+
|
|
134
|
+
// Media metadata (extracted on import)
|
|
135
|
+
mediaDuration?: number
|
|
136
|
+
mediaWidth?: number
|
|
137
|
+
mediaHeight?: number
|
|
138
|
+
mediaCamera?: string
|
|
139
|
+
mediaLens?: string
|
|
140
|
+
mediaIso?: number
|
|
141
|
+
mediaFocalLength?: number
|
|
142
|
+
mediaAperture?: number
|
|
143
|
+
mediaShutterSpeed?: string
|
|
144
|
+
mediaArtist?: string
|
|
145
|
+
mediaAlbum?: string
|
|
146
|
+
mediaGenre?: string
|
|
147
|
+
mediaYear?: number
|
|
148
|
+
|
|
149
|
+
// Sheets cell formatting
|
|
150
|
+
bold?: boolean
|
|
151
|
+
italic?: boolean
|
|
152
|
+
textColor?: string
|
|
153
|
+
bgColor?: string
|
|
154
|
+
align?: string
|
|
155
|
+
formula?: string
|
|
156
|
+
|
|
157
|
+
// Coder plugin (per-file)
|
|
158
|
+
fileType?: string
|
|
159
|
+
entry?: boolean
|
|
160
|
+
|
|
161
|
+
// Renderer config (set on the page doc itself, not children)
|
|
162
|
+
kanbanColumnWidth?: string
|
|
163
|
+
galleryColumns?: number
|
|
164
|
+
galleryAspect?: string
|
|
165
|
+
galleryCardStyle?: string
|
|
166
|
+
galleryShowLabels?: boolean
|
|
167
|
+
gallerySortBy?: string
|
|
168
|
+
calendarView?: string
|
|
169
|
+
calendarWeekStart?: string
|
|
170
|
+
calendarShowWeekNumbers?: boolean
|
|
171
|
+
tableMode?: string
|
|
172
|
+
tableSortKey?: string
|
|
173
|
+
tableSortDir?: string
|
|
174
|
+
tableColumns?: any[]
|
|
175
|
+
tableColumnWidths?: Record<string, number>
|
|
176
|
+
tableColumnOrder?: string[]
|
|
177
|
+
timelineZoom?: string
|
|
178
|
+
timelinePixelsPerDay?: number
|
|
179
|
+
timelineCenterDate?: string
|
|
180
|
+
checklistFilter?: string
|
|
181
|
+
checklistSort?: string
|
|
182
|
+
mapShowLabels?: boolean
|
|
183
|
+
spatialGridVisible?: boolean
|
|
184
|
+
graphSpacing?: string
|
|
185
|
+
graphShowLabels?: boolean
|
|
186
|
+
graphEdgeThickness?: string
|
|
187
|
+
mmSpacing?: string
|
|
188
|
+
showRefEdges?: boolean
|
|
189
|
+
chartType?: string
|
|
190
|
+
chartMetric?: string
|
|
191
|
+
chartColorScheme?: string
|
|
192
|
+
chartLimit?: number
|
|
193
|
+
chartShowLegend?: boolean
|
|
194
|
+
chartShowValues?: boolean
|
|
195
|
+
mediaRepeat?: string
|
|
196
|
+
mediaShuffle?: boolean
|
|
197
|
+
sheetsDefaultColWidth?: number
|
|
198
|
+
sheetsDefaultRowHeight?: number
|
|
199
|
+
sheetsShowGridlines?: boolean
|
|
200
|
+
sheetsColumnWidths?: Record<string, number>
|
|
201
|
+
sheetsRowHeights?: Record<string, number>
|
|
202
|
+
sheetsFreezeRows?: number
|
|
203
|
+
sheetsFreezeCols?: number
|
|
204
|
+
|
|
205
|
+
// Internal
|
|
206
|
+
_metaFields?: UserMetaField[]
|
|
207
|
+
_metaInitialized?: boolean
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ── Tree entry (flat row in the doc-tree Y.Map) ──────────────────────────────
|
|
211
|
+
|
|
212
|
+
export interface TreeEntry {
|
|
213
|
+
id: string
|
|
214
|
+
label: string
|
|
215
|
+
parentId: string | null
|
|
216
|
+
order: number
|
|
217
|
+
type?: string
|
|
218
|
+
meta?: PageMeta
|
|
219
|
+
createdAt?: number
|
|
220
|
+
updatedAt?: number
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ── Tree node (nested, for buildTree output) ─────────────────────────────────
|
|
224
|
+
|
|
225
|
+
export interface TreeNode {
|
|
226
|
+
id: string
|
|
227
|
+
label: string
|
|
228
|
+
type?: string
|
|
229
|
+
meta?: PageMeta
|
|
230
|
+
order: number
|
|
231
|
+
children: TreeNode[]
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// ── Search result (from TreeManager.find) ────────────────────────────────────
|
|
235
|
+
|
|
236
|
+
export interface TreeSearchResult {
|
|
237
|
+
id: string
|
|
238
|
+
label: string
|
|
239
|
+
type?: string
|
|
240
|
+
meta?: PageMeta
|
|
241
|
+
/** Ancestor labels from root → parent. */
|
|
242
|
+
path: string[]
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// ── Page type catalog ────────────────────────────────────────────────────────
|
|
246
|
+
|
|
247
|
+
export interface PageTypeMetaField {
|
|
248
|
+
type: MetaFieldType
|
|
249
|
+
label?: string
|
|
250
|
+
/** single-value fields */
|
|
251
|
+
key?: string
|
|
252
|
+
/** location */
|
|
253
|
+
latKey?: string
|
|
254
|
+
lngKey?: string
|
|
255
|
+
/** ranges */
|
|
256
|
+
startKey?: string
|
|
257
|
+
endKey?: string
|
|
258
|
+
allDayKey?: string
|
|
259
|
+
/** color preset */
|
|
260
|
+
presets?: string[]
|
|
261
|
+
/** icon / select / tags */
|
|
262
|
+
options?: string[]
|
|
263
|
+
/** slider / number */
|
|
264
|
+
min?: number
|
|
265
|
+
max?: number
|
|
266
|
+
step?: number
|
|
267
|
+
unit?: string
|
|
268
|
+
/** toggle default */
|
|
269
|
+
default?: boolean
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export interface PageTypeInfo {
|
|
273
|
+
key: string
|
|
274
|
+
label: string
|
|
275
|
+
icon: string
|
|
276
|
+
description?: string
|
|
277
|
+
/** true = core type (always available); false = requires plugin */
|
|
278
|
+
core: boolean
|
|
279
|
+
plugin?: string
|
|
280
|
+
supportsChildren: boolean
|
|
281
|
+
childLabel?: string
|
|
282
|
+
grandchildLabel?: string
|
|
283
|
+
/** -1 = unlimited depth */
|
|
284
|
+
defaultDepth?: number
|
|
285
|
+
/** Fields that apply to this doc's descendants (children, grandchildren, ...) */
|
|
286
|
+
metaSchema?: PageTypeMetaField[]
|
|
287
|
+
/** Fields written to this doc's own meta on first render (renderer config) */
|
|
288
|
+
defaultMetaFields?: PageTypeMetaField[]
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// ── Geo type meta schemas ────────────────────────────────────────────────────
|
|
292
|
+
|
|
293
|
+
const GEO_COLOR_PRESETS = ['#3b82f6', '#f97316', '#22c55e', '#ef4444', '#a855f7']
|
|
294
|
+
const GEO_ICON_OPTIONS = [
|
|
295
|
+
'map-pin', 'star', 'flag', 'home', 'building-2', 'coffee', 'utensils',
|
|
296
|
+
'camera', 'heart', 'zap', 'triangle-alert', 'car', 'plane', 'anchor',
|
|
297
|
+
'tree-pine', 'mountain', 'waves', 'shield', 'crosshair', 'circle-dot',
|
|
298
|
+
'bookmark', 'gem', 'radio', 'compass',
|
|
299
|
+
]
|
|
300
|
+
|
|
301
|
+
export const GEO_TYPE_META_SCHEMAS: Record<string, PageTypeMetaField[]> = {
|
|
302
|
+
marker: [
|
|
303
|
+
{ type: 'location', latKey: 'geoLat', lngKey: 'geoLng', label: 'Location' },
|
|
304
|
+
{ type: 'icon', key: 'icon', options: GEO_ICON_OPTIONS, label: 'Icon' },
|
|
305
|
+
{ type: 'colorPreset', key: 'color', presets: GEO_COLOR_PRESETS, label: 'Color' },
|
|
306
|
+
],
|
|
307
|
+
line: [
|
|
308
|
+
{ type: 'colorPreset', key: 'color', presets: GEO_COLOR_PRESETS, label: 'Color' },
|
|
309
|
+
],
|
|
310
|
+
measure: [],
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ── Static page type registry ────────────────────────────────────────────────
|
|
314
|
+
|
|
315
|
+
export const PAGE_TYPES: Record<string, PageTypeInfo> = {
|
|
316
|
+
doc: {
|
|
317
|
+
key: 'doc',
|
|
318
|
+
label: 'Document',
|
|
319
|
+
icon: 'file-text',
|
|
320
|
+
description: 'Rich text document with real-time collaboration',
|
|
321
|
+
core: true,
|
|
322
|
+
supportsChildren: true,
|
|
323
|
+
},
|
|
324
|
+
kanban: {
|
|
325
|
+
key: 'kanban',
|
|
326
|
+
label: 'Kanban',
|
|
327
|
+
icon: 'kanban',
|
|
328
|
+
description: 'Drag-and-drop task board with columns and cards',
|
|
329
|
+
core: true,
|
|
330
|
+
supportsChildren: true,
|
|
331
|
+
childLabel: 'Column',
|
|
332
|
+
grandchildLabel: 'Card',
|
|
333
|
+
defaultMetaFields: [
|
|
334
|
+
{ type: 'select', key: 'kanbanColumnWidth', options: ['narrow', 'default', 'wide'], label: 'Column Width' },
|
|
335
|
+
],
|
|
336
|
+
},
|
|
337
|
+
gallery: {
|
|
338
|
+
key: 'gallery',
|
|
339
|
+
label: 'Gallery',
|
|
340
|
+
icon: 'images',
|
|
341
|
+
description: 'Visual grid of items with rich content',
|
|
342
|
+
core: true,
|
|
343
|
+
supportsChildren: true,
|
|
344
|
+
childLabel: 'Item',
|
|
345
|
+
metaSchema: [
|
|
346
|
+
{ type: 'location', latKey: 'geoLat', lngKey: 'geoLng', label: 'Location' },
|
|
347
|
+
{ type: 'datetime', key: 'datetimeStart', label: 'Date' },
|
|
348
|
+
{ type: 'tags', key: 'tags', label: 'Tags' },
|
|
349
|
+
{ type: 'rating', key: 'rating', max: 5, label: 'Rating' },
|
|
350
|
+
{ type: 'icon', key: 'icon', label: 'Icon' },
|
|
351
|
+
{ type: 'colorPreset', key: 'color', presets: ['#6366f1', '#ec4899', '#f97316', '#22c55e', '#3b82f6', '#a855f7'], label: 'Color' },
|
|
352
|
+
],
|
|
353
|
+
defaultMetaFields: [
|
|
354
|
+
{ type: 'number', key: 'galleryColumns', min: 1, max: 6, step: 1, label: 'Columns' },
|
|
355
|
+
{ type: 'select', key: 'galleryAspect', options: ['square', '4:3', '3:2', '16:9', 'free'], label: 'Aspect Ratio' },
|
|
356
|
+
{ type: 'select', key: 'galleryCardStyle', options: ['default', 'compact', 'detailed'], label: 'Card Style' },
|
|
357
|
+
{ type: 'toggle', key: 'galleryShowLabels', label: 'Show Labels' },
|
|
358
|
+
{ type: 'select', key: 'gallerySortBy', options: ['manual', 'date', 'name', 'rating'], label: 'Sort' },
|
|
359
|
+
],
|
|
360
|
+
},
|
|
361
|
+
table: {
|
|
362
|
+
key: 'table',
|
|
363
|
+
label: 'Table',
|
|
364
|
+
icon: 'table',
|
|
365
|
+
description: 'Collaborative spreadsheet with custom fields',
|
|
366
|
+
core: true,
|
|
367
|
+
supportsChildren: true,
|
|
368
|
+
childLabel: 'Column',
|
|
369
|
+
grandchildLabel: 'Row',
|
|
370
|
+
defaultMetaFields: [
|
|
371
|
+
{ type: 'select', key: 'tableMode', options: ['hierarchy', 'flat'], label: 'Mode' },
|
|
372
|
+
{ type: 'select', key: 'tableSortDir', options: ['asc', 'desc'], label: 'Sort Direction' },
|
|
373
|
+
],
|
|
374
|
+
},
|
|
375
|
+
outline: {
|
|
376
|
+
key: 'outline',
|
|
377
|
+
label: 'Outline',
|
|
378
|
+
icon: 'list-tree',
|
|
379
|
+
description: 'Hierarchical outline with keyboard navigation',
|
|
380
|
+
core: true,
|
|
381
|
+
supportsChildren: true,
|
|
382
|
+
childLabel: 'Item',
|
|
383
|
+
defaultDepth: -1,
|
|
384
|
+
},
|
|
385
|
+
checklist: {
|
|
386
|
+
key: 'checklist',
|
|
387
|
+
label: 'Checklist',
|
|
388
|
+
icon: 'check-square',
|
|
389
|
+
description: 'Collaborative checklist with sub-tasks, drag-and-drop, and due dates',
|
|
390
|
+
core: true,
|
|
391
|
+
supportsChildren: true,
|
|
392
|
+
childLabel: 'Task',
|
|
393
|
+
defaultDepth: -1,
|
|
394
|
+
metaSchema: [
|
|
395
|
+
{ type: 'toggle', key: 'checked', label: 'Done' },
|
|
396
|
+
{ type: 'select', key: 'priority', options: ['none', 'low', 'medium', 'high'], label: 'Priority' },
|
|
397
|
+
{ type: 'date', key: 'dateEnd', label: 'Due date' },
|
|
398
|
+
],
|
|
399
|
+
defaultMetaFields: [
|
|
400
|
+
{ type: 'select', key: 'checklistFilter', options: ['all', 'active', 'completed'], label: 'Filter' },
|
|
401
|
+
{ type: 'select', key: 'checklistSort', options: ['manual', 'priority', 'due'], label: 'Sort' },
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
graph: {
|
|
405
|
+
key: 'graph',
|
|
406
|
+
label: 'Graph',
|
|
407
|
+
icon: 'git-fork',
|
|
408
|
+
description: 'Force-directed knowledge graph — full document tree as nodes & edges',
|
|
409
|
+
core: true,
|
|
410
|
+
supportsChildren: true,
|
|
411
|
+
childLabel: 'Node',
|
|
412
|
+
defaultMetaFields: [
|
|
413
|
+
{ type: 'toggle', key: 'showRefEdges', label: 'Show Ref Edges', default: true },
|
|
414
|
+
],
|
|
415
|
+
},
|
|
416
|
+
timeline: {
|
|
417
|
+
key: 'timeline',
|
|
418
|
+
label: 'Timeline',
|
|
419
|
+
icon: 'gantt-chart',
|
|
420
|
+
description: 'Gantt-style project timeline with epics and tasks',
|
|
421
|
+
core: true,
|
|
422
|
+
supportsChildren: true,
|
|
423
|
+
childLabel: 'Epic',
|
|
424
|
+
grandchildLabel: 'Task',
|
|
425
|
+
metaSchema: [
|
|
426
|
+
{ type: 'daterange', startKey: 'dateStart', endKey: 'dateEnd' },
|
|
427
|
+
{ type: 'slider', key: 'taskProgress', min: 0, max: 100, label: 'Progress' },
|
|
428
|
+
{ type: 'colorPreset', key: 'color', presets: ['#6366f1', '#818cf8', '#f97316', '#22c55e', '#3b82f6', '#a855f7'], label: 'Color' },
|
|
429
|
+
],
|
|
430
|
+
},
|
|
431
|
+
calendar: {
|
|
432
|
+
key: 'calendar',
|
|
433
|
+
label: 'Calendar',
|
|
434
|
+
icon: 'calendar',
|
|
435
|
+
description: 'Event calendar with month, week, and day views',
|
|
436
|
+
core: true,
|
|
437
|
+
supportsChildren: true,
|
|
438
|
+
childLabel: 'Event',
|
|
439
|
+
metaSchema: [
|
|
440
|
+
{ type: 'datetimerange', startKey: 'datetimeStart', endKey: 'datetimeEnd', allDayKey: 'allDay' },
|
|
441
|
+
{ type: 'colorPreset', key: 'color', presets: ['#6366f1', '#ec4899', '#f97316', '#22c55e', '#3b82f6', '#a855f7'], label: 'Color' },
|
|
442
|
+
{ type: 'icon', key: 'icon', label: 'Icon' },
|
|
443
|
+
],
|
|
444
|
+
defaultMetaFields: [
|
|
445
|
+
{ type: 'select', key: 'calendarWeekStart', options: ['sun', 'mon'], label: 'Week Starts' },
|
|
446
|
+
{ type: 'select', key: 'calendarView', options: ['month', 'week', 'day'], label: 'Default View' },
|
|
447
|
+
{ type: 'toggle', key: 'calendarShowWeekNumbers', label: 'Show Week Numbers' },
|
|
448
|
+
],
|
|
449
|
+
},
|
|
450
|
+
map: {
|
|
451
|
+
key: 'map',
|
|
452
|
+
label: 'Map',
|
|
453
|
+
icon: 'map',
|
|
454
|
+
description: 'Collaborative world map with shared markers',
|
|
455
|
+
core: true,
|
|
456
|
+
supportsChildren: true,
|
|
457
|
+
childLabel: 'Location',
|
|
458
|
+
defaultMetaFields: [
|
|
459
|
+
{ type: 'toggle', key: 'mapShowLabels', label: 'Show Labels', default: true },
|
|
460
|
+
],
|
|
461
|
+
},
|
|
462
|
+
dashboard: {
|
|
463
|
+
key: 'dashboard',
|
|
464
|
+
label: 'Dashboard',
|
|
465
|
+
icon: 'layout-dashboard',
|
|
466
|
+
description: 'Arrange documents as draggable icons with optional widget views',
|
|
467
|
+
core: true,
|
|
468
|
+
supportsChildren: true,
|
|
469
|
+
childLabel: 'Item',
|
|
470
|
+
},
|
|
471
|
+
call: {
|
|
472
|
+
key: 'call',
|
|
473
|
+
label: 'Call',
|
|
474
|
+
icon: 'phone',
|
|
475
|
+
description: 'Video call room with live audio and screen sharing',
|
|
476
|
+
core: true,
|
|
477
|
+
supportsChildren: false,
|
|
478
|
+
},
|
|
479
|
+
chart: {
|
|
480
|
+
key: 'chart',
|
|
481
|
+
label: 'Chart',
|
|
482
|
+
icon: 'bar-chart-3',
|
|
483
|
+
description: 'Charts — manual data points or aggregation over document trees',
|
|
484
|
+
core: true,
|
|
485
|
+
supportsChildren: true,
|
|
486
|
+
childLabel: 'Data Point',
|
|
487
|
+
grandchildLabel: 'Data Point',
|
|
488
|
+
metaSchema: [
|
|
489
|
+
{ type: 'number', key: 'number', step: 0.01, label: 'Value' },
|
|
490
|
+
{ type: 'colorPreset', key: 'color', presets: ['#6366f1', '#ec4899', '#f97316', '#22c55e', '#3b82f6', '#a855f7', '#14b8a6', '#eab308'], label: 'Color' },
|
|
491
|
+
{ type: 'tags', key: 'tags', label: 'Tags' },
|
|
492
|
+
],
|
|
493
|
+
defaultMetaFields: [
|
|
494
|
+
{ type: 'select', key: 'chartType', options: ['bar', 'stacked bar', 'line', 'donut', 'treemap'], label: 'Chart Type' },
|
|
495
|
+
{ type: 'select', key: 'chartMetric', options: ['value', 'type', 'tag', 'status', 'priority', 'activity', 'completion'], label: 'Metric' },
|
|
496
|
+
{ type: 'select', key: 'chartColorScheme', options: ['default', 'warm', 'cool', 'mono'], label: 'Colors' },
|
|
497
|
+
{ type: 'number', key: 'chartLimit', min: 3, max: 30, step: 1, label: 'Max Items' },
|
|
498
|
+
{ type: 'toggle', key: 'chartShowLegend', label: 'Show Legend', default: true },
|
|
499
|
+
{ type: 'toggle', key: 'chartShowValues', label: 'Show Values' },
|
|
500
|
+
],
|
|
501
|
+
},
|
|
502
|
+
sheets: {
|
|
503
|
+
key: 'sheets',
|
|
504
|
+
label: 'Sheets',
|
|
505
|
+
icon: 'grid-3x3',
|
|
506
|
+
description: 'Spreadsheet — cells, formulas, and formatting in a collaborative grid',
|
|
507
|
+
core: true,
|
|
508
|
+
supportsChildren: true,
|
|
509
|
+
childLabel: 'Column',
|
|
510
|
+
grandchildLabel: 'Cell',
|
|
511
|
+
defaultMetaFields: [
|
|
512
|
+
{ type: 'number', key: 'sheetsDefaultColWidth', min: 40, max: 500, step: 10, label: 'Column Width' },
|
|
513
|
+
{ type: 'number', key: 'sheetsDefaultRowHeight', min: 20, max: 100, step: 2, label: 'Row Height' },
|
|
514
|
+
{ type: 'toggle', key: 'sheetsShowGridlines', label: 'Gridlines' },
|
|
515
|
+
],
|
|
516
|
+
},
|
|
517
|
+
slides: {
|
|
518
|
+
key: 'slides',
|
|
519
|
+
label: 'Slides',
|
|
520
|
+
icon: 'presentation',
|
|
521
|
+
description: 'Presentation slides with two-axis navigation',
|
|
522
|
+
core: true,
|
|
523
|
+
supportsChildren: true,
|
|
524
|
+
childLabel: 'Slide',
|
|
525
|
+
grandchildLabel: 'Sub-slide',
|
|
526
|
+
metaSchema: [
|
|
527
|
+
{ type: 'select', key: 'slidesTransition', options: ['none', 'fade', 'slide'], label: 'Transition' },
|
|
528
|
+
{ type: 'colorPreset', key: 'color', presets: ['#6366f1', '#ec4899', '#f97316', '#22c55e', '#3b82f6', '#a855f7'], label: 'Accent' },
|
|
529
|
+
],
|
|
530
|
+
defaultMetaFields: [
|
|
531
|
+
{ type: 'select', key: 'slidesTheme', options: ['dark', 'light'], label: 'Theme' },
|
|
532
|
+
],
|
|
533
|
+
},
|
|
534
|
+
overview: {
|
|
535
|
+
key: 'overview',
|
|
536
|
+
label: 'Overview',
|
|
537
|
+
icon: 'radar',
|
|
538
|
+
description: 'Space home — activity, people, stats, and health at a glance',
|
|
539
|
+
core: true,
|
|
540
|
+
supportsChildren: true,
|
|
541
|
+
childLabel: 'Page',
|
|
542
|
+
},
|
|
543
|
+
|
|
544
|
+
// Plugin-contributed types — require the named plugin to be enabled server-side.
|
|
545
|
+
|
|
546
|
+
spatial: {
|
|
547
|
+
key: 'spatial',
|
|
548
|
+
label: 'Spatial',
|
|
549
|
+
icon: 'box',
|
|
550
|
+
description: '3D scene with collaborative objects and real-time presence',
|
|
551
|
+
core: false,
|
|
552
|
+
plugin: 'spatial',
|
|
553
|
+
supportsChildren: true,
|
|
554
|
+
childLabel: 'Object',
|
|
555
|
+
grandchildLabel: 'Part',
|
|
556
|
+
defaultDepth: -1,
|
|
557
|
+
metaSchema: [
|
|
558
|
+
{ type: 'select', key: 'spShape', options: ['box', 'sphere', 'cylinder', 'cone', 'plane', 'torus', 'glb'], label: 'Shape' },
|
|
559
|
+
{ type: 'colorPreset', key: 'color', presets: ['#6366f1', '#ef4444', '#22c55e', '#3b82f6', '#f97316', '#a855f7', '#ec4899', '#14b8a6'], label: 'Color' },
|
|
560
|
+
{ type: 'slider', key: 'spOpacity', min: 0, max: 100, label: 'Opacity' },
|
|
561
|
+
{ type: 'number', key: 'spX', step: 0.1, label: 'X' },
|
|
562
|
+
{ type: 'number', key: 'spY', step: 0.1, label: 'Y' },
|
|
563
|
+
{ type: 'number', key: 'spZ', step: 0.1, label: 'Z' },
|
|
564
|
+
{ type: 'number', key: 'spRX', min: -180, max: 180, step: 1, label: 'Rot X' },
|
|
565
|
+
{ type: 'number', key: 'spRY', min: -180, max: 180, step: 1, label: 'Rot Y' },
|
|
566
|
+
{ type: 'number', key: 'spRZ', min: -180, max: 180, step: 1, label: 'Rot Z' },
|
|
567
|
+
{ type: 'number', key: 'spSX', min: 0.01, max: 100, step: 0.1, label: 'Scale X' },
|
|
568
|
+
{ type: 'number', key: 'spSY', min: 0.01, max: 100, step: 0.1, label: 'Scale Y' },
|
|
569
|
+
{ type: 'number', key: 'spSZ', min: 0.01, max: 100, step: 0.1, label: 'Scale Z' },
|
|
570
|
+
],
|
|
571
|
+
defaultMetaFields: [
|
|
572
|
+
{ type: 'toggle', key: 'spatialGridVisible', label: 'Show Grid', default: true },
|
|
573
|
+
],
|
|
574
|
+
},
|
|
575
|
+
media: {
|
|
576
|
+
key: 'media',
|
|
577
|
+
label: 'Media',
|
|
578
|
+
icon: 'disc-3',
|
|
579
|
+
description: 'Media player with synced listening and playlists',
|
|
580
|
+
core: false,
|
|
581
|
+
plugin: 'media',
|
|
582
|
+
supportsChildren: true,
|
|
583
|
+
childLabel: 'Track',
|
|
584
|
+
defaultDepth: -1,
|
|
585
|
+
metaSchema: [
|
|
586
|
+
{ type: 'tags', key: 'tags', label: 'Tags' },
|
|
587
|
+
],
|
|
588
|
+
defaultMetaFields: [
|
|
589
|
+
{ type: 'select', key: 'mediaRepeat', options: ['off', 'all', 'one'], label: 'Repeat' },
|
|
590
|
+
{ type: 'toggle', key: 'mediaShuffle', label: 'Shuffle' },
|
|
591
|
+
],
|
|
592
|
+
},
|
|
593
|
+
coder: {
|
|
594
|
+
key: 'coder',
|
|
595
|
+
label: 'Coder',
|
|
596
|
+
icon: 'code-2',
|
|
597
|
+
description: 'Collaborative multi-file coding environment',
|
|
598
|
+
core: false,
|
|
599
|
+
plugin: 'coder',
|
|
600
|
+
supportsChildren: true,
|
|
601
|
+
childLabel: 'File',
|
|
602
|
+
defaultDepth: -1,
|
|
603
|
+
metaSchema: [
|
|
604
|
+
{ type: 'select', key: 'fileType', options: ['vue', 'ts', 'js', 'css', 'json', 'folder'], label: 'Type' },
|
|
605
|
+
{ type: 'toggle', key: 'entry', label: 'Entry Point' },
|
|
606
|
+
],
|
|
607
|
+
},
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export const TYPE_ALIASES: Record<string, string> = {
|
|
611
|
+
desktop: 'dashboard',
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export function resolvePageType(key: string | undefined): PageTypeInfo | undefined {
|
|
615
|
+
if (!key) return undefined
|
|
616
|
+
const resolved = TYPE_ALIASES[key] ?? key
|
|
617
|
+
return PAGE_TYPES[resolved]
|
|
618
|
+
}
|
package/src/DocUtils.ts
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utilities for the DocumentManager ORM layer.
|
|
3
|
+
*
|
|
4
|
+
* These functions were previously duplicated across `mcp/src/utils.ts`,
|
|
5
|
+
* `mcp/src/server.ts`, `cli/src/connection.ts`, and `mcp/src/tools/tree.ts`.
|
|
6
|
+
*/
|
|
7
|
+
import * as Y from "yjs";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Wait for a provider's `synced` event with a timeout.
|
|
11
|
+
* Resolves immediately if the provider is already synced.
|
|
12
|
+
*/
|
|
13
|
+
export function waitForSync(
|
|
14
|
+
provider: {
|
|
15
|
+
isSynced?: boolean;
|
|
16
|
+
on(event: string, cb: () => void): void;
|
|
17
|
+
off(event: string, cb: () => void): void;
|
|
18
|
+
},
|
|
19
|
+
timeoutMs = 15000,
|
|
20
|
+
): Promise<void> {
|
|
21
|
+
// Already synced — resolve immediately.
|
|
22
|
+
if (provider.isSynced) return Promise.resolve();
|
|
23
|
+
|
|
24
|
+
return new Promise<void>((resolve, reject) => {
|
|
25
|
+
const timer = setTimeout(() => {
|
|
26
|
+
provider.off("synced", handler);
|
|
27
|
+
reject(new Error(`Sync timed out after ${timeoutMs}ms`));
|
|
28
|
+
}, timeoutMs);
|
|
29
|
+
|
|
30
|
+
function handler() {
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
resolve();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
provider.on("synced", handler);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Wrap a promise with a timeout.
|
|
41
|
+
*/
|
|
42
|
+
export function withTimeout<T>(
|
|
43
|
+
promise: Promise<T>,
|
|
44
|
+
timeoutMs: number,
|
|
45
|
+
message?: string,
|
|
46
|
+
): Promise<T> {
|
|
47
|
+
return new Promise<T>((resolve, reject) => {
|
|
48
|
+
const timer = setTimeout(
|
|
49
|
+
() =>
|
|
50
|
+
reject(
|
|
51
|
+
new Error(
|
|
52
|
+
message ?? `Operation timed out after ${timeoutMs}ms`,
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
timeoutMs,
|
|
56
|
+
);
|
|
57
|
+
promise.then(
|
|
58
|
+
(val) => {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
resolve(val);
|
|
61
|
+
},
|
|
62
|
+
(err) => {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
reject(err);
|
|
65
|
+
},
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Normalize a document ID so the hub/root doc ID is treated as the tree root
|
|
72
|
+
* (null). This lets callers pass the hub doc_id from list_spaces as
|
|
73
|
+
* parentId/rootId and get the expected root-level results instead of an empty
|
|
74
|
+
* set.
|
|
75
|
+
*/
|
|
76
|
+
export function normalizeRootId(
|
|
77
|
+
id: string | null | undefined,
|
|
78
|
+
rootDocId: string | null,
|
|
79
|
+
): string | null {
|
|
80
|
+
if (id == null) return null;
|
|
81
|
+
return id === rootDocId ? null : id;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Safely read a tree map value, converting Y.Map to plain object if needed.
|
|
86
|
+
*/
|
|
87
|
+
export function toPlain(val: unknown): unknown {
|
|
88
|
+
return val instanceof Y.Map ? val.toJSON() : val;
|
|
89
|
+
}
|