@moloodev/editor-sdk 0.0.0-stage → 0.1.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 (110) hide show
  1. package/package.json +62 -3
  2. package/src/channel.ts +287 -0
  3. package/src/chrome-manifest.ts +111 -0
  4. package/src/commands/clipboard/router.ts +99 -0
  5. package/src/commands/clipboard/types.ts +20 -0
  6. package/src/commands/history/stack.ts +53 -0
  7. package/src/commands/icons/catalog.ts +172 -0
  8. package/src/commands/index.ts +100 -0
  9. package/src/commands/keys/display.ts +16 -0
  10. package/src/commands/keys/normalize.ts +55 -0
  11. package/src/commands/keys/reserved.ts +62 -0
  12. package/src/commands/keys/validate.ts +77 -0
  13. package/src/commands/manifest/configuration.ts +59 -0
  14. package/src/commands/manifest/contribution-manifest-schema.ts +56 -0
  15. package/src/commands/manifest/editor-document.ts +501 -0
  16. package/src/commands/manifest/ids.ts +2 -0
  17. package/src/commands/manifest/merge.ts +215 -0
  18. package/src/commands/manifest/types.ts +113 -0
  19. package/src/commands/manifest/validate-manifest.ts +45 -0
  20. package/src/commands/react/context.tsx +249 -0
  21. package/src/commands/react/hotkey-defaults.ts +11 -0
  22. package/src/commands/react/scope-context.tsx +31 -0
  23. package/src/commands/react/scope-provider.tsx +123 -0
  24. package/src/commands/react/store.ts +182 -0
  25. package/src/commands/registry/create.ts +55 -0
  26. package/src/commands/registry/types.ts +12 -0
  27. package/src/commands/when/evaluate.ts +80 -0
  28. package/src/commands/when/index.ts +19 -0
  29. package/src/commands/when/parse.ts +276 -0
  30. package/src/commands/when/types.ts +24 -0
  31. package/src/commands/when/validate.ts +20 -0
  32. package/src/crdt/awareness.ts +29 -0
  33. package/src/crdt/bytes.ts +26 -0
  34. package/src/crdt/connect.ts +285 -0
  35. package/src/crdt/diff.ts +86 -0
  36. package/src/crdt/doc.ts +67 -0
  37. package/src/crdt/front-matter.ts +45 -0
  38. package/src/crdt/index.ts +76 -0
  39. package/src/crdt/persist.ts +40 -0
  40. package/src/crdt/protocol.ts +119 -0
  41. package/src/crdt/shared.ts +104 -0
  42. package/src/crdt/text-body.ts +125 -0
  43. package/src/crdt/undo.ts +59 -0
  44. package/src/crdt/vite-plugin.ts +42 -0
  45. package/src/crdt/yjs.ts +16 -0
  46. package/src/editor-common.ts +160 -0
  47. package/src/editor-id.ts +56 -0
  48. package/src/frame-attributes.ts +9 -0
  49. package/src/index.ts +229 -0
  50. package/src/json-schema.ts +13 -0
  51. package/src/layout/bind-toolbar.ts +60 -0
  52. package/src/layout/catalog.ts +82 -0
  53. package/src/layout/chrome/command-affordances.ts +47 -0
  54. package/src/layout/chrome/command-layout-state.ts +42 -0
  55. package/src/layout/chrome/editor-menu.tsx +358 -0
  56. package/src/layout/chrome/editor-shortcut-keys.tsx +27 -0
  57. package/src/layout/chrome/menu-styles.ts +3 -0
  58. package/src/layout/chrome/mid-menu-nodes.ts +27 -0
  59. package/src/layout/chrome/use-editor-command-affordances.ts +33 -0
  60. package/src/layout/chrome/visible-menu-leaves.ts +15 -0
  61. package/src/layout/content-error-notice.tsx +31 -0
  62. package/src/layout/define-editor-layout.ts +60 -0
  63. package/src/layout/define-editor-layout.types.ts +57 -0
  64. package/src/layout/doc-undo-bridge.tsx +22 -0
  65. package/src/layout/dock-zones.tsx +61 -0
  66. package/src/layout/drop.ts +39 -0
  67. package/src/layout/editor-layout.tsx +287 -0
  68. package/src/layout/editor-loading.tsx +23 -0
  69. package/src/layout/frame-layout-binding.tsx +74 -0
  70. package/src/layout/frame.ts +23 -0
  71. package/src/layout/hide.ts +103 -0
  72. package/src/layout/index.ts +14 -0
  73. package/src/layout/layout-binding.tsx +42 -0
  74. package/src/layout/layout-storage-key.ts +6 -0
  75. package/src/layout/layout-values.ts +48 -0
  76. package/src/layout/mutate.ts +486 -0
  77. package/src/layout/nesting-context.tsx +20 -0
  78. package/src/layout/panel-header-action.tsx +29 -0
  79. package/src/layout/panel-header.tsx +168 -0
  80. package/src/layout/panel-hide-menu.tsx +6 -0
  81. package/src/layout/panel-menu.tsx +85 -0
  82. package/src/layout/panel-section.tsx +114 -0
  83. package/src/layout/panel-size.ts +94 -0
  84. package/src/layout/panel-title.tsx +5 -0
  85. package/src/layout/registry.tsx +333 -0
  86. package/src/layout/restore-panel.ts +26 -0
  87. package/src/layout/slots-context.tsx +189 -0
  88. package/src/layout/tab-button.tsx +60 -0
  89. package/src/layout/toolbar-scroll.ts +22 -0
  90. package/src/layout/toolbar.tsx +168 -0
  91. package/src/layout/types.ts +41 -0
  92. package/src/layout/use-collapsed-sections.ts +50 -0
  93. package/src/layout/validate-layout-spec.ts +143 -0
  94. package/src/message-samples.ts +377 -0
  95. package/src/origin-headers.ts +57 -0
  96. package/src/print/index.ts +10 -0
  97. package/src/print/inspect.ts +16 -0
  98. package/src/print/schema.ts +122 -0
  99. package/src/protocol-entry.ts +19 -0
  100. package/src/protocol.ts +471 -0
  101. package/src/render-result.ts +25 -0
  102. package/src/view/editor-chrome.ts +28 -0
  103. package/src/view/hooks.ts +260 -0
  104. package/src/view/mount-editor-view.ts +36 -0
  105. package/src/view/port-binding.ts +127 -0
  106. package/src/view/port-commands.ts +36 -0
  107. package/src/view/port.ts +35 -0
  108. package/src/view/theme-class.ts +11 -0
  109. package/src/view.ts +313 -0
  110. package/README.md +0 -3
