@moloodev/editor-sdk 0.0.0-stage → 0.2.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/package.json +62 -3
- package/src/channel.ts +287 -0
- package/src/chrome-manifest.ts +111 -0
- package/src/commands/clipboard/router.ts +99 -0
- package/src/commands/clipboard/types.ts +20 -0
- package/src/commands/history/stack.ts +53 -0
- package/src/commands/icons/catalog.ts +172 -0
- package/src/commands/index.ts +100 -0
- package/src/commands/keys/display.ts +16 -0
- package/src/commands/keys/normalize.ts +55 -0
- package/src/commands/keys/reserved.ts +62 -0
- package/src/commands/keys/validate.ts +77 -0
- package/src/commands/manifest/configuration.ts +59 -0
- package/src/commands/manifest/contribution-manifest-schema.ts +56 -0
- package/src/commands/manifest/editor-document.ts +501 -0
- package/src/commands/manifest/ids.ts +2 -0
- package/src/commands/manifest/merge.ts +215 -0
- package/src/commands/manifest/types.ts +113 -0
- package/src/commands/manifest/validate-manifest.ts +45 -0
- package/src/commands/react/context.tsx +249 -0
- package/src/commands/react/hotkey-defaults.ts +11 -0
- package/src/commands/react/scope-context.tsx +31 -0
- package/src/commands/react/scope-provider.tsx +123 -0
- package/src/commands/react/store.ts +182 -0
- package/src/commands/registry/create.ts +55 -0
- package/src/commands/registry/types.ts +12 -0
- package/src/commands/when/evaluate.ts +80 -0
- package/src/commands/when/index.ts +19 -0
- package/src/commands/when/parse.ts +276 -0
- package/src/commands/when/types.ts +24 -0
- package/src/commands/when/validate.ts +20 -0
- package/src/crdt/awareness.ts +29 -0
- package/src/crdt/bytes.ts +26 -0
- package/src/crdt/connect.ts +285 -0
- package/src/crdt/diff.ts +86 -0
- package/src/crdt/doc.ts +67 -0
- package/src/crdt/front-matter.ts +45 -0
- package/src/crdt/index.ts +76 -0
- package/src/crdt/persist.ts +40 -0
- package/src/crdt/protocol.ts +119 -0
- package/src/crdt/shared.ts +104 -0
- package/src/crdt/text-body.ts +125 -0
- package/src/crdt/undo.ts +59 -0
- package/src/crdt/vite-plugin.ts +42 -0
- package/src/crdt/yjs.ts +16 -0
- package/src/editor-common.ts +160 -0
- package/src/editor-id.ts +56 -0
- package/src/frame-attributes.ts +9 -0
- package/src/index.ts +229 -0
- package/src/json-schema.ts +13 -0
- package/src/layout/bind-toolbar.ts +60 -0
- package/src/layout/catalog.ts +82 -0
- package/src/layout/chrome/command-affordances.ts +47 -0
- package/src/layout/chrome/command-layout-state.ts +42 -0
- package/src/layout/chrome/editor-menu.tsx +358 -0
- package/src/layout/chrome/editor-shortcut-keys.tsx +27 -0
- package/src/layout/chrome/menu-styles.ts +3 -0
- package/src/layout/chrome/mid-menu-nodes.ts +27 -0
- package/src/layout/chrome/use-editor-command-affordances.ts +33 -0
- package/src/layout/chrome/visible-menu-leaves.ts +15 -0
- package/src/layout/content-error-notice.tsx +31 -0
- package/src/layout/define-editor-layout.ts +60 -0
- package/src/layout/define-editor-layout.types.ts +57 -0
- package/src/layout/doc-undo-bridge.tsx +22 -0
- package/src/layout/dock-zones.tsx +61 -0
- package/src/layout/drop.ts +39 -0
- package/src/layout/editor-layout.tsx +287 -0
- package/src/layout/editor-loading.tsx +23 -0
- package/src/layout/frame-layout-binding.tsx +74 -0
- package/src/layout/frame.ts +23 -0
- package/src/layout/hide.ts +103 -0
- package/src/layout/index.ts +14 -0
- package/src/layout/layout-binding.tsx +42 -0
- package/src/layout/layout-storage-key.ts +6 -0
- package/src/layout/layout-values.ts +48 -0
- package/src/layout/mutate.ts +486 -0
- package/src/layout/nesting-context.tsx +20 -0
- package/src/layout/panel-header-action.tsx +29 -0
- package/src/layout/panel-header.tsx +168 -0
- package/src/layout/panel-hide-menu.tsx +6 -0
- package/src/layout/panel-menu.tsx +85 -0
- package/src/layout/panel-section.tsx +114 -0
- package/src/layout/panel-size.ts +94 -0
- package/src/layout/panel-title.tsx +5 -0
- package/src/layout/registry.tsx +333 -0
- package/src/layout/restore-panel.ts +26 -0
- package/src/layout/slots-context.tsx +189 -0
- package/src/layout/tab-button.tsx +60 -0
- package/src/layout/toolbar-scroll.ts +22 -0
- package/src/layout/toolbar.tsx +168 -0
- package/src/layout/types.ts +41 -0
- package/src/layout/use-collapsed-sections.ts +50 -0
- package/src/layout/validate-layout-spec.ts +143 -0
- package/src/message-samples.ts +377 -0
- package/src/origin-headers.ts +57 -0
- package/src/print/index.ts +10 -0
- package/src/print/inspect.ts +16 -0
- package/src/print/schema.ts +122 -0
- package/src/protocol-entry.ts +19 -0
- package/src/protocol.ts +471 -0
- package/src/render-result.ts +25 -0
- package/src/view/editor-chrome.ts +28 -0
- package/src/view/hooks.ts +260 -0
- package/src/view/mount-editor-view.ts +36 -0
- package/src/view/port-binding.ts +127 -0
- package/src/view/port-commands.ts +36 -0
- package/src/view/port.ts +35 -0
- package/src/view/theme-class.ts +11 -0
- package/src/view.ts +313 -0
- 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,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";
|