@@ -0,0 +1,377 @@
1
+ import type { BundleConfirm, Composition, Publication } from "@moloodev/platform";
2
+ import type {
3
+ EditorAccess,
4
+ EditorAsset,
5
+ EditorEvent,
6
+ EditorFailure,
7
+ EditorRequest,
8
+ EditorRevision,
9
+ EditorSession,
10
+ EditorSuccess,
11
+ } from "./index";
12
+
13
+ export const asset = {
14
+ id: "asset-1",
15
+ name: "Note",
16
+ type: "moloo.markdown",
17
+ path: "/Note",
18
+ epoch: 3,
19
+ headRevision: 2,
20
+ updatedAt: "2026-09-30T00:00:00.000Z",
21
+ contentBytes: 12,
22
+ locked: false,
23
+ lockHeld: false,
24
+ trashed: false,
25
+ } satisfies EditorAsset;
26
+
27
+ const revision = {
28
+ id: "rev-1",
29
+ assetId: "asset-1",
30
+ revision: 2,
31
+ message: "Pin note",
32
+ contentBytes: 12,
33
+ createdAt: "2026-09-30T00:00:00.000Z",
34
+ } satisfies EditorRevision;
35
+
36
+ export const publication = {
37
+ visibility: "private",
38
+ } satisfies Publication;
39
+
40
+ export const composition = {
41
+ bundleId: "bundle-1",
42
+ bundleName: "Pack",
43
+ bundleEpoch: 1,
44
+ bundleUpdatedAt: "2026-09-30T00:00:00.000Z",
45
+ headRevision: 2,
46
+ entries: {
47
+ "asset-1": { inclusion: "direct", revision: 1, type: "moloo.markdown" },
48
+ },
49
+ members: [
50
+ {
51
+ assetId: "asset-1",
52
+ name: "Note",
53
+ path: "/Note",
54
+ type: "moloo.markdown",
55
+ inclusion: "direct",
56
+ via: null,
57
+ selected: 1,
58
+ previous: null,
59
+ latest: 1,
60
+ locked: false,
61
+ size: 12,
62
+ },
63
+ ],
64
+ refs: [],
65
+ previousMembers: [],
66
+ previousRefs: [],
67
+ added: ["asset-1"],
68
+ removed: [],
69
+ issues: [],
70
+ reviewed: "rev-1",
71
+ totalBytes: 12,
72
+ deltaBytes: 12,
73
+ } satisfies Composition;
74
+
75
+ const confirmed = {
76
+ composition,
77
+ revision: 4,
78
+ } satisfies BundleConfirm;
79
+
80
+ export const requests = {
81
+ "asset.rename": { v: 1, id: "rename-1", type: "asset.rename", body: { name: "notes" } },
82
+ "asset.read": { v: 1, id: "read-1", type: "asset.read", body: { id: "asset-1" } },
83
+ "layout.load": { v: 1, id: "layout-load-1", type: "layout.load", body: {} },
84
+ "layout.save": { v: 1, id: "layout-save-1", type: "layout.save", body: { layout: { panels: { body: { visible: true, size: "50%" } } } } },
85
+ "asset.list": {
86
+ v: 1,
87
+ id: "list-1",
88
+ type: "asset.list",
89
+ body: { type: "moloo.markdown" },
90
+ },
91
+ "asset.listRevisions": {
92
+ v: 1,
93
+ id: "revisions-1",
94
+ type: "asset.listRevisions",
95
+ body: { id: "asset-1" },
96
+ },
97
+ "asset.getComposition": {
98
+ v: 1,
99
+ id: "composition-1",
100
+ type: "asset.getComposition",
101
+ body: { id: "bundle-1" },
102
+ },
103
+ "asset.getPublication": {
104
+ v: 1,
105
+ id: "publication-get-1",
106
+ type: "asset.getPublication",
107
+ body: { id: "bundle-1" },
108
+ },
109
+ "asset.confirmBundle": {
110
+ v: 1,
111
+ id: "confirm-1",
112
+ type: "asset.confirmBundle",
113
+ body: { id: "bundle-1", message: "Publish pack", reviewed: "rev-1" },
114
+ },
115
+ "asset.putPublication": {
116
+ v: 1,
117
+ id: "publication-put-1",
118
+ type: "asset.putPublication",
119
+ body: { id: "bundle-1", publication },
120
+ },
121
+ "host.pick": {
122
+ v: 1,
123
+ id: "pick-1",
124
+ type: "host.pick",
125
+ body: {
126
+ acceptedTypes: ["moloo.markdown"],
127
+ excludeTypes: ["moloo.folder"],
128
+ excludeIds: ["asset-1"],
129
+ },
130
+ },
131
+ "host.openAsset": {
132
+ v: 1,
133
+ id: "open-asset-1",
134
+ type: "host.openAsset",
135
+ body: { id: "asset-1", type: "moloo.markdown" },
136
+ },
137
+ "host.openInfo": {
138
+ v: 1,
139
+ id: "open-info-1",
140
+ type: "host.openInfo",
141
+ body: { id: "asset-1" },
142
+ },
143
+ "host.start": {
144
+ v: 1,
145
+ id: "start-1",
146
+ type: "host.start",
147
+ body: {},
148
+ },
149
+ "host.openBrowser": {
150
+ v: 1,
151
+ id: "browser-1",
152
+ type: "host.openBrowser",
153
+ body: {},
154
+ },
155
+ "host.clipboardWrite": { v: 1, id: "clipboard-1", type: "host.clipboardWrite", body: { text: "hello" } },
156
+ "host.download": { v: 1, id: "download-1", type: "host.download", body: { filename: "note.md", mimeType: "text/markdown;charset=utf-8", content: { kind: "text", text: "hello" } } },
157
+ "host.openPopup": { v: 1, id: "popup-1", type: "host.openPopup", body: { url: "https://example.com/" } },
158
+ "host.render": {
159
+ v: 1,
160
+ id: "render-1",
161
+ type: "host.render",
162
+ body: {
163
+ format: "pdf",
164
+ document: {
165
+ version: 1,
166
+ blocks: [{ type: "paragraph", inlines: [{ type: "text", text: "Hello" }] }],
167
+ },
168
+ name: "Note",
169
+ },
170
+ },
171
+ "doc.append": {
172
+ v: 1,
173
+ id: "append-1",
174
+ type: "doc.append",
175
+ body: { assetId: asset.id, update: "AA==" },
176
+ },
177
+ "chrome.submit": {
178
+ v: 1,
179
+ id: "chrome-1",
180
+ type: "chrome.submit",
181
+ body: {
182
+ contributes: {
183
+ commands: [{ id: "editor.undo", title: "Undo" }],
184
+ menus: [{ path: ["edit"], commandId: "editor.undo" }],
185
+ keybindings: [{ commandId: "editor.undo", key: "Mod+Z" }],
186
+ },
187
+ layout: {
188
+ root: "body",
189
+ elements: {
190
+ body: {
191
+ type: "Panel",
192
+ props: { contentId: "body" },
193
+ },
194
+ back: {
195
+ type: "ToolbarButton",
196
+ props: { commandId: "editor.undo", icon: "arrow-back-up" },
197
+ },
198
+ },
199
+ },
200
+ titles: { body: "Body" },
201
+ },
202
+ },
203
+ } satisfies { [Type in EditorRequest["type"]]: Extract<EditorRequest, { type: Type }> };
204
+
205
+ export const successes = {
206
+ "asset.rename": { v: 1, id: "rename-1", ok: true, body: { name: "notes" } },
207
+ "asset.read": { v: 1, id: "read-1", ok: true, body: { asset, payload: { body: "Note" }, fileUrl: null } },
208
+ "layout.load": { v: 1, id: "layout-load-1", ok: true, body: { layout: { panels: { body: { visible: true, size: "50%" } } } } },
209
+ "layout.save": { v: 1, id: "layout-save-1", ok: true, body: {} },
210
+ "asset.list": {
211
+ v: 1,
212
+ id: "list-1",
213
+ ok: true,
214
+ body: [asset],
215
+ },
216
+ "asset.listRevisions": {
217
+ v: 1,
218
+ id: "revisions-1",
219
+ ok: true,
220
+ body: [revision],
221
+ },
222
+ "asset.getComposition": {
223
+ v: 1,
224
+ id: "composition-1",
225
+ ok: true,
226
+ body: composition,
227
+ },
228
+ "asset.getPublication": {
229
+ v: 1,
230
+ id: "publication-get-1",
231
+ ok: true,
232
+ body: publication,
233
+ },
234
+ "asset.confirmBundle": {
235
+ v: 1,
236
+ id: "confirm-1",
237
+ ok: true,
238
+ body: confirmed,
239
+ },
240
+ "asset.putPublication": {
241
+ v: 1,
242
+ id: "publication-put-1",
243
+ ok: true,
244
+ body: publication,
245
+ },
246
+ "host.pick": {
247
+ v: 1,
248
+ id: "pick-1",
249
+ ok: true,
250
+ body: { cancelled: false, assets: [asset] },
251
+ },
252
+ "host.openAsset": {
253
+ v: 1,
254
+ id: "open-asset-1",
255
+ ok: true,
256
+ body: {},
257
+ },
258
+ "host.openInfo": {
259
+ v: 1,
260
+ id: "open-info-1",
261
+ ok: true,
262
+ body: {},
263
+ },
264
+ "host.start": {
265
+ v: 1,
266
+ id: "start-1",
267
+ ok: true,
268
+ body: {},
269
+ },
270
+ "host.openBrowser": {
271
+ v: 1,
272
+ id: "browser-1",
273
+ ok: true,
274
+ body: {},
275
+ },
276
+ "host.clipboardWrite": { v: 1, id: "clipboard-1", ok: true, body: {} },
277
+ "host.download": { v: 1, id: "download-1", ok: true, body: {} },
278
+ "host.openPopup": { v: 1, id: "popup-1", ok: true, body: {} },
279
+ "host.render": { v: 1, id: "render-1", ok: true, body: { url: "https://example.com/Note.pdf?download=1" } },
280
+ "doc.append": {
281
+ v: 1,
282
+ id: "append-1",
283
+ ok: true,
284
+ body: {},
285
+ },
286
+ "chrome.submit": {
287
+ v: 1,
288
+ id: "chrome-1",
289
+ ok: true,
290
+ body: {},
291
+ },
292
+ } satisfies { [Type in EditorRequest["type"]]: EditorSuccess<Type> };
293
+
294
+ export const cancelledPick = {
295
+ v: 1,
296
+ id: "pick-1",
297
+ ok: true,
298
+ body: { cancelled: true },
299
+ } satisfies EditorSuccess<"host.pick">;
300
+
301
+ export const failure = {
302
+ v: 1,
303
+ id: "pick-1",
304
+ ok: false,
305
+ code: "version",
306
+ } satisfies EditorFailure;
307
+
308
+ export const session = {
309
+ asset: { id: asset.id, type: asset.type, name: asset.name },
310
+ mode: "edit",
311
+ data: { text: "hello" },
312
+ syncStatus: "live",
313
+ } satisfies EditorSession;
314
+
315
+ export const events = {
316
+ "file.import": { v: 1, type: "file.import", body: { name: "notes.md", data: "" } },
317
+ session: {
318
+ v: 1,
319
+ type: "session",
320
+ body: session,
321
+ },
322
+ access: {
323
+ v: 1,
324
+ type: "access",
325
+ body: { canManage: true },
326
+ },
327
+ theme: {
328
+ v: 1,
329
+ type: "theme",
330
+ body: { theme: "dark" },
331
+ },
332
+ "doc.update": {
333
+ v: 1,
334
+ type: "doc.update",
335
+ body: { assetId: asset.id, update: "AA==" },
336
+ },
337
+ "host.createRequested": {
338
+ v: 1,
339
+ type: "host.createRequested",
340
+ },
341
+ "command.invoke": {
342
+ v: 1,
343
+ type: "command.invoke",
344
+ body: { commandId: "editor.copy" },
345
+ },
346
+ "command.shortcut": {
347
+ v: 1,
348
+ type: "command.shortcut",
349
+ body: { key: "Mod+Z", commandId: "editor.undo" },
350
+ },
351
+ "command.state": {
352
+ v: 1,
353
+ type: "command.state",
354
+ body: {
355
+ id: "editor.copy",
356
+ visible: true,
357
+ disabled: false,
358
+ pressed: false,
359
+ label: "Copy",
360
+ },
361
+ },
362
+ } satisfies { [Type in EditorEvent["type"]]: Extract<EditorEvent, { type: Type }> };
363
+
364
+ export const idleSession = {
365
+ v: 1,
366
+ type: "session",
367
+ body: {
368
+ asset: null,
369
+ mode: "idle",
370
+ data: null,
371
+ syncStatus: "offline",
372
+ },
373
+ } satisfies Extract<EditorEvent, { type: "session" }>;
374
+
375
+ export const access = {
376
+ canManage: false,
377
+ } satisfies EditorAccess;
@@ -0,0 +1,57 @@
1
+ import { getWorkspaceHostUrl } from "@moloodev/platform";
2
+
3
+ type EditorOriginDroppedHeader =
4
+ | "set-cookie"
5
+ | "service-worker-allowed";
6
+
7
+ export type EditorOriginHeaderPolicy = {
8
+ readonly "content-security-policy": string;
9
+ readonly "x-content-type-options": "nosniff";
10
+ readonly drop: readonly EditorOriginDroppedHeader[];
11
+ };
12
+
13
+ export function editorOriginHeaders(input: {
14
+ readonly parent: string | null;
15
+ readonly verifiedOrigins: readonly string[];
16
+ }): EditorOriginHeaderPolicy {
17
+ return {
18
+ "content-security-policy": `sandbox allow-scripts; frame-ancestors ${frameAncestor(input.parent, input.verifiedOrigins)}; font-src https://ui.moloo.dev`,
19
+ "x-content-type-options": "nosniff",
20
+ drop: ["set-cookie", "service-worker-allowed"],
21
+ };
22
+ }
23
+
24
+ export function allowedFrameAncestor(
25
+ parent: string | null,
26
+ verifiedOrigins: readonly string[],
27
+ ): string | null {
28
+ if (parent !== null && isBareOrigin(parent) && allowed(parent, verifiedOrigins)) {
29
+ return parent;
30
+ }
31
+ return null;
32
+ }
33
+
34
+ function frameAncestor(
35
+ parent: string | null,
36
+ verifiedOrigins: readonly string[],
37
+ ): string {
38
+ return allowedFrameAncestor(parent, verifiedOrigins) ?? "'none'";
39
+ }
40
+
41
+ function allowed(parent: string, verifiedOrigins: readonly string[]): boolean {
42
+ if (
43
+ parent === getWorkspaceHostUrl("production") ||
44
+ parent === getWorkspaceHostUrl("development")
45
+ ) {
46
+ return true;
47
+ }
48
+ return verifiedOrigins.includes(parent);
49
+ }
50
+
51
+ function isBareOrigin(value: string): boolean {
52
+ try {
53
+ return new URL(value).origin === value;
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
@@ -0,0 +1,10 @@
1
+ export { inspectPrint } from "./inspect";
2
+ export {
3
+ PRINT_BYTES_MAX,
4
+ PRINT_SCHEMA_VERSION,
5
+ documentSchema,
6
+ type Block,
7
+ type Inline,
8
+ type Mark,
9
+ type PrintDocument,
10
+ } from "./schema";
@@ -0,0 +1,16 @@
1
+ import { PRINT_BYTES_MAX, documentSchema, type PrintDocument } from "./schema";
2
+
3
+ type Inspection =
4
+ | { ok: true; document: PrintDocument }
5
+ | { ok: false; code: "invalid" | "too-large" };
6
+
7
+ const utf8 = new TextEncoder();
8
+
9
+ export function inspectPrint(value: unknown): Inspection {
10
+ const parsed = documentSchema.safeParse(value);
11
+ if (!parsed.success) return { ok: false, code: "invalid" };
12
+ if (utf8.encode(JSON.stringify(parsed.data)).byteLength > PRINT_BYTES_MAX) {
13
+ return { ok: false, code: "too-large" };
14
+ }
15
+ return { ok: true, document: parsed.data };
16
+ }
@@ -0,0 +1,122 @@
1
+ import { z } from "zod";
2
+
3
+ export const PRINT_SCHEMA_VERSION = 1;
4
+
5
+ /** UTF-8 byte length of `JSON.stringify` of the document. */
6
+ export const PRINT_BYTES_MAX = 4 * 1024 * 1024;
7
+
8
+ export type Mark = "bold" | "italic" | "strike" | "code";
9
+
10
+ export type Inline =
11
+ | { type: "text"; text: string; marks?: Mark[] }
12
+ | {
13
+ type: "link";
14
+ href: string;
15
+ inlines: (
16
+ | { type: "text"; text: string; marks?: Mark[] }
17
+ | { type: "break" }
18
+ )[];
19
+ }
20
+ | { type: "break" };
21
+
22
+ export type Block =
23
+ | { type: "heading"; level: 1 | 2 | 3 | 4 | 5 | 6; inlines: Inline[] }
24
+ | { type: "paragraph"; inlines: Inline[] }
25
+ | {
26
+ type: "list";
27
+ ordered: boolean;
28
+ items: { checked?: boolean; inlines: Inline[] }[];
29
+ }
30
+ | { type: "quote"; inlines: Inline[] }
31
+ | { type: "code"; text: string }
32
+ | { type: "table"; rows: { cells: Inline[][] }[] }
33
+ | { type: "rule" };
34
+
35
+ export type PrintDocument = {
36
+ version: typeof PRINT_SCHEMA_VERSION;
37
+ blocks: Block[];
38
+ };
39
+
40
+ const markSchema: z.ZodType<Mark> = z.enum([
41
+ "bold",
42
+ "italic",
43
+ "strike",
44
+ "code",
45
+ ]);
46
+
47
+ const headingLevelSchema: z.ZodType<1 | 2 | 3 | 4 | 5 | 6> = z.union([
48
+ z.literal(1),
49
+ z.literal(2),
50
+ z.literal(3),
51
+ z.literal(4),
52
+ z.literal(5),
53
+ z.literal(6),
54
+ ]);
55
+
56
+ const textSchema = z.strictObject({
57
+ type: z.literal("text"),
58
+ text: z.string(),
59
+ marks: z.array(markSchema).exactOptional(),
60
+ });
61
+
62
+ const breakSchema = z.strictObject({
63
+ type: z.literal("break"),
64
+ });
65
+
66
+ const inlineSchema: z.ZodType<Inline> = z.discriminatedUnion("type", [
67
+ textSchema,
68
+ z.strictObject({
69
+ type: z.literal("link"),
70
+ href: z.string().regex(/^(https|http|mailto):/i),
71
+ inlines: z.array(z.discriminatedUnion("type", [textSchema, breakSchema])),
72
+ }),
73
+ breakSchema,
74
+ ]);
75
+
76
+ const inlinesSchema = z.array(inlineSchema);
77
+
78
+ const blockSchema: z.ZodType<Block> = z.discriminatedUnion("type", [
79
+ z.strictObject({
80
+ type: z.literal("heading"),
81
+ level: headingLevelSchema,
82
+ inlines: inlinesSchema,
83
+ }),
84
+ z.strictObject({
85
+ type: z.literal("paragraph"),
86
+ inlines: inlinesSchema,
87
+ }),
88
+ z.strictObject({
89
+ type: z.literal("list"),
90
+ ordered: z.boolean(),
91
+ items: z.array(
92
+ z.strictObject({
93
+ checked: z.boolean().exactOptional(),
94
+ inlines: inlinesSchema,
95
+ }),
96
+ ),
97
+ }),
98
+ z.strictObject({
99
+ type: z.literal("quote"),
100
+ inlines: inlinesSchema,
101
+ }),
102
+ z.strictObject({
103
+ type: z.literal("code"),
104
+ text: z.string(),
105
+ }),
106
+ z.strictObject({
107
+ type: z.literal("table"),
108
+ rows: z.array(
109
+ z.strictObject({
110
+ cells: z.array(inlinesSchema),
111
+ }),
112
+ ),
113
+ }),
114
+ z.strictObject({
115
+ type: z.literal("rule"),
116
+ }),
117
+ ]);
118
+
119
+ export const documentSchema: z.ZodType<PrintDocument> = z.strictObject({
120
+ version: z.literal(PRINT_SCHEMA_VERSION),
121
+ blocks: z.array(blockSchema),
122
+ });
@@ -0,0 +1,19 @@
1
+ export * from "./protocol";
2
+ export * from "./channel";
3
+ export { editorFrameAttributes } from "./frame-attributes";
4
+ export type {
5
+ EditorAccess,
6
+ EditorAsset,
7
+ EditorEvent,
8
+ EditorFailure,
9
+ EditorLayoutValues,
10
+ EditorOperation,
11
+ EditorRequest,
12
+ EditorRequestType,
13
+ EditorResponse,
14
+ EditorRevision,
15
+ EditorSession,
16
+ EditorSessionAsset,
17
+ EditorSuccess,
18
+ Json,
19
+ } from "./index";